From 3c96c3012dcaecd23e111616867bb5e4574e32b7 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Fri, 10 Nov 2017 20:31:51 +0900 Subject: [PATCH] Normalize inlined function in MIR inliner --- src/librustc_mir/transform/inline.rs | 38 ++++++++++++++++--- .../run-pass/mir-inlining/ice-issue-45885.rs | 38 +++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 src/test/run-pass/mir-inlining/ice-issue-45885.rs diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index f2453d39461..05ab80acf84 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -18,7 +18,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::mir::*; use rustc::mir::transform::{MirPass, MirSource}; use rustc::mir::visit::*; -use rustc::ty::{self, Ty, TyCtxt, Instance}; +use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst::{Subst,Substs}; use std::collections::VecDeque; @@ -77,8 +77,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let mut callsites = VecDeque::new(); + let param_env; + // Only do inlining into fn bodies. if let MirSource::Fn(caller_id) = self.source { + let caller_def_id = self.tcx.hir.local_def_id(caller_id); + param_env = self.tcx.param_env(caller_def_id); + for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated() { // Don't inline calls that are in cleanup blocks. if bb_data.is_cleanup { continue; } @@ -88,9 +93,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { if let TerminatorKind::Call { func: Operand::Constant(ref f), .. } = terminator.kind { if let ty::TyFnDef(callee_def_id, substs) = f.ty.sty { - let caller_def_id = self.tcx.hir.local_def_id(caller_id); - let param_env = self.tcx.param_env(caller_def_id); - if let Some(instance) = Instance::resolve(self.tcx, param_env, callee_def_id, @@ -105,6 +107,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } } + } else { + return; } let mut local_change; @@ -121,7 +125,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { callsite.location.span, callsite.callee) { Ok(ref callee_mir) if self.should_inline(callsite, callee_mir) => { - callee_mir.subst(self.tcx, callsite.substs) + subst_and_normalize(callee_mir, self.tcx, &callsite.substs, param_env) } Ok(_) => continue, @@ -570,6 +574,30 @@ fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } +fn subst_and_normalize<'a, 'tcx: 'a>( + mir: &Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + substs: &'tcx ty::subst::Substs<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> Mir<'tcx> { + struct Folder<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + substs: &'tcx ty::subst::Substs<'tcx>, + } + impl<'a, 'tcx: 'a> ty::fold::TypeFolder<'tcx, 'tcx> for Folder<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + self.tcx.trans_apply_param_substs_env(&self.substs, self.param_env, &t) + } + } + let mut f = Folder { tcx, param_env, substs }; + mir.fold_with(&mut f) +} + /** * Integrator. * diff --git a/src/test/run-pass/mir-inlining/ice-issue-45885.rs b/src/test/run-pass/mir-inlining/ice-issue-45885.rs new file mode 100644 index 00000000000..702cb6a9bc1 --- /dev/null +++ b/src/test/run-pass/mir-inlining/ice-issue-45885.rs @@ -0,0 +1,38 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Zmir-opt-level=2 + +pub enum Enum { + A, + B, +} + +trait SliceIndex { + type Output; + fn get(&self) -> &Self::Output; +} + +impl SliceIndex for usize { + type Output = Enum; + #[inline(never)] + fn get(&self) -> &Enum { + &Enum::A + } +} + +#[inline(always)] +fn index(t: &T) -> &T::Output { + t.get() +} + +fn main() { + match *index(&0) { Enum::A => true, _ => false }; +}