Auto merge of #108052 - matthiaskrgr:rollup-p6r6rnl, r=matthiaskrgr
Rollup of 10 pull requests Successful merges: - #103478 ( Suggest fix for misplaced generic params on fn item #103366 ) - #107739 (Check for overflow in evaluate_canonical_goal) - #108003 (Avoid ICE when the generic_span is empty) - #108016 ("Basic usage" is redundant for there is just one example) - #108023 (Shrink size of array benchmarks) - #108024 (add message to update Cargo.toml when x is changed) - #108025 (rustdoc: add more tooltips to intra-doc links) - #108029 (s/eval_usize/eval_target_usize/ for clarity) - #108035 (Avoid using a dead email address as the main email address) - #108038 (Remove needless supertrait constraints from Interner projections) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
6e0115778b
87 changed files with 917 additions and 442 deletions
24
.mailmap
24
.mailmap
|
@ -419,18 +419,18 @@ Nixon Enraght-Moony <nixon.emoony@gmail.com>
|
|||
NODA Kai <nodakai@gmail.com>
|
||||
oliver <16816606+o752d@users.noreply.github.com>
|
||||
Oliver Middleton <olliemail27@gmail.com> <ollie27@users.noreply.github.com>
|
||||
Oliver Scherer <oliver.schneider@kit.edu> <git-spam-no-reply9815368754983@oli-obk.de>
|
||||
Oliver Scherer <oliver.schneider@kit.edu> <git-spam9815368754983@oli-obk.de>
|
||||
Oliver Scherer <oliver.schneider@kit.edu> <github333195615777966@oli-obk.de>
|
||||
Oliver Scherer <oliver.schneider@kit.edu> <rust19446194516@oli-obk.de>
|
||||
Oliver Scherer <oliver.schneider@kit.edu> <git-no-reply-9879165716479413131@oli-obk.de>
|
||||
Oliver Scherer <oliver.schneider@kit.edu> <git1984941651981@oli-obk.de>
|
||||
Oliver Scherer <oliver.schneider@kit.edu> <github35764891676564198441@oli-obk.de>
|
||||
Oliver Scherer <oliver.schneider@kit.edu> <github6541940@oli-obk.de>
|
||||
Oliver Scherer <oliver.schneider@kit.edu> <oli-obk@users.noreply.github.com>
|
||||
Oliver Scherer <oliver.schneider@kit.edu> <public.oliver.schneider@kit.edu>
|
||||
Oliver Scherer <oliver.schneider@kit.edu> <obk8176014uqher834@olio-obk.de>
|
||||
Oliver Scherer <oliver.schneider@kit.edu>
|
||||
Oliver Scherer <oli-obk@users.noreply.github.com> <git-spam-no-reply9815368754983@oli-obk.de>
|
||||
Oliver Scherer <oli-obk@users.noreply.github.com> <git-spam9815368754983@oli-obk.de>
|
||||
Oliver Scherer <oli-obk@users.noreply.github.com> <github333195615777966@oli-obk.de>
|
||||
Oliver Scherer <oli-obk@users.noreply.github.com> <rust19446194516@oli-obk.de>
|
||||
Oliver Scherer <oli-obk@users.noreply.github.com> <git-no-reply-9879165716479413131@oli-obk.de>
|
||||
Oliver Scherer <oli-obk@users.noreply.github.com> <git1984941651981@oli-obk.de>
|
||||
Oliver Scherer <oli-obk@users.noreply.github.com> <github35764891676564198441@oli-obk.de>
|
||||
Oliver Scherer <oli-obk@users.noreply.github.com> <github6541940@oli-obk.de>
|
||||
Oliver Scherer <oli-obk@users.noreply.github.com> <public.oliver.schneider@kit.edu>
|
||||
Oliver Scherer <oli-obk@users.noreply.github.com> <oliver.schneider@kit.edu>
|
||||
Oliver Scherer <oli-obk@users.noreply.github.com> <obk8176014uqher834@olio-obk.de>
|
||||
Oliver Scherer <oli-obk@users.noreply.github.com>
|
||||
Ömer Sinan Ağacan <omeragacan@gmail.com>
|
||||
Ophir LOJKINE <pere.jobs@gmail.com>
|
||||
Ožbolt Menegatti <ozbolt.menegatti@gmail.com> gareins <ozbolt.menegatti@gmail.com>
|
||||
|
|
|
@ -1782,7 +1782,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// than 1.
|
||||
// If the length is larger than 1, the repeat expression will need to copy the
|
||||
// element, so we require the `Copy` trait.
|
||||
if len.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
|
||||
if len.try_eval_target_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
|
||||
match operand {
|
||||
Operand::Copy(..) | Operand::Constant(..) => {
|
||||
// These are always okay: direct use of a const, or a value that can evidently be copied.
|
||||
|
|
|
@ -857,7 +857,7 @@ fn codegen_stmt<'tcx>(
|
|||
fn codegen_array_len<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, place: CPlace<'tcx>) -> Value {
|
||||
match *place.layout().ty.kind() {
|
||||
ty::Array(_elem_ty, len) => {
|
||||
let len = fx.monomorphize(len).eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64;
|
||||
let len = fx.monomorphize(len).eval_target_usize(fx.tcx, ParamEnv::reveal_all()) as i64;
|
||||
fx.bcx.ins().iconst(fx.pointer_type, len)
|
||||
}
|
||||
ty::Slice(_elem_ty) => {
|
||||
|
|
|
@ -141,7 +141,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
let idx_ty = fx.monomorphize(idx.ty(fx.mir, fx.tcx));
|
||||
match idx_ty.kind() {
|
||||
ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => len
|
||||
.try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all())
|
||||
.try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all())
|
||||
.unwrap_or_else(|| {
|
||||
span_bug!(span, "could not evaluate shuffle index array length")
|
||||
})
|
||||
|
@ -735,7 +735,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {}
|
||||
ty::Array(elem, len)
|
||||
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
|
||||
&& len.try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all())
|
||||
&& len.try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all())
|
||||
== Some(expected_bytes) => {}
|
||||
_ => {
|
||||
fx.tcx.sess.span_fatal(
|
||||
|
|
|
@ -24,7 +24,7 @@ pub(crate) fn unsized_info<'tcx>(
|
|||
(&ty::Array(_, len), &ty::Slice(_)) => fx
|
||||
.bcx
|
||||
.ins()
|
||||
.iconst(fx.pointer_type, len.eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64),
|
||||
.iconst(fx.pointer_type, len.eval_target_usize(fx.tcx, ParamEnv::reveal_all()) as i64),
|
||||
(
|
||||
&ty::Dynamic(ref data_a, _, src_dyn_kind),
|
||||
&ty::Dynamic(ref data_b, _, target_dyn_kind),
|
||||
|
|
|
@ -564,8 +564,8 @@ impl<'tcx> CPlace<'tcx> {
|
|||
CPlaceInner::Var(_local, var) => {
|
||||
if let ty::Array(element, len) = dst_layout.ty.kind() {
|
||||
// Can only happen for vector types
|
||||
let len =
|
||||
u32::try_from(len.eval_usize(fx.tcx, ParamEnv::reveal_all())).unwrap();
|
||||
let len = u32::try_from(len.eval_target_usize(fx.tcx, ParamEnv::reveal_all()))
|
||||
.unwrap();
|
||||
let vector_ty = fx.clif_type(*element).unwrap().by(len).unwrap();
|
||||
|
||||
let data = match from.0 {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::cmp::Ordering;
|
||||
|
||||
use gccjit::{BinaryOp, RValue, Type, ToRValue};
|
||||
use gccjit::{BinaryOp, RValue, ToRValue, Type};
|
||||
use rustc_codegen_ssa::base::compare_simd_types;
|
||||
use rustc_codegen_ssa::common::TypeKind;
|
||||
use rustc_codegen_ssa::mir::operand::OperandRef;
|
||||
|
@ -10,52 +10,57 @@ use rustc_hir as hir;
|
|||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::layout::HasTyCtxt;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
use rustc_target::abi::Align;
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::errors::{
|
||||
InvalidMonomorphizationInvalidFloatVector,
|
||||
InvalidMonomorphizationNotFloat,
|
||||
InvalidMonomorphizationUnrecognized,
|
||||
InvalidMonomorphizationExpectedSignedUnsigned,
|
||||
InvalidMonomorphizationUnsupportedElement,
|
||||
InvalidMonomorphizationInvalidBitmask,
|
||||
InvalidMonomorphizationSimdShuffle,
|
||||
InvalidMonomorphizationExpectedSimd,
|
||||
InvalidMonomorphizationMaskType,
|
||||
InvalidMonomorphizationReturnLength,
|
||||
InvalidMonomorphizationReturnLengthInputType,
|
||||
InvalidMonomorphizationReturnElement,
|
||||
InvalidMonomorphizationReturnType,
|
||||
InvalidMonomorphizationInsertedType,
|
||||
InvalidMonomorphizationReturnIntegerType,
|
||||
InvalidMonomorphizationMismatchedLengths,
|
||||
InvalidMonomorphizationUnsupportedCast,
|
||||
InvalidMonomorphizationUnsupportedOperation
|
||||
InvalidMonomorphizationExpectedSignedUnsigned, InvalidMonomorphizationExpectedSimd,
|
||||
InvalidMonomorphizationInsertedType, InvalidMonomorphizationInvalidBitmask,
|
||||
InvalidMonomorphizationInvalidFloatVector, InvalidMonomorphizationMaskType,
|
||||
InvalidMonomorphizationMismatchedLengths, InvalidMonomorphizationNotFloat,
|
||||
InvalidMonomorphizationReturnElement, InvalidMonomorphizationReturnIntegerType,
|
||||
InvalidMonomorphizationReturnLength, InvalidMonomorphizationReturnLengthInputType,
|
||||
InvalidMonomorphizationReturnType, InvalidMonomorphizationSimdShuffle,
|
||||
InvalidMonomorphizationUnrecognized, InvalidMonomorphizationUnsupportedCast,
|
||||
InvalidMonomorphizationUnsupportedElement, InvalidMonomorphizationUnsupportedOperation,
|
||||
};
|
||||
use crate::intrinsic;
|
||||
|
||||
pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result<RValue<'gcc>, ()> {
|
||||
pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
||||
bx: &mut Builder<'a, 'gcc, 'tcx>,
|
||||
name: Symbol,
|
||||
callee_ty: Ty<'tcx>,
|
||||
args: &[OperandRef<'tcx, RValue<'gcc>>],
|
||||
ret_ty: Ty<'tcx>,
|
||||
llret_ty: Type<'gcc>,
|
||||
span: Span,
|
||||
) -> Result<RValue<'gcc>, ()> {
|
||||
// macros for error handling:
|
||||
macro_rules! return_error {
|
||||
($err:expr) => {
|
||||
{
|
||||
bx.sess().emit_err($err);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
($err:expr) => {{
|
||||
bx.sess().emit_err($err);
|
||||
return Err(());
|
||||
}};
|
||||
}
|
||||
macro_rules! require {
|
||||
($cond:expr, $err:expr) => {
|
||||
if !$cond {
|
||||
return_error!($err);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! require_simd {
|
||||
($ty: expr, $position: expr) => {
|
||||
require!($ty.is_simd(), InvalidMonomorphizationExpectedSimd { span, name, position: $position, found_ty: $ty })
|
||||
require!(
|
||||
$ty.is_simd(),
|
||||
InvalidMonomorphizationExpectedSimd {
|
||||
span,
|
||||
name,
|
||||
position: $position,
|
||||
found_ty: $ty
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -77,7 +82,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
|
||||
ty::Array(elem, len)
|
||||
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
|
||||
&& len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
|
||||
&& len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
|
||||
== Some(expected_bytes) =>
|
||||
{
|
||||
let place = PlaceRef::alloca(bx, args[0].layout);
|
||||
|
@ -86,9 +91,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty));
|
||||
bx.load(int_ty, ptr, Align::ONE)
|
||||
}
|
||||
_ => return_error!(
|
||||
InvalidMonomorphizationInvalidBitmask { span, name, ty: mask_ty, expected_int_bits, expected_bytes }
|
||||
),
|
||||
_ => return_error!(InvalidMonomorphizationInvalidBitmask {
|
||||
span,
|
||||
name,
|
||||
ty: mask_ty,
|
||||
expected_int_bits,
|
||||
expected_bytes
|
||||
}),
|
||||
};
|
||||
|
||||
let arg1 = args[1].immediate();
|
||||
|
@ -129,11 +138,18 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
|
||||
require!(
|
||||
in_len == out_len,
|
||||
InvalidMonomorphizationReturnLengthInputType { span, name, in_len, in_ty, ret_ty, out_len }
|
||||
InvalidMonomorphizationReturnLengthInputType {
|
||||
span,
|
||||
name,
|
||||
in_len,
|
||||
in_ty,
|
||||
ret_ty,
|
||||
out_len
|
||||
}
|
||||
);
|
||||
require!(
|
||||
bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
|
||||
InvalidMonomorphizationReturnIntegerType {span, name, ret_ty, out_ty}
|
||||
InvalidMonomorphizationReturnIntegerType { span, name, ret_ty, out_ty }
|
||||
);
|
||||
|
||||
return Ok(compare_simd_types(
|
||||
|
@ -147,26 +163,26 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
}
|
||||
|
||||
if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") {
|
||||
let n: u64 =
|
||||
if stripped.is_empty() {
|
||||
// Make sure this is actually an array, since typeck only checks the length-suffixed
|
||||
// version of this intrinsic.
|
||||
match args[2].layout.ty.kind() {
|
||||
ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
|
||||
len.try_eval_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| {
|
||||
span_bug!(span, "could not evaluate shuffle index array length")
|
||||
})
|
||||
}
|
||||
_ => return_error!(
|
||||
InvalidMonomorphizationSimdShuffle { span, name, ty: args[2].layout.ty }
|
||||
),
|
||||
let n: u64 = if stripped.is_empty() {
|
||||
// Make sure this is actually an array, since typeck only checks the length-suffixed
|
||||
// version of this intrinsic.
|
||||
match args[2].layout.ty.kind() {
|
||||
ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
|
||||
len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(
|
||||
|| span_bug!(span, "could not evaluate shuffle index array length"),
|
||||
)
|
||||
}
|
||||
_ => return_error!(InvalidMonomorphizationSimdShuffle {
|
||||
span,
|
||||
name,
|
||||
ty: args[2].layout.ty
|
||||
}),
|
||||
}
|
||||
else {
|
||||
stripped.parse().unwrap_or_else(|_| {
|
||||
span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
|
||||
})
|
||||
};
|
||||
} else {
|
||||
stripped.parse().unwrap_or_else(|_| {
|
||||
span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
|
||||
})
|
||||
};
|
||||
|
||||
require_simd!(ret_ty, "return");
|
||||
|
||||
|
@ -182,14 +198,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
|
||||
let vector = args[2].immediate();
|
||||
|
||||
return Ok(bx.shuffle_vector(
|
||||
args[0].immediate(),
|
||||
args[1].immediate(),
|
||||
vector,
|
||||
));
|
||||
return Ok(bx.shuffle_vector(args[0].immediate(), args[1].immediate(), vector));
|
||||
}
|
||||
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
if name == sym::simd_insert {
|
||||
require!(
|
||||
in_elem == arg_tys[2],
|
||||
|
@ -205,44 +217,44 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
// not be an l-value. So, call a builtin to set the element.
|
||||
// TODO(antoyo): perhaps we could create a new vector or maybe there's a GIMPLE instruction for that?
|
||||
// TODO(antoyo): don't use target specific builtins here.
|
||||
let func_name =
|
||||
match in_len {
|
||||
2 => {
|
||||
if element_type == bx.i64_type {
|
||||
"__builtin_ia32_vec_set_v2di"
|
||||
}
|
||||
else {
|
||||
unimplemented!();
|
||||
}
|
||||
},
|
||||
4 => {
|
||||
if element_type == bx.i32_type {
|
||||
"__builtin_ia32_vec_set_v4si"
|
||||
}
|
||||
else {
|
||||
unimplemented!();
|
||||
}
|
||||
},
|
||||
8 => {
|
||||
if element_type == bx.i16_type {
|
||||
"__builtin_ia32_vec_set_v8hi"
|
||||
}
|
||||
else {
|
||||
unimplemented!();
|
||||
}
|
||||
},
|
||||
_ => unimplemented!("Len: {}", in_len),
|
||||
};
|
||||
let func_name = match in_len {
|
||||
2 => {
|
||||
if element_type == bx.i64_type {
|
||||
"__builtin_ia32_vec_set_v2di"
|
||||
} else {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
if element_type == bx.i32_type {
|
||||
"__builtin_ia32_vec_set_v4si"
|
||||
} else {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
8 => {
|
||||
if element_type == bx.i16_type {
|
||||
"__builtin_ia32_vec_set_v8hi"
|
||||
} else {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
_ => unimplemented!("Len: {}", in_len),
|
||||
};
|
||||
let builtin = bx.context.get_target_builtin_function(func_name);
|
||||
let param1_type = builtin.get_param(0).to_rvalue().get_type();
|
||||
// TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
|
||||
let vector = bx.cx.bitcast_if_needed(vector, param1_type);
|
||||
let result = bx.context.new_call(None, builtin, &[vector, value, bx.context.new_cast(None, index, bx.int_type)]);
|
||||
let result = bx.context.new_call(
|
||||
None,
|
||||
builtin,
|
||||
&[vector, value, bx.context.new_cast(None, index, bx.int_type)],
|
||||
);
|
||||
// TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
|
||||
return Ok(bx.context.new_bitcast(None, result, vector.get_type()));
|
||||
}
|
||||
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
if name == sym::simd_extract {
|
||||
require!(
|
||||
ret_ty == in_elem,
|
||||
|
@ -273,7 +285,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
|
||||
require!(
|
||||
in_len == out_len,
|
||||
InvalidMonomorphizationReturnLengthInputType { span, name, in_len, in_ty, ret_ty, out_len }
|
||||
InvalidMonomorphizationReturnLengthInputType {
|
||||
span,
|
||||
name,
|
||||
in_len,
|
||||
in_ty,
|
||||
ret_ty,
|
||||
out_len
|
||||
}
|
||||
);
|
||||
// casting cares about nominal type, not just structural type
|
||||
if in_elem == out_elem {
|
||||
|
@ -322,19 +341,27 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
|
||||
let cast_vec_element = |index| {
|
||||
let index = bx.context.new_rvalue_from_int(bx.int_type, index);
|
||||
bx.context.new_cast(None, bx.context.new_array_access(None, array, index).to_rvalue(), out_type)
|
||||
bx.context.new_cast(
|
||||
None,
|
||||
bx.context.new_array_access(None, array, index).to_rvalue(),
|
||||
out_type,
|
||||
)
|
||||
};
|
||||
|
||||
bx.context.new_rvalue_from_vector(None, vector_type, &[
|
||||
cast_vec_element(0),
|
||||
cast_vec_element(1),
|
||||
cast_vec_element(2),
|
||||
cast_vec_element(3),
|
||||
cast_vec_element(4),
|
||||
cast_vec_element(5),
|
||||
cast_vec_element(6),
|
||||
cast_vec_element(7),
|
||||
])
|
||||
bx.context.new_rvalue_from_vector(
|
||||
None,
|
||||
vector_type,
|
||||
&[
|
||||
cast_vec_element(0),
|
||||
cast_vec_element(1),
|
||||
cast_vec_element(2),
|
||||
cast_vec_element(3),
|
||||
cast_vec_element(4),
|
||||
cast_vec_element(5),
|
||||
cast_vec_element(6),
|
||||
cast_vec_element(7),
|
||||
],
|
||||
)
|
||||
};
|
||||
|
||||
match (in_style, out_style) {
|
||||
|
@ -385,9 +412,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
}
|
||||
_ => { /* Unsupported. Fallthrough. */ }
|
||||
}
|
||||
return_error!(
|
||||
InvalidMonomorphizationUnsupportedCast { span, name, in_ty, in_elem, ret_ty, out_elem }
|
||||
);
|
||||
return_error!(InvalidMonomorphizationUnsupportedCast {
|
||||
span,
|
||||
name,
|
||||
in_ty,
|
||||
in_elem,
|
||||
ret_ty,
|
||||
out_elem
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! arith_binary {
|
||||
|
@ -414,54 +446,60 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
args: &[OperandRef<'tcx, RValue<'gcc>>],
|
||||
) -> Result<RValue<'gcc>, ()> {
|
||||
macro_rules! return_error {
|
||||
($err:expr) => {
|
||||
{
|
||||
bx.sess().emit_err($err);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
($err:expr) => {{
|
||||
bx.sess().emit_err($err);
|
||||
return Err(());
|
||||
}};
|
||||
}
|
||||
let (elem_ty_str, elem_ty) =
|
||||
if let ty::Float(f) = in_elem.kind() {
|
||||
let elem_ty = bx.cx.type_float_from_ty(*f);
|
||||
match f.bit_width() {
|
||||
32 => ("f32", elem_ty),
|
||||
64 => ("f64", elem_ty),
|
||||
_ => {
|
||||
return_error!(InvalidMonomorphizationInvalidFloatVector { span, name, elem_ty: f.name_str(), vec_ty: in_ty });
|
||||
}
|
||||
let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() {
|
||||
let elem_ty = bx.cx.type_float_from_ty(*f);
|
||||
match f.bit_width() {
|
||||
32 => ("f32", elem_ty),
|
||||
64 => ("f64", elem_ty),
|
||||
_ => {
|
||||
return_error!(InvalidMonomorphizationInvalidFloatVector {
|
||||
span,
|
||||
name,
|
||||
elem_ty: f.name_str(),
|
||||
vec_ty: in_ty
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
return_error!(InvalidMonomorphizationNotFloat { span, name, ty: in_ty });
|
||||
};
|
||||
} else {
|
||||
return_error!(InvalidMonomorphizationNotFloat { span, name, ty: in_ty });
|
||||
};
|
||||
|
||||
let vec_ty = bx.cx.type_vector(elem_ty, in_len);
|
||||
|
||||
let (intr_name, fn_ty) =
|
||||
match name {
|
||||
sym::simd_ceil => ("ceil", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fabs => ("fabs", bx.type_func(&[vec_ty], vec_ty)), // TODO(antoyo): pand with 170141183420855150465331762880109871103
|
||||
sym::simd_fcos => ("cos", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fexp2 => ("exp2", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fexp => ("exp", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_flog10 => ("log10", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_flog2 => ("log2", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)),
|
||||
sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)),
|
||||
sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)),
|
||||
sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)),
|
||||
_ => return_error!(InvalidMonomorphizationUnrecognized { span, name })
|
||||
};
|
||||
let (intr_name, fn_ty) = match name {
|
||||
sym::simd_ceil => ("ceil", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fabs => ("fabs", bx.type_func(&[vec_ty], vec_ty)), // TODO(antoyo): pand with 170141183420855150465331762880109871103
|
||||
sym::simd_fcos => ("cos", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fexp2 => ("exp2", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fexp => ("exp", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_flog10 => ("log10", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_flog2 => ("log2", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)),
|
||||
sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)),
|
||||
sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)),
|
||||
sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)),
|
||||
_ => return_error!(InvalidMonomorphizationUnrecognized { span, name }),
|
||||
};
|
||||
let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
|
||||
let function = intrinsic::llvm::intrinsic(llvm_name, &bx.cx);
|
||||
let function: RValue<'gcc> = unsafe { std::mem::transmute(function) };
|
||||
let c = bx.call(fn_ty, None, function, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
|
||||
let c = bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
function,
|
||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||
None,
|
||||
);
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
|
@ -518,7 +556,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
simd_neg: Int => neg, Float => fneg;
|
||||
}
|
||||
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
if name == sym::simd_saturating_add || name == sym::simd_saturating_sub {
|
||||
let lhs = args[0].immediate();
|
||||
let rhs = args[1].immediate();
|
||||
|
@ -536,18 +574,23 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
});
|
||||
}
|
||||
};
|
||||
let builtin_name =
|
||||
match (signed, is_add, in_len, elem_width) {
|
||||
(true, true, 32, 8) => "__builtin_ia32_paddsb256", // TODO(antoyo): cast arguments to unsigned.
|
||||
(false, true, 32, 8) => "__builtin_ia32_paddusb256",
|
||||
(true, true, 16, 16) => "__builtin_ia32_paddsw256",
|
||||
(false, true, 16, 16) => "__builtin_ia32_paddusw256",
|
||||
(true, false, 16, 16) => "__builtin_ia32_psubsw256",
|
||||
(false, false, 16, 16) => "__builtin_ia32_psubusw256",
|
||||
(true, false, 32, 8) => "__builtin_ia32_psubsb256",
|
||||
(false, false, 32, 8) => "__builtin_ia32_psubusb256",
|
||||
_ => unimplemented!("signed: {}, is_add: {}, in_len: {}, elem_width: {}", signed, is_add, in_len, elem_width),
|
||||
};
|
||||
let builtin_name = match (signed, is_add, in_len, elem_width) {
|
||||
(true, true, 32, 8) => "__builtin_ia32_paddsb256", // TODO(antoyo): cast arguments to unsigned.
|
||||
(false, true, 32, 8) => "__builtin_ia32_paddusb256",
|
||||
(true, true, 16, 16) => "__builtin_ia32_paddsw256",
|
||||
(false, true, 16, 16) => "__builtin_ia32_paddusw256",
|
||||
(true, false, 16, 16) => "__builtin_ia32_psubsw256",
|
||||
(false, false, 16, 16) => "__builtin_ia32_psubusw256",
|
||||
(true, false, 32, 8) => "__builtin_ia32_psubsb256",
|
||||
(false, false, 32, 8) => "__builtin_ia32_psubusb256",
|
||||
_ => unimplemented!(
|
||||
"signed: {}, is_add: {}, in_len: {}, elem_width: {}",
|
||||
signed,
|
||||
is_add,
|
||||
in_len,
|
||||
elem_width
|
||||
),
|
||||
};
|
||||
let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
|
||||
|
||||
let func = bx.context.get_target_builtin_function(builtin_name);
|
||||
|
@ -575,8 +618,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
// if overflow occurs, the result is the
|
||||
// mathematical result modulo 2^n:
|
||||
Ok(bx.$op(args[1].immediate(), r))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Ok(bx.vector_reduce_op(args[0].immediate(), $vec_op))
|
||||
}
|
||||
}
|
||||
|
@ -585,12 +627,17 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
// ordered arithmetic reductions take an accumulator
|
||||
let acc = args[1].immediate();
|
||||
Ok(bx.$float_reduce(acc, args[0].immediate()))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Ok(bx.vector_reduce_op(args[0].immediate(), $vec_op))
|
||||
}
|
||||
}
|
||||
_ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }),
|
||||
_ => return_error!(InvalidMonomorphizationUnsupportedElement {
|
||||
span,
|
||||
name,
|
||||
in_ty,
|
||||
elem_ty: in_elem,
|
||||
ret_ty
|
||||
}),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -603,13 +650,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
add,
|
||||
0.0 // TODO: Use this argument.
|
||||
);
|
||||
arith_red!(
|
||||
simd_reduce_mul_unordered: BinaryOp::Mult,
|
||||
vector_reduce_fmul_fast,
|
||||
false,
|
||||
mul,
|
||||
1.0
|
||||
);
|
||||
arith_red!(simd_reduce_mul_unordered: BinaryOp::Mult, vector_reduce_fmul_fast, false, mul, 1.0);
|
||||
|
||||
macro_rules! minmax_red {
|
||||
($name:ident: $reduction:ident) => {
|
||||
|
@ -619,8 +660,16 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty }
|
||||
);
|
||||
return match in_elem.kind() {
|
||||
ty::Int(_) | ty::Uint(_) | ty::Float(_) => Ok(bx.$reduction(args[0].immediate())),
|
||||
_ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }),
|
||||
ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
|
||||
Ok(bx.$reduction(args[0].immediate()))
|
||||
}
|
||||
_ => return_error!(InvalidMonomorphizationUnsupportedElement {
|
||||
span,
|
||||
name,
|
||||
in_ty,
|
||||
elem_ty: in_elem,
|
||||
ret_ty
|
||||
}),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -641,7 +690,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
} else {
|
||||
match in_elem.kind() {
|
||||
ty::Int(_) | ty::Uint(_) => {}
|
||||
_ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }),
|
||||
_ => return_error!(InvalidMonomorphizationUnsupportedElement {
|
||||
span,
|
||||
name,
|
||||
in_ty,
|
||||
elem_ty: in_elem,
|
||||
ret_ty
|
||||
}),
|
||||
}
|
||||
|
||||
// boolean reductions operate on vectors of i1s:
|
||||
|
@ -654,9 +709,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||
let r = bx.vector_reduce_op(input, $op);
|
||||
Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) })
|
||||
}
|
||||
_ => return_error!(
|
||||
InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }
|
||||
),
|
||||
_ => return_error!(InvalidMonomorphizationUnsupportedElement {
|
||||
span,
|
||||
name,
|
||||
in_ty,
|
||||
elem_ty: in_elem,
|
||||
ret_ty
|
||||
}),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -132,7 +132,7 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>(
|
|||
|
||||
let (size, align) = cx.size_and_align_of(array_type);
|
||||
|
||||
let upper_bound = len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong;
|
||||
let upper_bound = len.eval_target_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong;
|
||||
|
||||
let subrange =
|
||||
unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) };
|
||||
|
|
|
@ -877,7 +877,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
|
||||
ty::Array(elem, len)
|
||||
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
|
||||
&& len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
|
||||
&& len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
|
||||
== Some(expected_bytes) =>
|
||||
{
|
||||
let place = PlaceRef::alloca(bx, args[0].layout);
|
||||
|
@ -957,9 +957,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
// version of this intrinsic.
|
||||
match args[2].layout.ty.kind() {
|
||||
ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
|
||||
len.try_eval_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| {
|
||||
span_bug!(span, "could not evaluate shuffle index array length")
|
||||
})
|
||||
len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(
|
||||
|| span_bug!(span, "could not evaluate shuffle index array length"),
|
||||
)
|
||||
}
|
||||
_ => return_error!(InvalidMonomorphization::SimdShuffle {
|
||||
span,
|
||||
|
@ -1123,7 +1123,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
}
|
||||
ty::Array(elem, len)
|
||||
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
|
||||
&& len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
|
||||
&& len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all())
|
||||
== Some(expected_bytes) =>
|
||||
{
|
||||
// Zero-extend iN to the array length:
|
||||
|
|
|
@ -148,7 +148,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, bx.param_env());
|
||||
match (source.kind(), target.kind()) {
|
||||
(&ty::Array(_, len), &ty::Slice(_)) => {
|
||||
cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
|
||||
cx.const_usize(len.eval_target_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
|
||||
}
|
||||
(
|
||||
&ty::Dynamic(ref data_a, _, src_dyn_kind),
|
||||
|
|
|
@ -181,16 +181,24 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
|
||||
match len.kind() {
|
||||
ty::ConstKind::Param(param) => write!(output, ",{}>", param.name).unwrap(),
|
||||
_ => write!(output, ",{}>", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
|
||||
.unwrap(),
|
||||
_ => write!(
|
||||
output,
|
||||
",{}>",
|
||||
len.eval_target_usize(tcx, ty::ParamEnv::reveal_all())
|
||||
)
|
||||
.unwrap(),
|
||||
}
|
||||
} else {
|
||||
output.push('[');
|
||||
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
|
||||
match len.kind() {
|
||||
ty::ConstKind::Param(param) => write!(output, "; {}]", param.name).unwrap(),
|
||||
_ => write!(output, "; {}]", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
|
||||
.unwrap(),
|
||||
_ => write!(
|
||||
output,
|
||||
"; {}]",
|
||||
len.eval_target_usize(tcx, ty::ParamEnv::reveal_all())
|
||||
)
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,8 +100,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
|
||||
let count =
|
||||
self.monomorphize(count).eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
|
||||
let count = self
|
||||
.monomorphize(count)
|
||||
.eval_target_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
|
||||
|
||||
bx.write_operand_repeatedly(cg_elem, count, dest);
|
||||
}
|
||||
|
@ -492,7 +493,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
if let Some(index) = place.as_local() {
|
||||
if let LocalRef::Operand(Some(op)) = self.locals[index] {
|
||||
if let ty::Array(_, n) = op.layout.ty.kind() {
|
||||
let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
|
||||
let n = n.eval_target_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
|
||||
return bx.cx().const_usize(n);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
|
|||
|
||||
// We go to `usize` as we cannot allocate anything bigger anyway.
|
||||
let (field_count, variant, down) = match val.ty().kind() {
|
||||
ty::Array(_, len) => (len.eval_usize(tcx, param_env) as usize, None, op),
|
||||
ty::Array(_, len) => (len.eval_target_usize(tcx, param_env) as usize, None, op),
|
||||
ty::Adt(def, _) if def.variants().is_empty() => {
|
||||
throw_ub!(Unreachable)
|
||||
}
|
||||
|
|
|
@ -328,8 +328,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
(&ty::Array(_, length), &ty::Slice(_)) => {
|
||||
let ptr = self.read_scalar(src)?;
|
||||
// u64 cast is from usize to u64, which is always good
|
||||
let val =
|
||||
Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self);
|
||||
let val = Immediate::new_slice(
|
||||
ptr,
|
||||
length.eval_target_usize(*self.tcx, self.param_env),
|
||||
self,
|
||||
);
|
||||
self.write_immediate(val, dest)
|
||||
}
|
||||
(ty::Dynamic(data_a, ..), ty::Dynamic(data_b, ..)) => {
|
||||
|
|
|
@ -473,7 +473,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
// that this is merely a ZST and it is already eligible for promotion.
|
||||
// This may require an RFC?
|
||||
/*
|
||||
ty::Array(_, len) if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0)
|
||||
ty::Array(_, len) if len.try_eval_target_usize(cx.tcx, cx.param_env) == Some(0)
|
||||
=> true,
|
||||
*/
|
||||
_ => false,
|
||||
|
|
|
@ -364,31 +364,33 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
ProjectionElem::Index(local) => {
|
||||
let mut promotable = false;
|
||||
// Only accept if we can predict the index and are indexing an array.
|
||||
let val =
|
||||
if let TempState::Defined { location: loc, .. } = self.temps[local] {
|
||||
let block = &self.body[loc.block];
|
||||
if loc.statement_index < block.statements.len() {
|
||||
let statement = &block.statements[loc.statement_index];
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(box (
|
||||
_,
|
||||
Rvalue::Use(Operand::Constant(c)),
|
||||
)) => c.literal.try_eval_usize(self.tcx, self.param_env),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
let val = if let TempState::Defined { location: loc, .. } =
|
||||
self.temps[local]
|
||||
{
|
||||
let block = &self.body[loc.block];
|
||||
if loc.statement_index < block.statements.len() {
|
||||
let statement = &block.statements[loc.statement_index];
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(box (
|
||||
_,
|
||||
Rvalue::Use(Operand::Constant(c)),
|
||||
)) => c.literal.try_eval_target_usize(self.tcx, self.param_env),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(idx) = val {
|
||||
// Determine the type of the thing we are indexing.
|
||||
let ty = place_base.ty(self.body, self.tcx).ty;
|
||||
match ty.kind() {
|
||||
ty::Array(_, len) => {
|
||||
// It's an array; determine its length.
|
||||
if let Some(len) = len.try_eval_usize(self.tcx, self.param_env)
|
||||
if let Some(len) =
|
||||
len.try_eval_target_usize(self.tcx, self.param_env)
|
||||
{
|
||||
// If the index is in-bounds, go ahead.
|
||||
if idx < len {
|
||||
|
@ -470,7 +472,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
// mutably without consequences. However, only &mut []
|
||||
// is allowed right now.
|
||||
if let ty::Array(_, len) = ty.kind() {
|
||||
match len.try_eval_usize(self.tcx, self.param_env) {
|
||||
match len.try_eval_target_usize(self.tcx, self.param_env) {
|
||||
Some(0) => {}
|
||||
_ => return Err(Unpromotable),
|
||||
}
|
||||
|
|
|
@ -901,7 +901,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
|
|||
}
|
||||
|
||||
let len = if let ty::Array(_ty, c) = e.kind() {
|
||||
c.try_eval_usize(tcx, tcx.param_env(def.did()))
|
||||
c.try_eval_target_usize(tcx, tcx.param_env(def.did()))
|
||||
} else {
|
||||
Some(fields.len() as u64)
|
||||
};
|
||||
|
|
|
@ -1396,7 +1396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let count = self.array_length_to_const(count);
|
||||
if let Some(count) = count.try_eval_usize(tcx, self.param_env) {
|
||||
if let Some(count) = count.try_eval_target_usize(tcx, self.param_env) {
|
||||
self.suggest_array_len(expr, count);
|
||||
}
|
||||
|
||||
|
@ -1463,7 +1463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// If the length is 0, we don't create any elements, so we don't copy any. If the length is 1, we
|
||||
// don't copy that one element, we move it. Only check for Copy if the length is larger.
|
||||
if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
|
||||
if count.try_eval_target_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
|
||||
let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
|
||||
let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn };
|
||||
self.require_type_meets(element_ty, element.span, code, lang_item);
|
||||
|
@ -2602,7 +2602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
len: ty::Const<'tcx>,
|
||||
) {
|
||||
if let (Some(len), Ok(user_index)) =
|
||||
(len.try_eval_usize(self.tcx, self.param_env), field.as_str().parse::<u64>())
|
||||
(len.try_eval_target_usize(self.tcx, self.param_env), field.as_str().parse::<u64>())
|
||||
&& let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span)
|
||||
{
|
||||
let help = "instead of using tuple indexing, use array indexing";
|
||||
|
|
|
@ -647,7 +647,8 @@ fn check_must_not_suspend_ty<'tcx>(
|
|||
hir_id,
|
||||
SuspendCheckData {
|
||||
descr_pre,
|
||||
plural_len: len.try_eval_usize(fcx.tcx, fcx.param_env).unwrap_or(0) as usize
|
||||
plural_len: len.try_eval_target_usize(fcx.tcx, fcx.param_env).unwrap_or(0)
|
||||
as usize
|
||||
+ 1,
|
||||
..data
|
||||
},
|
||||
|
|
|
@ -2063,7 +2063,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
len: ty::Const<'tcx>,
|
||||
min_len: u64,
|
||||
) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
|
||||
if let Some(len) = len.try_eval_usize(self.tcx, self.param_env) {
|
||||
if let Some(len) = len.try_eval_target_usize(self.tcx, self.param_env) {
|
||||
// Now we know the length...
|
||||
if slice.is_none() {
|
||||
// ...and since there is no variable-length pattern,
|
||||
|
|
|
@ -2605,7 +2605,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
|
|||
ty.tuple_fields().iter().find_map(|field| ty_find_init_error(cx, field, init))
|
||||
}
|
||||
Array(ty, len) => {
|
||||
if matches!(len.try_eval_usize(cx.tcx, cx.param_env), Some(v) if v > 0) {
|
||||
if matches!(len.try_eval_target_usize(cx.tcx, cx.param_env), Some(v) if v > 0) {
|
||||
// Array length known at array non-empty -- recurse.
|
||||
ty_find_init_error(cx, *ty, init)
|
||||
} else {
|
||||
|
|
|
@ -837,9 +837,17 @@ pub trait LintContext: Sized {
|
|||
(use_span, "'_".to_owned())
|
||||
};
|
||||
debug!(?deletion_span, ?use_span);
|
||||
|
||||
// issue 107998 for the case such as a wrong function pointer type
|
||||
// `deletion_span` is empty and there is no need to report lifetime uses here
|
||||
let suggestions = if deletion_span.is_empty() {
|
||||
vec![(use_span, replace_lt)]
|
||||
} else {
|
||||
vec![(deletion_span, String::new()), (use_span, replace_lt)]
|
||||
};
|
||||
db.multipart_suggestion(
|
||||
msg,
|
||||
vec![(deletion_span, String::new()), (use_span, replace_lt)],
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -309,7 +309,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
|||
None
|
||||
}
|
||||
}
|
||||
ty::Array(ty, len) => match len.try_eval_usize(cx.tcx, cx.param_env) {
|
||||
ty::Array(ty, len) => match len.try_eval_target_usize(cx.tcx, cx.param_env) {
|
||||
// If the array is empty we don't lint, to avoid false positives
|
||||
Some(0) | None => None,
|
||||
// If the array is definitely non-empty, we can do `#[must_use]` checking.
|
||||
|
|
|
@ -2344,9 +2344,13 @@ impl<'tcx> ConstantKind<'tcx> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<u64> {
|
||||
pub fn try_eval_target_usize(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Option<u64> {
|
||||
match self {
|
||||
Self::Ty(ct) => ct.try_eval_usize(tcx, param_env),
|
||||
Self::Ty(ct) => ct.try_eval_target_usize(tcx, param_env),
|
||||
Self::Val(val, _) => val.try_to_machine_usize(tcx),
|
||||
Self::Unevaluated(uneval, _) => {
|
||||
match tcx.const_eval_resolve(param_env, *uneval, None) {
|
||||
|
|
|
@ -97,7 +97,7 @@ impl<'tcx> PlaceTy<'tcx> {
|
|||
ty::Slice(..) => self.ty,
|
||||
ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64),
|
||||
ty::Array(inner, size) if from_end => {
|
||||
let size = size.eval_usize(tcx, param_env);
|
||||
let size = size.eval_target_usize(tcx, param_env);
|
||||
let len = size - (from as u64) - (to as u64);
|
||||
tcx.mk_array(*inner, len)
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ impl<'tcx> Const<'tcx> {
|
|||
|
||||
#[inline]
|
||||
/// Creates an interned usize constant.
|
||||
pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
|
||||
pub fn from_target_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
|
||||
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,11 @@ impl<'tcx> Const<'tcx> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> {
|
||||
pub fn try_eval_target_usize(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Option<u64> {
|
||||
self.kind().eval(tcx, param_env).try_to_machine_usize(tcx)
|
||||
}
|
||||
|
||||
|
@ -229,8 +233,8 @@ impl<'tcx> Const<'tcx> {
|
|||
|
||||
#[inline]
|
||||
/// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
|
||||
pub fn eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
|
||||
self.try_eval_usize(tcx, param_env)
|
||||
pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
|
||||
self.try_eval_target_usize(tcx, param_env)
|
||||
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
|
||||
}
|
||||
|
||||
|
|
|
@ -1787,7 +1787,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
#[inline]
|
||||
pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
|
||||
self.mk_ty(Array(ty, ty::Const::from_usize(self, n)))
|
||||
self.mk_ty(Array(ty, ty::Const::from_target_usize(self, n)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -57,7 +57,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
|
|||
match self {
|
||||
Self::False => Ok(false),
|
||||
Self::True => Ok(true),
|
||||
Self::ConstIsZero(const_) => match const_.try_eval_usize(tcx, param_env) {
|
||||
Self::ConstIsZero(const_) => match const_.try_eval_target_usize(tcx, param_env) {
|
||||
None | Some(0) => Ok(true),
|
||||
Some(1..) => Ok(false),
|
||||
},
|
||||
|
|
|
@ -511,8 +511,8 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||
// we however cannot end up with errors in `Relate` during both
|
||||
// `type_of` and `predicates_of`. This means that evaluating the
|
||||
// constants should not cause cycle errors here.
|
||||
let sz_a = sz_a.try_eval_usize(tcx, relation.param_env());
|
||||
let sz_b = sz_b.try_eval_usize(tcx, relation.param_env());
|
||||
let sz_a = sz_a.try_eval_target_usize(tcx, relation.param_env());
|
||||
let sz_b = sz_b.try_eval_target_usize(tcx, relation.param_env());
|
||||
match (sz_a, sz_b) {
|
||||
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err(
|
||||
TypeError::FixedArraySize(expected_found(relation, sz_a_val, sz_b_val)),
|
||||
|
|
|
@ -1879,7 +1879,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
// The way we evaluate the `N` in `[T; N]` here only works since we use
|
||||
// `simd_size_and_type` post-monomorphization. It will probably start to ICE
|
||||
// if we use it in generic code. See the `simd-array-trait` ui test.
|
||||
(f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, *f0_elem_ty)
|
||||
(f0_len.eval_target_usize(tcx, ParamEnv::empty()) as u64, *f0_elem_ty)
|
||||
}
|
||||
// Otherwise, the fields of this Adt are the SIMD components (and we assume they
|
||||
// all have the same type).
|
||||
|
|
|
@ -55,7 +55,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
})
|
||||
}
|
||||
ExprKind::Repeat { value, count } => {
|
||||
if Some(0) == count.try_eval_usize(this.tcx, this.param_env) {
|
||||
if Some(0) == count.try_eval_target_usize(this.tcx, this.param_env) {
|
||||
this.build_zero_repeat(block, value, scope, source_info)
|
||||
} else {
|
||||
let value_operand = unpack!(
|
||||
|
|
|
@ -35,7 +35,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let tcx = self.tcx;
|
||||
let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
|
||||
match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
|
||||
ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
|
||||
ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true),
|
||||
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -922,8 +922,8 @@ impl<'tcx> SplitWildcard<'tcx> {
|
|||
// `cx.is_uninhabited()`).
|
||||
let all_ctors = match pcx.ty.kind() {
|
||||
ty::Bool => smallvec![make_range(0, 1)],
|
||||
ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
|
||||
let len = len.eval_usize(cx.tcx, cx.param_env) as usize;
|
||||
ty::Array(sub_ty, len) if len.try_eval_target_usize(cx.tcx, cx.param_env).is_some() => {
|
||||
let len = len.eval_target_usize(cx.tcx, cx.param_env) as usize;
|
||||
if len != 0 && cx.is_uninhabited(*sub_ty) {
|
||||
smallvec![]
|
||||
} else {
|
||||
|
@ -1406,7 +1406,9 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
|
|||
}
|
||||
PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
|
||||
let array_len = match pat.ty.kind() {
|
||||
ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env) as usize),
|
||||
ty::Array(_, length) => {
|
||||
Some(length.eval_target_usize(cx.tcx, cx.param_env) as usize)
|
||||
}
|
||||
ty::Slice(_) => None,
|
||||
_ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty),
|
||||
};
|
||||
|
|
|
@ -416,7 +416,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
ty::Slice(..) => PatKind::Slice { prefix, slice, suffix },
|
||||
// Fixed-length array, `[T; len]`.
|
||||
ty::Array(_, len) => {
|
||||
let len = len.eval_usize(self.tcx, self.param_env);
|
||||
let len = len.eval_target_usize(self.tcx, self.param_env);
|
||||
assert!(len >= prefix.len() as u64 + suffix.len() as u64);
|
||||
PatKind::Array { prefix, slice, suffix }
|
||||
}
|
||||
|
|
|
@ -890,7 +890,7 @@ where
|
|||
}
|
||||
ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
|
||||
ty::Array(ety, size) => {
|
||||
let size = size.try_eval_usize(self.tcx(), self.elaborator.param_env());
|
||||
let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env());
|
||||
self.open_drop_for_array(*ety, size)
|
||||
}
|
||||
ty::Slice(ety) => self.open_drop_for_array(*ety, None),
|
||||
|
|
|
@ -490,7 +490,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
};
|
||||
let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty;
|
||||
let len: u64 = match base_ty.kind() {
|
||||
ty::Array(_, size) => size.eval_usize(self.builder.tcx, self.builder.param_env),
|
||||
ty::Array(_, size) => {
|
||||
size.eval_target_usize(self.builder.tcx, self.builder.param_env)
|
||||
}
|
||||
_ => bug!("from_end: false slice pattern of non-array type"),
|
||||
};
|
||||
for offset in from..to {
|
||||
|
|
|
@ -1845,7 +1845,7 @@ fn check_must_not_suspend_ty<'tcx>(
|
|||
param_env,
|
||||
SuspendCheckData {
|
||||
descr_pre,
|
||||
plural_len: len.try_eval_usize(tcx, param_env).unwrap_or(0) as usize + 1,
|
||||
plural_len: len.try_eval_target_usize(tcx, param_env).unwrap_or(0) as usize + 1,
|
||||
..data
|
||||
},
|
||||
)
|
||||
|
|
|
@ -143,7 +143,7 @@ impl EnumSizeOpt {
|
|||
|
||||
let tmp_ty = tcx.mk_ty(ty::Array(
|
||||
tcx.types.usize,
|
||||
Const::from_usize(tcx, num_variants as u64),
|
||||
Const::from_target_usize(tcx, num_variants as u64),
|
||||
));
|
||||
|
||||
let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span));
|
||||
|
|
|
@ -284,7 +284,7 @@ impl<'a> Parser<'a> {
|
|||
self.sess.source_map().span_to_snippet(span)
|
||||
}
|
||||
|
||||
pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
let valid_follow = &[
|
||||
TokenKind::Eq,
|
||||
TokenKind::Colon,
|
||||
|
@ -324,7 +324,61 @@ impl<'a> Parser<'a> {
|
|||
suggest_raw,
|
||||
suggest_remove_comma,
|
||||
};
|
||||
err.into_diagnostic(&self.sess.span_diagnostic)
|
||||
let mut err = err.into_diagnostic(&self.sess.span_diagnostic);
|
||||
|
||||
// if the token we have is a `<`
|
||||
// it *might* be a misplaced generic
|
||||
if self.token == token::Lt {
|
||||
// all keywords that could have generic applied
|
||||
let valid_prev_keywords =
|
||||
[kw::Fn, kw::Type, kw::Struct, kw::Enum, kw::Union, kw::Trait];
|
||||
|
||||
// If we've expected an identifier,
|
||||
// and the current token is a '<'
|
||||
// if the previous token is a valid keyword
|
||||
// that might use a generic, then suggest a correct
|
||||
// generic placement (later on)
|
||||
let maybe_keyword = self.prev_token.clone();
|
||||
if valid_prev_keywords.into_iter().any(|x| maybe_keyword.is_keyword(x)) {
|
||||
// if we have a valid keyword, attempt to parse generics
|
||||
// also obtain the keywords symbol
|
||||
match self.parse_generics() {
|
||||
Ok(generic) => {
|
||||
if let TokenKind::Ident(symbol, _) = maybe_keyword.kind {
|
||||
let ident_name = symbol;
|
||||
// at this point, we've found something like
|
||||
// `fn <T>id`
|
||||
// and current token should be Ident with the item name (i.e. the function name)
|
||||
// if there is a `<` after the fn name, then don't show a suggestion, show help
|
||||
|
||||
if !self.look_ahead(1, |t| *t == token::Lt) &&
|
||||
let Ok(snippet) = self.sess.source_map().span_to_snippet(generic.span) {
|
||||
err.multipart_suggestion_verbose(
|
||||
format!("place the generic parameter name after the {ident_name} name"),
|
||||
vec![
|
||||
(self.token.span.shrink_to_hi(), snippet),
|
||||
(generic.span, String::new())
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.help(format!(
|
||||
"place the generic parameter name after the {ident_name} name"
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
// if there's an error parsing the generics,
|
||||
// then don't do a misplaced generics suggestion
|
||||
// and emit the expected ident error instead;
|
||||
err.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(super) fn expected_one_of_not_found(
|
||||
|
|
|
@ -31,6 +31,7 @@ use rustc_middle::ty::{
|
|||
};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
use crate::solve::search_graph::OverflowHandler;
|
||||
use crate::traits::ObligationCause;
|
||||
|
||||
mod assembly;
|
||||
|
@ -210,27 +211,16 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
search_graph: &'a mut search_graph::SearchGraph<'tcx>,
|
||||
canonical_goal: CanonicalGoal<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
match search_graph.try_push_stack(tcx, canonical_goal) {
|
||||
Ok(()) => {}
|
||||
// Our goal is already on the stack, eager return.
|
||||
Err(response) => return response,
|
||||
}
|
||||
|
||||
// We may have to repeatedly recompute the goal in case of coinductive cycles,
|
||||
// check out the `cache` module for more information.
|
||||
// Deal with overflow, caching, and coinduction.
|
||||
//
|
||||
// FIXME: Similar to `evaluate_all`, this has to check for overflow.
|
||||
loop {
|
||||
// The actual solver logic happens in `ecx.compute_goal`.
|
||||
search_graph.with_new_goal(tcx, canonical_goal, |search_graph| {
|
||||
let (ref infcx, goal, var_values) =
|
||||
tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
|
||||
let mut ecx =
|
||||
EvalCtxt { infcx, var_values, search_graph, in_projection_eq_hack: false };
|
||||
let result = ecx.compute_goal(goal);
|
||||
|
||||
if search_graph.try_finalize_goal(tcx, canonical_goal, result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
ecx.compute_goal(goal)
|
||||
})
|
||||
}
|
||||
|
||||
fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> {
|
||||
|
@ -485,35 +475,38 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
mut goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) -> Result<Certainty, NoSolution> {
|
||||
let mut new_goals = Vec::new();
|
||||
self.repeat_while_none(|this| {
|
||||
let mut has_changed = Err(Certainty::Yes);
|
||||
for goal in goals.drain(..) {
|
||||
let (changed, certainty) = match this.evaluate_goal(goal) {
|
||||
Ok(result) => result,
|
||||
Err(NoSolution) => return Some(Err(NoSolution)),
|
||||
};
|
||||
self.repeat_while_none(
|
||||
|_| Ok(Certainty::Maybe(MaybeCause::Overflow)),
|
||||
|this| {
|
||||
let mut has_changed = Err(Certainty::Yes);
|
||||
for goal in goals.drain(..) {
|
||||
let (changed, certainty) = match this.evaluate_goal(goal) {
|
||||
Ok(result) => result,
|
||||
Err(NoSolution) => return Some(Err(NoSolution)),
|
||||
};
|
||||
|
||||
if changed {
|
||||
has_changed = Ok(());
|
||||
}
|
||||
if changed {
|
||||
has_changed = Ok(());
|
||||
}
|
||||
|
||||
match certainty {
|
||||
Certainty::Yes => {}
|
||||
Certainty::Maybe(_) => {
|
||||
new_goals.push(goal);
|
||||
has_changed = has_changed.map_err(|c| c.unify_and(certainty));
|
||||
match certainty {
|
||||
Certainty::Yes => {}
|
||||
Certainty::Maybe(_) => {
|
||||
new_goals.push(goal);
|
||||
has_changed = has_changed.map_err(|c| c.unify_and(certainty));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match has_changed {
|
||||
Ok(()) => {
|
||||
mem::swap(&mut new_goals, &mut goals);
|
||||
None
|
||||
match has_changed {
|
||||
Ok(()) => {
|
||||
mem::swap(&mut new_goals, &mut goals);
|
||||
None
|
||||
}
|
||||
Err(certainty) => Some(Ok(certainty)),
|
||||
}
|
||||
Err(certainty) => Some(Ok(certainty)),
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Recursively evaluates a list of goals to completion, making a query response.
|
||||
|
|
|
@ -3,6 +3,7 @@ mod overflow;
|
|||
|
||||
use self::cache::ProvisionalEntry;
|
||||
use super::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
|
||||
pub(super) use crate::solve::search_graph::overflow::OverflowHandler;
|
||||
use cache::ProvisionalCache;
|
||||
use overflow::OverflowData;
|
||||
use rustc_index::vec::IndexVec;
|
||||
|
@ -46,7 +47,7 @@ impl<'tcx> SearchGraph<'tcx> {
|
|||
///
|
||||
/// This correctly updates the provisional cache if there is a cycle.
|
||||
#[instrument(level = "debug", skip(self, tcx), ret)]
|
||||
pub(super) fn try_push_stack(
|
||||
fn try_push_stack(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalGoal<'tcx>,
|
||||
|
@ -121,19 +122,19 @@ impl<'tcx> SearchGraph<'tcx> {
|
|||
///
|
||||
/// FIXME: Refer to the rustc-dev-guide entry once it exists.
|
||||
#[instrument(level = "debug", skip(self, tcx, actual_goal), ret)]
|
||||
pub(super) fn try_finalize_goal(
|
||||
fn try_finalize_goal(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
actual_goal: CanonicalGoal<'tcx>,
|
||||
response: QueryResult<'tcx>,
|
||||
) -> bool {
|
||||
let StackElem { goal, has_been_used } = self.stack.pop().unwrap();
|
||||
let stack_elem = self.stack.pop().unwrap();
|
||||
let StackElem { goal, has_been_used } = stack_elem;
|
||||
assert_eq!(goal, actual_goal);
|
||||
|
||||
let cache = &mut self.provisional_cache;
|
||||
let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap();
|
||||
let provisional_entry = &mut cache.entries[provisional_entry_index];
|
||||
let depth = provisional_entry.depth;
|
||||
// We eagerly update the response in the cache here. If we have to reevaluate
|
||||
// this goal we use the new response when hitting a cycle, and we definitely
|
||||
// want to access the final response whenever we look at the cache.
|
||||
|
@ -157,29 +158,72 @@ impl<'tcx> SearchGraph<'tcx> {
|
|||
self.stack.push(StackElem { goal, has_been_used: false });
|
||||
false
|
||||
} else {
|
||||
// If not, we're done with this goal.
|
||||
//
|
||||
// Check whether that this goal doesn't depend on a goal deeper on the stack
|
||||
// and if so, move it and all nested goals to the global cache.
|
||||
//
|
||||
// Note that if any nested goal were to depend on something deeper on the stack,
|
||||
// this would have also updated the depth of the current goal.
|
||||
if depth == self.stack.next_index() {
|
||||
for (i, entry) in cache.entries.drain_enumerated(provisional_entry_index.index()..)
|
||||
{
|
||||
let actual_index = cache.lookup_table.remove(&entry.goal);
|
||||
debug_assert_eq!(Some(i), actual_index);
|
||||
debug_assert!(entry.depth == depth);
|
||||
cache::try_move_finished_goal_to_global_cache(
|
||||
tcx,
|
||||
&mut self.overflow_data,
|
||||
&self.stack,
|
||||
entry.goal,
|
||||
entry.response,
|
||||
);
|
||||
}
|
||||
}
|
||||
self.try_move_finished_goal_to_global_cache(tcx, stack_elem);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn try_move_finished_goal_to_global_cache(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
stack_elem: StackElem<'tcx>,
|
||||
) {
|
||||
let StackElem { goal, .. } = stack_elem;
|
||||
let cache = &mut self.provisional_cache;
|
||||
let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap();
|
||||
let provisional_entry = &mut cache.entries[provisional_entry_index];
|
||||
let depth = provisional_entry.depth;
|
||||
|
||||
// If not, we're done with this goal.
|
||||
//
|
||||
// Check whether that this goal doesn't depend on a goal deeper on the stack
|
||||
// and if so, move it and all nested goals to the global cache.
|
||||
//
|
||||
// Note that if any nested goal were to depend on something deeper on the stack,
|
||||
// this would have also updated the depth of the current goal.
|
||||
if depth == self.stack.next_index() {
|
||||
for (i, entry) in cache.entries.drain_enumerated(provisional_entry_index.index()..) {
|
||||
let actual_index = cache.lookup_table.remove(&entry.goal);
|
||||
debug_assert_eq!(Some(i), actual_index);
|
||||
debug_assert!(entry.depth == depth);
|
||||
cache::try_move_finished_goal_to_global_cache(
|
||||
tcx,
|
||||
&mut self.overflow_data,
|
||||
&self.stack,
|
||||
entry.goal,
|
||||
entry.response,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn with_new_goal(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
canonical_goal: CanonicalGoal<'tcx>,
|
||||
mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
match self.try_push_stack(tcx, canonical_goal) {
|
||||
Ok(()) => {}
|
||||
// Our goal is already on the stack, eager return.
|
||||
Err(response) => return response,
|
||||
}
|
||||
|
||||
self.repeat_while_none(
|
||||
|this| {
|
||||
let result = this.deal_with_overflow(tcx, canonical_goal);
|
||||
let stack_elem = this.stack.pop().unwrap();
|
||||
this.try_move_finished_goal_to_global_cache(tcx, stack_elem);
|
||||
result
|
||||
},
|
||||
|this| {
|
||||
let result = loop_body(this);
|
||||
if this.try_finalize_goal(tcx, canonical_goal, result) {
|
||||
Some(result)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,42 @@ impl OverflowData {
|
|||
}
|
||||
}
|
||||
|
||||
pub(in crate::solve) trait OverflowHandler<'tcx> {
|
||||
fn search_graph(&mut self) -> &mut SearchGraph<'tcx>;
|
||||
|
||||
fn repeat_while_none<T>(
|
||||
&mut self,
|
||||
on_overflow: impl FnOnce(&mut Self) -> Result<T, NoSolution>,
|
||||
mut loop_body: impl FnMut(&mut Self) -> Option<Result<T, NoSolution>>,
|
||||
) -> Result<T, NoSolution> {
|
||||
let start_depth = self.search_graph().overflow_data.additional_depth;
|
||||
let depth = self.search_graph().stack.len();
|
||||
while !self.search_graph().overflow_data.has_overflow(depth) {
|
||||
if let Some(result) = loop_body(self) {
|
||||
self.search_graph().overflow_data.additional_depth = start_depth;
|
||||
return result;
|
||||
}
|
||||
|
||||
self.search_graph().overflow_data.additional_depth += 1;
|
||||
}
|
||||
self.search_graph().overflow_data.additional_depth = start_depth;
|
||||
self.search_graph().overflow_data.deal_with_overflow();
|
||||
on_overflow(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> OverflowHandler<'tcx> for EvalCtxt<'_, 'tcx> {
|
||||
fn search_graph(&mut self) -> &mut SearchGraph<'tcx> {
|
||||
&mut self.search_graph
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> OverflowHandler<'tcx> for SearchGraph<'tcx> {
|
||||
fn search_graph(&mut self) -> &mut SearchGraph<'tcx> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> SearchGraph<'tcx> {
|
||||
pub fn deal_with_overflow(
|
||||
&mut self,
|
||||
|
@ -60,25 +96,3 @@ impl<'tcx> SearchGraph<'tcx> {
|
|||
response_no_constraints(tcx, goal, Certainty::Maybe(MaybeCause::Overflow))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
/// A `while`-loop which tracks overflow.
|
||||
pub fn repeat_while_none(
|
||||
&mut self,
|
||||
mut loop_body: impl FnMut(&mut Self) -> Option<Result<Certainty, NoSolution>>,
|
||||
) -> Result<Certainty, NoSolution> {
|
||||
let start_depth = self.search_graph.overflow_data.additional_depth;
|
||||
let depth = self.search_graph.stack.len();
|
||||
while !self.search_graph.overflow_data.has_overflow(depth) {
|
||||
if let Some(result) = loop_body(self) {
|
||||
self.search_graph.overflow_data.additional_depth = start_depth;
|
||||
return result;
|
||||
}
|
||||
|
||||
self.search_graph.overflow_data.additional_depth += 1;
|
||||
}
|
||||
self.search_graph.overflow_data.additional_depth = start_depth;
|
||||
self.search_graph.overflow_data.deal_with_overflow();
|
||||
Ok(Certainty::Maybe(MaybeCause::Overflow))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
|
|||
return ControlFlow::Continue(());
|
||||
}
|
||||
ty::Array(_, n)
|
||||
if { n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } =>
|
||||
if { n.try_eval_target_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } =>
|
||||
{
|
||||
// rust-lang/rust#62336: ignore type of contents
|
||||
// for empty array.
|
||||
|
|
|
@ -284,8 +284,9 @@ pub(crate) mod rustc {
|
|||
}
|
||||
|
||||
ty::Array(ty, len) => {
|
||||
let len =
|
||||
len.try_eval_usize(tcx, ParamEnv::reveal_all()).ok_or(Err::Unspecified)?;
|
||||
let len = len
|
||||
.try_eval_target_usize(tcx, ParamEnv::reveal_all())
|
||||
.ok_or(Err::Unspecified)?;
|
||||
let elt = Tree::from_ty(*ty, tcx)?;
|
||||
Ok(std::iter::repeat(elt)
|
||||
.take(len as usize)
|
||||
|
|
|
@ -209,7 +209,8 @@ fn layout_of_uncached<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
let count = count.try_eval_usize(tcx, param_env).ok_or(LayoutError::Unknown(ty))?;
|
||||
let count =
|
||||
count.try_eval_target_usize(tcx, param_env).ok_or(LayoutError::Unknown(ty))?;
|
||||
let element = cx.layout_of(element)?;
|
||||
let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?;
|
||||
|
||||
|
|
|
@ -39,35 +39,35 @@ pub use ty_info::*;
|
|||
pub trait HashStableContext {}
|
||||
|
||||
pub trait Interner: Sized {
|
||||
type AdtDef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type SubstsRef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type DefId: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type AdtDef: Clone + Debug + Hash + Ord;
|
||||
type SubstsRef: Clone + Debug + Hash + Ord;
|
||||
type DefId: Clone + Debug + Hash + Ord;
|
||||
type Binder<T>;
|
||||
type Ty: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type Const: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type Region: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type Ty: Clone + Debug + Hash + Ord;
|
||||
type Const: Clone + Debug + Hash + Ord;
|
||||
type Region: Clone + Debug + Hash + Ord;
|
||||
type Predicate;
|
||||
type TypeAndMut: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type Mutability: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type Movability: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type PolyFnSig: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type ListBinderExistentialPredicate: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type BinderListTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type ListTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type AliasTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type ParamTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type BoundTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type PlaceholderType: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type InferTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type ErrorGuaranteed: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type TypeAndMut: Clone + Debug + Hash + Ord;
|
||||
type Mutability: Clone + Debug + Hash + Ord;
|
||||
type Movability: Clone + Debug + Hash + Ord;
|
||||
type PolyFnSig: Clone + Debug + Hash + Ord;
|
||||
type ListBinderExistentialPredicate: Clone + Debug + Hash + Ord;
|
||||
type BinderListTy: Clone + Debug + Hash + Ord;
|
||||
type ListTy: Clone + Debug + Hash + Ord;
|
||||
type AliasTy: Clone + Debug + Hash + Ord;
|
||||
type ParamTy: Clone + Debug + Hash + Ord;
|
||||
type BoundTy: Clone + Debug + Hash + Ord;
|
||||
type PlaceholderType: Clone + Debug + Hash + Ord;
|
||||
type InferTy: Clone + Debug + Hash + Ord;
|
||||
type ErrorGuaranteed: Clone + Debug + Hash + Ord;
|
||||
type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
|
||||
type AllocId: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type AllocId: Clone + Debug + Hash + Ord;
|
||||
|
||||
type EarlyBoundRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type BoundRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type FreeRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type RegionVid: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type PlaceholderRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
|
||||
type EarlyBoundRegion: Clone + Debug + Hash + Ord;
|
||||
type BoundRegion: Clone + Debug + Hash + Ord;
|
||||
type FreeRegion: Clone + Debug + Hash + Ord;
|
||||
type RegionVid: Clone + Debug + Hash + Ord;
|
||||
type PlaceholderRegion: Clone + Debug + Hash + Ord;
|
||||
}
|
||||
|
||||
pub trait InternAs<T: ?Sized, R> {
|
||||
|
|
|
@ -11,9 +11,9 @@ macro_rules! map_array {
|
|||
};
|
||||
}
|
||||
|
||||
map_array!(map_8byte_8byte_8, 0u64, 1u64, 800);
|
||||
map_array!(map_8byte_8byte_64, 0u64, 1u64, 6400);
|
||||
map_array!(map_8byte_8byte_256, 0u64, 1u64, 25600);
|
||||
map_array!(map_8byte_8byte_8, 0u64, 1u64, 80);
|
||||
map_array!(map_8byte_8byte_64, 0u64, 1u64, 640);
|
||||
map_array!(map_8byte_8byte_256, 0u64, 1u64, 2560);
|
||||
|
||||
map_array!(map_8byte_256byte_256, 0u64, [0u64; 4], 25600);
|
||||
map_array!(map_256byte_8byte_256, [0u64; 4], 0u64, 25600);
|
||||
map_array!(map_8byte_256byte_256, 0u64, [0u64; 4], 2560);
|
||||
map_array!(map_256byte_8byte_256, [0u64; 4], 0u64, 2560);
|
||||
|
|
|
@ -23,8 +23,6 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "Follow the rabbit";
|
||||
/// let ptr: *const u8 = s.as_ptr();
|
||||
|
@ -323,8 +321,6 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let ptr: *const u8 = &10u8 as *const u8;
|
||||
///
|
||||
|
@ -384,8 +380,6 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_as_uninit)]
|
||||
///
|
||||
|
@ -449,8 +443,6 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "123";
|
||||
/// let ptr: *const u8 = s.as_ptr();
|
||||
|
@ -526,8 +518,6 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // Iterate using a raw pointer in increments of two elements
|
||||
/// let data = [1u8, 2, 3, 4, 5];
|
||||
|
@ -908,8 +898,6 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "123";
|
||||
/// let ptr: *const u8 = s.as_ptr();
|
||||
|
@ -993,8 +981,6 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "123";
|
||||
///
|
||||
|
@ -1072,8 +1058,6 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // Iterate using a raw pointer in increments of two elements
|
||||
/// let data = [1u8, 2, 3, 4, 5];
|
||||
|
@ -1152,8 +1136,6 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // Iterate using a raw pointer in increments of two elements (backwards)
|
||||
/// let data = [1u8, 2, 3, 4, 5];
|
||||
|
@ -1359,7 +1341,6 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
/// ```
|
||||
/// #![feature(pointer_is_aligned)]
|
||||
/// #![feature(pointer_byte_offsets)]
|
||||
|
@ -1482,7 +1463,6 @@ impl<T: ?Sized> *const T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
/// ```
|
||||
/// #![feature(pointer_is_aligned)]
|
||||
/// #![feature(pointer_byte_offsets)]
|
||||
|
|
|
@ -22,8 +22,6 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let mut s = [1, 2, 3];
|
||||
/// let ptr: *mut u32 = s.as_mut_ptr();
|
||||
|
@ -332,8 +330,6 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let ptr: *mut u8 = &mut 10u8 as *mut u8;
|
||||
///
|
||||
|
@ -396,8 +392,6 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_as_uninit)]
|
||||
///
|
||||
|
@ -461,8 +455,6 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let mut s = [1, 2, 3];
|
||||
/// let ptr: *mut u32 = s.as_mut_ptr();
|
||||
|
@ -539,8 +531,6 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // Iterate using a raw pointer in increments of two elements
|
||||
/// let mut data = [1u8, 2, 3, 4, 5];
|
||||
|
@ -660,8 +650,6 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let mut s = [1, 2, 3];
|
||||
/// let ptr: *mut u32 = s.as_mut_ptr();
|
||||
|
@ -1010,8 +998,6 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "123";
|
||||
/// let ptr: *const u8 = s.as_ptr();
|
||||
|
@ -1095,8 +1081,6 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "123";
|
||||
///
|
||||
|
@ -1174,8 +1158,6 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // Iterate using a raw pointer in increments of two elements
|
||||
/// let data = [1u8, 2, 3, 4, 5];
|
||||
|
@ -1254,8 +1236,6 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // Iterate using a raw pointer in increments of two elements (backwards)
|
||||
/// let data = [1u8, 2, 3, 4, 5];
|
||||
|
@ -1627,7 +1607,6 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
/// ```
|
||||
/// #![feature(pointer_is_aligned)]
|
||||
/// #![feature(pointer_byte_offsets)]
|
||||
|
@ -1752,7 +1731,6 @@ impl<T: ?Sized> *mut T {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
/// ```
|
||||
/// #![feature(pointer_is_aligned)]
|
||||
/// #![feature(pointer_byte_offsets)]
|
||||
|
|
|
@ -482,16 +482,16 @@ impl Item {
|
|||
}
|
||||
|
||||
pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
|
||||
use crate::html::format::href;
|
||||
use crate::html::format::{href, link_tooltip};
|
||||
|
||||
cx.cache()
|
||||
.intra_doc_links
|
||||
.get(&self.item_id)
|
||||
.map_or(&[][..], |v| v.as_slice())
|
||||
.iter()
|
||||
.filter_map(|ItemLink { link: s, link_text, page_id: did, ref fragment }| {
|
||||
debug!(?did);
|
||||
if let Ok((mut href, ..)) = href(*did, cx) {
|
||||
.filter_map(|ItemLink { link: s, link_text, page_id: id, ref fragment }| {
|
||||
debug!(?id);
|
||||
if let Ok((mut href, ..)) = href(*id, cx) {
|
||||
debug!(?href);
|
||||
if let Some(ref fragment) = *fragment {
|
||||
fragment.render(&mut href, cx.tcx())
|
||||
|
@ -499,6 +499,7 @@ impl Item {
|
|||
Some(RenderedLink {
|
||||
original_text: s.clone(),
|
||||
new_text: link_text.clone(),
|
||||
tooltip: link_tooltip(*id, fragment, cx),
|
||||
href,
|
||||
})
|
||||
} else {
|
||||
|
@ -523,6 +524,7 @@ impl Item {
|
|||
original_text: s.clone(),
|
||||
new_text: link_text.clone(),
|
||||
href: String::new(),
|
||||
tooltip: String::new(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -1040,6 +1042,8 @@ pub struct RenderedLink {
|
|||
pub(crate) new_text: String,
|
||||
/// The URL to put in the `href`
|
||||
pub(crate) href: String,
|
||||
/// The tooltip.
|
||||
pub(crate) tooltip: String,
|
||||
}
|
||||
|
||||
/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
|
||||
|
|
|
@ -34,6 +34,7 @@ use crate::clean::{
|
|||
use crate::formats::item_type::ItemType;
|
||||
use crate::html::escape::Escape;
|
||||
use crate::html::render::Context;
|
||||
use crate::passes::collect_intra_doc_links::UrlFragment;
|
||||
|
||||
use super::url_parts_builder::estimate_item_path_byte_length;
|
||||
use super::url_parts_builder::UrlPartsBuilder;
|
||||
|
@ -768,6 +769,21 @@ pub(crate) fn href_relative_parts<'fqp>(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Context<'_>) -> String {
|
||||
let cache = cx.cache();
|
||||
let Some((fqp, shortty)) = cache.paths.get(&did)
|
||||
.or_else(|| cache.external_paths.get(&did))
|
||||
else { return String::new() };
|
||||
let fqp = fqp.iter().map(|sym| sym.as_str()).join("::");
|
||||
if let &Some(UrlFragment::Item(id)) = fragment {
|
||||
let name = cx.tcx().item_name(id);
|
||||
let descr = cx.tcx().def_kind(id).descr(id);
|
||||
format!("{descr} {fqp}::{name}")
|
||||
} else {
|
||||
format!("{shortty} {fqp}")
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to render a [`clean::Path`].
|
||||
fn resolved_path<'cx>(
|
||||
w: &mut fmt::Formatter<'_>,
|
||||
|
|
|
@ -360,6 +360,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
|
|||
trace!("it matched");
|
||||
assert!(self.shortcut_link.is_none(), "shortcut links cannot be nested");
|
||||
self.shortcut_link = Some(link);
|
||||
if title.is_empty() && !link.tooltip.is_empty() {
|
||||
*title = CowStr::Borrowed(link.tooltip.as_ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now that we're done with the shortcut link, don't replace any more text.
|
||||
|
@ -410,9 +413,12 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
|
|||
}
|
||||
// If this is a link, but not a shortcut link,
|
||||
// replace the URL, since the broken_link_callback was not called.
|
||||
Some(Event::Start(Tag::Link(_, dest, _))) => {
|
||||
Some(Event::Start(Tag::Link(_, dest, title))) => {
|
||||
if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest) {
|
||||
*dest = CowStr::Borrowed(link.href.as_ref());
|
||||
if title.is_empty() && !link.tooltip.is_empty() {
|
||||
*title = CowStr::Borrowed(link.tooltip.as_ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Anything else couldn't have been a valid Rust path, so no need to replace the text.
|
||||
|
@ -976,7 +982,7 @@ impl Markdown<'_> {
|
|||
links
|
||||
.iter()
|
||||
.find(|link| link.original_text.as_str() == &*broken_link.reference)
|
||||
.map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
|
||||
.map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
|
||||
};
|
||||
|
||||
let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer));
|
||||
|
@ -1059,7 +1065,7 @@ impl MarkdownSummaryLine<'_> {
|
|||
links
|
||||
.iter()
|
||||
.find(|link| link.original_text.as_str() == &*broken_link.reference)
|
||||
.map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
|
||||
.map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
|
||||
};
|
||||
|
||||
let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer))
|
||||
|
@ -1106,7 +1112,7 @@ fn markdown_summary_with_limit(
|
|||
link_names
|
||||
.iter()
|
||||
.find(|link| link.original_text.as_str() == &*broken_link.reference)
|
||||
.map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
|
||||
.map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
|
||||
};
|
||||
|
||||
let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
|
||||
|
@ -1187,7 +1193,7 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
|
|||
link_names
|
||||
.iter()
|
||||
.find(|link| link.original_text.as_str() == &*broken_link.reference)
|
||||
.map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
|
||||
.map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
|
||||
};
|
||||
|
||||
let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
|
||||
|
|
|
@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
|||
if let Some(range) = higher::Range::hir(index) {
|
||||
// Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
|
||||
if let ty::Array(_, s) = ty.kind() {
|
||||
let size: u128 = if let Some(size) = s.try_eval_usize(cx.tcx, cx.param_env) {
|
||||
let size: u128 = if let Some(size) = s.try_eval_target_usize(cx.tcx, cx.param_env) {
|
||||
size.into()
|
||||
} else {
|
||||
return;
|
||||
|
|
|
@ -68,7 +68,7 @@ fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
|
|||
// IntoIterator is currently only implemented for array sizes <= 32 in rustc
|
||||
match ty.kind() {
|
||||
ty::Array(_, n) => n
|
||||
.try_eval_usize(cx.tcx, cx.param_env)
|
||||
.try_eval_target_usize(cx.tcx, cx.param_env)
|
||||
.map_or(false, |val| (0..=32).contains(&val)),
|
||||
_ => false,
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ fn is_end_eq_array_len<'tcx>(
|
|||
if let ExprKind::Lit(ref lit) = end.kind;
|
||||
if let ast::LitKind::Int(end_int, _) = lit.node;
|
||||
if let ty::Array(_, arr_len_const) = indexed_ty.kind();
|
||||
if let Some(arr_len) = arr_len_const.try_eval_usize(cx.tcx, cx.param_env);
|
||||
if let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env);
|
||||
then {
|
||||
return match limits {
|
||||
ast::RangeLimits::Closed => end_int + 1 >= arr_len.into(),
|
||||
|
|
|
@ -22,7 +22,7 @@ pub(super) fn derefs_to_slice<'tcx>(
|
|||
ty::Slice(_) => true,
|
||||
ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
|
||||
ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::Vec),
|
||||
ty::Array(_, size) => size.try_eval_usize(cx.tcx, cx.param_env).is_some(),
|
||||
ty::Array(_, size) => size.try_eval_target_usize(cx.tcx, cx.param_env).is_some(),
|
||||
ty::Ref(_, inner, _) => may_slice(cx, *inner),
|
||||
_ => false,
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ impl MutableKeyType {
|
|||
Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty),
|
||||
Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty),
|
||||
Array(inner_ty, size) => {
|
||||
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
|
||||
size.try_eval_target_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
|
||||
&& self.is_interior_mutable_type(cx, inner_ty)
|
||||
},
|
||||
Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)),
|
||||
|
|
|
@ -62,7 +62,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_
|
|||
|
||||
// Then check if that that array zero-sized
|
||||
let length = Const::from_anon_const(cx.tcx, length.def_id);
|
||||
let length = length.try_eval_usize(cx.tcx, cx.param_env);
|
||||
let length = length.try_eval_target_usize(cx.tcx, cx.param_env);
|
||||
if let Some(length) = length;
|
||||
then {
|
||||
length == 0
|
||||
|
|
|
@ -335,7 +335,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||
ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
|
||||
ExprKind::Repeat(value, _) => {
|
||||
let n = match self.typeck_results.expr_ty(e).kind() {
|
||||
ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
|
||||
ty::Array(_, n) => n.try_eval_target_usize(self.lcx.tcx, self.lcx.param_env)?,
|
||||
_ => span_bug!(e.span, "typeck error"),
|
||||
};
|
||||
self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
|
||||
|
|
|
@ -949,7 +949,7 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
|
|||
(Ok(size), _) => size,
|
||||
(Err(_), ty::Tuple(list)) => list.as_substs().types().map(|t| approx_ty_size(cx, t)).sum(),
|
||||
(Err(_), ty::Array(t, n)) => {
|
||||
n.try_eval_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t)
|
||||
n.try_eval_target_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t)
|
||||
},
|
||||
(Err(_), ty::Adt(def, subst)) if def.is_struct() => def
|
||||
.variants()
|
||||
|
|
|
@ -469,7 +469,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let ty::Array(_, index_len) = index.layout.ty.kind() else {
|
||||
span_bug!(this.cur_span(), "simd_shuffle index argument has non-array type {}", index.layout.ty)
|
||||
};
|
||||
let index_len = index_len.eval_usize(*this.tcx, this.param_env());
|
||||
let index_len = index_len.eval_target_usize(*this.tcx, this.param_env());
|
||||
|
||||
assert_eq!(left_len, right_len);
|
||||
assert_eq!(index_len, dest_len);
|
||||
|
|
|
@ -1,21 +1,38 @@
|
|||
// @has basic/index.html
|
||||
// @has - '//a/@href' 'struct.ThisType.html'
|
||||
// @has - '//a/@title' 'struct basic::ThisType'
|
||||
// @has - '//a/@href' 'struct.ThisType.html#method.this_method'
|
||||
// @has - '//a/@title' 'associated function basic::ThisType::this_method'
|
||||
// @has - '//a/@href' 'enum.ThisEnum.html'
|
||||
// @has - '//a/@title' 'enum basic::ThisEnum'
|
||||
// @has - '//a/@href' 'enum.ThisEnum.html#variant.ThisVariant'
|
||||
// @has - '//a/@title' 'variant basic::ThisEnum::ThisVariant'
|
||||
// @has - '//a/@href' 'trait.ThisTrait.html'
|
||||
// @has - '//a/@title' 'trait basic::ThisTrait'
|
||||
// @has - '//a/@href' 'trait.ThisTrait.html#tymethod.this_associated_method'
|
||||
// @has - '//a/@title' 'associated function basic::ThisTrait::this_associated_method'
|
||||
// @has - '//a/@href' 'trait.ThisTrait.html#associatedtype.ThisAssociatedType'
|
||||
// @has - '//a/@title' 'associated type basic::ThisTrait::ThisAssociatedType'
|
||||
// @has - '//a/@href' 'trait.ThisTrait.html#associatedconstant.THIS_ASSOCIATED_CONST'
|
||||
// @has - '//a/@title' 'associated constant basic::ThisTrait::THIS_ASSOCIATED_CONST'
|
||||
// @has - '//a/@href' 'trait.ThisTrait.html'
|
||||
// @has - '//a/@title' 'trait basic::ThisTrait'
|
||||
// @has - '//a/@href' 'type.ThisAlias.html'
|
||||
// @has - '//a/@title' 'type basic::ThisAlias'
|
||||
// @has - '//a/@href' 'union.ThisUnion.html'
|
||||
// @has - '//a/@title' 'union basic::ThisUnion'
|
||||
// @has - '//a/@href' 'fn.this_function.html'
|
||||
// @has - '//a/@title' 'fn basic::this_function'
|
||||
// @has - '//a/@href' 'constant.THIS_CONST.html'
|
||||
// @has - '//a/@title' 'constant basic::THIS_CONST'
|
||||
// @has - '//a/@href' 'static.THIS_STATIC.html'
|
||||
// @has - '//a/@title' 'static basic::THIS_STATIC'
|
||||
// @has - '//a/@href' 'macro.this_macro.html'
|
||||
// @has - '//a/@title' 'macro basic::this_macro'
|
||||
// @has - '//a/@href' 'trait.SoAmbiguous.html'
|
||||
// @has - '//a/@title' 'trait basic::SoAmbiguous'
|
||||
// @has - '//a/@href' 'fn.SoAmbiguous.html'
|
||||
// @has - '//a/@title' 'fn basic::SoAmbiguous'
|
||||
//! In this crate we would like to link to:
|
||||
//!
|
||||
//! * [`ThisType`](ThisType)
|
||||
|
|
9
tests/ui/parser/suggest_misplaced_generics/enum.fixed
Normal file
9
tests/ui/parser/suggest_misplaced_generics/enum.fixed
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// run-rustfix
|
||||
|
||||
#[allow(unused)]
|
||||
enum Foo<T> { Variant(T) }
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the enum name
|
||||
|
||||
fn main() {}
|
9
tests/ui/parser/suggest_misplaced_generics/enum.rs
Normal file
9
tests/ui/parser/suggest_misplaced_generics/enum.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// run-rustfix
|
||||
|
||||
#[allow(unused)]
|
||||
enum<T> Foo { Variant(T) }
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the enum name
|
||||
|
||||
fn main() {}
|
14
tests/ui/parser/suggest_misplaced_generics/enum.stderr
Normal file
14
tests/ui/parser/suggest_misplaced_generics/enum.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error: expected identifier, found `<`
|
||||
--> $DIR/enum.rs:5:5
|
||||
|
|
||||
LL | enum<T> Foo { Variant(T) }
|
||||
| ^ expected identifier
|
||||
|
|
||||
help: place the generic parameter name after the enum name
|
||||
|
|
||||
LL - enum<T> Foo { Variant(T) }
|
||||
LL + enum Foo<T> { Variant(T) }
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// Issue: 103366
|
||||
// there is already an existing generic on f, so don't show a suggestion
|
||||
|
||||
#[allow(unused)]
|
||||
fn<'a, B: 'a + std::ops::Add<Output = u32>> f<T>(_x: B) { }
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the fn name
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,10 @@
|
|||
error: expected identifier, found `<`
|
||||
--> $DIR/existing_generics.rs:5:3
|
||||
|
|
||||
LL | fn<'a, B: 'a + std::ops::Add<Output = u32>> f<T>(_x: B) { }
|
||||
| ^ expected identifier
|
||||
|
|
||||
= help: place the generic parameter name after the fn name
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// run-rustfix
|
||||
|
||||
#[allow(unused)]
|
||||
fn f<'a, B: 'a + std::ops::Add<Output = u32>>(_x: B) { }
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the fn name
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,9 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// run-rustfix
|
||||
|
||||
#[allow(unused)]
|
||||
fn<'a, B: 'a + std::ops::Add<Output = u32>> f(_x: B) { }
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the fn name
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,14 @@
|
|||
error: expected identifier, found `<`
|
||||
--> $DIR/fn-complex-generics.rs:5:3
|
||||
|
|
||||
LL | fn<'a, B: 'a + std::ops::Add<Output = u32>> f(_x: B) { }
|
||||
| ^ expected identifier
|
||||
|
|
||||
help: place the generic parameter name after the fn name
|
||||
|
|
||||
LL - fn<'a, B: 'a + std::ops::Add<Output = u32>> f(_x: B) { }
|
||||
LL + fn f<'a, B: 'a + std::ops::Add<Output = u32>>(_x: B) { }
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// The generics fail to parse here, so don't make any suggestions/help
|
||||
|
||||
#[allow(unused)]
|
||||
fn<~>()> id(x: T) -> T { x }
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,8 @@
|
|||
error: expected identifier, found `<`
|
||||
--> $DIR/fn-invalid-generics.rs:5:3
|
||||
|
|
||||
LL | fn<~>()> id(x: T) -> T { x }
|
||||
| ^ expected identifier
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// run-rustfix
|
||||
|
||||
#[allow(unused)]
|
||||
fn id<T>(x: T) -> T { x }
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the fn name
|
||||
|
||||
fn main() {}
|
9
tests/ui/parser/suggest_misplaced_generics/fn-simple.rs
Normal file
9
tests/ui/parser/suggest_misplaced_generics/fn-simple.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// run-rustfix
|
||||
|
||||
#[allow(unused)]
|
||||
fn<T> id(x: T) -> T { x }
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the fn name
|
||||
|
||||
fn main() {}
|
14
tests/ui/parser/suggest_misplaced_generics/fn-simple.stderr
Normal file
14
tests/ui/parser/suggest_misplaced_generics/fn-simple.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error: expected identifier, found `<`
|
||||
--> $DIR/fn-simple.rs:5:3
|
||||
|
|
||||
LL | fn<T> id(x: T) -> T { x }
|
||||
| ^ expected identifier
|
||||
|
|
||||
help: place the generic parameter name after the fn name
|
||||
|
|
||||
LL - fn<T> id(x: T) -> T { x }
|
||||
LL + fn id<T>(x: T) -> T { x }
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
9
tests/ui/parser/suggest_misplaced_generics/struct.fixed
Normal file
9
tests/ui/parser/suggest_misplaced_generics/struct.fixed
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// run-rustfix
|
||||
|
||||
#[allow(unused)]
|
||||
struct Foo<T> { x: T }
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the struct name
|
||||
|
||||
fn main() {}
|
9
tests/ui/parser/suggest_misplaced_generics/struct.rs
Normal file
9
tests/ui/parser/suggest_misplaced_generics/struct.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// run-rustfix
|
||||
|
||||
#[allow(unused)]
|
||||
struct<T> Foo { x: T }
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the struct name
|
||||
|
||||
fn main() {}
|
14
tests/ui/parser/suggest_misplaced_generics/struct.stderr
Normal file
14
tests/ui/parser/suggest_misplaced_generics/struct.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error: expected identifier, found `<`
|
||||
--> $DIR/struct.rs:5:7
|
||||
|
|
||||
LL | struct<T> Foo { x: T }
|
||||
| ^ expected identifier
|
||||
|
|
||||
help: place the generic parameter name after the struct name
|
||||
|
|
||||
LL - struct<T> Foo { x: T }
|
||||
LL + struct Foo<T> { x: T }
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
11
tests/ui/parser/suggest_misplaced_generics/trait.fixed
Normal file
11
tests/ui/parser/suggest_misplaced_generics/trait.fixed
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// run-rustfix
|
||||
|
||||
#[allow(unused)]
|
||||
trait Foo<T> {
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the trait name
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
11
tests/ui/parser/suggest_misplaced_generics/trait.rs
Normal file
11
tests/ui/parser/suggest_misplaced_generics/trait.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// run-rustfix
|
||||
|
||||
#[allow(unused)]
|
||||
trait<T> Foo {
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the trait name
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
14
tests/ui/parser/suggest_misplaced_generics/trait.stderr
Normal file
14
tests/ui/parser/suggest_misplaced_generics/trait.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error: expected identifier, found `<`
|
||||
--> $DIR/trait.rs:5:6
|
||||
|
|
||||
LL | trait<T> Foo {
|
||||
| ^ expected identifier
|
||||
|
|
||||
help: place the generic parameter name after the trait name
|
||||
|
|
||||
LL - trait<T> Foo {
|
||||
LL + trait Foo<T> {
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
9
tests/ui/parser/suggest_misplaced_generics/type.fixed
Normal file
9
tests/ui/parser/suggest_misplaced_generics/type.fixed
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// run-rustfix
|
||||
|
||||
#[allow(unused)]
|
||||
type Foo<T> = T;
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the type name
|
||||
|
||||
fn main() {}
|
9
tests/ui/parser/suggest_misplaced_generics/type.rs
Normal file
9
tests/ui/parser/suggest_misplaced_generics/type.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Issue: 103366 , Suggest fix for misplaced generic params
|
||||
// run-rustfix
|
||||
|
||||
#[allow(unused)]
|
||||
type<T> Foo = T;
|
||||
//~^ ERROR expected identifier, found `<`
|
||||
//~| HELP place the generic parameter name after the type name
|
||||
|
||||
fn main() {}
|
14
tests/ui/parser/suggest_misplaced_generics/type.stderr
Normal file
14
tests/ui/parser/suggest_misplaced_generics/type.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error: expected identifier, found `<`
|
||||
--> $DIR/type.rs:5:5
|
||||
|
|
||||
LL | type<T> Foo = T;
|
||||
| ^ expected identifier
|
||||
|
|
||||
help: place the generic parameter name after the type name
|
||||
|
|
||||
LL - type<T> Foo = T;
|
||||
LL + type Foo<T> = T;
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
9
tests/ui/single-use-lifetime/issue-107998.rs
Normal file
9
tests/ui/single-use-lifetime/issue-107998.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
#![deny(single_use_lifetimes)]
|
||||
|
||||
fn with<R>(f: &fn<'a>(x: &'a i32) -> R) -> R {
|
||||
//~^ ERROR function pointer types may not have generic parameters
|
||||
//~| ERROR lifetime parameter `'a` only used once
|
||||
f(&3)
|
||||
}
|
||||
|
||||
fn main() {}
|
30
tests/ui/single-use-lifetime/issue-107998.stderr
Normal file
30
tests/ui/single-use-lifetime/issue-107998.stderr
Normal file
|
@ -0,0 +1,30 @@
|
|||
error: function pointer types may not have generic parameters
|
||||
--> $DIR/issue-107998.rs:3:18
|
||||
|
|
||||
LL | fn with<R>(f: &fn<'a>(x: &'a i32) -> R) -> R {
|
||||
| ^^^^
|
||||
|
|
||||
help: consider moving the lifetime parameter to a `for` parameter list
|
||||
|
|
||||
LL - fn with<R>(f: &fn<'a>(x: &'a i32) -> R) -> R {
|
||||
LL + fn with<R>(f: &for<'a> fn(x: &'a i32) -> R) -> R {
|
||||
|
|
||||
|
||||
error: lifetime parameter `'a` only used once
|
||||
--> $DIR/issue-107998.rs:3:19
|
||||
|
|
||||
LL | fn with<R>(f: &fn<'a>(x: &'a i32) -> R) -> R {
|
||||
| ^^ ---
|
||||
| | |
|
||||
| | ...is used only here
|
||||
| | help: elide the single-use lifetime
|
||||
| this lifetime...
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/issue-107998.rs:1:9
|
||||
|
|
||||
LL | #![deny(single_use_lifetimes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -468,6 +468,9 @@ This was probably unintentional and should be reverted before this PR is merged.
|
|||
If this was intentional then you can ignore this comment.
|
||||
"""
|
||||
|
||||
[mentions."src/tools/x"]
|
||||
message = "`src/tools/x` was changed. Bump version of Cargo.toml in `src/tools/x` so tidy will suggest installing the new version."
|
||||
|
||||
[assign]
|
||||
warn_non_default_branch = true
|
||||
contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue