about summary refs log tree commit diff
diff options
context:
space:
mode:
authorShotaro Yamada <sinkuu@sinkuu.xyz>2017-11-10 20:31:51 +0900
committerShotaro Yamada <sinkuu@sinkuu.xyz>2017-11-10 20:54:58 +0900
commit3c96c3012dcaecd23e111616867bb5e4574e32b7 (patch)
treec244dfeae419f48148a7d83311f91587313737ee
parentd5ff0e6422061c390a141354af8eacd540dca10b (diff)
downloadrust-3c96c3012dcaecd23e111616867bb5e4574e32b7.tar.gz
rust-3c96c3012dcaecd23e111616867bb5e4574e32b7.zip
Normalize inlined function in MIR inliner
-rw-r--r--src/librustc_mir/transform/inline.rs38
-rw-r--r--src/test/run-pass/mir-inlining/ice-issue-45885.rs38
2 files changed, 71 insertions, 5 deletions
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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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: SliceIndex>(t: &T) -> &T::Output {
+    t.get()
+}
+
+fn main() {
+    match *index(&0) { Enum::A => true, _ => false };
+}