about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCorey Farwell <coreyf@rwell.org>2017-04-17 23:21:18 -0400
committerGitHub <noreply@github.com>2017-04-17 23:21:18 -0400
commit24e8158213338326740b4efed4dc23dd4c2480c4 (patch)
tree72cbfdc6cbcd28acead54b688a8ff3c796cb32a1
parentb8c446eab808a16ea6e878171762d5a1a58ac927 (diff)
parent6dc21b71cfd8e5246e7953cf64ea5ee6a19ceb3d (diff)
downloadrust-24e8158213338326740b4efed4dc23dd4c2480c4.tar.gz
rust-24e8158213338326740b4efed4dc23dd4c2480c4.zip
Rollup merge of #41310 - eddyb:demand-const-eval, r=nikomatsakis
[on-demand] Turn monomorphic_const_eval into a proper query, not just a cache.

The error definitions and reporting logic, alongside with `eval_length` were moved to `librustc`.
Both local and cross-crate constant evaluation is on-demand now, but the latter is only used for `enum` discriminants, to replace the manual insertion into the cache which was done when decoding variants.

r? @nikomatsakis
-rw-r--r--src/Cargo.lock4
-rw-r--r--src/librustc/diagnostics.rs19
-rw-r--r--src/librustc/middle/const_val.rs199
-rw-r--r--src/librustc/ty/maps.rs4
-rw-r--r--src/librustc/ty/mod.rs47
-rw-r--r--src/librustc_const_eval/Cargo.toml1
-rw-r--r--src/librustc_const_eval/check_match.rs32
-rw-r--r--src/librustc_const_eval/diagnostics.rs19
-rw-r--r--src/librustc_const_eval/eval.rs226
-rw-r--r--src/librustc_const_eval/lib.rs1
-rw-r--r--src/librustc_const_eval/pattern.rs4
-rw-r--r--src/librustc_driver/driver.rs5
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs11
-rw-r--r--src/librustc_metadata/decoder.rs23
-rw-r--r--src/librustc_metadata/encoder.rs46
-rw-r--r--src/librustc_metadata/schema.rs13
-rw-r--r--src/librustc_mir/hair/cx/expr.rs7
-rw-r--r--src/librustc_mir/hair/cx/mod.rs17
-rw-r--r--src/librustc_passes/consts.rs9
-rw-r--r--src/librustc_trans/Cargo.toml1
-rw-r--r--src/librustc_trans/adt.rs20
-rw-r--r--src/librustc_trans/consts.rs2
-rw-r--r--src/librustc_trans/disr.rs82
-rw-r--r--src/librustc_trans/lib.rs3
-rw-r--r--src/librustc_trans/mir/block.rs5
-rw-r--r--src/librustc_trans/mir/constant.rs20
-rw-r--r--src/librustc_trans/mir/rvalue.rs6
-rw-r--r--src/librustc_trans/mir/statement.rs3
-rw-r--r--src/librustc_trans/trans_item.rs5
-rw-r--r--src/librustc_typeck/Cargo.toml1
-rw-r--r--src/librustc_typeck/astconv.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs4
-rw-r--r--src/librustc_typeck/collect.rs23
-rw-r--r--src/librustc_typeck/lib.rs1
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/test/incremental/hashes/enum_defs.rs8
38 files changed, 431 insertions, 448 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 1fa256197ce..62b85348039 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -503,7 +503,6 @@ name = "rustc_const_eval"
 version = "0.0.0"
 dependencies = [
  "arena 0.0.0",
- "graphviz 0.0.0",
  "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
  "rustc_back 0.0.0",
@@ -731,7 +730,6 @@ dependencies = [
  "rustc 0.0.0",
  "rustc_back 0.0.0",
  "rustc_bitflags 0.0.0",
- "rustc_const_eval 0.0.0",
  "rustc_const_math 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_errors 0.0.0",
@@ -762,7 +760,6 @@ dependencies = [
  "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
  "rustc_back 0.0.0",
- "rustc_const_eval 0.0.0",
  "rustc_const_math 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_errors 0.0.0",
@@ -783,7 +780,6 @@ dependencies = [
  "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
  "rustc_back 0.0.0",
- "rustc_const_eval 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_driver 0.0.0",
  "rustc_errors 0.0.0",
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 5a0fbf8efb7..8a391f9cde3 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -327,6 +327,25 @@ struct ListNode {
 This works because `Box` is a pointer, so its size is well-known.
 "##,
 
+E0080: r##"
+This error indicates that the compiler was unable to sensibly evaluate an
+constant expression that had to be evaluated. Attempting to divide by 0
+or causing integer overflow are two ways to induce this error. For example:
+
+```compile_fail,E0080
+enum Enum {
+    X = (1 << 500),
+    Y = (1 / 0)
+}
+```
+
+Ensure that the expressions given can be evaluated as the desired integer type.
+See the FFI section of the Reference for more information about using a custom
+integer type:
+
+https://doc.rust-lang.org/reference.html#ffi-attributes
+"##,
+
 E0106: r##"
 This error indicates that a lifetime is missing from a type. If it is an error
 inside a function signature, the problem may be with failing to adhere to the
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index d81f89827d9..b4c5af94019 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -8,17 +8,28 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use syntax::symbol::InternedString;
-use syntax::ast;
-use std::rc::Rc;
+use self::ConstVal::*;
+pub use rustc_const_math::ConstInt;
+
+use hir;
+use hir::def::Def;
 use hir::def_id::DefId;
+use ty::{self, TyCtxt};
 use ty::subst::Substs;
+use util::common::ErrorReported;
 use rustc_const_math::*;
 
-use self::ConstVal::*;
-pub use rustc_const_math::ConstInt;
+use graphviz::IntoCow;
+use errors::DiagnosticBuilder;
+use syntax::symbol::InternedString;
+use syntax::ast;
+use syntax_pos::Span;
 
+use std::borrow::Cow;
 use std::collections::BTreeMap;
+use std::rc::Rc;
+
+pub type EvalResult<'tcx> = Result<ConstVal<'tcx>, ConstEvalErr<'tcx>>;
 
 #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
 pub enum ConstVal<'tcx> {
@@ -61,3 +72,181 @@ impl<'tcx> ConstVal<'tcx> {
         }
     }
 }
+
+#[derive(Clone, Debug)]
+pub struct ConstEvalErr<'tcx> {
+    pub span: Span,
+    pub kind: ErrKind<'tcx>,
+}
+
+#[derive(Clone, Debug)]
+pub enum ErrKind<'tcx> {
+    CannotCast,
+    MissingStructField,
+    NegateOn(ConstVal<'tcx>),
+    NotOn(ConstVal<'tcx>),
+    CallOn(ConstVal<'tcx>),
+
+    NonConstPath,
+    UnimplementedConstVal(&'static str),
+    ExpectedConstTuple,
+    ExpectedConstStruct,
+    IndexedNonVec,
+    IndexNotUsize,
+    IndexOutOfBounds { len: u64, index: u64 },
+
+    MiscBinaryOp,
+    MiscCatchAll,
+
+    IndexOpFeatureGated,
+    Math(ConstMathErr),
+
+    ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
+
+    TypeckError
+}
+
+impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
+    fn from(err: ConstMathErr) -> ErrKind<'tcx> {
+        match err {
+            ConstMathErr::UnsignedNegation => ErrKind::TypeckError,
+            _ => ErrKind::Math(err)
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub enum ConstEvalErrDescription<'a> {
+    Simple(Cow<'a, str>),
+}
+
+impl<'a> ConstEvalErrDescription<'a> {
+    /// Return a one-line description of the error, for lints and such
+    pub fn into_oneline(self) -> Cow<'a, str> {
+        match self {
+            ConstEvalErrDescription::Simple(simple) => simple,
+        }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
+    pub fn description(&self) -> ConstEvalErrDescription {
+        use self::ErrKind::*;
+        use self::ConstEvalErrDescription::*;
+
+        macro_rules! simple {
+            ($msg:expr) => ({ Simple($msg.into_cow()) });
+            ($fmt:expr, $($arg:tt)+) => ({
+                Simple(format!($fmt, $($arg)+).into_cow())
+            })
+        }
+
+        match self.kind {
+            CannotCast => simple!("can't cast this type"),
+            NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
+            NotOn(ref const_val) => simple!("not on {}", const_val.description()),
+            CallOn(ref const_val) => simple!("call on {}", const_val.description()),
+
+            MissingStructField  => simple!("nonexistent struct field"),
+            NonConstPath        => simple!("non-constant path in constant expression"),
+            UnimplementedConstVal(what) =>
+                simple!("unimplemented constant expression: {}", what),
+            ExpectedConstTuple => simple!("expected constant tuple"),
+            ExpectedConstStruct => simple!("expected constant struct"),
+            IndexedNonVec => simple!("indexing is only supported for arrays"),
+            IndexNotUsize => simple!("indices must be of type `usize`"),
+            IndexOutOfBounds { len, index } => {
+                simple!("index out of bounds: the len is {} but the index is {}",
+                        len, index)
+            }
+
+            MiscBinaryOp => simple!("bad operands for binary"),
+            MiscCatchAll => simple!("unsupported constant expr"),
+            IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
+            Math(ref err) => Simple(err.description().into_cow()),
+
+            ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
+
+            TypeckError => simple!("type-checking failed"),
+        }
+    }
+
+    pub fn struct_error(&self,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        primary_span: Span,
+        primary_kind: &str)
+        -> DiagnosticBuilder<'gcx>
+    {
+        let mut err = self;
+        while let &ConstEvalErr {
+            kind: ErrKind::ErroneousReferencedConstant(box ref i_err), ..
+        } = err {
+            err = i_err;
+        }
+
+        let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
+        err.note(tcx, primary_span, primary_kind, &mut diag);
+        diag
+    }
+
+    pub fn note(&self,
+        _tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        primary_span: Span,
+        primary_kind: &str,
+        diag: &mut DiagnosticBuilder)
+    {
+        match self.description() {
+            ConstEvalErrDescription::Simple(message) => {
+                diag.span_label(self.span, &message);
+            }
+        }
+
+        if !primary_span.contains(self.span) {
+            diag.span_note(primary_span,
+                        &format!("for {} here", primary_kind));
+        }
+    }
+
+    pub fn report(&self,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        primary_span: Span,
+        primary_kind: &str)
+    {
+        if let ErrKind::TypeckError = self.kind {
+            return;
+        }
+        self.struct_error(tcx, primary_span, primary_kind).emit();
+    }
+}
+
+/// Returns the value of the length-valued expression
+pub fn eval_length(tcx: TyCtxt,
+                   count: hir::BodyId,
+                   reason: &str)
+                   -> Result<usize, ErrorReported>
+{
+    let count_expr = &tcx.hir.body(count).value;
+    let count_def_id = tcx.hir.body_owner_def_id(count);
+    match ty::queries::monomorphic_const_eval::get(tcx, count_expr.span, count_def_id) {
+        Ok(Integral(Usize(count))) => {
+            let val = count.as_u64(tcx.sess.target.uint_type);
+            assert_eq!(val as usize as u64, val);
+            Ok(val as usize)
+        },
+        Ok(_) |
+        Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported),
+        Err(err) => {
+            let mut diag = err.struct_error(tcx, count_expr.span, reason);
+
+            if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
+                if let Def::Local(..) = path.def {
+                    diag.note(&format!("`{}` is a variable",
+                                       tcx.hir.node_to_pretty_string(count_expr.id)));
+                }
+            }
+
+            diag.emit();
+            Err(ErrorReported)
+        }
+    }
+}
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 868ccad8a3a..e9eb5e97582 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -10,7 +10,7 @@
 
 use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig};
 use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
-use middle::const_val::ConstVal;
+use middle::const_val;
 use middle::privacy::AccessLevels;
 use mir;
 use session::CompileResult;
@@ -443,7 +443,7 @@ define_maps! { <'tcx>
 
     /// Results of evaluating monomorphic constants embedded in
     /// other items, such as enum variant explicit discriminants.
-    pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal<'tcx>, ()>,
+    pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> const_val::EvalResult<'tcx>,
 
     /// Performs the privacy check and computes "access levels".
     pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc<AccessLevels>,
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index b4f2deabd23..79d369595a5 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1690,7 +1690,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 {
-                match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] {
+                match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) {
                     Ok(ConstVal::Integral(v)) => {
                         discr = v;
                     }
@@ -1703,6 +1703,51 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         })
     }
 
+    /// Compute the discriminant value used by a specific variant.
+    /// Unlike `discriminants`, this is (amortized) constant-time,
+    /// only doing at most one query for evaluating an explicit
+    /// discriminant (the last one before the requested variant),
+    /// assuming there are no constant-evaluation errors there.
+    pub fn discriminant_for_variant(&self,
+                                    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                    variant_index: usize)
+                                    -> ConstInt {
+        let repr_type = self.repr.discr_type();
+        let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx());
+        let mut explicit_index = variant_index;
+        loop {
+            match self.variants[explicit_index].discr {
+                ty::VariantDiscr::Relative(0) => break,
+                ty::VariantDiscr::Relative(distance) => {
+                    explicit_index -= distance;
+                }
+                ty::VariantDiscr::Explicit(expr_did) => {
+                    match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) {
+                        Ok(ConstVal::Integral(v)) => {
+                            explicit_value = v;
+                            break;
+                        }
+                        _ => {
+                            explicit_index -= 1;
+                        }
+                    }
+                }
+            }
+        }
+        let discr = explicit_value.to_u128_unchecked()
+            .wrapping_add((variant_index - explicit_index) as u128);
+        match repr_type {
+            attr::UnsignedInt(ty) => {
+                ConstInt::new_unsigned_truncating(discr, ty,
+                                                  tcx.sess.target.uint_type)
+            }
+            attr::SignedInt(ty) => {
+                ConstInt::new_signed_truncating(discr as i128, ty,
+                                                tcx.sess.target.int_type)
+            }
+        }
+    }
+
     pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {
         queries::adt_destructor::get(tcx, DUMMY_SP, self.did)
     }
diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml
index 907410f74dc..bbc61480824 100644
--- a/src/librustc_const_eval/Cargo.toml
+++ b/src/librustc_const_eval/Cargo.toml
@@ -17,5 +17,4 @@ rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
 syntax = { path = "../libsyntax" }
-graphviz = { path = "../libgraphviz" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 9d55281d019..f1ab6a00aa2 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -14,8 +14,6 @@ use _match::WitnessPreference::*;
 
 use pattern::{Pattern, PatternContext, PatternError, PatternKind};
 
-use eval::report_const_eval_err;
-
 use rustc::dep_graph::DepNode;
 
 use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
@@ -108,27 +106,29 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
-    fn check_patterns(&self, has_guard: bool, pats: &[P<Pat>]) {
-        check_legality_of_move_bindings(self, has_guard, pats);
-        for pat in pats {
-            check_legality_of_bindings_in_at_patterns(self, pat);
-        }
-    }
-
-    fn report_inlining_errors(&self, patcx: PatternContext, pat_span: Span) {
-        for error in patcx.errors {
-            match error {
+impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
+    fn report_inlining_errors(&self, pat_span: Span) {
+        for error in &self.errors {
+            match *error {
                 PatternError::StaticInPattern(span) => {
                     span_err!(self.tcx.sess, span, E0158,
                               "statics cannot be referenced in patterns");
                 }
-                PatternError::ConstEval(err) => {
-                    report_const_eval_err(self.tcx, &err, pat_span, "pattern");
+                PatternError::ConstEval(ref err) => {
+                    err.report(self.tcx, pat_span, "pattern");
                 }
             }
         }
     }
+}
+
+impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
+    fn check_patterns(&self, has_guard: bool, pats: &[P<Pat>]) {
+        check_legality_of_move_bindings(self, has_guard, pats);
+        for pat in pats {
+            check_legality_of_bindings_in_at_patterns(self, pat);
+        }
+    }
 
     fn check_match(
         &self,
@@ -161,7 +161,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
                     let mut patcx = PatternContext::new(self.tcx, self.tables);
                     let pattern = expand_pattern(cx, patcx.lower_pattern(&pat));
                     if !patcx.errors.is_empty() {
-                        self.report_inlining_errors(patcx, pat.span);
+                        patcx.report_inlining_errors(pat.span);
                         have_errors = true;
                     }
                     (pattern, &**pat)
diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs
index 60eef8dd3bc..04fc3e68c8c 100644
--- a/src/librustc_const_eval/diagnostics.rs
+++ b/src/librustc_const_eval/diagnostics.rs
@@ -557,25 +557,6 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases.
 See also https://github.com/rust-lang/rust/issues/14587
 "##,
 
-E0080: r##"
-This error indicates that the compiler was unable to sensibly evaluate an
-constant expression that had to be evaluated. Attempting to divide by 0
-or causing integer overflow are two ways to induce this error. For example:
-
-```compile_fail,E0080
-enum Enum {
-    X = (1 << 500),
-    Y = (1 / 0)
-}
-```
-
-Ensure that the expressions given can be evaluated as the desired integer type.
-See the FFI section of the Reference for more information about using a custom
-integer type:
-
-https://doc.rust-lang.org/reference.html#ffi-attributes
-"##,
-
 }
 
 
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 54f5cff16ed..9c5a669bef0 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 use rustc::middle::const_val::ConstVal::*;
-use rustc::middle::const_val::ConstVal;
-use self::ErrKind::*;
+use rustc::middle::const_val::ErrKind::*;
+use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind};
 
 use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks::FnLikeNode;
@@ -18,22 +18,20 @@ use rustc::traits;
 use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::maps::Providers;
 use rustc::ty::util::IntTypeExt;
 use rustc::ty::subst::{Substs, Subst};
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::DefIdMap;
 
-use graphviz::IntoCow;
 use syntax::ast;
 use rustc::hir::{self, Expr};
 use syntax_pos::{Span, DUMMY_SP};
 
-use std::borrow::Cow;
 use std::cmp::Ordering;
 
 use rustc_const_math::*;
-use rustc_errors::DiagnosticBuilder;
 
 macro_rules! signal {
     ($e:expr, $exn:expr) => {
@@ -158,66 +156,6 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     }
 }
 
-fn build_const_eval_err<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    err: &ConstEvalErr,
-    primary_span: Span,
-    primary_kind: &str)
-    -> DiagnosticBuilder<'tcx>
-{
-    let mut err = err;
-    while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err {
-        err = i_err;
-    }
-
-    let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
-    note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag);
-    diag
-}
-
-pub fn report_const_eval_err<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    err: &ConstEvalErr,
-    primary_span: Span,
-    primary_kind: &str)
-{
-    if let TypeckError = err.kind {
-        return;
-    }
-    build_const_eval_err(tcx, err, primary_span, primary_kind).emit();
-}
-
-pub fn fatal_const_eval_err<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    err: &ConstEvalErr,
-    primary_span: Span,
-    primary_kind: &str)
-    -> !
-{
-    report_const_eval_err(tcx, err, primary_span, primary_kind);
-    tcx.sess.abort_if_errors();
-    unreachable!()
-}
-
-pub fn note_const_eval_err<'a, 'tcx>(
-    _tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    err: &ConstEvalErr,
-    primary_span: Span,
-    primary_kind: &str,
-    diag: &mut DiagnosticBuilder)
-{
-    match err.description() {
-        ConstEvalErrDescription::Simple(message) => {
-            diag.span_label(err.span, &message);
-        }
-    }
-
-    if !primary_span.contains(err.span) {
-        diag.span_note(primary_span,
-                       &format!("for {} here", primary_kind));
-    }
-}
-
 pub struct ConstContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     tables: &'a ty::TypeckTables<'tcx>,
@@ -226,12 +164,6 @@ pub struct ConstContext<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self {
-        let def_id = tcx.hir.body_owner_def_id(body);
-        ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
-        ConstContext::with_tables(tcx, tcx.item_tables(def_id))
-    }
-
     pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self {
         ConstContext {
             tcx: tcx,
@@ -251,107 +183,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
     }
 }
 
-#[derive(Clone, Debug)]
-pub struct ConstEvalErr<'tcx> {
-    pub span: Span,
-    pub kind: ErrKind<'tcx>,
-}
-
-#[derive(Clone, Debug)]
-pub enum ErrKind<'tcx> {
-    CannotCast,
-    MissingStructField,
-    NegateOn(ConstVal<'tcx>),
-    NotOn(ConstVal<'tcx>),
-    CallOn(ConstVal<'tcx>),
-
-    NonConstPath,
-    UnimplementedConstVal(&'static str),
-    ExpectedConstTuple,
-    ExpectedConstStruct,
-    IndexedNonVec,
-    IndexNotUsize,
-    IndexOutOfBounds { len: u64, index: u64 },
-
-    MiscBinaryOp,
-    MiscCatchAll,
-
-    IndexOpFeatureGated,
-    Math(ConstMathErr),
-
-    ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
-
-    TypeckError
-}
-
-impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
-    fn from(err: ConstMathErr) -> ErrKind<'tcx> {
-        match err {
-            ConstMathErr::UnsignedNegation => TypeckError,
-            _ => Math(err)
-        }
-    }
-}
-
-#[derive(Clone, Debug)]
-pub enum ConstEvalErrDescription<'a> {
-    Simple(Cow<'a, str>),
-}
-
-impl<'a> ConstEvalErrDescription<'a> {
-    /// Return a one-line description of the error, for lints and such
-    pub fn into_oneline(self) -> Cow<'a, str> {
-        match self {
-            ConstEvalErrDescription::Simple(simple) => simple,
-        }
-    }
-}
-
-impl<'tcx> ConstEvalErr<'tcx> {
-    pub fn description(&self) -> ConstEvalErrDescription {
-        use self::ErrKind::*;
-        use self::ConstEvalErrDescription::*;
-
-        macro_rules! simple {
-            ($msg:expr) => ({ Simple($msg.into_cow()) });
-            ($fmt:expr, $($arg:tt)+) => ({
-                Simple(format!($fmt, $($arg)+).into_cow())
-            })
-        }
-
-        match self.kind {
-            CannotCast => simple!("can't cast this type"),
-            NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
-            NotOn(ref const_val) => simple!("not on {}", const_val.description()),
-            CallOn(ref const_val) => simple!("call on {}", const_val.description()),
-
-            MissingStructField  => simple!("nonexistent struct field"),
-            NonConstPath        => simple!("non-constant path in constant expression"),
-            UnimplementedConstVal(what) =>
-                simple!("unimplemented constant expression: {}", what),
-            ExpectedConstTuple => simple!("expected constant tuple"),
-            ExpectedConstStruct => simple!("expected constant struct"),
-            IndexedNonVec => simple!("indexing is only supported for arrays"),
-            IndexNotUsize => simple!("indices must be of type `usize`"),
-            IndexOutOfBounds { len, index } => {
-                simple!("index out of bounds: the len is {} but the index is {}",
-                        len, index)
-            }
-
-            MiscBinaryOp => simple!("bad operands for binary"),
-            MiscCatchAll => simple!("unsupported constant expr"),
-            IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
-            Math(ref err) => Simple(err.description().into_cow()),
-
-            ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
-
-            TypeckError => simple!("type-checking failed"),
-        }
-    }
-}
-
-pub type EvalResult<'tcx> = Result<ConstVal<'tcx>, ConstEvalErr<'tcx>>;
-pub type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
+type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
 
 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                                      e: &Expr) -> EvalResult<'tcx> {
@@ -947,14 +779,14 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
         let a = match self.eval(a) {
             Ok(a) => a,
             Err(e) => {
-                report_const_eval_err(tcx, &e, a.span, "expression");
+                e.report(tcx, a.span, "expression");
                 return Err(ErrorReported);
             }
         };
         let b = match self.eval(b) {
             Ok(b) => b,
             Err(e) => {
-                report_const_eval_err(tcx, &e, b.span, "expression");
+                e.report(tcx, b.span, "expression");
                 return Err(ErrorReported);
             }
         };
@@ -962,35 +794,23 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
     }
 }
 
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        monomorphic_const_eval,
+        ..*providers
+    };
+}
 
-/// Returns the value of the length-valued expression
-pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             count: hir::BodyId,
-                             reason: &str)
-                             -> Result<usize, ErrorReported>
-{
-    let count_expr = &tcx.hir.body(count).value;
-    match ConstContext::new(tcx, count).eval(count_expr) {
-        Ok(Integral(Usize(count))) => {
-            let val = count.as_u64(tcx.sess.target.uint_type);
-            assert_eq!(val as usize as u64, val);
-            Ok(val as usize)
-        },
-        Ok(_) |
-        Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported),
-        Err(err) => {
-            let mut diag = build_const_eval_err(
-                tcx, &err, count_expr.span, reason);
-
-            if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
-                if let Def::Local(..) = path.def {
-                    diag.note(&format!("`{}` is a variable",
-                                       tcx.hir.node_to_pretty_string(count_expr.id)));
-                }
-            }
+fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                    def_id: DefId)
+                                    -> EvalResult<'tcx> {
+    let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id));
 
-            diag.emit();
-            Err(ErrorReported)
-        }
-    }
+    let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
+        ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
+        tcx.hir.body(tcx.hir.body_owned_by(id))
+    } else {
+        tcx.sess.cstore.maybe_get_item_body(tcx, def_id).unwrap()
+    };
+    cx.eval(&body.value)
 }
diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs
index 4434a901f94..fa3161a8604 100644
--- a/src/librustc_const_eval/lib.rs
+++ b/src/librustc_const_eval/lib.rs
@@ -40,7 +40,6 @@ extern crate rustc_back;
 extern crate rustc_const_math;
 extern crate rustc_data_structures;
 extern crate rustc_errors;
-extern crate graphviz;
 extern crate syntax_pos;
 
 // NB: This module needs to be declared first so diagnostics are
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index bd67dd2e6b2..f20fa27dc22 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -11,7 +11,7 @@
 use eval;
 
 use rustc::lint;
-use rustc::middle::const_val::ConstVal;
+use rustc::middle::const_val::{ConstEvalErr, ConstVal};
 use rustc::mir::{Field, BorrowKind, Mutability};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty, TypeVariants, Region};
 use rustc::ty::subst::{Substs, Kind};
@@ -29,7 +29,7 @@ use syntax_pos::Span;
 #[derive(Clone, Debug)]
 pub enum PatternError<'tcx> {
     StaticInPattern(Span),
-    ConstEval(eval::ConstEvalErr<'tcx>),
+    ConstEval(ConstEvalErr<'tcx>),
 }
 
 #[derive(Copy, Clone, Debug)]
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 48d9719e76c..7632b40ab4f 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -37,7 +37,7 @@ use rustc_plugin::registry::Registry;
 use rustc_plugin as plugin;
 use rustc_passes::{ast_validation, no_asm, loops, consts,
                    static_recursion, hir_stats, mir_stats};
-use rustc_const_eval::check_match;
+use rustc_const_eval::{self, check_match};
 use super::Compilation;
 
 use serialize::json;
@@ -895,10 +895,13 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
     typeck::provide(&mut local_providers);
     ty::provide(&mut local_providers);
     reachable::provide(&mut local_providers);
+    rustc_const_eval::provide(&mut local_providers);
 
     let mut extern_providers = ty::maps::Providers::default();
     cstore::provide(&mut extern_providers);
     ty::provide_extern(&mut extern_providers);
+    // FIXME(eddyb) get rid of this once we replace const_eval with miri.
+    rustc_const_eval::provide(&mut extern_providers);
 
     TyCtxt::create_and_enter(sess,
                              local_providers,
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index af5c1f05bd1..b73b3e161f9 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -266,6 +266,17 @@ impl<'a, 'tcx, 'm> intravisit::Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, '
         intravisit::walk_item(self, item);
     }
 
+    fn visit_variant(&mut self,
+                     variant: &'tcx hir::Variant,
+                     generics: &'tcx hir::Generics,
+                     parent_id: ast::NodeId) {
+        if let Some(e) = variant.node.disr_expr {
+            self.check_item(e.node_id, variant.span);
+        }
+
+        intravisit::walk_variant(self, variant, generics, parent_id);
+    }
+
     fn visit_variant_data(&mut self,
                           variant_data: &'tcx hir::VariantData,
                           _: ast::Name,
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 3498be9dfdf..fac6079529e 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -511,11 +511,7 @@ impl<'a, 'tcx> CrateMetadata {
         def
     }
 
-    fn get_variant(&self,
-                   item: &Entry<'tcx>,
-                   index: DefIndex,
-                   tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                   -> (ty::VariantDef, Option<DefIndex>) {
+    fn get_variant(&self, item: &Entry, index: DefIndex) -> ty::VariantDef {
         let data = match item.kind {
             EntryKind::Variant(data) |
             EntryKind::Struct(data, _) |
@@ -523,12 +519,7 @@ impl<'a, 'tcx> CrateMetadata {
             _ => bug!(),
         };
 
-        if let ty::VariantDiscr::Explicit(def_id) = data.discr {
-            let result = data.evaluated_discr.map_or(Err(()), Ok);
-            tcx.maps.monomorphic_const_eval.borrow_mut().insert(def_id, result);
-        }
-
-        (ty::VariantDef {
+        ty::VariantDef {
             did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
             name: self.item_name(index),
             fields: item.children.decode(self).map(|index| {
@@ -541,7 +532,7 @@ impl<'a, 'tcx> CrateMetadata {
             }).collect(),
             discr: data.discr,
             ctor_kind: data.ctor_kind,
-        }, data.struct_ctor)
+        }
     }
 
     pub fn get_adt_def(&self,
@@ -560,15 +551,11 @@ impl<'a, 'tcx> CrateMetadata {
             item.children
                 .decode(self)
                 .map(|index| {
-                    let (variant, struct_ctor) =
-                        self.get_variant(&self.entry(index), index, tcx);
-                    assert_eq!(struct_ctor, None);
-                    variant
+                    self.get_variant(&self.entry(index), index)
                 })
                 .collect()
         } else {
-            let (variant, _struct_ctor) = self.get_variant(&item, item_id, tcx);
-            vec![variant]
+            vec![self.get_variant(&item, item_id)]
         };
         let (kind, repr) = match item.kind {
             EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 0e204695e8f..ce9f0a73fe2 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -269,12 +269,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
         let data = VariantData {
             ctor_kind: variant.ctor_kind,
             discr: variant.discr,
-            evaluated_discr: match variant.discr {
-                ty::VariantDiscr::Explicit(def_id) => {
-                    ty::queries::monomorphic_const_eval::get(tcx, DUMMY_SP, def_id).ok()
-                }
-                ty::VariantDiscr::Relative(_) => None
-            },
             struct_ctor: None,
         };
 
@@ -408,7 +402,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
         let data = VariantData {
             ctor_kind: variant.ctor_kind,
             discr: variant.discr,
-            evaluated_discr: None,
             struct_ctor: Some(def_id.index),
         };
 
@@ -697,7 +690,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
                 EntryKind::Struct(self.lazy(&VariantData {
                     ctor_kind: variant.ctor_kind,
                     discr: variant.discr,
-                    evaluated_discr: None,
                     struct_ctor: struct_ctor,
                 }), repr_options)
             }
@@ -708,7 +700,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
                 EntryKind::Union(self.lazy(&VariantData {
                     ctor_kind: variant.ctor_kind,
                     discr: variant.discr,
-                    evaluated_discr: None,
                     struct_ctor: None,
                 }), repr_options)
             }
@@ -1037,6 +1028,17 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
                           EntryBuilder::encode_info_for_foreign_item,
                           (def_id, ni));
     }
+    fn visit_variant(&mut self,
+                     v: &'tcx hir::Variant,
+                     g: &'tcx hir::Generics,
+                     id: ast::NodeId) {
+        intravisit::walk_variant(self, v, g, id);
+
+        if let Some(discr) = v.node.disr_expr {
+            let def_id = self.index.tcx.hir.body_owner_def_id(discr);
+            self.index.record(def_id, EntryBuilder::encode_info_for_embedded_const, def_id);
+        }
+    }
     fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
         intravisit::walk_generics(self, generics);
         self.index.encode_info_for_generics(generics);
@@ -1160,6 +1162,32 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
         }
     }
 
+    fn encode_info_for_embedded_const(&mut self, def_id: DefId) -> Entry<'tcx> {
+        debug!("EntryBuilder::encode_info_for_embedded_const({:?})", def_id);
+        let tcx = self.tcx;
+        let id = tcx.hir.as_local_node_id(def_id).unwrap();
+        let body = tcx.hir.body_owned_by(id);
+
+        Entry {
+            kind: EntryKind::Const(ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id)),
+            visibility: self.lazy(&ty::Visibility::Public),
+            span: self.lazy(&tcx.def_span(def_id)),
+            attributes: LazySeq::empty(),
+            children: LazySeq::empty(),
+            stability: None,
+            deprecation: None,
+
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: Some(self.encode_body(body)),
+            mir: self.encode_mir(def_id),
+        }
+    }
+
     fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq<ast::Attribute> {
         // NOTE: This must use lazy_seq_from_slice(), not lazy_seq() because
         //       we really on the HashStable specialization for [Attribute]
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index 6cd35f1335e..2f2e0e125ae 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -15,7 +15,6 @@ use rustc::hir;
 use rustc::hir::def::{self, CtorKind};
 use rustc::hir::def_id::{DefIndex, DefId};
 use rustc::ich::StableHashingContext;
-use rustc::middle::const_val::ConstVal;
 use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
 use rustc::middle::lang_items;
 use rustc::mir;
@@ -271,9 +270,9 @@ pub enum EntryKind<'tcx> {
     Type,
     Enum(ReprOptions),
     Field,
-    Variant(Lazy<VariantData<'tcx>>),
-    Struct(Lazy<VariantData<'tcx>>, ReprOptions),
-    Union(Lazy<VariantData<'tcx>>, ReprOptions),
+    Variant(Lazy<VariantData>),
+    Struct(Lazy<VariantData>, ReprOptions),
+    Union(Lazy<VariantData>, ReprOptions),
     Fn(Lazy<FnData>),
     ForeignFn(Lazy<FnData>),
     Mod(Lazy<ModData>),
@@ -374,20 +373,18 @@ pub struct FnData {
 impl_stable_hash_for!(struct FnData { constness, arg_names });
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct VariantData<'tcx> {
+pub struct VariantData {
     pub ctor_kind: CtorKind,
     pub discr: ty::VariantDiscr,
-    pub evaluated_discr: Option<ConstVal<'tcx>>,
 
     /// If this is a struct's only variant, this
     /// is the index of the "struct ctor" item.
     pub struct_ctor: Option<DefIndex>,
 }
 
-impl_stable_hash_for!(struct VariantData<'tcx> {
+impl_stable_hash_for!(struct VariantData {
     ctor_kind,
     discr,
-    evaluated_discr,
     struct_ctor
 });
 
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index d9b8d04ad38..b7de50efe34 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -17,7 +17,6 @@ use hair::cx::to_ref::ToRef;
 use rustc::hir::map;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::middle::const_val::ConstVal;
-use rustc_const_eval::{ConstContext, fatal_const_eval_err};
 use rustc::ty::{self, AdtKind, VariantDef, Ty};
 use rustc::ty::cast::CastKind as TyCastKind;
 use rustc::hir;
@@ -592,12 +591,12 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
         // Now comes the rote stuff:
         hir::ExprRepeat(ref v, count) => {
-            let tcx = cx.tcx.global_tcx();
             let c = &cx.tcx.hir.body(count).value;
-            let count = match ConstContext::new(tcx, count).eval(c) {
+            let def_id = cx.tcx.hir.body_owner_def_id(count);
+            let count = match ty::queries::monomorphic_const_eval::get(cx.tcx, c.span, def_id) {
                 Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
                 Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
-                Err(s) => fatal_const_eval_err(tcx, &s, c.span, "expression")
+                Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
             };
 
             ExprKind::Repeat {
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 3eef5d83b8b..5f9fb8e1b12 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -17,8 +17,8 @@
 use hair::*;
 use rustc::mir::transform::MirSource;
 
-use rustc::middle::const_val::ConstVal;
-use rustc_const_eval::{ConstContext, fatal_const_eval_err};
+use rustc::middle::const_val::{ConstEvalErr, ConstVal};
+use rustc_const_eval::ConstContext;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::blocks::FnLikeNode;
@@ -115,10 +115,21 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         let tcx = self.tcx.global_tcx();
         match ConstContext::with_tables(tcx, self.tables()).eval(e) {
             Ok(value) => Literal::Value { value: value },
-            Err(s) => fatal_const_eval_err(tcx, &s, e.span, "expression")
+            Err(s) => self.fatal_const_eval_err(&s, e.span, "expression")
         }
     }
 
+    pub fn fatal_const_eval_err(&self,
+        err: &ConstEvalErr<'tcx>,
+        primary_span: Span,
+        primary_kind: &str)
+        -> !
+    {
+        err.report(self.tcx, primary_span, primary_kind);
+        self.tcx.sess.abort_if_errors();
+        unreachable!()
+    }
+
     pub fn trait_method(&mut self,
                         trait_def_id: DefId,
                         method_name: &str,
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 930a13e36bd..44d3026d80c 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -26,10 +26,11 @@
 
 use rustc::dep_graph::DepNode;
 use rustc::ty::cast::CastKind;
-use rustc_const_eval::{ConstEvalErr, ConstContext};
-use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
-use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
-use rustc_const_eval::ErrKind::{TypeckError};
+use rustc_const_eval::ConstContext;
+use rustc::middle::const_val::ConstEvalErr;
+use rustc::middle::const_val::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll};
+use rustc::middle::const_val::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
+use rustc::middle::const_val::ErrKind::{TypeckError, Math};
 use rustc_const_math::{ConstMathErr, Op};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml
index 07dcb2fc29d..af477f5a152 100644
--- a/src/librustc_trans/Cargo.toml
+++ b/src/librustc_trans/Cargo.toml
@@ -15,7 +15,6 @@ log = "0.3"
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
 rustc_bitflags = { path = "../librustc_bitflags" }
-rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 0fe180253b5..87ca410dece 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -41,8 +41,6 @@
 //!   used unboxed and any field can have pointers (including mutable)
 //!   taken to it, implementing them for Rust seems difficult.
 
-use super::Disr;
-
 use std;
 
 use llvm::{ValueRef, True, IntEQ, IntNE};
@@ -347,31 +345,31 @@ fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef,
 
 /// Set the discriminant for a new value of the given case of the given
 /// representation.
-pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr) {
+pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: u64) {
     let l = bcx.ccx.layout_of(t);
     match *l {
         layout::CEnum{ discr, min, max, .. } => {
-            assert_discr_in_range(Disr(min), Disr(max), to);
-            bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true),
+            assert_discr_in_range(min, max, to);
+            bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true),
                   val, None);
         }
         layout::General{ discr, .. } => {
-            bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true),
+            bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true),
                   bcx.struct_gep(val, 0), None);
         }
         layout::Univariant { .. }
         | layout::UntaggedUnion { .. }
         | layout::Vector { .. } => {
-            assert_eq!(to, Disr(0));
+            assert_eq!(to, 0);
         }
         layout::RawNullablePointer { nndiscr, .. } => {
-            if to.0 != nndiscr {
+            if to != nndiscr {
                 let llptrty = val_ty(val).element_type();
                 bcx.store(C_null(llptrty), val, None);
             }
         }
         layout::StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => {
-            if to.0 != nndiscr {
+            if to != nndiscr {
                 if target_sets_discr_via_memset(bcx) {
                     // Issue #34427: As workaround for LLVM bug on
                     // ARM, use memset of 0 on whole struct rather
@@ -397,7 +395,7 @@ fn target_sets_discr_via_memset<'a, 'tcx>(bcx: &Builder<'a, 'tcx>) -> bool {
     bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64"
 }
 
-pub fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) {
+pub fn assert_discr_in_range<D: PartialOrd>(min: D, max: D, discr: D) {
     if min <= max {
         assert!(min <= discr && discr <= max)
     } else {
@@ -415,7 +413,7 @@ fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
 /// (Not to be confused with `common::const_get_elt`, which operates on
 /// raw LLVM-level structs and arrays.)
 pub fn const_get_field<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
-                       val: ValueRef, _discr: Disr,
+                       val: ValueRef,
                        ix: usize) -> ValueRef {
     let l = ccx.layout_of(t);
     match *l {
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 6b6fa538dc0..7a53a03344f 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -13,9 +13,9 @@ use back::symbol_names;
 use llvm;
 use llvm::{SetUnnamedAddr};
 use llvm::{ValueRef, True};
-use rustc_const_eval::ConstEvalErr;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
+use rustc::middle::const_val::ConstEvalErr;
 use {debuginfo, machine};
 use base;
 use trans_item::TransItem;
diff --git a/src/librustc_trans/disr.rs b/src/librustc_trans/disr.rs
deleted file mode 100644
index a940faac838..00000000000
--- a/src/librustc_trans/disr.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2012-2015 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.
-
-use rustc::middle::const_val::ConstVal;
-use rustc::ty::{self, TyCtxt};
-use rustc_const_math::ConstInt;
-
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub struct Disr(pub u64);
-
-impl Disr {
-    pub fn for_variant(tcx: TyCtxt,
-                       def: &ty::AdtDef,
-                       variant_index: usize) -> Self {
-        let mut explicit_index = variant_index;
-        let mut explicit_value = Disr(0);
-        loop {
-            match def.variants[explicit_index].discr {
-                ty::VariantDiscr::Relative(0) => break,
-                ty::VariantDiscr::Relative(distance) => {
-                    explicit_index -= distance;
-                }
-                ty::VariantDiscr::Explicit(expr_did) => {
-                    match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] {
-                        Ok(ConstVal::Integral(v)) => {
-                            explicit_value = Disr::from(v);
-                            break;
-                        }
-                        _ => {
-                            explicit_index -= 1;
-                        }
-                    }
-                }
-            }
-        }
-        let distance = variant_index - explicit_index;
-        explicit_value.wrapping_add(Disr::from(distance))
-    }
-
-    pub fn wrapping_add(self, other: Self) -> Self {
-        Disr(self.0.wrapping_add(other.0))
-    }
-}
-
-impl ::std::ops::BitAnd for Disr {
-    type Output = Disr;
-    fn bitand(self, other: Self) -> Self {
-        Disr(self.0 & other.0)
-    }
-}
-
-impl From<ConstInt> for Disr {
-    fn from(i: ConstInt) -> Disr {
-        // FIXME: what if discr has 128 bit discr?
-        Disr(i.to_u128_unchecked() as u64)
-    }
-}
-
-impl From<usize> for Disr {
-    fn from(i: usize) -> Disr {
-        Disr(i as u64)
-    }
-}
-
-impl PartialOrd for Disr {
-    fn partial_cmp(&self, other: &Disr) -> Option<::std::cmp::Ordering> {
-        self.0.partial_cmp(&other.0)
-    }
-}
-
-impl Ord for Disr {
-    fn cmp(&self, other: &Disr) -> ::std::cmp::Ordering {
-        self.0.cmp(&other.0)
-    }
-}
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index abda358bc4f..be214a0f614 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -51,7 +51,6 @@ extern crate rustc_incremental;
 pub extern crate rustc_llvm as llvm;
 extern crate rustc_platform_intrinsics as intrinsics;
 extern crate rustc_const_math;
-extern crate rustc_const_eval;
 #[macro_use]
 #[no_link]
 extern crate rustc_bitflags;
@@ -68,7 +67,6 @@ pub use rustc::lint;
 pub use rustc::util;
 
 pub use base::trans_crate;
-pub use disr::Disr;
 
 pub mod back {
     pub use rustc::hir::svh;
@@ -119,7 +117,6 @@ mod consts;
 mod context;
 mod debuginfo;
 mod declare;
-mod disr;
 mod glue;
 mod intrinsic;
 mod machine;
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index caec4789edd..0976859e27f 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -9,9 +9,8 @@
 // except according to those terms.
 
 use llvm::{self, ValueRef, BasicBlockRef};
-use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
 use rustc::middle::lang_items;
-use rustc::middle::const_val::ConstInt;
+use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind};
 use rustc::ty::{self, TypeFoldable};
 use rustc::ty::layout::{self, LayoutTyper};
 use rustc::mir;
@@ -363,7 +362,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                         let err = ConstEvalErr{ span: span, kind: err };
                         let mut diag = bcx.tcx().sess.struct_span_warn(
                             span, "this expression will panic at run-time");
-                        note_const_eval_err(bcx.tcx(), &err, span, "expression", &mut diag);
+                        err.note(bcx.tcx(), span, "expression", &mut diag);
                         diag.emit();
                     }
                 }
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 4d5b691c86e..8bce0cf85c0 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -9,8 +9,7 @@
 // except according to those terms.
 
 use llvm::{self, ValueRef};
-use rustc::middle::const_val::ConstVal;
-use rustc_const_eval::{ErrKind, ConstEvalErr, report_const_eval_err};
+use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
 use rustc_const_math::ConstInt::*;
 use rustc_const_math::ConstFloat::*;
 use rustc_const_math::{ConstInt, ConstMathErr};
@@ -23,7 +22,7 @@ use rustc::ty::layout::{self, LayoutTyper};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::subst::{Kind, Substs, Subst};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use {abi, adt, base, Disr, machine};
+use {abi, adt, base, machine};
 use callee;
 use builder::Builder;
 use common::{self, CrateContext, const_get_elt, val_ty};
@@ -327,8 +326,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                             }
                         };
 
-                        let err = ConstEvalErr{ span: span, kind: err };
-                        report_const_eval_err(tcx, &err, span, "expression");
+                        let err = ConstEvalErr { span: span, kind: err };
+                        err.report(tcx, span, "expression");
                         failure = Err(err);
                     }
                     target
@@ -429,7 +428,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                     }
                     mir::ProjectionElem::Field(ref field, _) => {
                         let llprojected = adt::const_get_field(self.ccx, tr_base.ty, base.llval,
-                                                               Disr(0), field.index());
+                                                               field.index());
                         let llextra = if is_sized {
                             ptr::null_mut()
                         } else {
@@ -988,13 +987,14 @@ fn trans_const<'a, 'tcx>(
         layout::CEnum { discr: d, min, max, .. } => {
             let discr = match *kind {
                 mir::AggregateKind::Adt(adt_def, _, _, _) => {
-                    Disr::for_variant(ccx.tcx(), adt_def, variant_index)
+                    adt_def.discriminant_for_variant(ccx.tcx(), variant_index)
+                           .to_u128_unchecked() as u64
                 },
-                _ => Disr(0),
+                _ => 0,
             };
             assert_eq!(vals.len(), 0);
-            adt::assert_discr_in_range(Disr(min), Disr(max), discr);
-            C_integral(Type::from_integer(ccx, d), discr.0, true)
+            adt::assert_discr_in_range(min, max, discr);
+            C_integral(Type::from_integer(ccx, d), discr, true)
         }
         layout::General { discr: d, ref variants, .. } => {
             let variant = &variants[variant_index];
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index aa41720d717..98e9008f829 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -28,7 +28,6 @@ use type_::Type;
 use type_of;
 use tvec;
 use value::Value;
-use Disr;
 
 use super::MirContext;
 use super::constant::const_scalar_checked_binop;
@@ -107,9 +106,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
             mir::Rvalue::Aggregate(ref kind, ref operands) => {
                 match *kind {
                     mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => {
-                        let disr = Disr::for_variant(bcx.tcx(), adt_def, variant_index);
+                        let discr = adt_def.discriminant_for_variant(bcx.tcx(), variant_index)
+                           .to_u128_unchecked() as u64;
                         let dest_ty = dest.ty.to_ty(bcx.tcx());
-                        adt::trans_set_discr(&bcx, dest_ty, dest.llval, disr);
+                        adt::trans_set_discr(&bcx, dest_ty, dest.llval, discr);
                         for (i, operand) in operands.iter().enumerate() {
                             let op = self.trans_operand(&bcx, operand);
                             // Do not generate stores and GEPis for zero-sized fields.
diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs
index 29a0648c8f8..52c2afca474 100644
--- a/src/librustc_trans/mir/statement.rs
+++ b/src/librustc_trans/mir/statement.rs
@@ -18,7 +18,6 @@ use builder::Builder;
 use super::MirContext;
 use super::LocalRef;
 use super::super::adt;
-use super::super::disr::Disr;
 
 impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn trans_statement(&mut self,
@@ -65,7 +64,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 adt::trans_set_discr(&bcx,
                     ty,
                     lvalue_transed.llval,
-                    Disr::from(variant_index));
+                    variant_index as u64);
                 bcx
             }
             mir::StatementKind::StorageLive(ref lvalue) => {
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index f5556bb8382..4d908f3c94f 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -28,7 +28,6 @@ use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::subst::Substs;
-use rustc_const_eval::fatal_const_eval_err;
 use syntax::ast::{self, NodeId};
 use syntax::attr;
 use type_of;
@@ -82,9 +81,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
                     match consts::trans_static(&ccx, m, item.id, &item.attrs) {
                         Ok(_) => { /* Cool, everything's alright. */ },
                         Err(err) => {
-                            // FIXME: shouldn't this be a `span_err`?
-                            fatal_const_eval_err(
-                                ccx.tcx(), &err, item.span, "static");
+                            err.report(ccx.tcx(), item.span, "static");
                         }
                     };
                 } else {
diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml
index 07998aa4a30..194d37dcb81 100644
--- a/src/librustc_typeck/Cargo.toml
+++ b/src/librustc_typeck/Cargo.toml
@@ -16,7 +16,6 @@ arena = { path = "../libarena" }
 fmt_macros = { path = "../libfmt_macros" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
-rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 66c4a81a5c0..9426d601dfc 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -12,7 +12,7 @@
 //! representation.  The main routine here is `ast_ty_to_ty()`: each use
 //! is parameterized by an instance of `AstConv`.
 
-use rustc_const_eval::eval_length;
+use rustc::middle::const_val::eval_length;
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 use hir;
 use hir::def::Def;
@@ -1208,7 +1208,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
             }
             hir::TyArray(ref ty, length) => {
-                if let Ok(length) = eval_length(tcx.global_tcx(), length, "array length") {
+                if let Ok(length) = eval_length(tcx, length, "array length") {
                     tcx.mk_array(self.ast_ty_to_ty(&ty), length)
                 } else {
                     self.tcx().types.err
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index daa18aaa556..f894c0d32e0 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -126,7 +126,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::{self, PatKind};
 use rustc::middle::lang_items;
 use rustc_back::slice;
-use rustc_const_eval::eval_length;
+use rustc::middle::const_val::eval_length;
 use rustc_const_math::ConstInt;
 
 mod assoc;
@@ -3634,7 +3634,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               tcx.mk_array(element_ty, args.len())
           }
           hir::ExprRepeat(ref element, count) => {
-            let count = eval_length(self.tcx.global_tcx(), count, "repeat count")
+            let count = eval_length(self.tcx, count, "repeat count")
                   .unwrap_or(0);
 
             let uty = match expected {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 649353d52f6..73e3de0cc76 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -59,14 +59,12 @@ use constrained_type_params as ctp;
 use middle::lang_items::SizedTraitLangItem;
 use middle::const_val::ConstVal;
 use middle::resolve_lifetime as rl;
-use rustc_const_eval::{ConstContext, report_const_eval_err};
 use rustc::ty::subst::Substs;
 use rustc::ty::{ToPredicate, ReprOptions};
 use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
 use rustc::ty::maps::Providers;
 use rustc::ty::util::IntTypeExt;
 use rustc::dep_graph::DepNode;
-use util::common::MemoizationMap;
 use util::nodemap::{NodeMap, FxHashMap};
 
 use rustc_const_math::ConstInt;
@@ -587,17 +585,6 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     tcx.item_predicates(def_id);
 }
 
-fn evaluate_disr_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                body: hir::BodyId)
-                                -> Result<ConstVal<'tcx>, ()> {
-    let e = &tcx.hir.body(body).value;
-    ConstContext::new(tcx, body).eval(e).map_err(|err| {
-        // enum variant evaluation happens before the global constant check
-        // so we need to report the real error
-        report_const_eval_err(tcx, &err, e.span, "enum discriminant");
-    })
-}
-
 fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         def_id: DefId,
                                         variants: &[hir::Variant]) {
@@ -611,9 +598,13 @@ 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 result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || {
-                evaluate_disr_expr(tcx, e)
-            });
+            let result = ty::queries::monomorphic_const_eval::get(tcx, variant.span, expr_did);
+
+            // enum variant evaluation happens before the global constant check
+            // so we need to report the real error
+            if let Err(ref err) = result {
+                err.report(tcx, variant.span, "enum discriminant");
+            }
 
             match result {
                 Ok(ConstVal::Integral(x)) => Some(x),
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 12db76bf91c..e9d52c5eb98 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -94,7 +94,6 @@ extern crate fmt_macros;
 extern crate rustc_platform_intrinsics as intrinsics;
 extern crate rustc_back;
 extern crate rustc_const_math;
-extern crate rustc_const_eval;
 extern crate rustc_data_structures;
 extern crate rustc_errors as errors;
 
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index d1c98a5c6f1..7caae51e889 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -15,7 +15,6 @@ env_logger = { version = "0.4", default-features = false }
 log = "0.3"
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
-rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_driver = { path = "../librustc_driver" }
 rustc_errors = { path = "../librustc_errors" }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 99838635356..cf872db6823 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1718,7 +1718,7 @@ impl Clean<Type> for hir::Ty {
             }
             TySlice(ref ty) => Vector(box ty.clean(cx)),
             TyArray(ref ty, length) => {
-                use rustc_const_eval::eval_length;
+                use rustc::middle::const_val::eval_length;
                 let n = eval_length(cx.tcx, length, "array length").unwrap();
                 FixedVector(box ty.clean(cx), n.to_string())
             },
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 447d60018d9..d5b997001bb 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -33,7 +33,6 @@ extern crate getopts;
 extern crate env_logger;
 extern crate libc;
 extern crate rustc;
-extern crate rustc_const_eval;
 extern crate rustc_data_structures;
 extern crate rustc_trans;
 extern crate rustc_driver;
diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs
index 37c6ef58f5e..0f734683b60 100644
--- a/src/test/incremental/hashes/enum_defs.rs
+++ b/src/test/incremental/hashes/enum_defs.rs
@@ -27,6 +27,7 @@
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
+#![feature(stmt_expr_attributes)]
 #![crate_type="rlib"]
 
 
@@ -125,9 +126,12 @@ enum EnumChangeValueCStyleVariant0 {
 enum EnumChangeValueCStyleVariant0 {
     Variant1,
 
-    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
-    Variant2 = 22,
+    Variant2 =
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
+        22,
 }
 
 #[cfg(cfail1)]