From 37e1d2975e1002f0718552554055647392e46f0d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 20 Oct 2018 16:18:17 -0400 Subject: [PATCH] Don't rerun Mir passes when inlining When inlining a function using the Mir inliner, we shouldn't rerun the various Mir passes on it because the Mir has already been lowered and that wil break various early Mir passes. The issue in #50411 is that we've inlined a function with promotions whose Mir has already been lowered. The promotions are then copied into the local function and we begin to run passes on their lowered Mir which causes the ICE. Fixes #50411 --- src/librustc/mir/mod.rs | 29 +++++++++++++++++++++++++++++ src/librustc_mir/transform/mod.rs | 25 ++++++++++++++++++++----- src/test/ui/issues/issue-50411.rs | 11 +++++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/issues/issue-50411.rs diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 34fc81a495e..797836f1661 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 d18836999dc..61e150ea12a 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 00000000000..1ba47d3b932 --- /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(); +} -- GitLab