]> git.lizzy.rs Git - rust.git/commitdiff
Don't rerun Mir passes when inlining
authorNiko Matsakis <niko@alum.mit.edu>
Sat, 20 Oct 2018 20:18:17 +0000 (16:18 -0400)
committerWesley Wiser <wwiser@gmail.com>
Tue, 23 Oct 2018 02:45:36 +0000 (22:45 -0400)
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
src/librustc_mir/transform/mod.rs
src/test/ui/issues/issue-50411.rs [new file with mode: 0644]

index 34fc81a495e249682fa9ccd9bf63c2ab47b731e5..797836f166173f0366e7838afe7ce65cb3cca6b2 100644 (file)
@@ -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<BasicBlock, BasicBlockData<'tcx>>,
 
+    /// 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<SourceScope, SourceScopeData>,
@@ -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,
index d18836999dccfe7629c1c8221274c6a161571443..61e150ea12a2261837519190bbc905806bff5b38 100644 (file)
@@ -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 (file)
index 0000000..1ba47d3
--- /dev/null
@@ -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();
+}