Skip to content

Commit

Permalink
Don't rerun Mir passes when inlining
Browse files Browse the repository at this point in the history
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 rust-lang#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 rust-lang#50411
  • Loading branch information
nikomatsakis authored and wesleywiser committed Oct 23, 2018
1 parent 22cc2ae commit 37e1d29
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 5 deletions.
29 changes: 29 additions & 0 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,31 @@ impl<'tcx> HasLocalDecls<'tcx> for Mir<'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> {
/// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
/// 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>,
Expand Down Expand Up @@ -151,6 +169,7 @@ impl<'tcx> Mir<'tcx> {
);

Mir {
phase: MirPhase::Build,
basic_blocks,
source_scopes,
source_scope_local_data,
Expand Down Expand Up @@ -368,6 +387,7 @@ pub enum Safety {
}

impl_stable_hash_for!(struct Mir<'tcx> {
phase,
basic_blocks,
source_scopes,
source_scope_local_data,
Expand Down Expand Up @@ -616,6 +636,13 @@ impl_stable_hash_for!(enum self::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};
Expand Down Expand Up @@ -2777,6 +2804,7 @@ pub enum ClosureOutlivesSubject<'tcx> {

CloneTypeFoldableAndLiftImpls! {
BlockTailInfo,
MirPhase,
Mutability,
SourceInfo,
UpvarDecl,
Expand All @@ -2789,6 +2817,7 @@ CloneTypeFoldableAndLiftImpls! {

BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> {
phase,
basic_blocks,
source_scopes,
source_scope_local_data,
Expand Down
25 changes: 20 additions & 5 deletions src/librustc_mir/transform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -155,9 +155,22 @@ pub trait MirPass {
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
Expand All @@ -175,6 +188,8 @@ pub macro run_passes($tcx:ident, $mir:ident, $def_id:ident, $suite_index:expr; $
index += 1;
};
$(run_pass(&$pass);)*

mir.phase = $mir_phase;
};

run_passes(&mut $mir, None);
Expand All @@ -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,

Expand All @@ -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"),
Expand All @@ -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"),
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/issues/issue-50411.rs
Original file line number Diff line number Diff line change
@@ -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();
}

0 comments on commit 37e1d29

Please sign in to comment.