diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 1c2e8d807f4e6..0d3b8de57001e 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -9,6 +9,7 @@ use rustc_index::IndexVec; use rustc_middle::mir; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout, @@ -377,6 +378,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> FnAbiOfHelpers<'tcx> for InterpCx pub(super) fn mir_assign_valid_types<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, + anchor: DefiningAnchor, src: TyAndLayout<'tcx>, dest: TyAndLayout<'tcx>, ) -> bool { @@ -384,7 +386,7 @@ pub(super) fn mir_assign_valid_types<'tcx>( // all normal lifetimes are erased, higher-ranked types with their // late-bound lifetimes are still around and can lead to type // differences. - if util::relate_types(tcx, param_env, Variance::Covariant, src.ty, dest.ty) { + if util::relate_types(tcx, param_env, anchor, Variance::Covariant, src.ty, dest.ty) { // Make sure the layout is equal, too -- just to be safe. Miri really // needs layout equality. For performance reason we skip this check when // the types are equal. Equal types *can* have different layouts when @@ -405,6 +407,7 @@ pub(super) fn mir_assign_valid_types<'tcx>( pub(super) fn from_known_layout<'tcx>( tcx: TyCtxtAt<'tcx>, param_env: ParamEnv<'tcx>, + anchor: DefiningAnchor, known_layout: Option>, compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { @@ -413,7 +416,7 @@ pub(super) fn from_known_layout<'tcx>( Some(known_layout) => { if cfg!(debug_assertions) { let check_layout = compute()?; - if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) { + if !mir_assign_valid_types(tcx.tcx, param_env, anchor, check_layout, known_layout) { span_bug!( tcx.span, "expected type differs from actual type.\nexpected: {}\nactual: {}", @@ -514,6 +517,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.frame().body } + #[inline(always)] + pub fn defining_anchor_for_body(&self) -> DefiningAnchor { + if self.stack().is_empty() { + DefiningAnchor::Error + } else { + DefiningAnchor::from_def_id_and_reveal( + self.body().source.def_id(), + self.param_env.reveal(), + ) + } + } + #[inline(always)] pub fn sign_extend(&self, value: u128, ty: TyAndLayout<'_>) -> u128 { assert!(ty.abi.is_signed()); @@ -607,11 +622,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(layout); } - let layout = from_known_layout(self.tcx, self.param_env, layout, || { - let local_ty = frame.body.local_decls[local].ty; - let local_ty = self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?; - self.layout_of(local_ty) - })?; + let layout = from_known_layout( + self.tcx, + self.param_env, + DefiningAnchor::from_def_id_and_reveal( + frame.body.source.def_id(), + self.param_env.reveal(), + ), + layout, + || { + let local_ty = frame.body.local_decls[local].ty; + let local_ty = + self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?; + self.layout_of(local_ty) + }, + )?; // Layouts of locals are requested a lot, so we cache them. state.layout.set(Some(layout)); diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 99dba977a4395..0dbba06516251 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -677,6 +677,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if !mir_assign_valid_types( *self.tcx, self.param_env, + self.defining_anchor_for_body(), self.layout_of(normalized_place_ty)?, op.layout, ) { @@ -733,7 +734,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Scalar::Int(int) => Scalar::Int(int), }) }; - let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; + let layout = from_known_layout( + self.tcx, + self.param_env, + self.defining_anchor_for_body(), + layout, + || self.layout_of(ty), + )?; let op = match val_val { mir::ConstValue::Indirect { alloc_id, offset } => { // We rely on mutability being set correctly in that allocation to prevent writes diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 9f95d2a324617..251fbfac9208b 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -579,6 +579,7 @@ where if !mir_assign_valid_types( *self.tcx, self.param_env, + self.defining_anchor_for_body(), self.layout_of(normalized_place_ty)?, place.layout, ) { @@ -834,8 +835,13 @@ where ) -> InterpResult<'tcx> { // We do NOT compare the types for equality, because well-typed code can // actually "transmute" `&mut T` to `&T` in an assignment without a cast. - let layout_compat = - mir_assign_valid_types(*self.tcx, self.param_env, src.layout(), dest.layout()); + let layout_compat = mir_assign_valid_types( + *self.tcx, + self.param_env, + self.defining_anchor_for_body(), + src.layout(), + dest.layout(), + ); if !allow_transmute && !layout_compat { span_bug!( self.cur_span(), diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 4711f7b47cccc..246ced3f458ae 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -7,6 +7,7 @@ use rustc_infer::traits::Reveal; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; @@ -612,7 +613,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Variance::Covariant }; - crate::util::relate_types(self.tcx, self.param_env, variance, src, dest) + crate::util::relate_types( + self.tcx, + self.param_env, + DefiningAnchor::from_def_id_and_reveal( + self.body.source.def_id(), + self.param_env.reveal(), + ), + variance, + src, + dest, + ) } } @@ -767,6 +778,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if !relate_types( self.tcx, self.param_env, + DefiningAnchor::from_def_id_and_reveal( + self.body.source.def_id(), + self.param_env.reveal(), + ), Variance::Covariant, ty, place_ref.ty(&self.body.local_decls, self.tcx).ty, diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index 265ca0c7884ce..9d362e020846a 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -15,6 +15,7 @@ use rustc_trait_selection::traits::ObligationCtxt; pub fn is_equal_up_to_subtyping<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, + anchor: DefiningAnchor, src: Ty<'tcx>, dest: Ty<'tcx>, ) -> bool { @@ -24,8 +25,8 @@ pub fn is_equal_up_to_subtyping<'tcx>( } // Check for subtyping in either direction. - relate_types(tcx, param_env, Variance::Covariant, src, dest) - || relate_types(tcx, param_env, Variance::Covariant, dest, src) + relate_types(tcx, param_env, anchor, Variance::Covariant, src, dest) + || relate_types(tcx, param_env, anchor, Variance::Covariant, dest, src) } /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`. @@ -39,6 +40,7 @@ pub fn is_equal_up_to_subtyping<'tcx>( pub fn relate_types<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, + anchor: DefiningAnchor, variance: Variance, src: Ty<'tcx>, dest: Ty<'tcx>, @@ -47,8 +49,7 @@ pub fn relate_types<'tcx>( return true; } - let mut builder = - tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble); + let mut builder = tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(anchor); let infcx = builder.build(); let ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy(); @@ -59,19 +60,23 @@ pub fn relate_types<'tcx>( Err(_) => return false, }; let errors = ocx.select_all_or_error(); - // With `Reveal::All`, opaque types get normalized away, with `Reveal::UserFacing` - // we would get unification errors because we're unable to look into opaque types, - // even if they're constrained in our current function. - for (key, ty) in infcx.take_opaque_types() { - let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args); - if hidden_ty != ty.hidden_type.ty { - span_bug!( - ty.hidden_type.span, - "{}, {}", - tcx.type_of(key.def_id).instantiate(tcx, key.args), - ty.hidden_type.ty - ); + + if anchor != DefiningAnchor::Error { + // With `Reveal::All`, opaque types get normalized away, with `Reveal::UserFacing` + // we would get unification errors because we're unable to look into opaque types, + // even if they're constrained in our current function. + for (key, ty) in infcx.take_opaque_types() { + let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args); + if hidden_ty != ty.hidden_type.ty { + span_bug!( + ty.hidden_type.span, + "{}, {}", + tcx.type_of(key.def_id).instantiate(tcx, key.args), + ty.hidden_type.ty + ); + } } } + errors.is_empty() } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 99b750c9afc8c..306bfefcb58bf 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -945,3 +945,14 @@ pub enum DefiningAnchor { /// Used to catch type mismatch errors when handling opaque types. Error, } + +impl DefiningAnchor { + /// Mostly for use in the MIR validator, which only needs to pass a `Bind` + /// anchor if the reveal is not yet `All` and we're validating a local body. + pub fn from_def_id_and_reveal(body_def_id: DefId, reveal: Reveal) -> DefiningAnchor { + body_def_id + .as_local() + .filter(|_| reveal == Reveal::UserFacing) + .map_or(DefiningAnchor::Error, |def_id| DefiningAnchor::Bind(def_id)) + } +} diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 06ae070c9083a..948c7d5413d33 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -8,6 +8,7 @@ use rustc_index::Idx; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; use rustc_session::config::OptLevel; @@ -221,6 +222,7 @@ impl<'tcx> Inliner<'tcx> { if !util::relate_types( self.tcx, self.param_env, + DefiningAnchor::Error, ty::Variance::Covariant, output_type, destination_ty, @@ -257,6 +259,7 @@ impl<'tcx> Inliner<'tcx> { if !util::relate_types( self.tcx, self.param_env, + DefiningAnchor::Error, ty::Variance::Covariant, input_type, arg_ty, @@ -272,6 +275,7 @@ impl<'tcx> Inliner<'tcx> { if !util::relate_types( self.tcx, self.param_env, + DefiningAnchor::Error, ty::Variance::Covariant, input_type, arg_ty,