diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ebcc2da09551e..a4df881ba6db2 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -201,6 +201,21 @@ pub enum MentionedItem<'tcx> { Closure(Ty<'tcx>), } +/// Track what typing mode a MIR body should use at current stage. +/// A MIR body usually starts with `Borrowck`. After borrowck is done, it's set to `PostBorrowck`. +/// In `PostAnalysisNormalize` pass, we reveal all opaques types and set the typing mode to +/// `PostAnalysis`. +/// +/// We can't directly use `ty::TypingMode` since it's not `TyEncodable/TyDecodable`. +/// Previously we use MIR phase to derive this but it's inaccurate. +#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(TyEncodable, TyDecodable, StableHash, TypeFoldable, TypeVisitable)] +pub enum BodyTypingMode { + PostTypeckThroughBorrowck, + PostBorrowck, + PostAnalysis, +} + /// The lowered representation of a single function. #[derive(Clone, TyEncodable, TyDecodable, Debug, StableHash, TypeFoldable, TypeVisitable)] pub struct Body<'tcx> { @@ -215,6 +230,9 @@ pub struct Body<'tcx> { /// us to see the difference and forego optimization on the inlined promoted items. pub phase: MirPhase, + /// See [`BodyTypingMode`] for more info. + pub typing_mode: BodyTypingMode, + /// How many passes we have executed since starting the current phase. Used for debug output. pub pass_count: usize, @@ -353,6 +371,7 @@ impl<'tcx> Body<'tcx> { let mut body = Body { phase: MirPhase::Built, + typing_mode: BodyTypingMode::PostTypeckThroughBorrowck, pass_count: 0, source, basic_blocks: BasicBlocks::new(basic_blocks), @@ -384,6 +403,7 @@ impl<'tcx> Body<'tcx> { pub fn new_cfg_only(basic_blocks: IndexVec>) -> Self { let mut body = Body { phase: MirPhase::Built, + typing_mode: BodyTypingMode::PostTypeckThroughBorrowck, pass_count: 0, source: MirSource::item(CRATE_DEF_ID.to_def_id()), basic_blocks: BasicBlocks::new(basic_blocks), @@ -414,38 +434,35 @@ impl<'tcx> Body<'tcx> { pub fn typing_env(&self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> { if tcx.use_typing_mode_post_typeck_through_borrowck() { - match self.phase { - MirPhase::Built | MirPhase::Analysis(AnalysisPhase::Initial) - if let Some(def_id) = self.source.def_id().as_local() => - { + match self.typing_mode { + BodyTypingMode::PostTypeckThroughBorrowck => { + let local_def_id = + self.source.def_id().as_local().expect("We only build MIR for local body"); TypingEnv::new( tcx.param_env(self.source.def_id()), - ty::TypingMode::borrowck(tcx, def_id), + ty::TypingMode::borrowck(tcx, local_def_id), ) } - MirPhase::Analysis(AnalysisPhase::PostCleanup) - if let Some(def_id) = self.source.def_id().as_local() => - { + BodyTypingMode::PostBorrowck => { + let local_def_id = + self.source.def_id().as_local().expect("We only build MIR for local body"); TypingEnv::new( tcx.param_env(self.source.def_id()), - ty::TypingMode::post_borrowck_analysis(tcx, def_id), + ty::TypingMode::post_borrowck_analysis(tcx, local_def_id), ) } - MirPhase::Built | MirPhase::Analysis(_) => { - // This branch happens for drop glue and fn ptr shims. - // FIXME: why do we do any of this analysis on drop glue etc? - // This should ideally all be skipped. - TypingEnv::post_analysis(tcx, self.source.def_id()) - } - MirPhase::Runtime(_) => TypingEnv::post_analysis(tcx, self.source.def_id()), + // We build shims like `drop_in_place` in post analysis typing mode. + BodyTypingMode::PostAnalysis => TypingEnv::post_analysis(tcx, self.source.def_id()), } } else { - match self.phase { - MirPhase::Built | MirPhase::Analysis(_) => TypingEnv::new( - tcx.param_env(self.source.def_id()), - ty::TypingMode::non_body_analysis(), - ), - MirPhase::Runtime(_) => TypingEnv::post_analysis(tcx, self.source.def_id()), + match self.typing_mode { + BodyTypingMode::PostTypeckThroughBorrowck | BodyTypingMode::PostBorrowck => { + TypingEnv::new( + tcx.param_env(self.source.def_id()), + ty::TypingMode::non_body_analysis(), + ) + } + BodyTypingMode::PostAnalysis => TypingEnv::post_analysis(tcx, self.source.def_id()), } } } diff --git a/compiler/rustc_mir_build/src/builder/custom/mod.rs b/compiler/rustc_mir_build/src/builder/custom/mod.rs index f6c8658544b43..c03fb0e7dd09c 100644 --- a/compiler/rustc_mir_build/src/builder/custom/mod.rs +++ b/compiler/rustc_mir_build/src/builder/custom/mod.rs @@ -45,6 +45,7 @@ pub(super) fn build_custom_mir<'tcx>( basic_blocks: BasicBlocks::new(IndexVec::new()), source: MirSource::item(did), phase: MirPhase::Built, + typing_mode: BodyTypingMode::PostTypeckThroughBorrowck, source_scopes: IndexVec::new(), coroutine: None, local_decls: IndexVec::new(), @@ -73,6 +74,9 @@ pub(super) fn build_custom_mir<'tcx>( local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }), }); body.injection_phase = Some(parse_attribute(dialect, phase)); + if let Some(MirPhase::Runtime(_)) = body.injection_phase { + body.typing_mode = BodyTypingMode::PostAnalysis; + } let mut pctxt = ParseCtxt { tcx, diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs index 41c63d4857df8..1b688d261a6ef 100644 --- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs +++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs @@ -1,5 +1,5 @@ use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::TyCtxt; use tracing::debug; use crate::patch::MirPatch; @@ -41,9 +41,7 @@ impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span); let mut patch = MirPatch::new(body); - // FIXME(#132279): This is used during the phase transition from analysis - // to runtime, so we have to manually specify the correct typing mode. - let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id()); + let typing_env = body.typing_env(tcx); for (bb, data) in body.basic_blocks.iter_enumerated() { let loc = Location { block: bb, statement_index: data.statements.len() }; diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index a1acc308506c2..acbba72d01e48 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -52,9 +52,7 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops { #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", body.source, body.span); - // FIXME(#132279): This is used during the phase transition from analysis - // to runtime, so we have to manually specify the correct typing mode. - let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id()); + let typing_env = body.typing_env(tcx); // 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, |ty| ty.needs_drop(tcx, typing_env)); diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index f448371977068..6422ddc5fa393 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -181,9 +181,7 @@ impl<'tcx> ty::layout::HasTypingEnv<'tcx> for ConstPropagator<'_, 'tcx> { impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> { let def_id = body.source.def_id(); - // FIXME(#132279): This is used during the phase transition from analysis - // to runtime, so we have to manually specify the correct typing mode. - let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id()); + let typing_env = body.typing_env(tcx); let can_const_prop = CanConstProp::check(tcx, typing_env, body); let ecx = InterpCx::new(tcx, tcx.def_span(def_id), typing_env, DummyMachine); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index d73d9a82f1a22..63a229578e2bd 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -20,9 +20,9 @@ use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::LocalDefId; use rustc_index::IndexVec; use rustc_middle::mir::{ - AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl, - MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, START_BLOCK, - SourceInfo, Statement, StatementKind, TerminatorKind, WithRetag, + AnalysisPhase, Body, BodyTypingMode, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, + LocalDecl, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, + START_BLOCK, SourceInfo, Statement, StatementKind, TerminatorKind, WithRetag, }; use rustc_middle::query; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; @@ -596,6 +596,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & _ => {} } + body.typing_mode = BodyTypingMode::PostBorrowck; run_analysis_to_runtime_passes(tcx, &mut body); tcx.alloc_steal_mir(body) @@ -604,12 +605,13 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & // Made public so that `mir_drops_elaborated_and_const_checked` can be overridden // by custom rustc drivers, running all the steps by themselves. See #114628. pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - assert!(body.phase == MirPhase::Analysis(AnalysisPhase::Initial)); + assert_eq!(body.typing_mode, BodyTypingMode::PostBorrowck); + assert_eq!(body.phase, MirPhase::Analysis(AnalysisPhase::Initial)); let did = body.source.def_id(); debug!("analysis_mir_cleanup({:?})", did); run_analysis_cleanup_passes(tcx, body); - assert!(body.phase == MirPhase::Analysis(AnalysisPhase::PostCleanup)); + assert_eq!(body.phase, MirPhase::Analysis(AnalysisPhase::PostCleanup)); // Do a little drop elaboration before const-checking if `const_precise_live_drops` is enabled. if check_consts::post_drop_elaboration::checking_enabled(&ConstCx::new(tcx, body)) { @@ -627,11 +629,12 @@ pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' debug!("runtime_mir_lowering({:?})", did); run_runtime_lowering_passes(tcx, body); - assert!(body.phase == MirPhase::Runtime(RuntimePhase::Initial)); + assert_eq!(body.phase, MirPhase::Runtime(RuntimePhase::Initial)); debug!("runtime_mir_cleanup({:?})", did); run_runtime_cleanup_passes(tcx, body); - assert!(body.phase == MirPhase::Runtime(RuntimePhase::PostCleanup)); + assert_eq!(body.typing_mode, BodyTypingMode::PostAnalysis); + assert_eq!(body.phase, MirPhase::Runtime(RuntimePhase::PostCleanup)); } // FIXME(JakobDegen): Can we make these lists of passes consts? @@ -846,6 +849,7 @@ fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec( panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase); } + // Custom MIR can skip analysis-to-runtime lowering where we update + // the typing mode for normal MIR body. + // + // FIXME: it's ugly that we set the typing mode of custom MIR in the + // runtime phase to `PostBorrowck` after borrowck and then back to + // `PostAnalysis` here. + if matches!(body.injection_phase, Some(MirPhase::Runtime(_))) + && matches!(new_phase, MirPhase::Runtime(_)) + { + body.typing_mode = BodyTypingMode::PostAnalysis; + } + + // We perform type mode transitions in MIR transform. But some bodies don't actually + // undergo analysis-to-runtime lowering, such as shims and sometimes custom MIR. + // We try to guard against future MIR building procedures that don't go through the usual + // lowering. The final validation is expected to run in `TypingMode::PostAnalysis`. + if new_phase == MirPhase::Runtime(RuntimePhase::Optimized) { + assert_eq!(body.typing_mode, BodyTypingMode::PostAnalysis); + } + body.phase = new_phase; body.pass_count = 0; diff --git a/compiler/rustc_mir_transform/src/post_analysis_normalize.rs b/compiler/rustc_mir_transform/src/post_analysis_normalize.rs index 78f97c2eb1448..437c9378b1fda 100644 --- a/compiler/rustc_mir_transform/src/post_analysis_normalize.rs +++ b/compiler/rustc_mir_transform/src/post_analysis_normalize.rs @@ -12,9 +12,8 @@ pub(super) struct PostAnalysisNormalize; impl<'tcx> crate::MirPass<'tcx> for PostAnalysisNormalize { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // FIXME(#132279): This is used during the phase transition from analysis - // to runtime, so we have to manually specify the correct typing mode. - let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id()); + body.typing_mode = BodyTypingMode::PostAnalysis; + let typing_env = body.typing_env(tcx); PostAnalysisNormalizeVisitor { tcx, typing_env }.visit_body_preserves_cfg(body); } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index f1d85166653ff..a7952ad3aee16 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -395,6 +395,8 @@ fn new_body<'tcx>( ); // Shims do not directly mention any consts. body.set_required_consts(Vec::new()); + // We don't do any analysis on shims. + body.typing_mode = BodyTypingMode::PostAnalysis; body }