diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 34fc81a495e249682fa9ccd9bf63c2ab47b731e5..797836f166173f0366e7838afe7ce65cb3cca6b2 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -69,6 +69,17 @@ fn local_decls(&self) -> &LocalDecls<'tcx> { } } +/// The various "big phases" that MIR goes through. +/// +/// Warning: ordering of variants is significant +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum MirPhase { + Build, + Const, + Validated, + Optimized, +} + /// Lowered representation of a single function. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Mir<'tcx> { @@ -76,6 +87,13 @@ pub struct Mir<'tcx> { /// that indexes into this vector. basic_blocks: IndexVec>, + /// Records how far through the "desugaring and optimization" process this particular + /// MIR has traversed. This is particularly useful when inlining, since in that context + /// we instantiate the promoted constants and add them to our promoted vector -- but those + /// promoted items have already been optimized, whereas ours have not. This field allows + /// us to see the difference and forego optimization on the inlined promoted items. + pub phase: MirPhase, + /// List of source scopes; these are referenced by statements /// and used for debuginfo. Indexed by a `SourceScope`. pub source_scopes: IndexVec, @@ -151,6 +169,7 @@ pub fn new( ); Mir { + phase: MirPhase::Build, basic_blocks, source_scopes, source_scope_local_data, @@ -368,6 +387,7 @@ pub enum Safety { } impl_stable_hash_for!(struct Mir<'tcx> { + phase, basic_blocks, source_scopes, source_scope_local_data, @@ -616,6 +636,13 @@ pub enum ImplicitSelfKind { None }); +impl_stable_hash_for!(enum self::MirPhase { + Build, + Const, + Validated, + Optimized, +}); + mod binding_form_impl { use ich::StableHashingContext; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; @@ -2777,6 +2804,7 @@ pub enum ClosureOutlivesSubject<'tcx> { CloneTypeFoldableAndLiftImpls! { BlockTailInfo, + MirPhase, Mutability, SourceInfo, UpvarDecl, @@ -2789,6 +2817,7 @@ pub enum ClosureOutlivesSubject<'tcx> { BraceStructTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> { + phase, basic_blocks, source_scopes, source_scope_local_data, diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index d18836999dccfe7629c1c8221274c6a161571443..61e150ea12a2261837519190bbc905806bff5b38 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -11,7 +11,7 @@ use borrow_check::nll::type_check; use build; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc::mir::{Mir, Promoted}; +use rustc::mir::{Mir, MirPhase, Promoted}; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; use rustc::ty::steal::Steal; @@ -155,9 +155,22 @@ fn run_pass<'a, 'tcx>(&self, mir: &mut Mir<'tcx>); } -pub macro run_passes($tcx:ident, $mir:ident, $def_id:ident, $suite_index:expr; $($pass:expr,)*) {{ +pub macro run_passes( + $tcx:ident, + $mir:ident, + $def_id:ident, + $suite_index:expr, + $mir_phase:expr; + $($pass:expr,)* +) {{ let suite_index: usize = $suite_index; let run_passes = |mir: &mut _, promoted| { + let mir: &mut Mir<'_> = mir; + + if mir.phase >= $mir_phase { + return; + } + let source = MirSource { def_id: $def_id, promoted @@ -175,6 +188,8 @@ fn run_pass<'a, 'tcx>(&self, index += 1; }; $(run_pass(&$pass);)* + + mir.phase = $mir_phase; }; run_passes(&mut $mir, None); @@ -192,7 +207,7 @@ fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Stea let _ = tcx.unsafety_check_result(def_id); let mut mir = tcx.mir_built(def_id).steal(); - run_passes![tcx, mir, def_id, 0; + run_passes![tcx, mir, def_id, 0, MirPhase::Const; // Remove all `EndRegion` statements that are not involved in borrows. cleanup_post_borrowck::CleanEndRegions, @@ -214,7 +229,7 @@ fn mir_validated<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx } let mut mir = tcx.mir_const(def_id).steal(); - run_passes![tcx, mir, def_id, 1; + run_passes![tcx, mir, def_id, 1, MirPhase::Validated; // What we need to run borrowck etc. qualify_consts::QualifyAndPromoteConstants, simplify::SimplifyCfg::new("qualify-consts"), @@ -232,7 +247,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx } let mut mir = tcx.mir_validated(def_id).steal(); - run_passes![tcx, mir, def_id, 2; + run_passes![tcx, mir, def_id, 2, MirPhase::Optimized; // Remove all things not needed by analysis no_landing_pads::NoLandingPads, simplify_branches::SimplifyBranches::new("initial"), diff --git a/src/test/ui/issues/issue-50411.rs b/src/test/ui/issues/issue-50411.rs new file mode 100644 index 0000000000000000000000000000000000000000..1ba47d3b932ef70171f87e442d6d9fbdc506bc57 --- /dev/null +++ b/src/test/ui/issues/issue-50411.rs @@ -0,0 +1,11 @@ +// Regression test for #50411: the MIR inliner was causing problems +// here because it would inline promoted code (which had already had +// elaborate-drops invoked on it) and then try to elaboate drops a +// second time. Uncool. + +// compile-flags:-Zmir-opt-level=3 +// compile-pass + +fn main() { + let _ = (0 .. 1).filter(|_| [1].iter().all(|_| true)).count(); +}