about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2017-07-26 15:54:44 +0300
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2017-07-27 12:22:26 +0300
commit4c900c52482fd398cbec4d1d433fcc2e6888ff1b (patch)
treeada190e0f3340111d3355b63addc136a815ac6b6
parent5c126bdee6af3feef2d51956debab72f933078c6 (diff)
rustc_const_eval: always require correct Substs.
-rw-r--r--src/librustc/middle/const_val.rs2
-rw-r--r--src/librustc/ty/mod.rs4
-rw-r--r--src/librustc_const_eval/check_match.rs13
-rw-r--r--src/librustc_const_eval/eval.rs53
-rw-r--r--src/librustc_const_eval/pattern.rs44
-rw-r--r--src/librustc_lint/types.rs9
-rw-r--r--src/librustc_mir/build/mod.rs5
-rw-r--r--src/librustc_mir/hair/cx/block.rs5
-rw-r--r--src/librustc_mir/hair/cx/expr.rs6
-rw-r--r--src/librustc_mir/hair/cx/mod.rs26
-rw-r--r--src/librustc_passes/consts.rs37
-rw-r--r--src/librustc_typeck/collect.rs2
12 files changed, 113 insertions, 93 deletions
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index 2637afdea5b..33e9df1e413 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -229,7 +229,7 @@ pub fn eval_length(tcx: TyCtxt,
 {
     let count_expr = &tcx.hir.body(count).value;
     let count_def_id = tcx.hir.body_owner_def_id(count);
-    let substs = Substs::empty();
+    let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
     match tcx.at(count_expr.span).const_eval((count_def_id, substs)) {
         Ok(Integral(Usize(count))) => {
             let val = count.as_u64(tcx.sess.target.uint_type);
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 2a11b19f855..70aee6ffcf3 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1588,7 +1588,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         self.variants.iter().map(move |v| {
             let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
             if let VariantDiscr::Explicit(expr_did) = v.discr {
-                let substs = Substs::empty();
+                let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
                 match tcx.const_eval((expr_did, substs)) {
                     Ok(ConstVal::Integral(v)) => {
                         discr = v;
@@ -1627,7 +1627,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
                     explicit_index -= distance;
                 }
                 ty::VariantDiscr::Explicit(expr_did) => {
-                    let substs = Substs::empty();
+                    let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
                     match tcx.const_eval((expr_did, substs)) {
                         Ok(ConstVal::Integral(v)) => {
                             explicit_value = v;
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index fcdabf89e3c..e7a12df0a27 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -21,6 +21,7 @@ use rustc::middle::mem_categorization::{cmt};
 use rustc::middle::region::RegionMaps;
 use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::Substs;
 use rustc::lint;
 use rustc_errors::{Diagnostic, Level, DiagnosticBuilder};
 
@@ -51,7 +52,8 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
             tcx: self.tcx,
             tables: self.tcx.body_tables(b),
             region_maps: &self.tcx.region_maps(def_id),
-            param_env: self.tcx.param_env(def_id)
+            param_env: self.tcx.param_env(def_id),
+            identity_substs: Substs::identity_for_item(self.tcx, def_id),
         }.visit_body(self.tcx.hir.body(b));
     }
 }
@@ -69,6 +71,7 @@ struct MatchVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     tables: &'a ty::TypeckTables<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
+    identity_substs: &'tcx Substs<'tcx>,
     region_maps: &'a RegionMaps,
 }
 
@@ -110,7 +113,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
+impl<'a, 'tcx> PatternContext<'a, 'tcx> {
     fn report_inlining_errors(&self, pat_span: Span) {
         for error in &self.errors {
             match *error {
@@ -162,7 +165,8 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
 
             let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
                 arm.pats.iter().map(|pat| {
-                    let mut patcx = PatternContext::new(self.tcx, self.tables);
+                    let substs = self.identity_substs;
+                    let mut patcx = PatternContext::new(self.tcx, self.tables, substs);
                     let pattern = expand_pattern(cx, patcx.lower_pattern(&pat));
                     if !patcx.errors.is_empty() {
                         patcx.report_inlining_errors(pat.span);
@@ -229,7 +233,8 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
     fn check_irrefutable(&self, pat: &Pat, origin: &str) {
         let module = self.tcx.hir.get_module_parent(pat.id);
         MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
-            let mut patcx = PatternContext::new(self.tcx, self.tables);
+            let substs = self.identity_substs;
+            let mut patcx = PatternContext::new(self.tcx, self.tables, substs);
             let pattern = patcx.lower_pattern(pat);
             let pattern_ty = pattern.ty;
             let pats : Matrix = vec![vec![
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 72fa858e4cb..bcf5fd2b13d 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -94,11 +94,13 @@ pub struct ConstContext<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
-    pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+               tables: &'a ty::TypeckTables<'tcx>,
+               substs: &'tcx Substs<'tcx>) -> Self {
         ConstContext {
-            tcx: tcx,
-            tables: tables,
-            substs: tcx.intern_substs(&[]),
+            tcx,
+            tables,
+            substs,
             fn_args: None
         }
     }
@@ -118,14 +120,7 @@ type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                                      e: &Expr) -> EvalResult<'tcx> {
     let tcx = cx.tcx;
-    let ety = cx.tables.expr_ty(e);
-
-    // Avoid applying substitutions if they're empty, that'd ICE.
-    let ety = if cx.substs.is_empty() {
-        ety
-    } else {
-        ety.subst(tcx, cx.substs)
-    };
+    let ety = cx.tables.expr_ty(e).subst(tcx, cx.substs);
 
     let result = match e.node {
       hir::ExprUnary(hir::UnNeg, ref inner) => {
@@ -269,14 +264,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       }
       hir::ExprCast(ref base, _) => {
         let base_val = cx.eval(base)?;
-        let base_ty = cx.tables.expr_ty(base);
-
-        // Avoid applying substitutions if they're empty, that'd ICE.
-        let base_ty = if cx.substs.is_empty() {
-            base_ty
-        } else {
-            base_ty.subst(tcx, cx.substs)
-        };
+        let base_ty = cx.tables.expr_ty(base).subst(tcx, cx.substs);
         if ety == base_ty {
             base_val
         } else {
@@ -287,15 +275,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         }
       }
       hir::ExprPath(ref qpath) => {
-        let substs = cx.tables.node_substs(e.id);
-
-        // Avoid applying substitutions if they're empty, that'd ICE.
-        let substs = if cx.substs.is_empty() {
-            substs
-        } else {
-            substs.subst(tcx, cx.substs)
-        };
-
+        let substs = cx.tables.node_substs(e.id).subst(tcx, cx.substs);
           match cx.tables.qpath_def(qpath, e.id) {
               Def::Const(def_id) |
               Def::AssociatedConst(def_id) => {
@@ -538,7 +518,10 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 match ac {
                     // FIXME(eddyb) Use proper Instance resolution to
                     // get the correct Substs returned from here.
-                    Some(ic) => Some((ic.def_id, Substs::empty())),
+                    Some(ic) => {
+                        let substs = Substs::identity_for_item(tcx, ic.def_id);
+                        Some((ic.def_id, substs))
+                    }
                     None => {
                         if trait_item.defaultness.has_value() {
                             Some((def_id, substs))
@@ -789,18 +772,12 @@ fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         });
     };
 
-    let cx = ConstContext {
-        tcx,
-        tables: tcx.typeck_tables_of(def_id),
-        substs: substs,
-        fn_args: None
-    };
-
+    let tables = tcx.typeck_tables_of(def_id);
     let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
         tcx.mir_const_qualif(def_id);
         tcx.hir.body(tcx.hir.body_owned_by(id))
     } else {
         tcx.sess.cstore.item_body(tcx, def_id)
     };
-    cx.eval(&body.value)
+    ConstContext::new(tcx, tables, substs).eval(&body.value)
 }
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 0a966b0c170..07c45d3ee51 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -266,17 +266,19 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
     }
 }
 
-pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
-    pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    pub tables: &'a ty::TypeckTables<'gcx>,
+pub struct PatternContext<'a, 'tcx: 'a> {
+    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    pub tables: &'a ty::TypeckTables<'tcx>,
+    pub substs: &'tcx Substs<'tcx>,
     pub errors: Vec<PatternError<'tcx>>,
 }
 
-impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
-    pub fn from_hir(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                    tables: &'a ty::TypeckTables<'gcx>,
+impl<'a, 'tcx> Pattern<'tcx> {
+    pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                    tables: &'a ty::TypeckTables<'tcx>,
+                    substs: &'tcx Substs<'tcx>,
                     pat: &hir::Pat) -> Self {
-        let mut pcx = PatternContext::new(tcx, tables);
+        let mut pcx = PatternContext::new(tcx, tables, substs);
         let result = pcx.lower_pattern(pat);
         if !pcx.errors.is_empty() {
             span_bug!(pat.span, "encountered errors lowering pattern: {:?}", pcx.errors)
@@ -286,9 +288,11 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, tables: &'a ty::TypeckTables<'gcx>) -> Self {
-        PatternContext { tcx: tcx, tables: tables, errors: vec![] }
+impl<'a, 'tcx> PatternContext<'a, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+               tables: &'a ty::TypeckTables<'tcx>,
+               substs: &'tcx Substs<'tcx>) -> Self {
+        PatternContext { tcx, tables, substs, errors: vec![] }
     }
 
     pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
@@ -583,20 +587,22 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
         let def = self.tables.qpath_def(qpath, id);
         let kind = match def {
             Def::Const(def_id) | Def::AssociatedConst(def_id) => {
-                let tcx = self.tcx.global_tcx();
                 let substs = self.tables.node_substs(id);
-                match eval::lookup_const_by_id(tcx, def_id, substs) {
-                    Some((def_id, _substs)) => {
-                        // Enter the inlined constant's tables temporarily.
+                match eval::lookup_const_by_id(self.tcx, def_id, substs) {
+                    Some((def_id, substs)) => {
+                        // Enter the inlined constant's tables&substs temporarily.
                         let old_tables = self.tables;
-                        self.tables = tcx.typeck_tables_of(def_id);
-                        let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
-                            tcx.hir.body(tcx.hir.body_owned_by(id))
+                        let old_substs = self.substs;
+                        self.tables = self.tcx.typeck_tables_of(def_id);
+                        self.substs = substs;
+                        let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
+                            self.tcx.hir.body(self.tcx.hir.body_owned_by(id))
                         } else {
-                            tcx.sess.cstore.item_body(tcx, def_id)
+                            self.tcx.sess.cstore.item_body(self.tcx, def_id)
                         };
                         let pat = self.lower_const_expr(&body.value, pat_id, span);
                         self.tables = old_tables;
+                        self.substs = old_substs;
                         return pat;
                     }
                     None => {
@@ -616,7 +622,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
     }
 
     fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
-        let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
+        let const_cx = eval::ConstContext::new(self.tcx, self.tables, self.substs);
         match const_cx.eval(expr) {
             Ok(value) => {
                 if let ConstVal::Variant(def_id) = value {
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 1237132f615..be7976b7a93 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -106,7 +106,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                                 false
                             }
                         } else {
-                            let const_cx = ConstContext::with_tables(cx.tcx, cx.tables);
+                            // HACK(eddyb) This might be quite inefficient.
+                            // This would be better left to MIR constant propagation,
+                            // perhaps even at trans time (like is the case already
+                            // when the value being shifted is *also* constant).
+                            let parent_item = cx.tcx.hir.get_parent(e.id);
+                            let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
+                            let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
+                            let const_cx = ConstContext::new(cx.tcx, cx.tables, substs);
                             match const_cx.eval(&r) {
                                 Ok(ConstVal::Integral(i)) => {
                                     i.is_negative() ||
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index eb1414d42e1..9615dfa5093 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -513,7 +513,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             let lvalue = Lvalue::Local(Local::new(index + 1));
 
             if let Some(pattern) = pattern {
-                let pattern = Pattern::from_hir(self.hir.tcx(), self.hir.tables(), pattern);
+                let pattern = Pattern::from_hir(self.hir.tcx().global_tcx(),
+                                                self.hir.tables(),
+                                                self.hir.identity_substs,
+                                                pattern);
                 scope = self.declare_bindings(scope, ast_body.span, &pattern);
                 unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
             }
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index fad070ca8d8..f39c354fb30 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -70,7 +70,10 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                             first_statement_index: index as u32,
                         });
 
-                        let pattern = Pattern::from_hir(cx.tcx, cx.tables(), &local.pat);
+                        let pattern = Pattern::from_hir(cx.tcx.global_tcx(),
+                                                        cx.tables(),
+                                                        cx.identity_substs,
+                                                        &local.pat);
                         result.push(StmtRef::Mirror(Box::new(Stmt {
                             span: stmt.span,
                             kind: StmtKind::Let {
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 0010f312ef9..db3b15d44bc 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -466,7 +466,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprRepeat(ref v, count) => {
             let c = &cx.tcx.hir.body(count).value;
             let def_id = cx.tcx.hir.body_owner_def_id(count);
-            let substs = Substs::empty();
+            let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id);
             let count = match cx.tcx.at(c.span).const_eval((def_id, substs)) {
                 Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
                 Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
@@ -604,7 +604,9 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
 
 fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
     Arm {
-        patterns: arm.pats.iter().map(|p| Pattern::from_hir(cx.tcx, cx.tables(), p)).collect(),
+        patterns: arm.pats.iter().map(|p| {
+            Pattern::from_hir(cx.tcx.global_tcx(), cx.tables(), cx.identity_substs, p)
+        }).collect(),
         guard: arm.guard.to_ref(),
         body: arm.body.to_ref(),
     }
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 2bb6b39966a..2d6dce8adf5 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -26,6 +26,7 @@ use rustc::middle::region::RegionMaps;
 use rustc::infer::InferCtxt;
 use rustc::ty::subst::Subst;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::Substs;
 use syntax::symbol::Symbol;
 use rustc::hir;
 use rustc_const_math::{ConstInt, ConstUsize};
@@ -35,7 +36,12 @@ use std::rc::Rc;
 pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+
     pub param_env: ty::ParamEnv<'tcx>,
+
+    /// Identity `Substs` for use with const-evaluation.
+    pub identity_substs: &'gcx Substs<'gcx>,
+
     pub region_maps: Rc<RegionMaps>,
     pub tables: &'a ty::TypeckTables<'gcx>,
 
@@ -66,10 +72,6 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         let src_id = src.item_id();
         let src_def_id = tcx.hir.local_def_id(src_id);
 
-        let param_env = tcx.param_env(src_def_id);
-        let region_maps = tcx.region_maps(src_def_id);
-        let tables = tcx.typeck_tables_of(src_def_id);
-
         let attrs = tcx.hir.attrs(src_id);
 
         // Some functions always have overflow checks enabled,
@@ -84,7 +86,17 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         // Constants and const fn's always need overflow checks.
         check_overflow |= constness == hir::Constness::Const;
 
-        Cx { tcx, infcx, param_env, region_maps, tables, constness, src, check_overflow }
+        Cx {
+            tcx,
+            infcx,
+            param_env: tcx.param_env(src_def_id),
+            identity_substs: Substs::identity_for_item(tcx.global_tcx(), src_def_id),
+            region_maps: tcx.region_maps(src_def_id),
+            tables: tcx.typeck_tables_of(src_def_id),
+            constness,
+            src,
+            check_overflow,
+        }
     }
 }
 
@@ -123,13 +135,13 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
 
     pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
         let tcx = self.tcx.global_tcx();
-        match ConstContext::with_tables(tcx, self.tables()).eval(e) {
+        match ConstContext::new(tcx, self.tables(), self.identity_substs).eval(e) {
             Ok(value) => Literal::Value { value: value },
             Err(s) => self.fatal_const_eval_err(&s, e.span, "expression")
         }
     }
 
-    pub fn fatal_const_eval_err(&self,
+    pub fn fatal_const_eval_err(&mut self,
         err: &ConstEvalErr<'tcx>,
         primary_span: Span,
         primary_kind: &str)
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 468646c1ced..76a576cd17b 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -39,6 +39,7 @@ use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::mir::transform::MirSource;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::Substs;
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::NodeSet;
@@ -58,13 +59,17 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> {
     promotable: bool,
     mut_rvalue_borrows: NodeSet,
     param_env: ty::ParamEnv<'tcx>,
+    identity_substs: &'tcx Substs<'tcx>,
     tables: &'a ty::TypeckTables<'tcx>,
 }
 
 impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
+    fn const_cx(&self) -> ConstContext<'a, 'gcx> {
+        ConstContext::new(self.tcx, self.tables, self.identity_substs)
+    }
+
     fn check_const_eval(&self, expr: &'gcx hir::Expr) {
-        let const_cx = ConstContext::with_tables(self.tcx, self.tables);
-        if let Err(err) = const_cx.eval(expr) {
+        if let Err(err) = self.const_cx().eval(expr) {
             match err.kind {
                 UnimplementedConstVal(_) => {}
                 IndexOpFeatureGated => {}
@@ -121,25 +126,26 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
         }
 
         let item_id = self.tcx.hir.body_owner(body_id);
+        let item_def_id = self.tcx.hir.local_def_id(item_id);
 
         let outer_in_fn = self.in_fn;
+        let outer_tables = self.tables;
+        let outer_param_env = self.param_env;
+        let outer_identity_substs = self.identity_substs;
+
         self.in_fn = match MirSource::from_node(self.tcx, item_id) {
             MirSource::Fn(_) => true,
             _ => false
         };
-
-        let outer_tables = self.tables;
-        let item_def_id = self.tcx.hir.local_def_id(item_id);
         self.tables = self.tcx.typeck_tables_of(item_def_id);
+        self.param_env = self.tcx.param_env(item_def_id);
+        self.identity_substs = Substs::identity_for_item(self.tcx, item_def_id);
 
         let body = self.tcx.hir.body(body_id);
         if !self.in_fn {
             self.check_const_eval(&body.value);
         }
 
-        let outer_penv = self.param_env;
-        self.param_env = self.tcx.param_env(item_def_id);
-
         let tcx = self.tcx;
         let param_env = self.param_env;
         let region_maps = self.tcx.region_maps(item_def_id);
@@ -148,9 +154,10 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
 
         self.visit_body(body);
 
-        self.param_env = outer_penv;
-        self.tables = outer_tables;
         self.in_fn = outer_in_fn;
+        self.tables = outer_tables;
+        self.param_env = outer_param_env;
+        self.identity_substs = outer_identity_substs;
     }
 
     fn visit_pat(&mut self, p: &'tcx hir::Pat) {
@@ -159,8 +166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
                 self.check_const_eval(lit);
             }
             PatKind::Range(ref start, ref end, RangeEnd::Excluded) => {
-                let const_cx = ConstContext::with_tables(self.tcx, self.tables);
-                match const_cx.compare_lit_exprs(p.span, start, end) {
+                match self.const_cx().compare_lit_exprs(p.span, start, end) {
                     Ok(Ordering::Less) => {}
                     Ok(Ordering::Equal) |
                     Ok(Ordering::Greater) => {
@@ -173,8 +179,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
                 }
             }
             PatKind::Range(ref start, ref end, RangeEnd::Included) => {
-                let const_cx = ConstContext::with_tables(self.tcx, self.tables);
-                match const_cx.compare_lit_exprs(p.span, start, end) {
+                match self.const_cx().compare_lit_exprs(p.span, start, end) {
                     Ok(Ordering::Less) |
                     Ok(Ordering::Equal) => {}
                     Ok(Ordering::Greater) => {
@@ -240,8 +245,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
         }
 
         if self.in_fn && self.promotable {
-            let const_cx = ConstContext::with_tables(self.tcx, self.tables);
-            match const_cx.eval(ex) {
+            match self.const_cx().eval(ex) {
                 Ok(_) => {}
                 Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
                 Err(ConstEvalErr { kind: MiscCatchAll, .. }) |
@@ -472,6 +476,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         promotable: false,
         mut_rvalue_borrows: NodeSet(),
         param_env: ty::ParamEnv::empty(Reveal::UserFacing),
+        identity_substs: Substs::empty(),
     }.as_deep_visitor());
     tcx.sess.abort_if_errors();
 }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 143079b0a08..45ed6ecffd8 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -560,7 +560,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr());
         prev_discr = Some(if let Some(e) = variant.node.disr_expr {
             let expr_did = tcx.hir.local_def_id(e.node_id);
-            let substs = Substs::empty();
+            let substs = Substs::identity_for_item(tcx, expr_did);
             let result = tcx.at(variant.span).const_eval((expr_did, substs));
 
             // enum variant evaluation happens before the global constant check