diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index cbf8aa313c5..698fdafc936 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -187,10 +187,10 @@ fn do_mir_borrowck<'tcx>( let location_table = LocationTable::new(body); - let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true); + let move_data = MoveData::gather_moves(body, tcx, |_| true); let promoted_move_data = promoted .iter_enumerated() - .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, param_env, |_| true))); + .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true))); let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) .into_engine(tcx, body) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 238d7d0749a..7b60a632c30 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1128,7 +1128,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } let projected_ty = curr_projected_ty.projection_ty_core( tcx, - self.param_env, proj, |this, field, ()| { let ty = this.field_ty(tcx, field); @@ -1919,7 +1918,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_target_usize(tcx, self.param_env).map_or(true, |len| len > 1) { + if len.try_to_target_usize(tcx).is_none_or(|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. diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index cbe411d78d5..e7f9f894381 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -133,6 +133,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( .expect_const() .try_to_valtree() .expect("expected monomorphic const in codegen") + .0 .unwrap_branch(); assert_eq!(x.layout(), y.layout()); @@ -806,8 +807,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => m.load_scalar(fx), ty::Array(elem, len) if matches!(elem.kind(), ty::Uint(ty::UintTy::U8)) - && len.try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all()) - == Some(expected_bytes) => + && len + .try_to_target_usize(fx.tcx) + .expect("expected monomorphic const in codegen") + == expected_bytes => { m.force_stack(fx).0.load( fx, @@ -907,8 +910,10 @@ 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_target_usize(fx.tcx, ty::ParamEnv::reveal_all()) - == Some(expected_bytes) => {} + && len + .try_to_target_usize(fx.tcx) + .expect("expected monomorphic const in codegen") + == expected_bytes => {} _ => { fx.tcx.dcx().span_fatal( span, diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 4e1b99fdebf..43dbfafa871 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -76,8 +76,10 @@ pub fn generic_simd_intrinsic<'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_target_usize(bx.tcx, ty::ParamEnv::reveal_all()) - == Some(expected_bytes) => + && len + .try_to_target_usize(bx.tcx) + .expect("expected monomorphic const in codegen") + == expected_bytes => { let place = PlaceRef::alloca(bx, args[0].layout); args[0].val.store(bx, place); @@ -696,8 +698,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( } ty::Array(elem, len) if matches!(*elem.kind(), ty::Uint(ty::UintTy::U8)) - && len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all()) - == Some(expected_bytes) => + && len + .try_to_target_usize(bx.tcx) + .expect("expected monomorphic const in codegen") + == expected_bytes => { // Zero-extend iN to the array length: let ze = bx.zext(result, bx.type_ix(expected_bytes * 8)); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 64f1d21b438..c9a17c9852d 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1179,8 +1179,10 @@ 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_target_usize(bx.tcx, ty::ParamEnv::reveal_all()) - == Some(expected_bytes) => + && len + .try_to_target_usize(bx.tcx) + .expect("expected monomorphic const in codegen") + == expected_bytes => { let place = PlaceRef::alloca(bx, args[0].layout); args[0].val.store(bx, place); @@ -1245,12 +1247,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } if name == sym::simd_shuffle_generic { - let idx = fn_args[2] - .expect_const() - .eval(tcx, ty::ParamEnv::reveal_all(), span) - .unwrap() - .1 - .unwrap_branch(); + let idx = fn_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch(); let n = idx.len() as u64; let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn); @@ -1469,8 +1466,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } ty::Array(elem, len) if matches!(elem.kind(), ty::Uint(ty::UintTy::U8)) - && len.try_eval_target_usize(bx.tcx, ty::ParamEnv::reveal_all()) - == Some(expected_bytes) => + && len + .try_to_target_usize(bx.tcx) + .expect("expected monomorphic const in codegen") + == expected_bytes => { // Zero-extend iN to the array length: let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8)); diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 369ab387bea..526d2b86d48 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -23,7 +23,6 @@ use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{ self, ExistentialProjection, GenericArgKind, GenericArgsRef, ParamEnv, Ty, TyCtxt, }; -use rustc_span::DUMMY_SP; use rustc_target::abi::Integer; use smallvec::SmallVec; @@ -685,21 +684,25 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S ty::ConstKind::Param(param) => { write!(output, "{}", param.name) } - ty::ConstKind::Value(ty, _) => { + ty::ConstKind::Value(ty, valtree) => { match ty.kind() { ty::Int(ity) => { // FIXME: directly extract the bits from a valtree instead of evaluating an // already evaluated `Const` in order to get the bits. - let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); + let bits = ct + .try_to_bits(tcx, ty::ParamEnv::reveal_all()) + .expect("expected monomorphic const in codegen"); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; write!(output, "{val}") } ty::Uint(_) => { - let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); + let val = ct + .try_to_bits(tcx, ty::ParamEnv::reveal_all()) + .expect("expected monomorphic const in codegen"); write!(output, "{val}") } ty::Bool => { - let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap(); + let val = ct.try_to_bool().expect("expected monomorphic const in codegen"); write!(output, "{val}") } _ => { @@ -711,8 +714,9 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S // avoiding collisions and will make the emitted type names shorter. let hash_short = tcx.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); - let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP).unwrap(); - hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher)); + hcx.while_hashing_spans(false, |hcx| { + (ty, valtree).hash_stable(hcx, &mut hasher) + }); hasher.finish::() }); diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index ba19f642795..e2e4754a45c 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -43,7 +43,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( // We go to `usize` as we cannot allocate anything bigger anyway. let (field_count, variant, down) = match ty.kind() { - ty::Array(_, len) => (len.eval_target_usize(tcx.tcx, param_env) as usize, None, op), + ty::Array(_, len) => (len.try_to_target_usize(tcx.tcx)? as usize, None, op), ty::Adt(def, _) if def.variants().is_empty() => { return None; } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 1def3d08328..64b15611316 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -391,7 +391,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ptr = self.read_pointer(src)?; let val = Immediate::new_slice( ptr, - length.eval_target_usize(*self.tcx, self.param_env), + length + .try_to_target_usize(*self.tcx) + .expect("expected monomorphic const in const eval"), self, ); self.write_immediate(val, dest) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 94da3d4ea84..34f596271aa 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1037,7 +1037,11 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { return; } - if let Some(len) = len_const.try_eval_target_usize(tcx, tcx.param_env(def.did())) { + // FIXME(repr_simd): This check is nice, but perhaps unnecessary due to the fact + // we do not expect users to implement their own `repr(simd)` types. If they could, + // this check is easily side-steppable by hiding the const behind normalization. + // The consequence is that the error is, in general, only observable post-mono. + if let Some(len) = len_const.try_to_target_usize(tcx) { if len == 0 { struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit(); return; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 71eb368185e..bbff00cd3b3 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -76,9 +76,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { let (size, ty) = match elem_ty.kind() { ty::Array(ty, len) => { - if let Some(len) = - len.try_eval_target_usize(self.tcx, self.tcx.param_env(adt.did())) - { + if let Some(len) = len.try_to_target_usize(self.tcx) { (len, *ty) } else { return None; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index eccb18ad6c4..2bc84d1ac67 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1487,7 +1487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } else if self.tcx.features().generic_const_exprs { - ct.normalize(self.tcx, self.param_env) + ct.normalize_internal(self.tcx, self.param_env) } else { ct } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8bd9c899a62..ef8100da9e2 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2601,7 +2601,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_target_usize(cx.tcx, cx.param_env), Some(v) if v > 0) { + if matches!(len.try_to_target_usize(cx.tcx), Some(v) if v > 0) { // Array length known at array non-empty -- recurse. ty_find_init_error(cx, *ty, init) } else { diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 1a007250961..ddc18c755a8 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -346,7 +346,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { None } } - ty::Array(ty, len) => match len.try_eval_target_usize(cx.tcx, cx.param_env) { + ty::Array(ty, len) => match len.try_to_target_usize(cx.tcx) { // 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. diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 4262460d928..465aa0eee03 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -1,5 +1,6 @@ use std::fmt::{self, Debug, Display, Formatter}; +use either::Either; use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_session::RemapFileNameExt; @@ -320,8 +321,14 @@ impl<'tcx> Const<'tcx> { Const::Ty(_, c) => { // We want to consistently have a "clean" value for type system constants (i.e., no // data hidden in the padding), so we always go through a valtree here. - let (ty, val) = c.eval(tcx, param_env, span)?; - Ok(tcx.valtree_to_const_val((ty, val))) + match c.eval_valtree(tcx, param_env, span) { + Ok((ty, val)) => Ok(tcx.valtree_to_const_val((ty, val))), + Err(Either::Left(_bad_ty)) => Err(tcx + .dcx() + .delayed_bug("`mir::Const::eval` called on a non-valtree-compatible type") + .into()), + Err(Either::Right(e)) => Err(e), + } } Const::Unevaluated(uneval, _) => { // FIXME: We might want to have a `try_eval`-like function on `Unevaluated` diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 8d57d0d8654..476e352ed92 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -55,7 +55,7 @@ impl<'tcx> PlaceTy<'tcx> { /// `PlaceElem`, where we can just use the `Ty` that is already /// stored inline on field projection elems. pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { - self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty, |_, ty| ty) + self.projection_ty_core(tcx, &elem, |_, _, ty| ty, |_, ty| ty) } /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` @@ -66,7 +66,6 @@ impl<'tcx> PlaceTy<'tcx> { pub fn projection_ty_core( self, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, elem: &ProjectionElem, mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>, mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>, @@ -93,7 +92,9 @@ impl<'tcx> PlaceTy<'tcx> { ty::Slice(..) => self.ty, ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from), ty::Array(inner, size) if from_end => { - let size = size.eval_target_usize(tcx, param_env); + let size = size + .try_to_target_usize(tcx) + .expect("expected subslice projection on fixed-size array"); let len = size - from - to; Ty::new_array(tcx, *inner, len) } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 389d20f315f..eb715be22b1 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -398,133 +398,65 @@ impl<'tcx> Const<'tcx> { } } - /// Returns the evaluated constant - #[inline] - pub fn eval( - self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - span: Span, - ) -> Result<(Ty<'tcx>, ValTree<'tcx>), ErrorHandled> { - self.eval_valtree(tcx, param_env, span).map_err(|err| { - match err { - Either::Right(err) => err, - Either::Left(_bad_ty) => { - // This can happen when we run on ill-typed code. - let e = tcx.dcx().span_delayed_bug( - span, - "`ty::Const::eval` called on a non-valtree-compatible type", - ); - e.into() - } - } - }) - } - /// Normalizes the constant to a value or an error if possible. #[inline] - pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { - match self.eval(tcx, param_env, DUMMY_SP) { + pub fn normalize_internal(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { + match self.eval_valtree(tcx, param_env, DUMMY_SP) { Ok((ty, val)) => Self::new_value(tcx, val, ty), - Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into()), - Err(ErrorHandled::TooGeneric(_span)) => self, + Err(Either::Left(_bad_ty)) => { + // This can happen when we run on ill-typed code. + Self::new_error( + tcx, + tcx.dcx() + .delayed_bug("`ty::Const::eval` called on a non-valtree-compatible type"), + ) + } + Err(Either::Right(ErrorHandled::Reported(r, _span))) => Self::new_error(tcx, r.into()), + Err(Either::Right(ErrorHandled::TooGeneric(_span))) => self, } } - #[inline] - pub fn try_eval_scalar( - self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Option<(Ty<'tcx>, Scalar)> { - let (ty, val) = self.eval(tcx, param_env, DUMMY_SP).ok()?; - let val = val.try_to_scalar()?; - Some((ty, val)) - } - - #[inline] - /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of - /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it - /// contains const generic parameters or pointers). - pub fn try_eval_scalar_int( - self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ) -> Option<(Ty<'tcx>, ScalarInt)> { - let (ty, scalar) = self.try_eval_scalar(tcx, param_env)?; - let val = scalar.try_to_scalar_int().ok()?; - Some((ty, val)) - } - - #[inline] - /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of - /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it - /// contains const generic parameters or pointers). - pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option { - let (ty, scalar) = self.try_eval_scalar_int(tcx, param_env)?; - let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; - // if `ty` does not depend on generic parameters, use an empty param_env - Some(scalar.to_bits(size)) - } - - #[inline] - /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. - pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u128 { - self.try_eval_bits(tcx, param_env) - .unwrap_or_else(|| bug!("failed to evalate {:#?} to bits", self)) - } - - #[inline] - pub fn try_eval_target_usize( - self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ) -> Option { - let (_, scalar) = self.try_eval_scalar_int(tcx, param_env)?; - Some(scalar.to_target_usize(tcx)) - } - - #[inline] - pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option { - let (_, scalar) = self.try_eval_scalar_int(tcx, param_env)?; - scalar.try_into().ok() - } - - #[inline] - /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`. - 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)) - } - /// Panics if self.kind != ty::ConstKind::Value - pub fn to_valtree(self) -> ty::ValTree<'tcx> { + pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) { match self.kind() { - ty::ConstKind::Value(_, valtree) => valtree, + ty::ConstKind::Value(ty, valtree) => (valtree, ty), _ => bug!("expected ConstKind::Value, got {:?}", self.kind()), } } /// Attempts to convert to a `ValTree` - pub fn try_to_valtree(self) -> Option> { + pub fn try_to_valtree(self) -> Option<(ty::ValTree<'tcx>, Ty<'tcx>)> { match self.kind() { - ty::ConstKind::Value(_, valtree) => Some(valtree), + ty::ConstKind::Value(ty, valtree) => Some((valtree, ty)), _ => None, } } #[inline] - pub fn try_to_scalar(self) -> Option { - self.try_to_valtree()?.try_to_scalar() + pub fn try_to_scalar(self) -> Option<(Scalar, Ty<'tcx>)> { + let (valtree, ty) = self.try_to_valtree()?; + Some((valtree.try_to_scalar()?, ty)) } pub fn try_to_bool(self) -> Option { - self.try_to_valtree()?.try_to_scalar_int()?.try_to_bool().ok() + self.try_to_valtree()?.0.try_to_scalar_int()?.try_to_bool().ok() } #[inline] pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option { - self.try_to_valtree()?.try_to_target_usize(tcx) + self.try_to_valtree()?.0.try_to_target_usize(tcx) + } + + #[inline] + /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of + /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it + /// contains const generic parameters or pointers). + pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option { + let (scalar, ty) = self.try_to_scalar()?; + let scalar = scalar.try_to_scalar_int().ok()?; + let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; + // if `ty` does not depend on generic parameters, use an empty param_env + Some(scalar.to_bits(size)) } pub fn is_ct_infer(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index 54b8507babf..bf741f63a3d 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -85,7 +85,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { match self { Self::False => Ok(false), Self::True => Ok(true), - Self::ConstIsZero(const_) => match const_.try_eval_target_usize(tcx, param_env) { + Self::ConstIsZero(const_) => match const_.try_to_target_usize(tcx) { None | Some(0) => Ok(true), Some(1..) => Ok(false), }, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 6c12b691c26..3670b6bbc77 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -397,7 +397,7 @@ impl<'tcx> SizeSkeleton<'tcx> { } } ty::Array(inner, len) if tcx.features().transmute_generic_consts => { - let len_eval = len.try_eval_target_usize(tcx, param_env); + let len_eval = len.try_to_target_usize(tcx); if len_eval == Some(0) { return Ok(SizeSkeleton::Known(Size::from_bytes(0), None)); } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 3f00458d195..74de378c4d7 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1117,7 +1117,12 @@ 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_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty) + ( + f0_len + .try_to_target_usize(tcx) + .expect("expected SIMD field to have definite array size"), + *f0_elem_ty, + ) } #[inline] diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index a3b117a3f19..7f2a07e2f5e 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -863,7 +863,7 @@ where ty::Adt(def, args) => self.open_drop_for_adt(*def, args), ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind), ty::Array(ety, size) => { - let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env()); + let size = size.try_to_target_usize(self.tcx()); self.open_drop_for_array(*ety, size) } ty::Slice(ety) => self.drop_loop_pair(*ety), diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 162245cb950..fd8e403ebc2 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -18,18 +18,12 @@ struct MoveDataBuilder<'a, 'tcx, F> { body: &'a Body<'tcx>, loc: Location, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, data: MoveData<'tcx>, filter: F, } impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { - fn new( - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - filter: F, - ) -> Self { + fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, filter: F) -> Self { let mut move_paths = IndexVec::new(); let mut path_map = IndexVec::new(); let mut init_path_map = IndexVec::new(); @@ -59,7 +53,6 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { body, loc: Location::START, tcx, - param_env, data: MoveData { moves: IndexVec::new(), loc_map: LocationMap::new(body), @@ -308,10 +301,9 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { pub(super) fn gather_moves<'tcx>( body: &Body<'tcx>, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, filter: impl Fn(Ty<'tcx>) -> bool, ) -> MoveData<'tcx> { - let mut builder = MoveDataBuilder::new(body, tcx, param_env, filter); + let mut builder = MoveDataBuilder::new(body, tcx, filter); builder.gather_args(); @@ -550,7 +542,9 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { }; let base_ty = base_place.ty(self.body, self.tcx).ty; let len: u64 = match base_ty.kind() { - ty::Array(_, size) => size.eval_target_usize(self.tcx, self.param_env), + ty::Array(_, size) => size + .try_to_target_usize(self.tcx) + .expect("expected subslice projection on fixed-size array"), _ => bug!("from_end: false slice pattern of non-array type"), }; for offset in from..to { diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index bc1177976b5..926bd187431 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -4,7 +4,7 @@ use std::ops::{Index, IndexMut}; use rustc_data_structures::fx::FxHashMap; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::*; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{Ty, TyCtxt}; use rustc_span::Span; use smallvec::SmallVec; @@ -352,10 +352,9 @@ impl<'tcx> MoveData<'tcx> { pub fn gather_moves( body: &Body<'tcx>, tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, filter: impl Fn(Ty<'tcx>) -> bool, ) -> MoveData<'tcx> { - builder::gather_moves(body, tcx, param_env, filter) + builder::gather_moves(body, tcx, filter) } /// For the move path `mpi`, returns the root local variable that starts the path. diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 75732b19cd0..5727517bd61 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -40,8 +40,7 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); } - let param_env = tcx.param_env(def_id); - let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true); + let move_data = MoveData::gather_moves(body, tcx, |_| true); if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() { let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 8f032728f6b..0a413d68020 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1957,7 +1957,8 @@ fn check_must_not_suspend_ty<'tcx>( let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix); check_must_not_suspend_ty(tcx, ty, hir_id, param_env, SuspendCheckData { descr_pre, - plural_len: len.try_eval_target_usize(tcx, param_env).unwrap_or(0) as usize + 1, + // FIXME(must_not_suspend): This is wrong. We should handle printing unevaluated consts. + plural_len: len.try_to_target_usize(tcx).unwrap_or(0) as usize + 1, ..data }) } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index f4ac4d9fee6..30e1ac05e03 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -58,8 +58,7 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops { let param_env = tcx.param_env_reveal_all_normalized(def_id); // For types that do not need dropping, the behaviour is trivial. So we only need to track // init/uninit for types that do need dropping. - let move_data = - MoveData::gather_moves(body, tcx, param_env, |ty| ty.needs_drop(tcx, param_env)); + let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env)); let elaborate_patch = { let env = MoveDataParamEnv { move_data, param_env }; diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 2f97c408f2a..08923748eb2 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -602,7 +602,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Len(place) => { let len = if let ty::Array(_, n) = place.ty(self.local_decls(), self.tcx).ty.kind() { - n.try_eval_target_usize(self.tcx, self.param_env)? + n.try_to_target_usize(self.tcx)? } else { match self.get_const(place)? { Value::Immediate(src) => src.len(&self.ecx).discard_err()?, diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index d963ca5c485..86c4b241a2b 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -329,7 +329,7 @@ impl<'tcx> Validator<'_, 'tcx> { // Determine the type of the thing we are indexing. && let ty::Array(_, len) = place_base.ty(self.body, self.tcx).ty.kind() // It's an array; determine its length. - && let Some(len) = len.try_eval_target_usize(self.tcx, self.param_env) + && let Some(len) = len.try_to_target_usize(self.tcx) // If the index is in-bounds, go ahead. && idx < len { @@ -407,7 +407,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_target_usize(self.tcx, self.param_env) { + match len.try_to_target_usize(self.tcx) { Some(0) => {} _ => return Err(Unpromotable), } diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index e6647edf3f5..09969a4c7cc 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -19,8 +19,7 @@ pub(super) struct RemoveUninitDrops; impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let param_env = tcx.param_env(body.source.def_id()); - let move_data = - MoveData::gather_moves(body, tcx, param_env, |ty| ty.needs_drop(tcx, param_env)); + let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env)); let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) .into_engine(tcx, body) diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index ff91fa13fd0..a475a58e483 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -295,6 +295,37 @@ where Ok(ty) } } + + /// Normalize a const for when it is structurally matched on, or more likely + /// when it needs `.try_to_*` called on it (e.g. to turn it into a usize). + /// + /// This function is necessary in nearly all cases before matching on a const. + /// Not doing so is likely to be incomplete and therefore unsound during + /// coherence. + #[instrument(level = "trace", skip(self, param_env), ret)] + fn structurally_normalize_const( + &mut self, + param_env: I::ParamEnv, + ct: I::Const, + ) -> Result { + if let ty::ConstKind::Unevaluated(..) = ct.kind() { + let normalized_ct = self.next_const_infer(); + let alias_relate_goal = Goal::new( + self.cx(), + param_env, + ty::PredicateKind::AliasRelate( + ct.into(), + normalized_ct.into(), + ty::AliasRelationDirection::Equate, + ), + ); + self.add_goal(GoalSource::Misc, alias_relate_goal); + self.try_evaluate_added_goals()?; + Ok(self.resolve_vars_if_possible(normalized_ct)) + } else { + Ok(ct) + } + } } fn response_no_constraints_raw( diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 2cbed0bceb2..a8d6536baad 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -627,11 +627,16 @@ where } ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + let assume = ecx.structurally_normalize_const( + goal.param_env, + goal.predicate.trait_ref.args.const_at(2), + )?; + let certainty = ecx.is_transmutable( goal.param_env, goal.predicate.trait_ref.args.type_at(0), goal.predicate.trait_ref.args.type_at(1), - goal.predicate.trait_ref.args.const_at(2), + assume, )?; ecx.evaluate_added_goals_and_make_canonical_response(certainty) }) diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 53834198f63..ca75952fe3d 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -133,7 +133,9 @@ fn encode_const<'tcx>( // bool value false is encoded as 0 and true as 1. match ct_ty.kind() { ty::Int(ity) => { - let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all()); + let bits = c + .try_to_bits(tcx, ty::ParamEnv::reveal_all()) + .expect("expected monomorphic const in cfi"); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; if val < 0 { s.push('n'); @@ -141,7 +143,9 @@ fn encode_const<'tcx>( let _ = write!(s, "{val}"); } ty::Uint(_) => { - let val = c.eval_bits(tcx, ty::ParamEnv::reveal_all()); + let val = c + .try_to_bits(tcx, ty::ParamEnv::reveal_all()) + .expect("expected monomorphic const in cfi"); let _ = write!(s, "{val}"); } ty::Bool => { diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index ed5d2d1e799..8fa8f2ac402 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -406,7 +406,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; let mir_const = cnst.internal(&mut *tables, tcx); mir_const - .try_eval_target_usize(tables.tcx, ParamEnv::empty()) + .try_to_target_usize(tables.tcx) .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64"))) } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index f3da7ff1ca7..d092fa8f082 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -555,7 +555,6 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { // We only mangle a typed value if the const can be evaluated. - let ct = ct.normalize(self.tcx, ty::ParamEnv::reveal_all()); let (ct_ty, valtree) = match ct.kind() { ty::ConstKind::Value(ty, val) => (ty, val), @@ -592,7 +591,9 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => { ct_ty.print(self)?; - let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all()); + let mut bits = ct + .try_to_bits(self.tcx, ty::ParamEnv::reveal_all()) + .expect("expected const to be monomorphic"); // Negative integer values are mangled using `n` as a "sign prefix". if let ty::Int(ity) = ct_ty.kind() { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 44373ca4866..322421340e9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2230,124 +2230,143 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span: Span, ) -> GetSafeTransmuteErrorAndReason { use rustc_transmute::Answer; + self.probe(|_| { + // We don't assemble a transmutability candidate for types that are generic + // and we should have ambiguity for types that still have non-region infer. + if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() { + return GetSafeTransmuteErrorAndReason::Default; + } - // We don't assemble a transmutability candidate for types that are generic - // and we should have ambiguity for types that still have non-region infer. - if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() { - return GetSafeTransmuteErrorAndReason::Default; - } + // Erase regions because layout code doesn't particularly care about regions. + let trait_ref = + self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref)); - // Erase regions because layout code doesn't particularly care about regions. - let trait_ref = - self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref)); + let src_and_dst = rustc_transmute::Types { + dst: trait_ref.args.type_at(0), + src: trait_ref.args.type_at(1), + }; - let src_and_dst = rustc_transmute::Types { - dst: trait_ref.args.type_at(0), - src: trait_ref.args.type_at(1), - }; - let Some(assume) = rustc_transmute::Assume::from_const( - self.infcx.tcx, - obligation.param_env, - trait_ref.args.const_at(2), - ) else { - self.dcx().span_delayed_bug( - span, - "Unable to construct rustc_transmute::Assume where it was previously possible", - ); - return GetSafeTransmuteErrorAndReason::Silent; - }; + let ocx = ObligationCtxt::new(self); + let Ok(assume) = ocx.structurally_normalize_const( + &obligation.cause, + obligation.param_env, + trait_ref.args.const_at(2), + ) else { + self.dcx().span_delayed_bug( + span, + "Unable to construct rustc_transmute::Assume where it was previously possible", + ); + return GetSafeTransmuteErrorAndReason::Silent; + }; - let dst = trait_ref.args.type_at(0); - let src = trait_ref.args.type_at(1); + let Some(assume) = + rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume) + else { + self.dcx().span_delayed_bug( + span, + "Unable to construct rustc_transmute::Assume where it was previously possible", + ); + return GetSafeTransmuteErrorAndReason::Silent; + }; - let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); + let dst = trait_ref.args.type_at(0); + let src = trait_ref.args.type_at(1); + let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); - match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( - obligation.cause, - src_and_dst, - assume, - ) { - Answer::No(reason) => { - let safe_transmute_explanation = match reason { - rustc_transmute::Reason::SrcIsNotYetSupported => { - format!("analyzing the transmutability of `{src}` is not yet supported") - } + match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( + obligation.cause, + src_and_dst, + assume, + ) { + Answer::No(reason) => { + let safe_transmute_explanation = match reason { + rustc_transmute::Reason::SrcIsNotYetSupported => { + format!("analyzing the transmutability of `{src}` is not yet supported") + } - rustc_transmute::Reason::DstIsNotYetSupported => { - format!("analyzing the transmutability of `{dst}` is not yet supported") - } + rustc_transmute::Reason::DstIsNotYetSupported => { + format!("analyzing the transmutability of `{dst}` is not yet supported") + } - rustc_transmute::Reason::DstIsBitIncompatible => { - format!("at least one value of `{src}` isn't a bit-valid value of `{dst}`") - } + rustc_transmute::Reason::DstIsBitIncompatible => { + format!( + "at least one value of `{src}` isn't a bit-valid value of `{dst}`" + ) + } - rustc_transmute::Reason::DstUninhabited => { - format!("`{dst}` is uninhabited") - } + rustc_transmute::Reason::DstUninhabited => { + format!("`{dst}` is uninhabited") + } - rustc_transmute::Reason::DstMayHaveSafetyInvariants => { - format!("`{dst}` may carry safety invariants") + rustc_transmute::Reason::DstMayHaveSafetyInvariants => { + format!("`{dst}` may carry safety invariants") + } + rustc_transmute::Reason::DstIsTooBig => { + format!("the size of `{src}` is smaller than the size of `{dst}`") + } + rustc_transmute::Reason::DstRefIsTooBig { src, dst } => { + let src_size = src.size; + let dst_size = dst.size; + format!( + "the referent size of `{src}` ({src_size} bytes) \ + is smaller than that of `{dst}` ({dst_size} bytes)" + ) + } + rustc_transmute::Reason::SrcSizeOverflow => { + format!( + "values of the type `{src}` are too big for the target architecture" + ) + } + rustc_transmute::Reason::DstSizeOverflow => { + format!( + "values of the type `{dst}` are too big for the target architecture" + ) + } + rustc_transmute::Reason::DstHasStricterAlignment { + src_min_align, + dst_min_align, + } => { + format!( + "the minimum alignment of `{src}` ({src_min_align}) should \ + be greater than that of `{dst}` ({dst_min_align})" + ) + } + rustc_transmute::Reason::DstIsMoreUnique => { + format!( + "`{src}` is a shared reference, but `{dst}` is a unique reference" + ) + } + // Already reported by rustc + rustc_transmute::Reason::TypeError => { + return GetSafeTransmuteErrorAndReason::Silent; + } + rustc_transmute::Reason::SrcLayoutUnknown => { + format!("`{src}` has an unknown layout") + } + rustc_transmute::Reason::DstLayoutUnknown => { + format!("`{dst}` has an unknown layout") + } + }; + GetSafeTransmuteErrorAndReason::Error { + err_msg, + safe_transmute_explanation: Some(safe_transmute_explanation), } - rustc_transmute::Reason::DstIsTooBig => { - format!("the size of `{src}` is smaller than the size of `{dst}`") - } - rustc_transmute::Reason::DstRefIsTooBig { src, dst } => { - let src_size = src.size; - let dst_size = dst.size; - format!( - "the referent size of `{src}` ({src_size} bytes) is smaller than that of `{dst}` ({dst_size} bytes)" - ) - } - rustc_transmute::Reason::SrcSizeOverflow => { - format!( - "values of the type `{src}` are too big for the target architecture" - ) - } - rustc_transmute::Reason::DstSizeOverflow => { - format!( - "values of the type `{dst}` are too big for the target architecture" - ) - } - rustc_transmute::Reason::DstHasStricterAlignment { - src_min_align, - dst_min_align, - } => { - format!( - "the minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})" - ) - } - rustc_transmute::Reason::DstIsMoreUnique => { - format!("`{src}` is a shared reference, but `{dst}` is a unique reference") - } - // Already reported by rustc - rustc_transmute::Reason::TypeError => { - return GetSafeTransmuteErrorAndReason::Silent; - } - rustc_transmute::Reason::SrcLayoutUnknown => { - format!("`{src}` has an unknown layout") - } - rustc_transmute::Reason::DstLayoutUnknown => { - format!("`{dst}` has an unknown layout") - } - }; - GetSafeTransmuteErrorAndReason::Error { - err_msg, - safe_transmute_explanation: Some(safe_transmute_explanation), } + // Should never get a Yes at this point! We already ran it before, and did not get a Yes. + Answer::Yes => span_bug!( + span, + "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes", + ), + // Reached when a different obligation (namely `Freeze`) causes the + // transmutability analysis to fail. In this case, silence the + // transmutability error message in favor of that more specific + // error. + Answer::If(_) => GetSafeTransmuteErrorAndReason::Error { + err_msg, + safe_transmute_explanation: None, + }, } - // Should never get a Yes at this point! We already ran it before, and did not get a Yes. - Answer::Yes => span_bug!( - span, - "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes", - ), - // Reached when a different obligation (namely `Freeze`) causes the - // transmutability analysis to fail. In this case, silence the - // transmutability error message in favor of that more specific - // error. - Answer::If(_) => { - GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation: None } - } - } + }) } /// For effects predicates such as `::Effects: Compat`, pretend that the diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index cd41ab9fa6c..7f42c932fcf 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -231,7 +231,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]` if let ty::Array(aty, len) = self_ty.kind() { flags.push((sym::_Self, Some("[]".to_string()))); - let len = len.try_to_valtree().and_then(|v| v.try_to_target_usize(self.tcx)); + let len = len.try_to_target_usize(self.tcx); flags.push((sym::_Self, Some(format!("[{aty}; _]")))); if let Some(n) = len { flags.push((sym::_Self, Some(format!("[{aty}; {n}]")))); diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index a45ec8b3c44..5e270b62b00 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -329,4 +329,15 @@ where .at(cause, param_env) .structurally_normalize(value, &mut **self.engine.borrow_mut()) } + + pub fn structurally_normalize_const( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: ty::Const<'tcx>, + ) -> Result, Vec> { + self.infcx + .at(cause, param_env) + .structurally_normalize_const(value, &mut **self.engine.borrow_mut()) + } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 0fb795fc184..960d34d7253 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -368,7 +368,7 @@ pub fn normalize_param_env_or_error<'tcx>( // should actually be okay since without `feature(generic_const_exprs)` the only // const arguments that have a non-empty param env are array repeat counts. These // do not appear in the type system though. - c.normalize(self.0, ty::ParamEnv::empty()) + c.normalize_internal(self.0, ty::ParamEnv::empty()) } } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 7eac3559348..d246d37f748 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -413,7 +413,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx self.selcx.infcx, &mut self.universes, constant, - |constant| constant.normalize(tcx, self.param_env), + |constant| constant.normalize_internal(tcx, self.param_env), ) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 18412b844ff..01e6516302c 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -340,7 +340,7 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { self.infcx, &mut self.universes, constant, - |constant| constant.normalize(self.infcx.tcx, self.param_env), + |constant| constant.normalize_internal(self.infcx.tcx, self.param_env), ); debug!(?constant, ?self.param_env); constant.try_super_fold_with(self) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 0ba3b4e6e55..f78cd6c1aa0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -405,11 +405,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let predicate = obligation.predicate.skip_binder(); - let Some(assume) = rustc_transmute::Assume::from_const( - self.infcx.tcx, - obligation.param_env, - predicate.trait_ref.args.const_at(2), - ) else { + let mut assume = predicate.trait_ref.args.const_at(2); + // FIXME(min_generic_const_exprs): We should shallowly normalize this. + if self.tcx().features().generic_const_exprs { + assume = assume.normalize_internal(self.tcx(), obligation.param_env); + } + let Some(assume) = + rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume) + else { return Err(Unimplemented); }; diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 3814f8112e9..f8d98eb856e 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -82,6 +82,8 @@ impl<'tcx> At<'_, 'tcx> { } Ok(self.infcx.resolve_vars_if_possible(new_infer_ct)) + } else if self.infcx.tcx.features().generic_const_exprs { + Ok(ct.normalize_internal(self.infcx.tcx, self.param_env)) } else { Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx)) } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index c1d0b704ab2..f7651e49cdd 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -85,7 +85,6 @@ mod rustc { use rustc_macros::TypeVisitable; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{Const, ParamEnv, Ty, TyCtxt, ValTree}; - use rustc_span::DUMMY_SP; use super::*; @@ -134,13 +133,8 @@ mod rustc { use rustc_middle::ty::ScalarInt; use rustc_span::symbol::sym; - let Ok((ty, cv)) = c.eval(tcx, param_env, DUMMY_SP) else { - return Some(Self { - alignment: true, - lifetimes: true, - safety: true, - validity: true, - }); + let Some((cv, ty)) = c.try_to_valtree() else { + return None; }; let adt_def = ty.ty_adt_def()?; diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 38b292afe8d..e755e90aa65 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -176,12 +176,12 @@ fn layout_of_uncached<'tcx>( if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi { if let Some(start) = start { scalar.valid_range_mut().start = start - .try_eval_bits(tcx, param_env) + .try_to_bits(tcx, param_env) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; } if let Some(end) = end { let mut end = end - .try_eval_bits(tcx, param_env) + .try_to_bits(tcx, param_env) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; if !include_end { end = end.wrapping_sub(1); @@ -321,7 +321,7 @@ fn layout_of_uncached<'tcx>( } let count = count - .try_eval_target_usize(tcx, param_env) + .try_to_target_usize(tcx) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; let element = cx.layout_of(element)?; let size = element diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1ddad917b78..7d4d8d8941d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1817,7 +1817,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T // Only anon consts can implicitly capture params. // FIXME: is this correct behavior? let param_env = cx.tcx.param_env(*def_id); - ct.normalize(cx.tcx, param_env) + cx.tcx.normalize_erasing_regions(param_env, ct) } else { ct }; @@ -2033,8 +2033,8 @@ pub(crate) fn clean_middle_ty<'tcx>( Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), format!("{pat:?}").into_boxed_str(), ), - ty::Array(ty, mut n) => { - n = n.normalize(cx.tcx, ty::ParamEnv::reveal_all()); + ty::Array(ty, n) => { + let n = cx.tcx.normalize_erasing_regions(cx.param_env, n); let n = print_const(cx, n); Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), n.into()) } diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index 22e9674714f..ae2c3e0491f 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -114,7 +114,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_target_usize(cx.tcx, cx.param_env) { + let size: u128 = if let Some(size) = s.try_to_target_usize(cx.tcx) { size.into() } else { return; @@ -183,7 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { && let ty::Uint(utype) = cx.typeck_results().expr_ty(index).kind() && *utype == ty::UintTy::Usize && let ty::Array(_, s) = ty.kind() - && let Some(size) = s.try_eval_target_usize(cx.tcx, cx.param_env) + && let Some(size) = s.try_to_target_usize(cx.tcx) { // get constant offset and check whether it is in bounds let off = usize::try_from(off).unwrap(); diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index b134af500f5..022c6bcc70b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs @@ -30,7 +30,7 @@ pub(super) fn check( return; } } else if count - .try_eval_target_usize(cx.tcx, cx.param_env) + .try_to_target_usize(cx.tcx) .map_or(true, |x| x > 32) && !msrv.meets(msrvs::ARRAY_IMPL_ANY_LEN) { diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index 68d063ad5e5..af089451759 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -472,7 +472,7 @@ fn is_array_length_equal_to_range(cx: &LateContext<'_>, start: &Expr<'_>, end: & let arr_ty = cx.typeck_results().expr_ty(arr).peel_refs(); if let ty::Array(_, s) = arr_ty.kind() { - let size: u128 = if let Some(size) = s.try_eval_target_usize(cx.tcx, cx.param_env) { + let size: u128 = if let Some(size) = s.try_to_target_usize(cx.tcx) { size.into() } else { return false; diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 214b8b0f379..2e6442156ef 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -207,7 +207,7 @@ fn is_end_eq_array_len<'tcx>( if let ExprKind::Lit(lit) = end.kind && let ast::LitKind::Int(end_int, _) = lit.node && let ty::Array(_, arr_len_const) = indexed_ty.kind() - && let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env) + && let Some(arr_len) = arr_len_const.try_to_target_usize(cx.tcx) { return match limits { ast::RangeLimits::Closed => end_int.get() + 1 >= arr_len.into(), diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 2eda238ae8c..047d070a131 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -11,7 +11,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{Visitor, walk_pat}; use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, AdtDef, ParamEnv, TyCtxt, TypeckResults, VariantDef}; +use rustc_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef}; use rustc_span::{Span, sym}; use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; @@ -67,7 +67,6 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tc if v.has_enum { let cx = PatCtxt { tcx: cx.tcx, - param_env: cx.param_env, typeck, arena: DroplessArena::default(), }; @@ -185,7 +184,6 @@ impl<'tcx> Visitor<'tcx> for PatVisitor<'tcx> { /// The context needed to manipulate a `PatState`. struct PatCtxt<'tcx> { tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, typeck: &'tcx TypeckResults<'tcx>, arena: DroplessArena, } @@ -334,7 +332,7 @@ impl<'a> PatState<'a> { if match *cx.typeck.pat_ty(pat).peel_refs().kind() { ty::Adt(adt, _) => adt.is_enum() || (adt.is_struct() && !adt.non_enum_variant().fields.is_empty()), ty::Tuple(tys) => !tys.is_empty(), - ty::Array(_, len) => len.try_eval_target_usize(cx.tcx, cx.param_env) != Some(1), + ty::Array(_, len) => len.try_to_target_usize(cx.tcx) != Some(1), ty::Slice(..) => true, _ => false, } => @@ -353,7 +351,7 @@ impl<'a> PatState<'a> { }, PatKind::Slice([sub_pat], _, []) | PatKind::Slice([], _, [sub_pat]) if let ty::Array(_, len) = *cx.typeck.pat_ty(pat).kind() - && len.try_eval_target_usize(cx.tcx, cx.param_env) == Some(1) => + && len.try_to_target_usize(cx.tcx) == Some(1) => { self.add_pat(cx, sub_pat) }, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs index f198849c5c0..9d462bd1845 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs @@ -31,14 +31,14 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> // parameter. substs .const_at(1) - .try_eval_target_usize(cx.tcx, cx.param_env) + .try_to_target_usize(cx.tcx) .map(u128::from) } else if cx.tcx.is_diagnostic_item(sym::SliceIter, did) && let ExprKind::MethodCall(_, recv, ..) = iter.kind { if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() { // For slice::Iter<'_, T>, the receiver might be an array literal: [1,2,3].iter().skip(..) - len.try_eval_target_usize(cx.tcx, cx.param_env).map(u128::from) + len.try_to_target_usize(cx.tcx).map(u128::from) } else if let Some(args) = VecArgs::hir(cx, expr_or_init(cx, recv)) { match args { VecArgs::Vec(vec) => vec.len().try_into().ok(), diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs index cf0ee569f13..6e39e7be2c4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/utils.rs +++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs @@ -18,7 +18,7 @@ pub(super) fn derefs_to_slice<'tcx>( ty::Slice(_) => true, ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => may_slice(cx, boxed), ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::Vec), - ty::Array(_, size) => size.try_eval_target_usize(cx.tcx, cx.param_env).is_some(), + ty::Array(_, size) => size.try_to_target_usize(cx.tcx).is_some(), ty::Ref(_, inner, _) => may_slice(cx, *inner), _ => false, } diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs index db8c63892b8..52bb7c4bd68 100644 --- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs +++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::has_repr_attr; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{Const, FeedConstTy}; +use rustc_middle::ty; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -55,16 +55,14 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray { fn is_struct_with_trailing_zero_sized_array<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool { if let ItemKind::Struct(data, _) = &item.kind - // First check if last field is an array && let Some(last_field) = data.fields().last() - && let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind - - // Then check if that array is zero-sized - && let length = Const::from_const_arg(cx.tcx, length, FeedConstTy::No) - && let length = length.try_eval_target_usize(cx.tcx, cx.param_env) - && let Some(length) = length + && let field_ty = cx + .tcx + .normalize_erasing_regions(cx.param_env, cx.tcx.type_of(last_field.def_id).instantiate_identity()) + && let ty::Array(_, array_len) = *field_ty.kind() + && let Some(0) = array_len.try_to_target_usize(cx.tcx) { - length == 0 + true } else { false } diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs index 3da8a449a7c..07d0f59b91c 100644 --- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs @@ -190,7 +190,7 @@ fn all_bindings_are_for_conv<'tcx>( tys.len() == elements.len() && tys.iter().chain(final_tys.iter().copied()).all_equal() }, (ToType::Tuple, ty::Array(ty, len)) => { - let Some(len) = len.try_eval_target_usize(cx.tcx, cx.param_env) else { return false }; + let Some(len) = len.try_to_target_usize(cx.tcx) else { return false }; len as usize == elements.len() && final_tys.iter().chain(once(ty)).all_equal() }, _ => false, diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index a1cfb7be647..67c31abbdda 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -472,7 +472,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple), ExprKind::Repeat(value, _) => { let n = match self.typeck.expr_ty(e).kind() { - ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?, + ty::Array(_, n) => n.try_to_target_usize(self.tcx)?, _ => span_bug!(e.span, "typeck error"), }; self.expr(value).map(|v| Constant::Repeat(Box::new(v), n)) @@ -553,7 +553,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { ExprKind::Array(vec) => self.multi(vec).map(|v| v.is_empty()), ExprKind::Repeat(..) => { if let ty::Array(_, n) = self.typeck.expr_ty(e).kind() { - Some(n.try_eval_target_usize(self.tcx, self.param_env)? == 0) + Some(n.try_to_target_usize(self.tcx)? == 0) } else { span_bug!(e.span, "typeck error"); } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index b7a3569ccf0..21793f761d9 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -989,7 +989,7 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 { (Ok(size), _) => size, (Err(_), ty::Tuple(list)) => list.iter().map(|t| approx_ty_size(cx, t)).sum(), (Err(_), ty::Array(t, n)) => { - n.try_eval_target_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t) + n.try_to_target_usize(cx.tcx).unwrap_or_default() * approx_ty_size(cx, *t) }, (Err(_), ty::Adt(def, subst)) if def.is_struct() => def .variants() @@ -1207,7 +1207,7 @@ impl<'tcx> InteriorMut<'tcx> { let chain = match *ty.kind() { ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.interior_mut_ty_chain(cx, inner_ty), ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.interior_mut_ty_chain(cx, inner_ty), - ty::Array(inner_ty, size) if size.try_eval_target_usize(cx.tcx, cx.param_env) != Some(0) => { + ty::Array(inner_ty, size) if size.try_to_target_usize(cx.tcx) != Some(0) => { self.interior_mut_ty_chain(cx, inner_ty) }, ty::Tuple(fields) => fields.iter().find_map(|ty| self.interior_mut_ty_chain(cx, ty)), diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 59776a484b5..0799b93dbb0 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -1,8 +1,7 @@ use either::Either; use rustc_apfloat::{Float, Round}; -use rustc_middle::ty::FloatTy; -use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; -use rustc_middle::{mir, ty}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::{mir, ty, ty::FloatTy}; use rustc_span::{Symbol, sym}; use rustc_target::abi::{Endian, HasDataLayout}; @@ -633,9 +632,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let index = generic_args[2] .expect_const() - .eval(*this.tcx, this.param_env(), this.tcx.span) + .try_to_valtree() .unwrap() - .1 + .0 .unwrap_branch(); let index_len = index.len(); diff --git a/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.rs b/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.rs new file mode 100644 index 00000000000..eeb0777c856 --- /dev/null +++ b/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.rs @@ -0,0 +1,19 @@ +#![feature(transmutability)] +#![feature(generic_const_exprs)] +//~^ WARN the feature `generic_const_exprs` is incomplete + +use std::mem::{Assume, TransmuteFrom}; + +pub fn is_transmutable() +where + (): TransmuteFrom<(), { Assume::SAFETY }>, +{ +} + +fn foo() { + is_transmutable::<{}>(); + //~^ ERROR the trait bound `(): TransmuteFrom<(), { Assume::SAFETY }>` is not satisfied + //~| ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.stderr b/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.stderr new file mode 100644 index 00000000000..6cb6a85c78a --- /dev/null +++ b/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.stderr @@ -0,0 +1,34 @@ +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/dont-assume-err-is-yes-issue-126377.rs:2:12 + | +LL | #![feature(generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/dont-assume-err-is-yes-issue-126377.rs:14:23 + | +LL | is_transmutable::<{}>(); + | ^^ expected `bool`, found `()` + +error[E0277]: the trait bound `(): TransmuteFrom<(), { Assume::SAFETY }>` is not satisfied + --> $DIR/dont-assume-err-is-yes-issue-126377.rs:14:23 + | +LL | is_transmutable::<{}>(); + | ^^ the trait `TransmuteFrom<(), { Assume::SAFETY }>` is not implemented for `()` + | +note: required by a bound in `is_transmutable` + --> $DIR/dont-assume-err-is-yes-issue-126377.rs:9:9 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | (): TransmuteFrom<(), { Assume::SAFETY }>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to 2 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`.