diff --git a/src/Cargo.lock b/src/Cargo.lock
index b70a01ebb3c18..34c077a6f7a03 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -1858,20 +1858,6 @@ dependencies = [
  "syntax_pos 0.0.0",
 ]
 
-[[package]]
-name = "rustc_const_eval"
-version = "0.0.0"
-dependencies = [
- "arena 0.0.0",
- "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc 0.0.0",
- "rustc_const_math 0.0.0",
- "rustc_data_structures 0.0.0",
- "rustc_errors 0.0.0",
- "syntax 0.0.0",
- "syntax_pos 0.0.0",
-]
-
 [[package]]
 name = "rustc_const_math"
 version = "0.0.0"
@@ -1914,7 +1900,6 @@ dependencies = [
  "rustc_allocator 0.0.0",
  "rustc_back 0.0.0",
  "rustc_borrowck 0.0.0",
- "rustc_const_eval 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_errors 0.0.0",
  "rustc_incremental 0.0.0",
@@ -1964,7 +1949,7 @@ version = "0.0.0"
 dependencies = [
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
- "rustc_const_eval 0.0.0",
+ "rustc_mir 0.0.0",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
 ]
@@ -2012,6 +1997,7 @@ dependencies = [
 name = "rustc_mir"
 version = "0.0.0"
 dependencies = [
+ "arena 0.0.0",
  "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "graphviz 0.0.0",
@@ -2020,7 +2006,6 @@ dependencies = [
  "rustc 0.0.0",
  "rustc_apfloat 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",
@@ -2046,10 +2031,10 @@ version = "0.0.0"
 dependencies = [
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 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",
+ "rustc_mir 0.0.0",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
 ]
diff --git a/src/doc/rustc-ux-guidelines.md b/src/doc/rustc-ux-guidelines.md
index 323d49e469120..b62762ef69e01 100644
--- a/src/doc/rustc-ux-guidelines.md
+++ b/src/doc/rustc-ux-guidelines.md
@@ -64,7 +64,6 @@ for details on how to format and write long error codes.
   [librustc](https://github.com/rust-lang/rust/blob/master/src/librustc/diagnostics.rs),
   [libsyntax](https://github.com/rust-lang/rust/blob/master/src/libsyntax/diagnostics.rs),
   [librustc_borrowck](https://github.com/rust-lang/rust/blob/master/src/librustc_borrowck/diagnostics.rs),
-  [librustc_const_eval](https://github.com/rust-lang/rust/blob/master/src/librustc_const_eval/diagnostics.rs),
   [librustc_metadata](https://github.com/rust-lang/rust/blob/master/src/librustc_metadata/diagnostics.rs),
   [librustc_mir](https://github.com/rust-lang/rust/blob/master/src/librustc_mir/diagnostics.rs),
   [librustc_passes](https://github.com/rust-lang/rust/blob/master/src/librustc_passes/diagnostics.rs),
diff --git a/src/doc/unstable-book/src/language-features/const-indexing.md b/src/doc/unstable-book/src/language-features/const-indexing.md
deleted file mode 100644
index 42d46ce15f676..0000000000000
--- a/src/doc/unstable-book/src/language-features/const-indexing.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# `const_indexing`
-
-The tracking issue for this feature is: [#29947]
-
-[#29947]: https://github.com/rust-lang/rust/issues/29947
-
-------------------------
-
-The `const_indexing` feature allows the constant evaluation of index operations
-on constant arrays and repeat expressions.
-
-## Examples
-
-```rust
-#![feature(const_indexing)]
-
-const ARR: [usize; 5] = [1, 2, 3, 4, 5];
-const ARR2: [usize; ARR[1]] = [42, 99];
-```
\ No newline at end of file
diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs
index b98470449827e..6602643dc5106 100644
--- a/src/libcore/cmp.rs
+++ b/src/libcore/cmp.rs
@@ -427,6 +427,7 @@ impl<T: Ord> Ord for Reverse<T> {
 ///     }
 /// }
 /// ```
+#[cfg_attr(not(stage0), lang = "ord")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Ord: Eq + PartialOrd<Self> {
     /// This method returns an `Ordering` between `self` and `other`.
@@ -596,7 +597,8 @@ impl PartialOrd for Ordering {
 /// assert_eq!(x < y, true);
 /// assert_eq!(x.lt(&y), true);
 /// ```
-#[lang = "ord"]
+#[cfg_attr(stage0, lang = "ord")]
+#[cfg_attr(not(stage0), lang = "partial_ord")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"]
 pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index ed46296389da4..7d8709a82f4d3 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -60,15 +60,15 @@
 //! user of the `DepNode` API of having to know how to compute the expected
 //! fingerprint for a given set of node parameters.
 
+use mir::interpret::{GlobalId};
 use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
 use hir::map::DefPathHash;
 use hir::{HirId, ItemLocalId};
 
-use ich::Fingerprint;
+use ich::{Fingerprint, StableHashingContext};
+use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
 use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
 use ty::subst::Substs;
-use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
-use ich::StableHashingContext;
 use std::fmt;
 use std::hash::Hash;
 use syntax_pos::symbol::InternedString;
@@ -518,7 +518,7 @@ define_dep_nodes!( <'tcx>
     [] TypeckTables(DefId),
     [] UsedTraitImports(DefId),
     [] HasTypeckTables(DefId),
-    [] ConstEval { param_env: ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)> },
+    [] ConstEval { param_env: ParamEnvAnd<'tcx, GlobalId<'tcx>> },
     [] CheckMatch(DefId),
     [] SymbolName(DefId),
     [] InstanceSymbolName { instance: Instance<'tcx> },
@@ -661,7 +661,7 @@ trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
 }
 
 impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T
-    where T: HashStable<StableHashingContext<'gcx>> + fmt::Debug
+    where T: HashStable<StableHashingContext<'a>> + fmt::Debug
 {
     default const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
 
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 287516474d49a..b3a904f2f5fec 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -14,19 +14,6 @@
 // Each message should start and end with a new line, and be wrapped to 80 characters.
 // In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
 register_long_diagnostics! {
-E0020: r##"
-This error indicates that an attempt was made to divide by zero (or take the
-remainder of a zero divisor) in a static or constant expression. Erroneous
-code example:
-
-```compile_fail
-#[deny(const_err)]
-
-const X: i32 = 42 / 0;
-// error: attempt to divide by zero in a constant expression
-```
-"##,
-
 E0038: r##"
 Trait objects like `Box<Trait>` can only be constructed when certain
 requirements are satisfied by the trait in question.
diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs
index 637b156ceef5d..34b3aa53d6bcf 100644
--- a/src/librustc/hir/def_id.rs
+++ b/src/librustc/hir/def_id.rs
@@ -220,7 +220,6 @@ impl serialize::UseSpecializedDecodable for DefId {}
 pub struct LocalDefId(DefIndex);
 
 impl LocalDefId {
-
     #[inline]
     pub fn from_def_id(def_id: DefId) -> LocalDefId {
         assert!(def_id.is_local());
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 9bbda9d74479b..3c523f5633e11 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -529,7 +529,7 @@ struct HirItemLike<T> {
     hash_bodies: bool,
 }
 
-impl<'hir, T> HashStable<StableHashingContext<'hir>> for HirItemLike<T>
+impl<'a, 'hir, T> HashStable<StableHashingContext<'hir>> for HirItemLike<T>
     where T: HashStable<StableHashingContext<'hir>>
 {
     fn hash_stable<W: StableHasherResult>(&self,
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
index 4dcab6a04ee20..6ae588b2a07b6 100644
--- a/src/librustc/ich/hcx.rs
+++ b/src/librustc/ich/hcx.rs
@@ -46,19 +46,19 @@ pub fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
 /// a reference to the TyCtxt) and it holds a few caches for speeding up various
 /// things (e.g. each DefId/DefPath is only hashed once).
 #[derive(Clone)]
-pub struct StableHashingContext<'gcx> {
-    sess: &'gcx Session,
-    definitions: &'gcx Definitions,
-    cstore: &'gcx dyn CrateStore,
-    body_resolver: BodyResolver<'gcx>,
+pub struct StableHashingContext<'a> {
+    sess: &'a Session,
+    definitions: &'a Definitions,
+    cstore: &'a dyn CrateStore,
+    body_resolver: BodyResolver<'a>,
     hash_spans: bool,
     hash_bodies: bool,
     node_id_hashing_mode: NodeIdHashingMode,
 
     // Very often, we are hashing something that does not need the
     // CachingCodemapView, so we initialize it lazily.
-    raw_codemap: &'gcx CodeMap,
-    caching_codemap: Option<CachingCodemapView<'gcx>>,
+    raw_codemap: &'a CodeMap,
+    caching_codemap: Option<CachingCodemapView<'a>>,
 }
 
 #[derive(PartialEq, Eq, Clone, Copy)]
@@ -81,14 +81,14 @@ impl<'gcx> BodyResolver<'gcx> {
     }
 }
 
-impl<'gcx> StableHashingContext<'gcx> {
+impl<'a> StableHashingContext<'a> {
     // The `krate` here is only used for mapping BodyIds to Bodies.
     // Don't use it for anything else or you'll run the risk of
     // leaking data out of the tracking system.
-    pub fn new(sess: &'gcx Session,
-               krate: &'gcx hir::Crate,
-               definitions: &'gcx Definitions,
-               cstore: &'gcx dyn CrateStore)
+    pub fn new(sess: &'a Session,
+               krate: &'a hir::Crate,
+               definitions: &'a Definitions,
+               cstore: &'a dyn CrateStore)
                -> Self {
         let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans;
 
@@ -106,7 +106,7 @@ impl<'gcx> StableHashingContext<'gcx> {
     }
 
     #[inline]
-    pub fn sess(&self) -> &'gcx Session {
+    pub fn sess(&self) -> &'a Session {
         self.sess
     }
 
@@ -165,7 +165,7 @@ impl<'gcx> StableHashingContext<'gcx> {
     }
 
     #[inline]
-    pub fn codemap(&mut self) -> &mut CachingCodemapView<'gcx> {
+    pub fn codemap(&mut self) -> &mut CachingCodemapView<'a> {
         match self.caching_codemap {
             Some(ref mut cm) => {
                 cm
@@ -193,27 +193,27 @@ impl<'gcx> StableHashingContext<'gcx> {
 }
 
 impl<'a, 'gcx, 'lcx> StableHashingContextProvider for TyCtxt<'a, 'gcx, 'lcx> {
-    type ContextType = StableHashingContext<'gcx>;
+    type ContextType = StableHashingContext<'a>;
     fn create_stable_hashing_context(&self) -> Self::ContextType {
         (*self).create_stable_hashing_context()
     }
 }
 
 
-impl<'gcx> StableHashingContextProvider for StableHashingContext<'gcx> {
-    type ContextType = StableHashingContext<'gcx>;
+impl<'a> StableHashingContextProvider for StableHashingContext<'a> {
+    type ContextType = StableHashingContext<'a>;
     fn create_stable_hashing_context(&self) -> Self::ContextType {
         self.clone()
     }
 }
 
-impl<'gcx> ::dep_graph::DepGraphSafe for StableHashingContext<'gcx> {
+impl<'a> ::dep_graph::DepGraphSafe for StableHashingContext<'a> {
 }
 
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::BodyId {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::BodyId {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         if hcx.hash_bodies() {
             hcx.body_resolver.body(*self).hash_stable(hcx, hasher);
@@ -221,10 +221,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::BodyId {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::HirId {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::HirId {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         match hcx.node_id_hashing_mode {
             NodeIdHashingMode::Ignore => {
@@ -243,21 +243,21 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::HirId {
     }
 }
 
-impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for hir::HirId {
+impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::HirId {
     type KeyType = (DefPathHash, hir::ItemLocalId);
 
     #[inline]
     fn to_stable_hash_key(&self,
-                          hcx: &StableHashingContext<'gcx>)
+                          hcx: &StableHashingContext<'a>)
                           -> (DefPathHash, hir::ItemLocalId) {
         let def_path_hash = hcx.local_def_path_hash(self.owner);
         (def_path_hash, self.local_id)
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::NodeId {
+impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         match hcx.node_id_hashing_mode {
             NodeIdHashingMode::Ignore => {
@@ -270,18 +270,18 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::NodeId {
     }
 }
 
-impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for ast::NodeId {
+impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::NodeId {
     type KeyType = (DefPathHash, hir::ItemLocalId);
 
     #[inline]
     fn to_stable_hash_key(&self,
-                          hcx: &StableHashingContext<'gcx>)
+                          hcx: &StableHashingContext<'a>)
                           -> (DefPathHash, hir::ItemLocalId) {
         hcx.definitions.node_to_hir_id(*self).to_stable_hash_key(hcx)
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for Span {
+impl<'a> HashStable<StableHashingContext<'a>> for Span {
 
     // Hash a span in a stable way. We can't directly hash the span's BytePos
     // fields (that would be similar to hashing pointers, since those are just
@@ -293,7 +293,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Span {
     // Also, hashing filenames is expensive so we avoid doing it twice when the
     // span starts and ends in the same file, which is almost always the case.
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         const TAG_VALID_SPAN: u8 = 0;
         const TAG_INVALID_SPAN: u8 = 1;
@@ -373,8 +373,8 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Span {
     }
 }
 
-pub fn hash_stable_trait_impls<'gcx, W, R>(
-    hcx: &mut StableHashingContext<'gcx>,
+pub fn hash_stable_trait_impls<'a, 'gcx, W, R>(
+    hcx: &mut StableHashingContext<'a>,
     hasher: &mut StableHasher<W>,
     blanket_impls: &Vec<DefId>,
     non_blanket_impls: &HashMap<fast_reject::SimplifiedType, Vec<DefId>, R>)
diff --git a/src/librustc/ich/impls_const_math.rs b/src/librustc/ich/impls_const_math.rs
index 6790c2ac7dece..5f3ff461c0c7e 100644
--- a/src/librustc/ich/impls_const_math.rs
+++ b/src/librustc/ich/impls_const_math.rs
@@ -16,33 +16,6 @@ impl_stable_hash_for!(struct ::rustc_const_math::ConstFloat {
     bits
 });
 
-impl_stable_hash_for!(enum ::rustc_const_math::ConstInt {
-    I8(val),
-    I16(val),
-    I32(val),
-    I64(val),
-    I128(val),
-    Isize(val),
-    U8(val),
-    U16(val),
-    U32(val),
-    U64(val),
-    U128(val),
-    Usize(val)
-});
-
-impl_stable_hash_for!(enum ::rustc_const_math::ConstIsize {
-    Is16(i16),
-    Is32(i32),
-    Is64(i64)
-});
-
-impl_stable_hash_for!(enum ::rustc_const_math::ConstUsize {
-    Us16(i16),
-    Us32(i32),
-    Us64(i64)
-});
-
 impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr {
     NotInRange,
     CmpBetweenUnequalTypes,
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index faad3f3563164..c085b803085a8 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -21,46 +21,46 @@ use std::mem;
 use syntax::ast;
 use syntax::attr;
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for DefId {
+impl<'a> HashStable<StableHashingContext<'a>> for DefId {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         hcx.def_path_hash(*self).hash_stable(hcx, hasher);
     }
 }
 
-impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for DefId {
+impl<'a> ToStableHashKey<StableHashingContext<'a>> for DefId {
     type KeyType = DefPathHash;
 
     #[inline]
-    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'gcx>) -> DefPathHash {
+    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
         hcx.def_path_hash(*self)
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for LocalDefId {
+impl<'a> HashStable<StableHashingContext<'a>> for LocalDefId {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         hcx.def_path_hash(self.to_def_id()).hash_stable(hcx, hasher);
     }
 }
 
-impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for LocalDefId {
+impl<'a> ToStableHashKey<StableHashingContext<'a>> for LocalDefId {
     type KeyType = DefPathHash;
 
     #[inline]
-    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'gcx>) -> DefPathHash {
+    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
         hcx.def_path_hash(self.to_def_id())
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for CrateNum {
+impl<'a> HashStable<StableHashingContext<'a>> for CrateNum {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         hcx.def_path_hash(DefId {
             krate: *self,
@@ -69,11 +69,11 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for CrateNum {
     }
 }
 
-impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for CrateNum {
+impl<'a> ToStableHashKey<StableHashingContext<'a>> for CrateNum {
     type KeyType = DefPathHash;
 
     #[inline]
-    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'gcx>) -> DefPathHash {
+    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
         let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
         def_id.to_stable_hash_key(hcx)
     }
@@ -81,13 +81,13 @@ impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for CrateNum {
 
 impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index });
 
-impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>>
+impl<'a> ToStableHashKey<StableHashingContext<'a>>
 for hir::ItemLocalId {
     type KeyType = hir::ItemLocalId;
 
     #[inline]
     fn to_stable_hash_key(&self,
-                          _: &StableHashingContext<'gcx>)
+                          _: &StableHashingContext<'a>)
                           -> hir::ItemLocalId {
         *self
     }
@@ -100,9 +100,9 @@ for hir::ItemLocalId {
 // want to pick up on a reference changing its target, so we hash the NodeIds
 // in "DefPath Mode".
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ItemId {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::ItemId {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::ItemId {
             id
@@ -114,9 +114,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ItemId {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitItemId {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitItemId {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::TraitItemId {
             node_id
@@ -128,9 +128,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitItemId {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ImplItemId {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItemId {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::ImplItemId {
             node_id
@@ -271,9 +271,9 @@ impl_stable_hash_for!(struct hir::TypeBinding {
     span
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Ty {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::Ty {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         hcx.while_hashing_hir_bodies(true, |hcx| {
             let hir::Ty {
@@ -339,9 +339,9 @@ impl_stable_hash_for!(enum hir::FunctionRetTy {
     Return(t)
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitRef {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitRef {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::TraitRef {
             ref path,
@@ -376,9 +376,9 @@ impl_stable_hash_for!(struct hir::MacroDef {
 });
 
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Block {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::Block {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::Block {
             ref stmts,
@@ -400,9 +400,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Block {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Pat {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::Pat {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::Pat {
             id: _,
@@ -527,9 +527,9 @@ impl_stable_hash_for!(enum hir::UnsafeSource {
     UserProvided
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Expr {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::Expr {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         hcx.while_hashing_hir_bodies(true, |hcx| {
             let hir::Expr {
@@ -591,9 +591,9 @@ impl_stable_hash_for!(enum hir::LoopSource {
     ForLoop
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::MatchSource {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::MatchSource {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use hir::MatchSource;
 
@@ -647,9 +647,9 @@ impl_stable_hash_for!(enum hir::ScopeTarget {
     Loop(loop_id_result)
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Ident {
+impl<'a> HashStable<StableHashingContext<'a>> for ast::Ident {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let ast::Ident {
             ref name,
@@ -660,9 +660,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Ident {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitItem {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitItem {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::TraitItem {
             id: _,
@@ -695,9 +695,9 @@ impl_stable_hash_for!(enum hir::TraitItemKind {
     Type(bounds, rhs)
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ImplItem {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItem {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::ImplItem {
             id: _,
@@ -729,9 +729,9 @@ impl_stable_hash_for!(enum hir::ImplItemKind {
     Type(t)
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Visibility {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::Visibility {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -750,9 +750,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Visibility {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Defaultness {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::Defaultness {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -771,9 +771,9 @@ impl_stable_hash_for!(enum hir::ImplPolarity {
     Negative
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Mod {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::Mod {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::Mod {
             inner,
@@ -826,9 +826,9 @@ impl_stable_hash_for!(enum hir::VariantData {
     Unit(id)
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Item {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::Item {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::Item {
             name,
@@ -885,10 +885,10 @@ impl_stable_hash_for!(struct hir::ImplItemRef {
     defaultness
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for hir::AssociatedItemKind {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -930,9 +930,9 @@ impl_stable_hash_for!(struct hir::Arg {
     hir_id
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Body {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::Body {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::Body {
             ref arguments,
@@ -948,12 +948,12 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Body {
     }
 }
 
-impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for hir::BodyId {
+impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::BodyId {
     type KeyType = (DefPathHash, hir::ItemLocalId);
 
     #[inline]
     fn to_stable_hash_key(&self,
-                          hcx: &StableHashingContext<'gcx>)
+                          hcx: &StableHashingContext<'a>)
                           -> (DefPathHash, hir::ItemLocalId) {
         let hir::BodyId { node_id } = *self;
         node_id.to_stable_hash_key(hcx)
@@ -966,9 +966,9 @@ impl_stable_hash_for!(struct hir::InlineAsmOutput {
     is_indirect
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::GlobalAsm {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::GlobalAsm {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::GlobalAsm {
             asm,
@@ -979,9 +979,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::GlobalAsm {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::InlineAsm {
+impl<'a> HashStable<StableHashingContext<'a>> for hir::InlineAsm {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let hir::InlineAsm {
             asm,
@@ -1062,22 +1062,22 @@ impl_stable_hash_for!(enum hir::Constness {
     NotConst
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for hir::def_id::DefIndex {
 
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         hcx.local_def_path_hash(*self).hash_stable(hcx, hasher);
     }
 }
 
-impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>>
+impl<'a> ToStableHashKey<StableHashingContext<'a>>
 for hir::def_id::DefIndex {
     type KeyType = DefPathHash;
 
     #[inline]
-    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'gcx>) -> DefPathHash {
+    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
          hcx.local_def_path_hash(*self)
     }
 }
@@ -1090,10 +1090,10 @@ impl_stable_hash_for!(struct hir::def::Export {
     is_import
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for ::middle::lang_items::LangItem {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          _: &mut StableHashingContext<'gcx>,
+                                          _: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         ::std::hash::Hash::hash(self, hasher);
     }
@@ -1104,10 +1104,10 @@ impl_stable_hash_for!(struct ::middle::lang_items::LanguageItems {
     missing
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for hir::TraitCandidate {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
             let hir::TraitCandidate {
@@ -1121,11 +1121,11 @@ for hir::TraitCandidate {
     }
 }
 
-impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for hir::TraitCandidate {
+impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
     type KeyType = (DefPathHash, Option<(DefPathHash, hir::ItemLocalId)>);
 
     fn to_stable_hash_key(&self,
-                          hcx: &StableHashingContext<'gcx>)
+                          hcx: &StableHashingContext<'a>)
                           -> Self::KeyType {
         let hir::TraitCandidate {
             def_id,
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index 67b4cfb6fa7e4..1e6dadae36371 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -35,11 +35,11 @@ impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator,
 impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, kind });
 impl_stable_hash_for!(struct mir::UnsafetyCheckResult { violations, unsafe_blocks });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for mir::BorrowKind {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
 
@@ -54,11 +54,11 @@ for mir::BorrowKind {
 }
 
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for mir::UnsafetyViolationKind {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
 
         mem::discriminant(self).hash_stable(hcx, hasher);
@@ -79,12 +79,12 @@ impl_stable_hash_for!(struct mir::Terminator<'tcx> {
     source_info
 });
 
-impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for mir::ClearCrossCrate<T>
-    where T: HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for mir::ClearCrossCrate<T>
+    where T: HashStable<StableHashingContext<'a>>
 {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -96,61 +96,61 @@ impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for mir::ClearCrossCrate<T>
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Local {
+impl<'a> HashStable<StableHashingContext<'a>> for mir::Local {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use rustc_data_structures::indexed_vec::Idx;
         self.index().hash_stable(hcx, hasher);
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::BasicBlock {
+impl<'a> HashStable<StableHashingContext<'a>> for mir::BasicBlock {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use rustc_data_structures::indexed_vec::Idx;
         self.index().hash_stable(hcx, hasher);
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Field {
+impl<'a> HashStable<StableHashingContext<'a>> for mir::Field {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use rustc_data_structures::indexed_vec::Idx;
         self.index().hash_stable(hcx, hasher);
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for mir::VisibilityScope {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use rustc_data_structures::indexed_vec::Idx;
         self.index().hash_stable(hcx, hasher);
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Promoted {
+impl<'a> HashStable<StableHashingContext<'a>> for mir::Promoted {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use rustc_data_structures::indexed_vec::Idx;
         self.index().hash_stable(hcx, hasher);
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for mir::TerminatorKind<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
 
@@ -227,10 +227,10 @@ for mir::TerminatorKind<'gcx> {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for mir::AssertMessage<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
 
@@ -250,10 +250,10 @@ for mir::AssertMessage<'gcx> {
 
 impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for mir::StatementKind<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
 
@@ -287,12 +287,12 @@ for mir::StatementKind<'gcx> {
     }
 }
 
-impl<'gcx, T> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
     for mir::ValidationOperand<'gcx, T>
-    where T: HashStable<StableHashingContext<'gcx>>
+    where T: HashStable<StableHashingContext<'a>>
 {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>)
     {
         self.place.hash_stable(hcx, hasher);
@@ -304,9 +304,9 @@ impl<'gcx, T> HashStable<StableHashingContext<'gcx>>
 
 impl_stable_hash_for!(enum mir::ValidationOp { Acquire, Release, Suspend(region_scope) });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Place<'gcx> {
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Place<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -323,14 +323,14 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Place<'gcx> {
     }
 }
 
-impl<'gcx, B, V, T> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx, B, V, T> HashStable<StableHashingContext<'a>>
 for mir::Projection<'gcx, B, V, T>
-    where B: HashStable<StableHashingContext<'gcx>>,
-          V: HashStable<StableHashingContext<'gcx>>,
-          T: HashStable<StableHashingContext<'gcx>>
+    where B: HashStable<StableHashingContext<'a>>,
+          V: HashStable<StableHashingContext<'a>>,
+          T: HashStable<StableHashingContext<'a>>
 {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let mir::Projection {
             ref base,
@@ -342,13 +342,13 @@ for mir::Projection<'gcx, B, V, T>
     }
 }
 
-impl<'gcx, V, T> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx, V, T> HashStable<StableHashingContext<'a>>
 for mir::ProjectionElem<'gcx, V, T>
-    where V: HashStable<StableHashingContext<'gcx>>,
-          T: HashStable<StableHashingContext<'gcx>>
+    where V: HashStable<StableHashingContext<'a>>,
+          T: HashStable<StableHashingContext<'a>>
 {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -382,9 +382,9 @@ impl_stable_hash_for!(struct mir::VisibilityScopeInfo {
     lint_root, safety
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Safety {
+impl<'a> HashStable<StableHashingContext<'a>> for mir::Safety {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
 
@@ -399,9 +399,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Safety {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Operand<'gcx> {
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Operand<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
 
@@ -419,9 +419,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Operand<'gcx> {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Rvalue<'gcx> {
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Rvalue<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
 
@@ -479,10 +479,10 @@ impl_stable_hash_for!(enum mir::CastKind {
     Unsize
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for mir::AggregateKind<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -541,9 +541,9 @@ impl_stable_hash_for!(enum mir::NullOp {
 
 impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Literal<'gcx> {
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Literal<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -570,9 +570,9 @@ impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> {
     blame_span
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::ClosureOutlivesSubject<'gcx> {
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::ClosureOutlivesSubject<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -585,3 +585,5 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::ClosureOutlivesSubjec
         }
     }
 }
+
+impl_stable_hash_for!(struct mir::interpret::GlobalId<'tcx> { instance, promoted });
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index f935cbfcde992..52f43fbed7b0a 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -29,42 +29,42 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey,
                                            StableHasher, StableHasherResult};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for InternedString {
+impl<'a> HashStable<StableHashingContext<'a>> for InternedString {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let s: &str = &**self;
         s.hash_stable(hcx, hasher);
     }
 }
 
-impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for InternedString {
+impl<'a> ToStableHashKey<StableHashingContext<'a>> for InternedString {
     type KeyType = InternedString;
 
     #[inline]
     fn to_stable_hash_key(&self,
-                          _: &StableHashingContext<'gcx>)
+                          _: &StableHashingContext<'a>)
                           -> InternedString {
         self.clone()
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Name {
+impl<'a> HashStable<StableHashingContext<'a>> for ast::Name {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         self.as_str().hash_stable(hcx, hasher);
     }
 }
 
-impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for ast::Name {
+impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::Name {
     type KeyType = InternedString;
 
     #[inline]
     fn to_stable_hash_key(&self,
-                          _: &StableHashingContext<'gcx>)
+                          _: &StableHashingContext<'a>)
                           -> InternedString {
         self.as_str()
     }
@@ -111,10 +111,10 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
     rustc_const_unstable
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for ::syntax::attr::StabilityLevel {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -166,9 +166,9 @@ impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, ident });
 impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) });
 impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for [ast::Attribute] {
+impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         if self.len() == 0 {
             self.len().hash_stable(hcx, hasher);
@@ -191,9 +191,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for [ast::Attribute] {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Attribute {
+impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         // Make sure that these have been filtered out.
         debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true));
@@ -220,10 +220,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Attribute {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for tokenstream::TokenTree {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -242,10 +242,10 @@ for tokenstream::TokenTree {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for tokenstream::TokenStream {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         for sub_tt in self.trees() {
             sub_tt.hash_stable(hcx, hasher);
@@ -253,9 +253,11 @@ for tokenstream::TokenStream {
     }
 }
 
-fn hash_token<'gcx, W: StableHasherResult>(token: &token::Token,
-                                           hcx: &mut StableHashingContext<'gcx>,
-                                           hasher: &mut StableHasher<W>) {
+fn hash_token<'a, 'gcx, W: StableHasherResult>(
+    token: &token::Token,
+    hcx: &mut StableHashingContext<'a>,
+    hasher: &mut StableHasher<W>,
+) {
     mem::discriminant(token).hash_stable(hcx, hasher);
     match *token {
         token::Token::Eq |
@@ -383,9 +385,9 @@ impl_stable_hash_for!(enum ::syntax_pos::FileName {
     Custom(s)
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for FileMap {
+impl<'a> HashStable<StableHashingContext<'a>> for FileMap {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let FileMap {
             name: _, // We hash the smaller name_hash instead of this
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index a8ed885e78d55..d927a151610ef 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -21,12 +21,13 @@ use std::mem;
 use middle::region;
 use traits;
 use ty;
+use mir;
 
-impl<'gcx, T> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
 for &'gcx ty::Slice<T>
-    where T: HashStable<StableHashingContext<'gcx>> {
+    where T: HashStable<StableHashingContext<'a>> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         thread_local! {
             static CACHE: RefCell<FxHashMap<(usize, usize), Fingerprint>> =
@@ -51,19 +52,19 @@ for &'gcx ty::Slice<T>
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for ty::subst::Kind<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         self.unpack().hash_stable(hcx, hasher);
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for ty::subst::UnpackedKind<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         match self {
             ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher),
@@ -72,10 +73,10 @@ for ty::subst::UnpackedKind<'gcx> {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for ty::RegionKind {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -119,20 +120,20 @@ for ty::RegionKind {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::RegionVid {
+impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionVid {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use rustc_data_structures::indexed_vec::Idx;
         self.index().hash_stable(hcx, hasher);
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for ty::adjustment::AutoBorrow<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -147,10 +148,10 @@ for ty::adjustment::AutoBorrow<'gcx> {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for ty::adjustment::Adjust<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -196,10 +197,10 @@ impl_stable_hash_for!(enum ty::BorrowKind {
     MutBorrow
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for ty::UpvarCapture<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -223,11 +224,11 @@ impl_stable_hash_for!(struct ty::FnSig<'tcx> {
     abi
 });
 
-impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for ty::Binder<T>
-    where T: HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for ty::Binder<T>
+    where T: HashStable<StableHashingContext<'a>>
 {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let ty::Binder(ref inner) = *self;
         inner.hash_stable(hcx, hasher);
@@ -246,13 +247,13 @@ impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs });
 impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref });
 impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b });
 
-impl<'gcx, A, B> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx, A, B> HashStable<StableHashingContext<'a>>
 for ty::OutlivesPredicate<A, B>
-    where A: HashStable<StableHashingContext<'gcx>>,
-          B: HashStable<StableHashingContext<'gcx>>,
+    where A: HashStable<StableHashingContext<'a>>,
+          B: HashStable<StableHashingContext<'a>>,
 {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let ty::OutlivesPredicate(ref a, ref b) = *self;
         a.hash_stable(hcx, hasher);
@@ -264,9 +265,9 @@ impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty }
 impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { substs, item_def_id });
 
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Predicate<'gcx> {
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::Predicate<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -304,9 +305,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Predicate<'gcx> {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::AdtFlags {
+impl<'a> HashStable<StableHashingContext<'a>> for ty::AdtFlags {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          _: &mut StableHashingContext<'gcx>,
+                                          _: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         std_hash::Hash::hash(self, hasher);
     }
@@ -331,69 +332,102 @@ impl_stable_hash_for!(struct ty::FieldDef {
     vis
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for ::middle::const_val::ConstVal<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use middle::const_val::ConstVal::*;
-        use middle::const_val::ConstAggregate::*;
 
         mem::discriminant(self).hash_stable(hcx, hasher);
 
         match *self {
-            Integral(ref value) => {
-                value.hash_stable(hcx, hasher);
-            }
-            Float(ref value) => {
-                value.hash_stable(hcx, hasher);
-            }
-            Str(ref value) => {
-                value.hash_stable(hcx, hasher);
-            }
-            ByteStr(ref value) => {
-                value.hash_stable(hcx, hasher);
-            }
-            Bool(value) => {
-                value.hash_stable(hcx, hasher);
-            }
-            Char(value) => {
-                value.hash_stable(hcx, hasher);
-            }
-            Variant(def_id) => {
-                def_id.hash_stable(hcx, hasher);
-            }
-            Function(def_id, substs) => {
+            Unevaluated(def_id, substs) => {
                 def_id.hash_stable(hcx, hasher);
-                hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-                    substs.hash_stable(hcx, hasher);
-                });
-            }
-            Aggregate(Struct(ref name_values)) => {
-                let mut values = name_values.to_vec();
-                values.sort_unstable_by_key(|&(ref name, _)| name.clone());
-                values.hash_stable(hcx, hasher);
-            }
-            Aggregate(Tuple(ref value)) => {
-                value.hash_stable(hcx, hasher);
-            }
-            Aggregate(Array(ref value)) => {
-                value.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
             }
-            Aggregate(Repeat(ref value, times)) => {
+            Value(ref value) => {
                 value.hash_stable(hcx, hasher);
-                times.hash_stable(hcx, hasher);
             }
-            Unevaluated(def_id, substs) => {
+        }
+    }
+}
+
+impl_stable_hash_for!(enum mir::interpret::Value {
+    ByVal(v),
+    ByValPair(a, b),
+    ByRef(ptr, align)
+});
+
+impl_stable_hash_for!(struct mir::interpret::MemoryPointer {
+    alloc_id,
+    offset
+});
+
+enum AllocDiscriminant {
+    Static,
+    Constant,
+    Function,
+}
+impl_stable_hash_for!(enum self::AllocDiscriminant {
+    Static,
+    Constant,
+    Function
+});
+
+impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId {
+    fn hash_stable<W: StableHasherResult>(
+        &self,
+        hcx: &mut StableHashingContext<'a>,
+        hasher: &mut StableHasher<W>,
+    ) {
+        ty::tls::with_opt(|tcx| {
+            let tcx = tcx.expect("can't hash AllocIds during hir lowering");
+            if let Some(def_id) = tcx.interpret_interner.get_corresponding_static_def_id(*self) {
+                AllocDiscriminant::Static.hash_stable(hcx, hasher);
+                // statics are unique via their DefId
                 def_id.hash_stable(hcx, hasher);
-                substs.hash_stable(hcx, hasher);
+            } else if let Some(alloc) = tcx.interpret_interner.get_alloc(*self) {
+                // not a static, can't be recursive, hash the allocation
+                AllocDiscriminant::Constant.hash_stable(hcx, hasher);
+                alloc.hash_stable(hcx, hasher);
+            } else if let Some(inst) = tcx.interpret_interner.get_fn(*self) {
+                AllocDiscriminant::Function.hash_stable(hcx, hasher);
+                inst.hash_stable(hcx, hasher);
+            } else {
+                bug!("no allocation for {}", self);
             }
+        });
+    }
+}
+
+impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::Allocation {
+    fn hash_stable<W: StableHasherResult>(
+        &self,
+        hcx: &mut StableHashingContext<'a>,
+        hasher: &mut StableHasher<W>,
+    ) {
+        self.bytes.hash_stable(hcx, hasher);
+        for reloc in self.relocations.iter() {
+            reloc.hash_stable(hcx, hasher);
         }
+        self.undef_mask.hash_stable(hcx, hasher);
+        self.align.hash_stable(hcx, hasher);
+        self.runtime_mutability.hash_stable(hcx, hasher);
     }
 }
 
-impl_stable_hash_for!(struct ::middle::const_val::ByteArray<'tcx> {
-    data
+impl_stable_hash_for!(enum ::syntax::ast::Mutability {
+    Immutable,
+    Mutable
+});
+
+impl_stable_hash_for!(struct mir::interpret::Pointer{primval});
+
+impl_stable_hash_for!(enum mir::interpret::PrimVal {
+    Bytes(b),
+    Ptr(p),
+    Undef
 });
 
 impl_stable_hash_for!(struct ty::Const<'tcx> {
@@ -406,26 +440,22 @@ impl_stable_hash_for!(struct ::middle::const_val::ConstEvalErr<'tcx> {
     kind
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl_stable_hash_for!(struct ::middle::const_val::FrameInfo {
+    span,
+    location
+});
+
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for ::middle::const_val::ErrKind<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use middle::const_val::ErrKind::*;
 
         mem::discriminant(self).hash_stable(hcx, hasher);
 
         match *self {
-            CannotCast |
-            MissingStructField |
             NonConstPath |
-            ExpectedConstTuple |
-            ExpectedConstStruct |
-            IndexedNonVec |
-            IndexNotUsize |
-            MiscBinaryOp |
-            MiscCatchAll |
-            IndexOpFeatureGated |
             TypeckError |
             CheckMatchError => {
                 // nothing to do
@@ -443,9 +473,10 @@ for ::middle::const_val::ErrKind<'gcx> {
             LayoutError(ref layout_error) => {
                 layout_error.hash_stable(hcx, hasher);
             }
-            ErroneousReferencedConstant(ref const_val) => {
-                const_val.hash_stable(hcx, hasher);
-            }
+            Miri(ref err, ref trace) => {
+                err.hash_stable(hcx, hasher);
+                trace.hash_stable(hcx, hasher);
+            },
         }
     }
 }
@@ -459,6 +490,167 @@ impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> {
     predicates
 });
 
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
+for ::mir::interpret::EvalError<'gcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        use mir::interpret::EvalErrorKind::*;
+
+        mem::discriminant(&self.kind).hash_stable(hcx, hasher);
+
+        match self.kind {
+            DanglingPointerDeref |
+            DoubleFree |
+            InvalidMemoryAccess |
+            InvalidFunctionPointer |
+            InvalidBool |
+            InvalidDiscriminant |
+            InvalidNullPointerUsage |
+            ReadPointerAsBytes |
+            ReadBytesAsPointer |
+            InvalidPointerMath |
+            ReadUndefBytes |
+            DeadLocal |
+            ExecutionTimeLimitReached |
+            StackFrameLimitReached |
+            OutOfTls |
+            TlsOutOfBounds |
+            CalledClosureAsFunction |
+            VtableForArgumentlessMethod |
+            ModifiedConstantMemory |
+            AssumptionNotHeld |
+            InlineAsm |
+            ReallocateNonBasePtr |
+            DeallocateNonBasePtr |
+            HeapAllocZeroBytes |
+            Unreachable |
+            Panic |
+            ReadFromReturnPointer |
+            UnimplementedTraitSelection |
+            TypeckError |
+            DerefFunctionPointer |
+            ExecuteMemory |
+            ReferencedConstant |
+            OverflowingMath => {}
+            MachineError(ref err) => err.hash_stable(hcx, hasher),
+            FunctionPointerTyMismatch(a, b) => {
+                a.hash_stable(hcx, hasher);
+                b.hash_stable(hcx, hasher)
+            },
+            NoMirFor(ref s) => s.hash_stable(hcx, hasher),
+            UnterminatedCString(ptr) => ptr.hash_stable(hcx, hasher),
+            PointerOutOfBounds {
+                ptr,
+                access,
+                allocation_size,
+            } => {
+                ptr.hash_stable(hcx, hasher);
+                access.hash_stable(hcx, hasher);
+                allocation_size.hash_stable(hcx, hasher)
+            },
+            InvalidBoolOp(bop) => bop.hash_stable(hcx, hasher),
+            Unimplemented(ref s) => s.hash_stable(hcx, hasher),
+            ArrayIndexOutOfBounds(sp, a, b) => {
+                sp.hash_stable(hcx, hasher);
+                a.hash_stable(hcx, hasher);
+                b.hash_stable(hcx, hasher)
+            },
+            Math(sp, ref err) => {
+                sp.hash_stable(hcx, hasher);
+                err.hash_stable(hcx, hasher)
+            },
+            Intrinsic(ref s) => s.hash_stable(hcx, hasher),
+            InvalidChar(c) => c.hash_stable(hcx, hasher),
+            AbiViolation(ref s) => s.hash_stable(hcx, hasher),
+            AlignmentCheckFailed {
+                required,
+                has,
+            } => {
+                required.hash_stable(hcx, hasher);
+                has.hash_stable(hcx, hasher)
+            },
+            MemoryLockViolation {
+                ptr,
+                len,
+                frame,
+                access,
+                ref lock,
+            } =>  {
+                ptr.hash_stable(hcx, hasher);
+                len.hash_stable(hcx, hasher);
+                frame.hash_stable(hcx, hasher);
+                access.hash_stable(hcx, hasher);
+                lock.hash_stable(hcx, hasher)
+            },
+            MemoryAcquireConflict {
+                ptr,
+                len,
+                kind,
+                ref lock,
+            } =>  {
+                ptr.hash_stable(hcx, hasher);
+                len.hash_stable(hcx, hasher);
+                kind.hash_stable(hcx, hasher);
+                lock.hash_stable(hcx, hasher)
+            },
+            InvalidMemoryLockRelease {
+                ptr,
+                len,
+                frame,
+                ref lock,
+            } =>  {
+                ptr.hash_stable(hcx, hasher);
+                len.hash_stable(hcx, hasher);
+                frame.hash_stable(hcx, hasher);
+                lock.hash_stable(hcx, hasher)
+            },
+            DeallocatedLockedMemory {
+                ptr,
+                ref lock,
+            } => {
+                ptr.hash_stable(hcx, hasher);
+                lock.hash_stable(hcx, hasher)
+            },
+            ValidationFailure(ref s) => s.hash_stable(hcx, hasher),
+            TypeNotPrimitive(ty) => ty.hash_stable(hcx, hasher),
+            ReallocatedWrongMemoryKind(ref a, ref b) => {
+                a.hash_stable(hcx, hasher);
+                b.hash_stable(hcx, hasher)
+            },
+            DeallocatedWrongMemoryKind(ref a, ref b) => {
+                a.hash_stable(hcx, hasher);
+                b.hash_stable(hcx, hasher)
+            },
+            IncorrectAllocationInformation(a, b, c, d) => {
+                a.hash_stable(hcx, hasher);
+                b.hash_stable(hcx, hasher);
+                c.hash_stable(hcx, hasher);
+                d.hash_stable(hcx, hasher)
+            },
+            Layout(lay) => lay.hash_stable(hcx, hasher),
+            HeapAllocNonPowerOfTwoAlignment(n) => n.hash_stable(hcx, hasher),
+            PathNotFound(ref v) => v.hash_stable(hcx, hasher),
+        }
+    }
+}
+
+impl_stable_hash_for!(enum mir::interpret::Lock {
+    NoLock,
+    WriteLock(dl),
+    ReadLock(v)
+});
+
+impl_stable_hash_for!(struct mir::interpret::DynamicLifetime {
+    frame,
+    region
+});
+
+impl_stable_hash_for!(enum mir::interpret::AccessKind {
+    Read,
+    Write
+});
+
 impl_stable_hash_for!(enum ty::Variance {
     Covariant,
     Invariant,
@@ -470,9 +662,9 @@ impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized {
     Struct(index)
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Generics {
+impl<'a> HashStable<StableHashingContext<'a>> for ty::Generics {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let ty::Generics {
             parent,
@@ -498,10 +690,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Generics {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for ty::RegionParameterDef {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let ty::RegionParameterDef {
             name,
@@ -527,12 +719,12 @@ impl_stable_hash_for!(struct ty::TypeParameterDef {
     synthetic
 });
 
-impl<'gcx, T> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
 for ::middle::resolve_lifetime::Set1<T>
-    where T: HashStable<StableHashingContext<'gcx>>
+    where T: HashStable<StableHashingContext<'a>>
 {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use middle::resolve_lifetime::Set1;
 
@@ -583,11 +775,11 @@ impl_stable_hash_for!(enum ty::cast::CastKind {
 impl_stable_hash_for!(tuple_struct ::middle::region::FirstStatementIndex { idx });
 impl_stable_hash_for!(struct ::middle::region::Scope { id, code });
 
-impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for region::Scope {
+impl<'a> ToStableHashKey<StableHashingContext<'a>> for region::Scope {
     type KeyType = region::Scope;
 
     #[inline]
-    fn to_stable_hash_key(&self, _: &StableHashingContext<'gcx>) -> region::Scope {
+    fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> region::Scope {
         *self
     }
 }
@@ -613,11 +805,11 @@ impl_stable_hash_for!(enum ty::BoundRegion {
     BrEnv
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for ty::TypeVariants<'gcx>
 {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use ty::TypeVariants::*;
 
@@ -714,11 +906,11 @@ impl_stable_hash_for!(struct ty::TypeAndMut<'tcx> {
     mutbl
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 for ty::ExistentialPredicate<'gcx>
 {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
@@ -751,9 +943,9 @@ impl_stable_hash_for!(struct ty::Instance<'tcx> {
     substs
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::InstanceDef<'gcx> {
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::InstanceDef<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
 
@@ -775,21 +967,21 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::InstanceDef<'gcx> {
             ty::InstanceDef::ClosureOnceShim { call_once } => {
                 call_once.hash_stable(hcx, hasher);
             }
-            ty::InstanceDef::DropGlue(def_id, t) => {
+            ty::InstanceDef::DropGlue(def_id, ty) => {
                 def_id.hash_stable(hcx, hasher);
-                t.hash_stable(hcx, hasher);
+                ty.hash_stable(hcx, hasher);
             }
-            ty::InstanceDef::CloneShim(def_id, t) => {
+            ty::InstanceDef::CloneShim(def_id, ty) => {
                 def_id.hash_stable(hcx, hasher);
-                t.hash_stable(hcx, hasher);
+                ty.hash_stable(hcx, hasher);
             }
         }
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::TraitDef {
+impl<'a> HashStable<StableHashingContext<'a>> for ty::TraitDef {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let ty::TraitDef {
             // We already have the def_path_hash below, no need to hash it twice
@@ -817,9 +1009,9 @@ impl_stable_hash_for!(struct ty::DtorckConstraint<'tcx> {
 });
 
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::CrateVariancesMap {
+impl<'a> HashStable<StableHashingContext<'a>> for ty::CrateVariancesMap {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let ty::CrateVariancesMap {
             ref variances,
@@ -853,12 +1045,12 @@ impl_stable_hash_for!(enum ty::AssociatedItemContainer {
 });
 
 
-impl<'gcx, T> HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
 for ty::steal::Steal<T>
-    where T: HashStable<StableHashingContext<'gcx>>
+    where T: HashStable<StableHashingContext<'a>>
 {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         self.borrow().hash_stable(hcx, hasher);
     }
@@ -881,10 +1073,10 @@ impl_stable_hash_for!(enum ::middle::privacy::AccessLevel {
     Public
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>>
+impl<'a> HashStable<StableHashingContext<'a>>
 for ::middle::privacy::AccessLevels {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
             let ::middle::privacy::AccessLevels {
@@ -911,10 +1103,10 @@ impl_stable_hash_for!(tuple_struct ::middle::reachable::ReachableSet {
     reachable_set
 });
 
-impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
-for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
+impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
+for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use traits::Vtable::*;
 
@@ -933,10 +1125,10 @@ for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
     }
 }
 
-impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
-for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
+impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
+for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let traits::VtableImplData {
             impl_def_id,
@@ -949,10 +1141,10 @@ for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'gc
     }
 }
 
-impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
-for traits::VtableAutoImplData<N> where N: HashStable<StableHashingContext<'gcx>> {
+impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
+for traits::VtableAutoImplData<N> where N: HashStable<StableHashingContext<'a>> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let traits::VtableAutoImplData {
             trait_def_id,
@@ -963,10 +1155,10 @@ for traits::VtableAutoImplData<N> where N: HashStable<StableHashingContext<'gcx>
     }
 }
 
-impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
-for traits::VtableObjectData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
+impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
+for traits::VtableObjectData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let traits::VtableObjectData {
             upcast_trait_ref,
@@ -979,10 +1171,10 @@ for traits::VtableObjectData<'gcx, N> where N: HashStable<StableHashingContext<'
     }
 }
 
-impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
-for traits::VtableBuiltinData<N> where N: HashStable<StableHashingContext<'gcx>> {
+impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
+for traits::VtableBuiltinData<N> where N: HashStable<StableHashingContext<'a>> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let traits::VtableBuiltinData {
             ref nested,
@@ -991,10 +1183,10 @@ for traits::VtableBuiltinData<N> where N: HashStable<StableHashingContext<'gcx>>
     }
 }
 
-impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
-for traits::VtableClosureData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
+impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
+for traits::VtableClosureData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let traits::VtableClosureData {
             closure_def_id,
@@ -1007,10 +1199,10 @@ for traits::VtableClosureData<'gcx, N> where N: HashStable<StableHashingContext<
     }
 }
 
-impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
-for traits::VtableFnPointerData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
+impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
+for traits::VtableFnPointerData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let traits::VtableFnPointerData {
             fn_ty,
@@ -1021,10 +1213,10 @@ for traits::VtableFnPointerData<'gcx, N> where N: HashStable<StableHashingContex
     }
 }
 
-impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
-for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
+impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
+for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let traits::VtableGeneratorData {
             closure_def_id,
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index d08a41010ab16..56de2939ffae1 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -49,6 +49,7 @@
 #![feature(core_intrinsics)]
 #![feature(drain_filter)]
 #![feature(dyn_trait)]
+#![feature(entry_or_default)]
 #![feature(from_ref)]
 #![feature(fs_read_write)]
 #![feature(i128)]
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index b68b7dc6c0672..a951265d458bf 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -20,6 +20,12 @@ use session::Session;
 use session::config::Epoch;
 use syntax::codemap::Span;
 
+declare_lint! {
+    pub EXCEEDING_BITSHIFTS,
+    Deny,
+    "shift exceeds the type's number of bits"
+}
+
 declare_lint! {
     pub CONST_ERR,
     Warn,
@@ -263,6 +269,12 @@ declare_lint! {
     Epoch::Epoch2018
 }
 
+declare_lint! {
+    pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+    Warn,
+    "floating-point literals cannot be used in patterns"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -271,6 +283,8 @@ pub struct HardwiredLints;
 impl LintPass for HardwiredLints {
     fn get_lints(&self) -> LintArray {
         lint_array!(
+            ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+            EXCEEDING_BITSHIFTS,
             UNUSED_IMPORTS,
             UNUSED_EXTERN_CRATES,
             UNUSED_QUALIFICATIONS,
diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs
index 909904b4fc36c..8a899a35ecb54 100644
--- a/src/librustc/lint/levels.rs
+++ b/src/librustc/lint/levels.rs
@@ -394,10 +394,10 @@ impl LintLevelMap {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for LintLevelMap {
+impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let LintLevelMap {
             ref sets,
diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs
index f0285d6a93782..9a394e524817b 100644
--- a/src/librustc/macros.rs
+++ b/src/librustc/macros.rs
@@ -73,10 +73,10 @@ macro_rules! __impl_stable_hash_field {
 #[macro_export]
 macro_rules! impl_stable_hash_for {
     (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => {
-        impl<'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'tcx>> for $enum_name {
+        impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $enum_name {
             #[inline]
             fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
-                                                  __ctx: &mut $crate::ich::StableHashingContext<'tcx>,
+                                                  __ctx: &mut $crate::ich::StableHashingContext<'a>,
                                                   __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
                 use $enum_name::*;
                 ::std::mem::discriminant(self).hash_stable(__ctx, __hasher);
@@ -92,10 +92,10 @@ macro_rules! impl_stable_hash_for {
         }
     };
     (struct $struct_name:path { $($field:ident),* }) => {
-        impl<'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'tcx>> for $struct_name {
+        impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name {
             #[inline]
             fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
-                                                  __ctx: &mut $crate::ich::StableHashingContext<'tcx>,
+                                                  __ctx: &mut $crate::ich::StableHashingContext<'a>,
                                                   __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
                 let $struct_name {
                     $(ref $field),*
@@ -106,10 +106,10 @@ macro_rules! impl_stable_hash_for {
         }
     };
     (tuple_struct $struct_name:path { $($field:ident),* }) => {
-        impl<'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'tcx>> for $struct_name {
+        impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name {
             #[inline]
             fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
-                                                  __ctx: &mut $crate::ich::StableHashingContext<'tcx>,
+                                                  __ctx: &mut $crate::ich::StableHashingContext<'a>,
                                                   __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
                 let $struct_name (
                     $(ref $field),*
@@ -125,11 +125,11 @@ macro_rules! impl_stable_hash_for {
 macro_rules! impl_stable_hash_for_spanned {
     ($T:path) => (
 
-        impl<'tcx> HashStable<StableHashingContext<'tcx>> for ::syntax::codemap::Spanned<$T>
+        impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ::syntax::codemap::Spanned<$T>
         {
             #[inline]
             fn hash_stable<W: StableHasherResult>(&self,
-                                                  hcx: &mut StableHashingContext<'tcx>,
+                                                  hcx: &mut StableHashingContext<'a>,
                                                   hasher: &mut StableHasher<W>) {
                 self.node.hash_stable(hcx, hasher);
                 self.span.hash_stable(hcx, hasher);
diff --git a/src/librustc/middle/borrowck.rs b/src/librustc/middle/borrowck.rs
index 380f79361e27f..6f5791ed5d71b 100644
--- a/src/librustc/middle/borrowck.rs
+++ b/src/librustc/middle/borrowck.rs
@@ -20,9 +20,9 @@ pub struct BorrowCheckResult {
     pub used_mut_nodes: FxHashSet<HirId>,
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for BorrowCheckResult {
+impl<'a> HashStable<StableHashingContext<'a>> for BorrowCheckResult {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let BorrowCheckResult {
             ref used_mut_nodes,
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index 440af39a0d469..8c3dfd0bce752 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -8,72 +8,43 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use rustc_const_math::ConstInt;
-
 use hir::def_id::DefId;
 use ty::{self, TyCtxt, layout};
 use ty::subst::Substs;
 use rustc_const_math::*;
+use mir::interpret::{Value, PrimVal};
+use errors::DiagnosticBuilder;
 
 use graphviz::IntoCow;
-use errors::DiagnosticBuilder;
-use serialize::{self, Encodable, Encoder, Decodable, Decoder};
-use syntax::symbol::InternedString;
-use syntax::ast;
 use syntax_pos::Span;
 
 use std::borrow::Cow;
+use std::rc::Rc;
 
 pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>;
 
 #[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
 pub enum ConstVal<'tcx> {
-    Integral(ConstInt),
-    Float(ConstFloat),
-    Str(InternedString),
-    ByteStr(ByteArray<'tcx>),
-    Bool(bool),
-    Char(char),
-    Variant(DefId),
-    Function(DefId, &'tcx Substs<'tcx>),
-    Aggregate(ConstAggregate<'tcx>),
     Unevaluated(DefId, &'tcx Substs<'tcx>),
-}
-
-#[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)]
-pub struct ByteArray<'tcx> {
-    pub data: &'tcx [u8],
-}
-
-impl<'tcx> serialize::UseSpecializedDecodable for ByteArray<'tcx> {}
-
-#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
-pub enum ConstAggregate<'tcx> {
-    Struct(&'tcx [(ast::Name, &'tcx ty::Const<'tcx>)]),
-    Tuple(&'tcx [&'tcx ty::Const<'tcx>]),
-    Array(&'tcx [&'tcx ty::Const<'tcx>]),
-    Repeat(&'tcx ty::Const<'tcx>, u64),
-}
-
-impl<'tcx> Encodable for ConstAggregate<'tcx> {
-    fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> {
-        bug!("should never encode ConstAggregate::{:?}", self)
-    }
-}
-
-impl<'tcx> Decodable for ConstAggregate<'tcx> {
-    fn decode<D: Decoder>(_: &mut D) -> Result<Self, D::Error> {
-        bug!("should never decode ConstAggregate")
-    }
+    Value(Value),
 }
 
 impl<'tcx> ConstVal<'tcx> {
-    pub fn to_const_int(&self) -> Option<ConstInt> {
+    pub fn to_raw_bits(&self) -> Option<u128> {
         match *self {
-            ConstVal::Integral(i) => Some(i),
-            ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)),
-            ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
-            _ => None
+            ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
+                Some(b)
+            },
+            _ => None,
+        }
+    }
+    pub fn unwrap_u64(&self) -> u64 {
+        match self.to_raw_bits() {
+            Some(val) => {
+                assert_eq!(val as u64 as u128, val);
+                val as u64
+            },
+            None => bug!("expected constant u64, got {:#?}", self),
         }
     }
 }
@@ -81,33 +52,28 @@ impl<'tcx> ConstVal<'tcx> {
 #[derive(Clone, Debug)]
 pub struct ConstEvalErr<'tcx> {
     pub span: Span,
-    pub kind: ErrKind<'tcx>,
+    pub kind: Rc<ErrKind<'tcx>>,
 }
 
 #[derive(Clone, Debug)]
 pub enum ErrKind<'tcx> {
-    CannotCast,
-    MissingStructField,
 
     NonConstPath,
     UnimplementedConstVal(&'static str),
-    ExpectedConstTuple,
-    ExpectedConstStruct,
-    IndexedNonVec,
-    IndexNotUsize,
     IndexOutOfBounds { len: u64, index: u64 },
 
-    MiscBinaryOp,
-    MiscCatchAll,
-
-    IndexOpFeatureGated,
     Math(ConstMathErr),
     LayoutError(layout::LayoutError<'tcx>),
 
-    ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
-
     TypeckError,
     CheckMatchError,
+    Miri(::mir::interpret::EvalError<'tcx>, Vec<FrameInfo>),
+}
+
+#[derive(Clone, Debug)]
+pub struct FrameInfo {
+    pub span: Span,
+    pub location: String,
 }
 
 impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
@@ -120,21 +86,23 @@ impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
 }
 
 #[derive(Clone, Debug)]
-pub enum ConstEvalErrDescription<'a> {
+pub enum ConstEvalErrDescription<'a, 'tcx: 'a> {
     Simple(Cow<'a, str>),
+    Backtrace(&'a ::mir::interpret::EvalError<'tcx>, &'a [FrameInfo]),
 }
 
-impl<'a> ConstEvalErrDescription<'a> {
+impl<'a, 'tcx> ConstEvalErrDescription<'a, 'tcx> {
     /// 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,
+            ConstEvalErrDescription::Backtrace(miri, _) => format!("{}", miri).into_cow(),
         }
     }
 }
 
 impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
-    pub fn description(&self) -> ConstEvalErrDescription {
+    pub fn description(&'a self) -> ConstEvalErrDescription<'a, 'tcx> {
         use self::ErrKind::*;
         use self::ConstEvalErrDescription::*;
 
@@ -145,31 +113,21 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
             })
         }
 
-        match self.kind {
-            CannotCast => simple!("can't cast this type"),
-            MissingStructField  => simple!("nonexistent struct field"),
+        match *self.kind {
             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()),
             LayoutError(ref err) => Simple(err.to_string().into_cow()),
 
-            ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
-
             TypeckError => simple!("type-checking failed"),
             CheckMatchError => simple!("match-checking failed"),
+            Miri(ref err, ref trace) => Backtrace(err, trace),
         }
     }
 
@@ -179,15 +137,8 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
         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);
+        let mut diag = struct_error(tcx, self.span, "constant evaluation error");
+        self.note(tcx, primary_span, primary_kind, &mut diag);
         diag
     }
 
@@ -201,6 +152,12 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
             ConstEvalErrDescription::Simple(message) => {
                 diag.span_label(self.span, message);
             }
+            ConstEvalErrDescription::Backtrace(miri, frames) => {
+                diag.span_label(self.span, format!("{}", miri));
+                for frame in frames {
+                    diag.span_label(frame.span, format!("inside call to `{}`", frame.location));
+                }
+            }
         }
 
         if !primary_span.contains(self.span) {
@@ -214,10 +171,25 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
         primary_span: Span,
         primary_kind: &str)
     {
-        match self.kind {
+        match *self.kind {
             ErrKind::TypeckError | ErrKind::CheckMatchError => return,
+            ErrKind::Miri(ref miri, _) => {
+                match miri.kind {
+                    ::mir::interpret::EvalErrorKind::TypeckError |
+                    ::mir::interpret::EvalErrorKind::Layout(_) => return,
+                    _ => {},
+                }
+            }
             _ => {}
         }
         self.struct_error(tcx, primary_span, primary_kind).emit();
     }
 }
+
+pub fn struct_error<'a, 'gcx, 'tcx>(
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    span: Span,
+    msg: &str,
+) -> DiagnosticBuilder<'gcx> {
+    struct_span_err!(tcx.sess, span, E0080, "{}", msg)
+}
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 447ce46ee5c5c..3b37031cf4614 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -280,6 +280,7 @@ language_item_table! {
     GeneratorTraitLangItem,          "generator",               gen_trait;
 
     EqTraitLangItem,                 "eq",                      eq_trait;
+    PartialOrdTraitLangItem,         "partial_ord",             partial_ord_trait;
     OrdTraitLangItem,                "ord",                     ord_trait;
 
     // A number of panic-related lang items. The `panic` item corresponds to
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index c532427cc9b42..30d63b8443e3d 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -913,8 +913,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
         // Always promote `[T; 0]` (even when e.g. borrowed mutably).
         let promotable = match expr_ty.sty {
-            ty::TyArray(_, len) if
-                len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true,
+            ty::TyArray(_, len) if len.val.to_raw_bits() == Some(0) => true,
             _ => promotable,
         };
 
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 812ee0dc72fd6..c73930553cdea 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -1488,9 +1488,9 @@ pub fn provide(providers: &mut Providers) {
     };
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ScopeTree {
+impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let ScopeTree {
             root_body,
diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs
index efc2f647cfdf5..45cb70d007068 100644
--- a/src/librustc/mir/cache.rs
+++ b/src/librustc/mir/cache.rs
@@ -35,9 +35,9 @@ impl serialize::Decodable for Cache {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for Cache {
+impl<'a> HashStable<StableHashingContext<'a>> for Cache {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          _: &mut StableHashingContext<'gcx>,
+                                          _: &mut StableHashingContext<'a>,
                                           _: &mut StableHasher<W>) {
         // do nothing
     }
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index f9ea544156ce3..51660b180cd98 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -12,7 +12,7 @@ use rustc_const_math::ConstMathErr;
 use syntax::codemap::Span;
 use backtrace::Backtrace;
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct EvalError<'tcx> {
     pub kind: EvalErrorKind<'tcx>,
     pub backtrace: Option<Backtrace>,
@@ -31,11 +31,11 @@ impl<'tcx> From<EvalErrorKind<'tcx>> for EvalError<'tcx> {
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub enum EvalErrorKind<'tcx> {
     /// This variant is used by machines to signal their own errors that do not
     /// match an existing variant
-    MachineError(Box<dyn Error>),
+    MachineError(String),
     FunctionPointerTyMismatch(FnSig<'tcx>, FnSig<'tcx>),
     NoMirFor(String),
     UnterminatedCString(MemoryPointer),
@@ -65,11 +65,6 @@ pub enum EvalErrorKind<'tcx> {
     Intrinsic(String),
     OverflowingMath,
     InvalidChar(u128),
-    OutOfMemory {
-        allocation_size: u64,
-        memory_size: u64,
-        memory_usage: u64,
-    },
     ExecutionTimeLimitReached,
     StackFrameLimitReached,
     OutOfTls,
@@ -124,6 +119,9 @@ pub enum EvalErrorKind<'tcx> {
     UnimplementedTraitSelection,
     /// Abort in case type errors are reached
     TypeckError,
+    /// Cannot compute this constant because it depends on another one
+    /// which already produced an error
+    ReferencedConstant,
 }
 
 pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
@@ -132,7 +130,7 @@ impl<'tcx> Error for EvalError<'tcx> {
     fn description(&self) -> &str {
         use self::EvalErrorKind::*;
         match self.kind {
-            MachineError(ref inner) => inner.description(),
+            MachineError(ref inner) => inner,
             FunctionPointerTyMismatch(..) =>
                 "tried to call a function through a function pointer of a different type",
             InvalidMemoryAccess =>
@@ -190,10 +188,8 @@ impl<'tcx> Error for EvalError<'tcx> {
                 "mir not found",
             InvalidChar(..) =>
                 "tried to interpret an invalid 32-bit value as a char",
-            OutOfMemory{..} =>
-                "could not allocate more memory",
             ExecutionTimeLimitReached =>
-                "reached the configured maximum execution time",
+                "the expression was too complex to be evaluated or resulted in an infinite loop",
             StackFrameLimitReached =>
                 "reached the configured maximum number of stack frames",
             OutOfTls =>
@@ -245,14 +241,8 @@ impl<'tcx> Error for EvalError<'tcx> {
                 "there were unresolved type arguments during trait selection",
             TypeckError =>
                 "encountered constants with type errors, stopping evaluation",
-        }
-    }
-
-    fn cause(&self) -> Option<&dyn Error> {
-        use self::EvalErrorKind::*;
-        match self.kind {
-            MachineError(ref inner) => Some(&**inner),
-            _ => None,
+            ReferencedConstant =>
+                "referenced constant has errors",
         }
     }
 }
@@ -294,15 +284,12 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
                 write!(f, "tried to reallocate memory from {} to {}", old, new),
             DeallocatedWrongMemoryKind(ref old, ref new) =>
                 write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
-            Math(span, ref err) =>
-                write!(f, "{:?} at {:?}", err, span),
+            Math(_, ref err) =>
+                write!(f, "{}", err.description()),
             Intrinsic(ref err) =>
                 write!(f, "{}", err),
             InvalidChar(c) =>
                 write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
-            OutOfMemory { allocation_size, memory_size, memory_usage } =>
-                write!(f, "tried to allocate {} more bytes, but only {} bytes are free of the {} byte memory",
-                       allocation_size, memory_size - memory_usage, memory_size),
             AlignmentCheckFailed { required, has } =>
                write!(f, "tried to access memory with alignment {}, but alignment {} is required",
                       has, required),
@@ -313,7 +300,7 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
             PathNotFound(ref path) =>
                 write!(f, "Cannot find path {:?}", path),
             MachineError(ref inner) =>
-                write!(f, "machine error: {}", inner),
+                write!(f, "{}", inner),
             IncorrectAllocationInformation(size, size2, align, align2) =>
                 write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size, align, size2, align2),
             _ => write!(f, "{}", self.description()),
diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs
index a80695ec9b987..67f30f53a6810 100644
--- a/src/librustc/mir/interpret/mod.rs
+++ b/src/librustc/mir/interpret/mod.rs
@@ -10,7 +10,7 @@ mod value;
 
 pub use self::error::{EvalError, EvalResult, EvalErrorKind};
 
-pub use self::value::{PrimVal, PrimValKind, Value, Pointer, bytes_to_f32, bytes_to_f64};
+pub use self::value::{PrimVal, PrimValKind, Value, Pointer};
 
 use std::collections::BTreeMap;
 use std::fmt;
@@ -19,6 +19,7 @@ use ty;
 use ty::layout::{self, Align, HasDataLayout};
 use middle::region;
 use std::iter;
+use syntax::ast::Mutability;
 
 #[derive(Clone, Debug, PartialEq)]
 pub enum Lock {
@@ -41,7 +42,7 @@ pub enum AccessKind {
 }
 
 /// Uniquely identifies a specific constant or static.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
 pub struct GlobalId<'tcx> {
     /// For a constant or static, the `Instance` of the item itself.
     /// For a promoted global, the `Instance` of the function they belong to.
@@ -101,7 +102,7 @@ pub trait PointerArithmetic: layout::HasDataLayout {
 impl<T: layout::HasDataLayout> PointerArithmetic for T {}
 
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
 pub struct MemoryPointer {
     pub alloc_id: AllocId,
     pub offset: u64,
@@ -148,13 +149,16 @@ impl<'tcx> MemoryPointer {
 #[derive(Copy, Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)]
 pub struct AllocId(pub u64);
 
+impl ::rustc_serialize::UseSpecializedEncodable for AllocId {}
+impl ::rustc_serialize::UseSpecializedDecodable for AllocId {}
+
 impl fmt::Display for AllocId {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}", self.0)
     }
 }
 
-#[derive(Debug, Eq, PartialEq, Hash)]
+#[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
 pub struct Allocation {
     /// The actual bytes of the allocation.
     /// Note that the bytes of a pointer represent the offset of the pointer
@@ -166,6 +170,10 @@ pub struct Allocation {
     pub undef_mask: UndefMask,
     /// The alignment of the allocation to detect unaligned reads.
     pub align: Align,
+    /// Whether the allocation (of a static) should be put into mutable memory when translating
+    ///
+    /// Only happens for `static mut` or `static` with interior mutability
+    pub runtime_mutability: Mutability,
 }
 
 impl Allocation {
@@ -177,6 +185,7 @@ impl Allocation {
             relocations: BTreeMap::new(),
             undef_mask,
             align: Align::from_bytes(1, 1).unwrap(),
+            runtime_mutability: Mutability::Immutable,
         }
     }
 }
@@ -188,12 +197,14 @@ impl Allocation {
 type Block = u64;
 const BLOCK_SIZE: u64 = 64;
 
-#[derive(Clone, Debug, Eq, PartialEq, Hash)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
 pub struct UndefMask {
     blocks: Vec<Block>,
     len: u64,
 }
 
+impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len});
+
 impl UndefMask {
     pub fn new(size: u64) -> Self {
         let mut m = UndefMask {
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index 0bfff2a80e678..7289d74bfbb1b 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -1,24 +1,9 @@
 #![allow(unknown_lints)]
 
 use ty::layout::{Align, HasDataLayout};
+use ty;
 
 use super::{EvalResult, MemoryPointer, PointerArithmetic};
-use syntax::ast::FloatTy;
-use rustc_const_math::ConstFloat;
-
-pub fn bytes_to_f32(bits: u128) -> ConstFloat {
-    ConstFloat {
-        bits,
-        ty: FloatTy::F32,
-    }
-}
-
-pub fn bytes_to_f64(bits: u128) -> ConstFloat {
-    ConstFloat {
-        bits,
-        ty: FloatTy::F64,
-    }
-}
 
 /// A `Value` represents a single self-contained Rust value.
 ///
@@ -29,13 +14,22 @@ pub fn bytes_to_f64(bits: u128) -> ConstFloat {
 /// For optimization of a few very common cases, there is also a representation for a pair of
 /// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary
 /// operations and fat pointers. This idea was taken from rustc's trans.
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
 pub enum Value {
     ByRef(Pointer, Align),
     ByVal(PrimVal),
     ByValPair(PrimVal, PrimVal),
 }
 
+impl<'tcx> ty::TypeFoldable<'tcx> for Value {
+    fn super_fold_with<'gcx: 'tcx, F: ty::fold::TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self {
+        *self
+    }
+    fn super_visit_with<V: ty::fold::TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
+        false
+    }
+}
+
 /// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally.
 /// This type clears up a few APIs where having a `PrimVal` argument for something that is
 /// potentially an integer pointer or a pointer to an allocation was unclear.
@@ -43,9 +37,9 @@ pub enum Value {
 /// I (@oli-obk) believe it is less easy to mix up generic primvals and primvals that are just
 /// the representation of pointers. Also all the sites that convert between primvals and pointers
 /// are explicit now (and rare!)
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
 pub struct Pointer {
-    primval: PrimVal,
+    pub primval: PrimVal,
 }
 
 impl<'tcx> Pointer {
@@ -138,7 +132,7 @@ impl ::std::convert::From<MemoryPointer> for Pointer {
 /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
 /// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes
 /// of a simple value, a pointer into another `Allocation`, or be undefined.
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
 pub enum PrimVal {
     /// The raw bytes of a simple value.
     Bytes(u128),
@@ -172,10 +166,6 @@ impl<'tcx> PrimVal {
         PrimVal::Bytes(n as u128)
     }
 
-    pub fn from_float(f: ConstFloat) -> Self {
-        PrimVal::Bytes(f.bits)
-    }
-
     pub fn from_bool(b: bool) -> Self {
         PrimVal::Bytes(b as u128)
     }
@@ -250,14 +240,6 @@ impl<'tcx> PrimVal {
         })
     }
 
-    pub fn to_f32(self) -> EvalResult<'tcx, ConstFloat> {
-        self.to_bytes().map(bytes_to_f32)
-    }
-
-    pub fn to_f64(self) -> EvalResult<'tcx, ConstFloat> {
-        self.to_bytes().map(bytes_to_f64)
-    }
-
     pub fn to_bool(self) -> EvalResult<'tcx, bool> {
         match self.to_bytes()? {
             0 => Ok(false),
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 7c9feb506afd0..e39765699f9be 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -15,7 +15,7 @@
 use graphviz::IntoCow;
 use middle::const_val::ConstVal;
 use middle::region;
-use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr};
+use rustc_const_math::ConstMathErr;
 use rustc_data_structures::sync::{Lrc};
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators};
@@ -25,13 +25,14 @@ use rustc_serialize as serialize;
 use hir::def::CtorKind;
 use hir::def_id::DefId;
 use mir::visit::MirVisitable;
+use mir::interpret::{Value, PrimVal};
 use ty::subst::{Subst, Substs};
 use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use ty::TypeAndMut;
 use util::ppaux;
 use std::slice;
 use hir::{self, InlineAsm};
-use std::ascii;
 use std::borrow::{Cow};
 use std::cell::Ref;
 use std::fmt::{self, Debug, Formatter, Write};
@@ -707,7 +708,7 @@ pub enum TerminatorKind<'tcx> {
 
         /// Possible values. The locations to branch to in each case
         /// are found in the corresponding indices from the `targets` vector.
-        values: Cow<'tcx, [ConstInt]>,
+        values: Cow<'tcx, [u128]>,
 
         /// Possible branch sites. The last element of this vector is used
         /// for the otherwise branch, so targets.len() == values.len() + 1
@@ -858,7 +859,7 @@ impl<'tcx> Terminator<'tcx> {
 impl<'tcx> TerminatorKind<'tcx> {
     pub fn if_<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
                          t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
-        static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)];
+        static BOOL_SWITCH_FALSE: &'static [u128] = &[0];
         TerminatorKind::SwitchInt {
             discr: cond,
             switch_ty: tcx.types.bool,
@@ -1144,12 +1145,16 @@ impl<'tcx> TerminatorKind<'tcx> {
         match *self {
             Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
             Goto { .. } => vec!["".into()],
-            SwitchInt { ref values, .. } => {
+            SwitchInt { ref values, switch_ty, .. } => {
                 values.iter()
-                      .map(|const_val| {
-                          let mut buf = String::new();
-                          fmt_const_val(&mut buf, &ConstVal::Integral(*const_val)).unwrap();
-                          buf.into()
+                      .map(|&u| {
+                          let mut s = String::new();
+                          print_miri_value(
+                              Value::ByVal(PrimVal::Bytes(u)),
+                              switch_ty,
+                              &mut s,
+                          ).unwrap();
+                          s.into()
                       })
                       .chain(iter::once(String::from("otherwise").into()))
                       .collect()
@@ -1533,7 +1538,8 @@ impl<'tcx> Operand<'tcx> {
             ty,
             literal: Literal::Value {
                 value: tcx.mk_const(ty::Const {
-                    val: ConstVal::Function(def_id, substs),
+                    // ZST function type
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
                     ty
                 })
             },
@@ -1557,7 +1563,7 @@ pub enum Rvalue<'tcx> {
     Use(Operand<'tcx>),
 
     /// [x; 32]
-    Repeat(Operand<'tcx>, ConstUsize),
+    Repeat(Operand<'tcx>, u64),
 
     /// &x or &mut x
     Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
@@ -1853,7 +1859,7 @@ impl<'tcx> Debug for Literal<'tcx> {
         match *self {
             Value { value } => {
                 write!(fmt, "const ")?;
-                fmt_const_val(fmt, &value.val)
+                fmt_const_val(fmt, value)
             }
             Promoted { index } => {
                 write!(fmt, "{:?}", index)
@@ -1863,25 +1869,47 @@ impl<'tcx> Debug for Literal<'tcx> {
 }
 
 /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
-fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
+fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
     use middle::const_val::ConstVal::*;
-    match *const_val {
-        Float(f) => write!(fmt, "{:?}", f),
-        Integral(n) => write!(fmt, "{}", n),
-        Str(s) => write!(fmt, "{:?}", s),
-        ByteStr(bytes) => {
-            let escaped: String = bytes.data
-                .iter()
-                .flat_map(|&ch| ascii::escape_default(ch).map(|c| c as char))
-                .collect();
-            write!(fmt, "b\"{}\"", escaped)
-        }
-        Bool(b) => write!(fmt, "{:?}", b),
-        Char(c) => write!(fmt, "{:?}", c),
-        Variant(def_id) |
-        Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
-        Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val),
-        Unevaluated(..) => write!(fmt, "{:?}", const_val)
+    match const_val.val {
+        Unevaluated(..) => write!(fmt, "{:?}", const_val),
+        Value(val) => print_miri_value(val, const_val.ty, fmt),
+    }
+}
+
+pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Result {
+    use ty::TypeVariants::*;
+    use rustc_const_math::ConstFloat;
+    match (value, &ty.sty) {
+        (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
+        (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
+        (Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(fty)) =>
+            write!(f, "{}", ConstFloat { bits, ty: fty }),
+        (Value::ByVal(PrimVal::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui),
+        (Value::ByVal(PrimVal::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i),
+        (Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
+            write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
+        (Value::ByVal(PrimVal::Undef), &TyFnDef(did, _)) =>
+            write!(f, "{}", item_path_str(did)),
+        (Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len)), &TyRef(_, TypeAndMut {
+            ty: &ty::TyS { sty: TyStr, .. }, ..
+        })) => {
+            ty::tls::with(|tcx| {
+                let alloc = tcx
+                    .interpret_interner
+                    .get_alloc(ptr.alloc_id);
+                if let Some(alloc) = alloc {
+                    assert_eq!(len as usize as u128, len);
+                    let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)];
+                    let s = ::std::str::from_utf8(slice)
+                        .expect("non utf8 str from miri");
+                    write!(f, "{:?}", s)
+                } else {
+                    write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len)
+                }
+            })
+        },
+        _ => write!(f, "{:?}:{}", value, ty),
     }
 }
 
@@ -2467,6 +2495,15 @@ impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T>
     }
 }
 
+impl<'tcx> TypeFoldable<'tcx> for Field {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self {
+        *self
+    }
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
+        false
+    }
+}
+
 impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         Constant {
diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs
index d8eac2b415989..d01059a3e0171 100644
--- a/src/librustc/mir/mono.rs
+++ b/src/librustc/mir/mono.rs
@@ -41,9 +41,9 @@ impl<'tcx> MonoItem<'tcx> {
     }
 }
 
-impl<'tcx> HashStable<StableHashingContext<'tcx>> for MonoItem<'tcx> {
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                           hcx: &mut StableHashingContext<'tcx>,
+                                           hcx: &mut StableHashingContext<'a>,
                                            hasher: &mut StableHasher<W>) {
         ::std::mem::discriminant(self).hash_stable(hcx, hasher);
 
@@ -171,9 +171,9 @@ impl<'tcx> CodegenUnit<'tcx> {
     }
 }
 
-impl<'tcx> HashStable<StableHashingContext<'tcx>> for CodegenUnit<'tcx> {
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                           hcx: &mut StableHashingContext<'tcx>,
+                                           hcx: &mut StableHashingContext<'a>,
                                            hasher: &mut StableHasher<W>) {
         let CodegenUnit {
             ref items,
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index bbfb9c89b3fc4..7d232ac20bfd5 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
                 PlaceTy::Ty {
                     ty: match ty.sty {
                         ty::TyArray(inner, size) => {
-                            let size = size.val.to_const_int().unwrap().to_u64().unwrap();
+                            let size = size.val.unwrap_u64();
                             let len = size - (from as u64) - (to as u64);
                             tcx.mk_array(inner, len)
                         }
@@ -149,7 +149,7 @@ impl<'tcx> Rvalue<'tcx> {
         match *self {
             Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
             Rvalue::Repeat(ref operand, count) => {
-                tcx.mk_array_const_usize(operand.ty(local_decls, tcx), count)
+                tcx.mk_array(operand.ty(local_decls, tcx), count)
             }
             Rvalue::Ref(reg, bk, ref place) => {
                 let place_ty = place.ty(local_decls, tcx).to_ty(tcx);
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 0b6f1275bdb4c..650af8dc4d903 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -12,7 +12,6 @@ use hir::def_id::DefId;
 use ty::subst::Substs;
 use ty::{ClosureSubsts, Region, Ty, GeneratorInterior};
 use mir::*;
-use rustc_const_math::ConstUsize;
 use syntax_pos::Span;
 
 // # The MIR Visitor
@@ -243,18 +242,6 @@ macro_rules! make_mir_visitor {
                 self.super_generator_interior(interior);
             }
 
-            fn visit_const_int(&mut self,
-                               const_int: &ConstInt,
-                               _: Location) {
-                self.super_const_int(const_int);
-            }
-
-            fn visit_const_usize(&mut self,
-                                 const_usize: & $($mutability)* ConstUsize,
-                                 _: Location) {
-                self.super_const_usize(const_usize);
-            }
-
             fn visit_local_decl(&mut self,
                                 local: Local,
                                 local_decl: & $($mutability)* LocalDecl<'tcx>) {
@@ -426,13 +413,10 @@ macro_rules! make_mir_visitor {
 
                     TerminatorKind::SwitchInt { ref $($mutability)* discr,
                                                 ref $($mutability)* switch_ty,
-                                                ref values,
+                                                values: _,
                                                 ref targets } => {
                         self.visit_operand(discr, source_location);
                         self.visit_ty(switch_ty, TyContext::Location(source_location));
-                        for value in &values[..] {
-                            self.visit_const_int(value, source_location);
-                        }
                         for &target in targets {
                             self.visit_branch(block, target);
                         }
@@ -538,10 +522,8 @@ macro_rules! make_mir_visitor {
                         self.visit_operand(operand, location);
                     }
 
-                    Rvalue::Repeat(ref $($mutability)* value,
-                                   ref $($mutability)* length) => {
+                    Rvalue::Repeat(ref $($mutability)* value, _) => {
                         self.visit_operand(value, location);
-                        self.visit_const_usize(length, location);
                     }
 
                     Rvalue::Ref(ref $($mutability)* r, bk, ref $($mutability)* path) => {
@@ -798,12 +780,6 @@ macro_rules! make_mir_visitor {
                                     _substs: & $($mutability)* ClosureSubsts<'tcx>) {
             }
 
-            fn super_const_int(&mut self, _const_int: &ConstInt) {
-            }
-
-            fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) {
-            }
-
             // Convenience methods
 
             fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) {
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 157614f847a12..437369400ed11 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -179,10 +179,10 @@ impl_stable_hash_for!(enum self::OutputType {
     DepInfo
 });
 
-impl<'tcx> ToStableHashKey<StableHashingContext<'tcx>> for OutputType {
+impl<'a, 'tcx> ToStableHashKey<StableHashingContext<'a>> for OutputType {
     type KeyType = OutputType;
     #[inline]
-    fn to_stable_hash_key(&self, _: &StableHashingContext<'tcx>) -> Self::KeyType {
+    fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> Self::KeyType {
         *self
     }
 }
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 5e9eeb973007f..defc5731f2f8a 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -103,6 +103,11 @@ pub struct Session {
     /// The maximum length of types during monomorphization.
     pub type_length_limit: Cell<usize>,
 
+    /// The maximum number of stackframes allowed in const eval
+    pub const_eval_stack_frame_limit: Cell<usize>,
+    /// The maximum number miri steps per constant
+    pub const_eval_step_limit: Cell<usize>,
+
     /// The metadata::creader module may inject an allocator/panic_runtime
     /// dependency if it didn't already find one, and this tracks what was
     /// injected.
@@ -1004,6 +1009,8 @@ pub fn build_session_(sopts: config::Options,
         features: RefCell::new(None),
         recursion_limit: Cell::new(64),
         type_length_limit: Cell::new(1048576),
+        const_eval_stack_frame_limit: Cell::new(100),
+        const_eval_step_limit: Cell::new(1_000_000),
         next_node_id: Cell::new(NodeId::new(1)),
         injected_allocator: Cell::new(None),
         allocator_kind: Cell::new(None),
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index ce23cb2349609..cd2d0d7e2a043 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -32,7 +32,6 @@ use hir;
 use hir::def_id::DefId;
 use infer::{self, InferCtxt};
 use infer::type_variable::TypeVariableOrigin;
-use middle::const_val;
 use std::fmt;
 use syntax::ast;
 use session::DiagnosticMessageId;
@@ -776,7 +775,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             }
 
             ConstEvalFailure(ref err) => {
-                if let const_val::ErrKind::TypeckError = err.kind {
+                if let ::middle::const_val::ErrKind::TypeckError = *err.kind {
                     return;
                 }
                 err.struct_error(self.tcx, span, "constant expression")
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 2f3e19d92bcda..bb2c7977f265b 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -9,12 +9,14 @@
 // except according to those terms.
 
 use infer::{RegionObligation, InferCtxt};
+use mir::interpret::GlobalId;
 use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
 use ty::error::ExpectedFound;
 use rustc_data_structures::obligation_forest::{ObligationForest, Error};
 use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
 use std::marker::PhantomData;
 use hir::def_id::DefId;
+use middle::const_val::{ConstEvalErr, ErrKind};
 
 use super::CodeAmbiguity;
 use super::CodeProjectionError;
@@ -514,17 +516,35 @@ fn process_predicate<'a, 'gcx, 'tcx>(
                 }
                 Some(param_env) => {
                     match selcx.tcx().lift_to_global(&substs) {
+                        Some(substs) => {
+                            let instance = ty::Instance::resolve(
+                                selcx.tcx().global_tcx(),
+                                param_env,
+                                def_id,
+                                substs,
+                            );
+                            if let Some(instance) = instance {
+                                let cid = GlobalId {
+                                    instance,
+                                    promoted: None,
+                                };
+                                match selcx.tcx().at(obligation.cause.span)
+                                                 .const_eval(param_env.and(cid)) {
+                                    Ok(_) => Ok(Some(vec![])),
+                                    Err(err) => Err(CodeSelectionError(ConstEvalFailure(err)))
+                                }
+                            } else {
+                                Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr {
+                                    span: obligation.cause.span,
+                                    kind: ErrKind::UnimplementedConstVal("could not resolve")
+                                        .into(),
+                                })))
+                            }
+                        },
                         None => {
                             pending_obligation.stalled_on = substs.types().collect();
                             Ok(None)
                         }
-                        Some(substs) => {
-                            match selcx.tcx().at(obligation.cause.span)
-                                             .const_eval(param_env.and((def_id, substs))) {
-                                Ok(_) => Ok(Some(vec![])),
-                                Err(e) => Err(CodeSelectionError(ConstEvalFailure(e)))
-                            }
-                        }
                     }
                 }
             }
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 8ac69c4b5287a..e0e85600b9036 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -20,8 +20,8 @@ pub use self::ObligationCauseCode::*;
 use hir;
 use hir::def_id::DefId;
 use infer::outlives::env::OutlivesEnvironment;
-use middle::const_val::ConstEvalErr;
 use middle::region;
+use middle::const_val::ConstEvalErr;
 use ty::subst::Substs;
 use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, ToPredicate};
 use ty::error::{ExpectedFound, TypeError};
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 3fe72344e8fea..a9dc491574379 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -29,6 +29,7 @@ use hir::def_id::DefId;
 use infer::{InferCtxt, InferOk};
 use infer::type_variable::TypeVariableOrigin;
 use middle::const_val::ConstVal;
+use mir::interpret::{GlobalId};
 use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
 use syntax::symbol::Symbol;
 use ty::subst::{Subst, Substs};
@@ -400,12 +401,17 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
 
     fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
         if let ConstVal::Unevaluated(def_id, substs) = constant.val {
-            if substs.needs_infer() {
-                let identity_substs = Substs::identity_for_item(self.tcx(), def_id);
-                let data = self.param_env.and((def_id, identity_substs));
-                match self.tcx().lift_to_global(&data) {
-                    Some(data) => {
-                        match self.tcx().const_eval(data) {
+            let tcx = self.selcx.tcx().global_tcx();
+            if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) {
+                if substs.needs_infer() {
+                    let identity_substs = Substs::identity_for_item(tcx, def_id);
+                    let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs);
+                    if let Some(instance) = instance {
+                        let cid = GlobalId {
+                            instance,
+                            promoted: None
+                        };
+                        match tcx.const_eval(param_env.and(cid)) {
                             Ok(evaluated) => {
                                 let evaluated = evaluated.subst(self.tcx(), substs);
                                 return self.fold_const(evaluated);
@@ -413,18 +419,20 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
                             Err(_) => {}
                         }
                     }
-                    None => {}
-                }
-            } else {
-                let data = self.param_env.and((def_id, substs));
-                match self.tcx().lift_to_global(&data) {
-                    Some(data) => {
-                        match self.tcx().const_eval(data) {
-                            Ok(evaluated) => return self.fold_const(evaluated),
-                            Err(_) => {}
+                } else {
+                    if let Some(substs) = self.tcx().lift_to_global(&substs) {
+                        let instance = ty::Instance::resolve(tcx, param_env, def_id, substs);
+                        if let Some(instance) = instance {
+                            let cid = GlobalId {
+                                instance,
+                                promoted: None
+                            };
+                            match tcx.const_eval(param_env.and(cid)) {
+                                Ok(evaluated) => return self.fold_const(evaluated),
+                                Err(_) => {}
+                            }
                         }
                     }
-                    None => {}
                 }
             }
         }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 600b4a515f0bf..91d86394b0192 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -42,6 +42,7 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use ty::fast_reject;
 use ty::relate::TypeRelation;
 use middle::lang_items;
+use mir::interpret::{GlobalId};
 
 use rustc_data_structures::bitvec::BitVector;
 use std::iter;
@@ -732,11 +733,26 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             }
 
             ty::Predicate::ConstEvaluatable(def_id, substs) => {
-                match self.tcx().lift_to_global(&(obligation.param_env, substs)) {
+                let tcx = self.tcx();
+                match tcx.lift_to_global(&(obligation.param_env, substs)) {
                     Some((param_env, substs)) => {
-                        match self.tcx().const_eval(param_env.and((def_id, substs))) {
-                            Ok(_) => EvaluatedToOk,
-                            Err(_) => EvaluatedToErr
+                        let instance = ty::Instance::resolve(
+                            tcx.global_tcx(),
+                            param_env,
+                            def_id,
+                            substs,
+                        );
+                        if let Some(instance) = instance {
+                            let cid = GlobalId {
+                                instance,
+                                promoted: None
+                            };
+                            match self.tcx().const_eval(param_env.and(cid)) {
+                                Ok(_) => EvaluatedToOk,
+                                Err(_) => EvaluatedToErr
+                            }
+                        } else {
+                            EvaluatedToErr
                         }
                     }
                     None => {
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index dbf15ad17079d..f8b895177f381 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -391,9 +391,9 @@ pub fn ancestors(tcx: TyCtxt,
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for Children {
+impl<'a> HashStable<StableHashingContext<'a>> for Children {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let Children {
             ref nonblanket_impls,
diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs
index fbb14f39ade34..f98bc95356098 100644
--- a/src/librustc/ty/codec.rs
+++ b/src/librustc/ty/codec.rs
@@ -17,7 +17,6 @@
 // persisting to incr. comp. caches.
 
 use hir::def_id::{DefId, CrateNum};
-use middle::const_val::ByteArray;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque};
 use std::hash::Hash;
@@ -240,17 +239,6 @@ pub fn decode_existential_predicate_slice<'a, 'tcx, D>(decoder: &mut D)
               .mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?)
 }
 
-#[inline]
-pub fn decode_byte_array<'a, 'tcx, D>(decoder: &mut D)
-                                      -> Result<ByteArray<'tcx>, D::Error>
-    where D: TyDecoder<'a, 'tcx>,
-          'tcx: 'a,
-{
-    Ok(ByteArray {
-        data: decoder.tcx().alloc_byte_array(&Vec::decode(decoder)?)
-    })
-}
-
 #[inline]
 pub fn decode_const<'a, 'tcx, D>(decoder: &mut D)
                                  -> Result<&'tcx ty::Const<'tcx>, D::Error>
@@ -278,7 +266,6 @@ macro_rules! implement_ty_decoder {
             use $crate::ty::codec::*;
             use $crate::ty::subst::Substs;
             use $crate::hir::def_id::{CrateNum};
-            use $crate::middle::const_val::ByteArray;
             use rustc_serialize::{Decoder, SpecializedDecoder};
             use std::borrow::Cow;
 
@@ -377,13 +364,6 @@ macro_rules! implement_ty_decoder {
                 }
             }
 
-            impl<$($typaram),*> SpecializedDecoder<ByteArray<'tcx>>
-            for $DecoderName<$($typaram),*> {
-                fn specialized_decode(&mut self) -> Result<ByteArray<'tcx>, Self::Error> {
-                    decode_byte_array(self)
-                }
-            }
-
             impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::Const<'tcx>>
             for $DecoderName<$($typaram),*> {
                 fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 47a3580e86769..b760649c37d15 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -30,7 +30,8 @@ use middle::cstore::EncodedMetadata;
 use middle::lang_items;
 use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
 use middle::stability;
-use mir::{Mir, interpret};
+use mir::{self, Mir, interpret};
+use mir::interpret::{Value, PrimVal};
 use ty::subst::{Kind, Substs};
 use ty::ReprOptions;
 use ty::Instance;
@@ -53,7 +54,6 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
                                            StableHasher, StableHasherResult,
                                            StableVec};
 use arena::{TypedArena, DroplessArena};
-use rustc_const_math::{ConstInt, ConstUsize};
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_data_structures::sync::Lrc;
 use std::any::Any;
@@ -675,9 +675,9 @@ impl<'tcx> TypeckTables<'tcx> {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> {
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let ty::TypeckTables {
             local_id_root,
@@ -868,7 +868,7 @@ pub struct GlobalCtxt<'tcx> {
 
     stability_interner: RefCell<FxHashSet<&'tcx attr::Stability>>,
 
-    pub interpret_interner: RefCell<InterpretInterner<'tcx>>,
+    pub interpret_interner: InterpretInterner<'tcx>,
 
     layout_interner: RefCell<FxHashSet<&'tcx LayoutDetails>>,
 
@@ -892,6 +892,11 @@ pub struct GlobalCtxt<'tcx> {
 /// Everything needed to efficiently work with interned allocations
 #[derive(Debug, Default)]
 pub struct InterpretInterner<'tcx> {
+    inner: RefCell<InterpretInternerInner<'tcx>>,
+}
+
+#[derive(Debug, Default)]
+struct InterpretInternerInner<'tcx> {
     /// Stores the value of constants (and deduplicates the actual memory)
     allocs: FxHashSet<&'tcx interpret::Allocation>,
 
@@ -905,12 +910,18 @@ pub struct InterpretInterner<'tcx> {
     /// Allows obtaining const allocs via a unique identifier
     alloc_by_id: FxHashMap<interpret::AllocId, &'tcx interpret::Allocation>,
 
+    /// Reverse map of `alloc_cache`
+    global_cache: FxHashMap<interpret::AllocId, DefId>,
+
     /// The AllocId to assign to the next new regular allocation.
     /// Always incremented, never gets smaller.
     next_id: interpret::AllocId,
 
-    /// Allows checking whether a constant already has an allocation
-    alloc_cache: FxHashMap<interpret::GlobalId<'tcx>, interpret::AllocId>,
+    /// Allows checking whether a static already has an allocation
+    ///
+    /// This is only important for detecting statics referring to themselves
+    // FIXME(oli-obk) move it to the EvalContext?
+    alloc_cache: FxHashMap<DefId, interpret::AllocId>,
 
     /// A cache for basic byte allocations keyed by their contents. This is used to deduplicate
     /// allocations for string and bytestring literals.
@@ -918,14 +929,15 @@ pub struct InterpretInterner<'tcx> {
 }
 
 impl<'tcx> InterpretInterner<'tcx> {
-    pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> interpret::AllocId {
-        if let Some(&alloc_id) = self.function_cache.get(&instance) {
+    pub fn create_fn_alloc(&self, instance: Instance<'tcx>) -> interpret::AllocId {
+        if let Some(&alloc_id) = self.inner.borrow().function_cache.get(&instance) {
             return alloc_id;
         }
         let id = self.reserve();
         debug!("creating fn ptr: {}", id);
-        self.functions.insert(id, instance);
-        self.function_cache.insert(instance, id);
+        let mut inner = self.inner.borrow_mut();
+        inner.functions.insert(id, instance);
+        inner.function_cache.insert(instance, id);
         id
     }
 
@@ -933,39 +945,48 @@ impl<'tcx> InterpretInterner<'tcx> {
         &self,
         id: interpret::AllocId,
     ) -> Option<Instance<'tcx>> {
-        self.functions.get(&id).cloned()
+        self.inner.borrow().functions.get(&id).cloned()
     }
 
     pub fn get_alloc(
         &self,
         id: interpret::AllocId,
     ) -> Option<&'tcx interpret::Allocation> {
-        self.alloc_by_id.get(&id).cloned()
+        self.inner.borrow().alloc_by_id.get(&id).cloned()
     }
 
     pub fn get_cached(
         &self,
-        global_id: interpret::GlobalId<'tcx>,
+        static_id: DefId,
     ) -> Option<interpret::AllocId> {
-        self.alloc_cache.get(&global_id).cloned()
+        self.inner.borrow().alloc_cache.get(&static_id).cloned()
     }
 
     pub fn cache(
-        &mut self,
-        global_id: interpret::GlobalId<'tcx>,
-        ptr: interpret::AllocId,
+        &self,
+        static_id: DefId,
+        alloc_id: interpret::AllocId,
     ) {
-        if let Some(old) = self.alloc_cache.insert(global_id, ptr) {
-            bug!("tried to cache {:?}, but was already existing as {:#?}", global_id, old);
+        let mut inner = self.inner.borrow_mut();
+        inner.global_cache.insert(alloc_id, static_id);
+        if let Some(old) = inner.alloc_cache.insert(static_id, alloc_id) {
+            bug!("tried to cache {:?}, but was already existing as {:#?}", static_id, old);
         }
     }
 
+    pub fn get_corresponding_static_def_id(
+        &self,
+        ptr: interpret::AllocId,
+    ) -> Option<DefId> {
+        self.inner.borrow().global_cache.get(&ptr).cloned()
+    }
+
     pub fn intern_at_reserved(
-        &mut self,
+        &self,
         id: interpret::AllocId,
         alloc: &'tcx interpret::Allocation,
     ) {
-        if let Some(old) = self.alloc_by_id.insert(id, alloc) {
+        if let Some(old) = self.inner.borrow_mut().alloc_by_id.insert(id, alloc) {
             bug!("tried to intern allocation at {}, but was already existing as {:#?}", id, old);
         }
     }
@@ -973,10 +994,11 @@ impl<'tcx> InterpretInterner<'tcx> {
     /// obtains a new allocation ID that can be referenced but does not
     /// yet have an allocation backing it.
     pub fn reserve(
-        &mut self,
+        &self,
     ) -> interpret::AllocId {
-        let next = self.next_id;
-        self.next_id.0 = self.next_id.0
+        let mut inner = self.inner.borrow_mut();
+        let next = inner.next_id;
+        inner.next_id.0 = inner.next_id.0
             .checked_add(1)
             .expect("You overflowed a u64 by incrementing by 1... \
                      You've just earned yourself a free drink if we ever meet. \
@@ -1056,12 +1078,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self,
         alloc: interpret::Allocation,
     ) -> &'gcx interpret::Allocation {
-        if let Some(alloc) = self.interpret_interner.borrow().allocs.get(&alloc) {
+        if let Some(alloc) = self.interpret_interner.inner.borrow().allocs.get(&alloc) {
             return alloc;
         }
 
         let interned = self.global_arenas.const_allocs.alloc(alloc);
-        if let Some(prev) = self.interpret_interner.borrow_mut().allocs.replace(interned) {
+        if let Some(prev) = self.interpret_interner.inner.borrow_mut().allocs.replace(interned) {
             bug!("Tried to overwrite interned Allocation: {:#?}", prev)
         }
         interned
@@ -1070,20 +1092,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Allocates a byte or string literal for `mir::interpret`
     pub fn allocate_cached(self, bytes: &[u8]) -> interpret::AllocId {
         // check whether we already allocated this literal or a constant with the same memory
-        if let Some(&alloc_id) = self.interpret_interner.borrow().literal_alloc_cache.get(bytes) {
+        if let Some(&alloc_id) = self.interpret_interner.inner.borrow()
+                                     .literal_alloc_cache.get(bytes) {
             return alloc_id;
         }
         // create an allocation that just contains these bytes
         let alloc = interpret::Allocation::from_bytes(bytes);
         let alloc = self.intern_const_alloc(alloc);
 
-        let mut int = self.interpret_interner.borrow_mut();
         // the next unique id
-        let id = int.reserve();
+        let id = self.interpret_interner.reserve();
         // make the allocation identifiable
-        int.alloc_by_id.insert(id, alloc);
+        self.interpret_interner.inner.borrow_mut().alloc_by_id.insert(id, alloc);
         // cache it for the future
-        int.literal_alloc_cache.insert(bytes.to_owned(), id);
+        self.interpret_interner.inner.borrow_mut().literal_alloc_cache.insert(bytes.to_owned(), id);
         id
     }
 
@@ -1248,6 +1270,40 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.get_lang_items(LOCAL_CRATE)
     }
 
+    /// Due to missing llvm support for lowering 128 bit math to software emulation
+    /// (on some targets), the lowering can be done in MIR.
+    ///
+    /// This function only exists until said support is implemented.
+    pub fn is_binop_lang_item(&self, def_id: DefId) -> Option<(mir::BinOp, bool)> {
+        let items = self.lang_items();
+        let def_id = Some(def_id);
+        if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
+        else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
+        else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
+        else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
+        else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
+        else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
+        else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
+        else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
+        else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
+        else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
+        else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
+        else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
+        else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
+        else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
+        else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
+        else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
+        else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
+        else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
+        else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
+        else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
+        else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
+        else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
+        else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
+        else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
+        else { None }
+    }
+
     pub fn stability(self) -> Lrc<stability::Index<'tcx>> {
         self.stability_index(LOCAL_CRATE)
     }
@@ -1321,7 +1377,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.cstore.crate_data_as_rc_any(cnum)
     }
 
-    pub fn create_stable_hashing_context(self) -> StableHashingContext<'gcx> {
+    pub fn create_stable_hashing_context(self) -> StableHashingContext<'a> {
         let krate = self.dep_graph.with_ignore(|| self.gcx.hir.krate());
 
         StableHashingContext::new(self.sess,
@@ -1731,7 +1787,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
         println!("Substs interner: #{}", self.interners.substs.borrow().len());
         println!("Region interner: #{}", self.interners.region.borrow().len());
         println!("Stability interner: #{}", self.stability_interner.borrow().len());
-        println!("Interpret interner: #{}", self.interpret_interner.borrow().allocs.len());
+        println!("Interpret interner: #{}", self.interpret_interner.inner.borrow().allocs.len());
         println!("Layout interner: #{}", self.layout_interner.borrow().len());
     }
 }
@@ -2043,13 +2099,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
-        let n = ConstUsize::new(n, self.sess.target.usize_ty).unwrap();
-        self.mk_array_const_usize(ty, n)
-    }
-
-    pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> {
         self.mk_ty(TyArray(ty, self.mk_const(ty::Const {
-            val: ConstVal::Integral(ConstInt::Usize(n)),
+            val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))),
             ty: self.types.usize
         })))
     }
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index be89aeebdea75..dcb70a8f86a8a 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -9,17 +9,13 @@
 // except according to those terms.
 
 use hir::def_id::DefId;
-use middle::const_val::ConstVal;
 use ty::{self, BoundRegion, Region, Ty, TyCtxt};
-
 use std::fmt;
 use syntax::abi;
 use syntax::ast;
 use errors::DiagnosticBuilder;
 use syntax_pos::Span;
 
-use rustc_const_math::ConstInt;
-
 use hir;
 
 #[derive(Clone, Copy, Debug)]
@@ -186,10 +182,9 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
             ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
             ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
             ty::TyArray(_, n) => {
-                if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
-                    format!("array of {} elements", n)
-                } else {
-                    "array".to_string()
+                match n.val.to_raw_bits() {
+                    Some(n) => format!("array of {} elements", n),
+                    None => "array".to_string(),
                 }
             }
             ty::TySlice(_) => "slice".to_string(),
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index 97c259e6bf383..93d8a4d979de6 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -154,12 +154,12 @@ impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> {
     }
 }
 
-impl<'gcx, D> HashStable<StableHashingContext<'gcx>> for SimplifiedTypeGen<D>
+impl<'a, 'gcx, D> HashStable<StableHashingContext<'a>> for SimplifiedTypeGen<D>
     where D: Copy + Debug + Ord + Eq + Hash +
-             HashStable<StableHashingContext<'gcx>>,
+             HashStable<StableHashingContext<'a>>,
 {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 2889322a1ce77..f067789771c59 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::const_val::{ConstVal, ConstAggregate};
+use middle::const_val::ConstVal;
 use ty::subst::Substs;
 use ty::{self, Ty, TypeFlags, TypeFoldable};
 
@@ -218,30 +218,7 @@ impl FlagComputation {
     fn add_const(&mut self, constant: &ty::Const) {
         self.add_ty(constant.ty);
         match constant.val {
-            ConstVal::Integral(_) |
-            ConstVal::Float(_) |
-            ConstVal::Str(_) |
-            ConstVal::ByteStr(_) |
-            ConstVal::Bool(_) |
-            ConstVal::Char(_) |
-            ConstVal::Variant(_) => {}
-            ConstVal::Function(_, substs) => {
-                self.add_substs(substs);
-            }
-            ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
-                for &(_, v) in fields {
-                    self.add_const(v);
-                }
-            }
-            ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
-            ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
-                for v in fields {
-                    self.add_const(v);
-                }
-            }
-            ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
-                self.add_const(v);
-            }
+            ConstVal::Value(_) => {}
             ConstVal::Unevaluated(_, substs) => {
                 self.add_flags(TypeFlags::HAS_PROJECTION);
                 self.add_substs(substs);
diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs
index 93e4cd9adf888..3e653cf126a8d 100644
--- a/src/librustc/ty/inhabitedness/mod.rs
+++ b/src/librustc/ty/inhabitedness/mod.rs
@@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
                 }))
             },
             TyArray(ty, len) => {
-                match len.val.to_const_int().and_then(|i| i.to_u64()) {
+                match len.val.to_raw_bits() {
                     // If the array is definitely non-empty, it's uninhabited if
                     // the type of its elements is uninhabited.
                     Some(n) if n != 0 => ty.uninhabited_from(visited, tcx),
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index a5f0abb9bc05c..614158bafa638 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -17,13 +17,13 @@ use util::ppaux;
 
 use std::fmt;
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct Instance<'tcx> {
     pub def: InstanceDef<'tcx>,
     pub substs: &'tcx Substs<'tcx>,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub enum InstanceDef<'tcx> {
     Item(DefId),
     Intrinsic(DefId),
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 5069c59562678..1b919ad68d047 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -342,7 +342,7 @@ impl AddAssign for Size {
 /// Each field is a power of two, giving the alignment a maximum
 /// value of 2<sup>(2<sup>8</sup> - 1)</sup>, which is limited by LLVM to a i32, with
 /// a maximum capacity of 2<sup>31</sup> - 1 or 2147483647.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct Align {
     abi: u8,
     pref: u8,
@@ -794,6 +794,17 @@ impl Abi {
             Abi::Aggregate { sized } => !sized
         }
     }
+
+    /// Returns true if this is a single signed integer scalar
+    pub fn is_signed(&self) -> bool {
+        match *self {
+            Abi::Scalar(ref scal) => match scal.value {
+                Primitive::Int(_, signed) => signed,
+                _ => false,
+            },
+            _ => false,
+        }
+    }
 }
 
 #[derive(PartialEq, Eq, Hash, Debug)]
@@ -1237,7 +1248,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
                 }
 
                 let element = self.layout_of(element)?;
-                let count = count.val.to_const_int().unwrap().to_u64().unwrap();
+                let count = count.val.unwrap_u64();
                 let size = element.size.checked_mul(count, dl)
                     .ok_or(LayoutError::SizeOverflow(ty))?;
 
@@ -1537,7 +1548,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
                     if variants[i].iter().any(|f| f.abi == Abi::Uninhabited) {
                         continue;
                     }
-                    let x = discr.to_u128_unchecked() as i128;
+                    let x = discr.val as i128;
                     if x < min { min = x; }
                     if x > max { max = x; }
                 }
@@ -2369,9 +2380,9 @@ impl<'a, 'tcx> TyLayout<'tcx> {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for Variants {
+impl<'a> HashStable<StableHashingContext<'a>> for Variants {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use ty::layout::Variants::*;
         mem::discriminant(self).hash_stable(hcx, hasher);
@@ -2405,9 +2416,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Variants {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for FieldPlacement {
+impl<'a> HashStable<StableHashingContext<'a>> for FieldPlacement {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use ty::layout::FieldPlacement::*;
         mem::discriminant(self).hash_stable(hcx, hasher);
@@ -2428,9 +2439,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for FieldPlacement {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
+impl<'a> HashStable<StableHashingContext<'a>> for Abi {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use ty::layout::Abi::*;
         mem::discriminant(self).hash_stable(hcx, hasher);
@@ -2455,9 +2466,9 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for Scalar {
+impl<'a> HashStable<StableHashingContext<'a>> for Scalar {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let Scalar { value, valid_range: RangeInclusive { start, end } } = *self;
         value.hash_stable(hcx, hasher);
@@ -2498,10 +2509,10 @@ impl_stable_hash_for!(struct ::ty::layout::Size {
     raw
 });
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for LayoutError<'gcx>
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for LayoutError<'gcx>
 {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         use ty::layout::LayoutError::*;
         mem::discriminant(self).hash_stable(hcx, hasher);
diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs
index d880b022e2f18..21affcbc9ede7 100644
--- a/src/librustc/ty/maps/config.rs
+++ b/src/librustc/ty/maps/config.rs
@@ -10,9 +10,10 @@
 
 use dep_graph::SerializedDepNodeIndex;
 use hir::def_id::{CrateNum, DefId, DefIndex};
+use mir::interpret::{GlobalId};
 use ty::{self, Ty, TyCtxt};
-use ty::maps::queries;
 use ty::subst::Substs;
+use ty::maps::queries;
 
 use std::hash::Hash;
 use syntax_pos::symbol::InternedString;
@@ -152,8 +153,8 @@ impl<'tcx> QueryDescription<'tcx> for queries::reachable_set<'tcx> {
 }
 
 impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> {
-    fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) -> String {
-        format!("const-evaluating `{}`", tcx.item_path_str(key.value.0))
+    fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> String {
+        format!("const-evaluating `{}`", tcx.item_path_str(key.value.instance.def.def_id()))
     }
 }
 
diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs
index b7b64c9761a8e..8fb1ad0da823b 100644
--- a/src/librustc/ty/maps/keys.rs
+++ b/src/librustc/ty/maps/keys.rs
@@ -14,6 +14,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex};
 use ty::{self, Ty, TyCtxt};
 use ty::subst::Substs;
 use ty::fast_reject::SimplifiedType;
+use mir;
 
 use std::fmt::Debug;
 use std::hash::Hash;
@@ -52,6 +53,16 @@ impl<'tcx> Key for ty::Instance<'tcx> {
     }
 }
 
+impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
+    fn map_crate(&self) -> CrateNum {
+        self.instance.map_crate()
+    }
+
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        self.instance.default_span(tcx)
+    }
+}
+
 impl Key for CrateNum {
     fn map_crate(&self) -> CrateNum {
         *self
diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs
index 43a71f1c0d367..0ded759fec730 100644
--- a/src/librustc/ty/maps/mod.rs
+++ b/src/librustc/ty/maps/mod.rs
@@ -16,7 +16,6 @@ use hir::{self, TraitCandidate, ItemLocalId, TransFnAttrs};
 use hir::svh::Svh;
 use lint;
 use middle::borrowck::BorrowCheckResult;
-use middle::const_val;
 use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary,
                      ExternBodyNestedBodies};
 use middle::cstore::{NativeLibraryKind, DepKind, CrateSource, ExternConstBody};
@@ -27,8 +26,10 @@ use middle::resolve_lifetime::{ResolveLifetimes, Region, ObjectLifetimeDefault};
 use middle::stability::{self, DeprecationEntry};
 use middle::lang_items::{LanguageItems, LangItem};
 use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol};
+use middle::const_val::EvalResult;
 use mir::mono::{CodegenUnit, Stats};
 use mir;
+use mir::interpret::{GlobalId};
 use session::{CompileResult, CrateDisambiguator};
 use session::config::OutputFilenames;
 use traits::Vtable;
@@ -210,8 +211,8 @@ define_maps! { <'tcx>
 
     /// Results of evaluating const items or constants embedded in
     /// other items (such as enum variant explicit discriminants).
-    [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
-        -> const_val::EvalResult<'tcx>,
+    [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
+        -> EvalResult<'tcx>,
 
     [] fn check_match: CheckMatch(DefId)
         -> Result<(), ErrorReported>,
@@ -450,7 +451,7 @@ fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
     DepConstructor::TypeckBodiesKrate
 }
 
-fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
+fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
                              -> DepConstructor<'tcx> {
     DepConstructor::ConstEval { param_env }
 }
diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs
index b18837ff35aa8..49c4b8bc49d8c 100644
--- a/src/librustc/ty/maps/on_disk_cache.rs
+++ b/src/librustc/ty/maps/on_disk_cache.rs
@@ -15,7 +15,7 @@ use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId,
                   RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE};
 use hir::map::definitions::DefPathHash;
 use ich::{CachingCodemapView, Fingerprint};
-use mir;
+use mir::{self, interpret};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@@ -187,6 +187,7 @@ impl<'sess> OnDiskCache<'sess> {
                 type_shorthands: FxHashMap(),
                 predicate_shorthands: FxHashMap(),
                 expn_info_shorthands: FxHashMap(),
+                interpret_alloc_shorthands: FxHashMap(),
                 codemap: CachingCodemapView::new(tcx.sess.codemap()),
                 file_to_file_index,
             };
@@ -362,6 +363,7 @@ impl<'sess> OnDiskCache<'sess> {
             file_index_to_file: &self.file_index_to_file,
             file_index_to_stable_id: &self.file_index_to_stable_id,
             synthetic_expansion_infos: &self.synthetic_expansion_infos,
+            interpret_alloc_cache: FxHashMap::default(),
         };
 
         match decode_tagged(&mut decoder, dep_node_index) {
@@ -423,6 +425,7 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> {
     synthetic_expansion_infos: &'x RefCell<FxHashMap<AbsoluteBytePos, SyntaxContext>>,
     file_index_to_file: &'x RefCell<FxHashMap<FileMapIndex, Lrc<FileMap>>>,
     file_index_to_stable_id: &'x FxHashMap<FileMapIndex, StableFilemapId>,
+    interpret_alloc_cache: FxHashMap<usize, interpret::AllocId>,
 }
 
 impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> {
@@ -542,6 +545,50 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx,
 
 implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> );
 
+impl<'a, 'tcx, 'x> SpecializedDecoder<interpret::AllocId> for CacheDecoder<'a, 'tcx, 'x> {
+    fn specialized_decode(&mut self) -> Result<interpret::AllocId, Self::Error> {
+        const MAX1: usize = usize::max_value() - 1;
+        let tcx = self.tcx;
+        let pos = TyDecoder::position(self);
+        match usize::decode(self)? {
+            ::std::usize::MAX => {
+                let alloc_id = tcx.interpret_interner.reserve();
+                trace!("creating alloc id {:?} at {}", alloc_id, pos);
+                // insert early to allow recursive allocs
+                self.interpret_alloc_cache.insert(pos, alloc_id);
+
+                let allocation = interpret::Allocation::decode(self)?;
+                trace!("decoded alloc {:?} {:#?}", alloc_id, allocation);
+                let allocation = self.tcx.intern_const_alloc(allocation);
+                tcx.interpret_interner.intern_at_reserved(alloc_id, allocation);
+
+                if let Some(glob) = Option::<DefId>::decode(self)? {
+                    tcx.interpret_interner.cache(glob, alloc_id);
+                }
+
+                Ok(alloc_id)
+            },
+            MAX1 => {
+                trace!("creating fn alloc id at {}", pos);
+                let instance = ty::Instance::decode(self)?;
+                trace!("decoded fn alloc instance: {:?}", instance);
+                let id = tcx.interpret_interner.create_fn_alloc(instance);
+                trace!("created fn alloc id: {:?}", id);
+                self.interpret_alloc_cache.insert(pos, id);
+                Ok(id)
+            },
+            shorthand => {
+                trace!("loading shorthand {}", shorthand);
+                if let Some(&alloc_id) = self.interpret_alloc_cache.get(&shorthand) {
+                    return Ok(alloc_id);
+                }
+                trace!("shorthand {} not cached, loading entire allocation", shorthand);
+                // need to load allocation
+                self.with_position(shorthand, |this| interpret::AllocId::decode(this))
+            },
+        }
+    }
+}
 impl<'a, 'tcx, 'x> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx, 'x> {
     fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
         let tag: u8 = Decodable::decode(self)?;
@@ -703,6 +750,7 @@ struct CacheEncoder<'enc, 'a, 'tcx, E>
     type_shorthands: FxHashMap<ty::Ty<'tcx>, usize>,
     predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
     expn_info_shorthands: FxHashMap<Mark, AbsoluteBytePos>,
+    interpret_alloc_shorthands: FxHashMap<interpret::AllocId, usize>,
     codemap: CachingCodemapView<'tcx>,
     file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>,
 }
@@ -735,6 +783,37 @@ impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E>
     }
 }
 
+impl<'enc, 'a, 'tcx, E> SpecializedEncoder<interpret::AllocId> for CacheEncoder<'enc, 'a, 'tcx, E>
+    where E: 'enc + ty_codec::TyEncoder
+{
+    fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
+        trace!("encoding {:?} at {}", alloc_id, self.position());
+        if let Some(shorthand) = self.interpret_alloc_shorthands.get(alloc_id).cloned() {
+            trace!("encoding {:?} as shorthand to {}", alloc_id, shorthand);
+            return shorthand.encode(self);
+        }
+        let start = self.position();
+        // cache the allocation shorthand now, because the allocation itself might recursively
+        // point to itself.
+        self.interpret_alloc_shorthands.insert(*alloc_id, start);
+        if let Some(alloc) = self.tcx.interpret_interner.get_alloc(*alloc_id) {
+            trace!("encoding {:?} with {:#?}", alloc_id, alloc);
+            usize::max_value().encode(self)?;
+            alloc.encode(self)?;
+            self.tcx.interpret_interner
+                .get_corresponding_static_def_id(*alloc_id)
+                .encode(self)?;
+        } else if let Some(fn_instance) = self.tcx.interpret_interner.get_fn(*alloc_id) {
+            trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
+            (usize::max_value() - 1).encode(self)?;
+            fn_instance.encode(self)?;
+        } else {
+            bug!("alloc id without corresponding allocation: {}", alloc_id);
+        }
+        Ok(())
+    }
+}
+
 impl<'enc, 'a, 'tcx, E> SpecializedEncoder<Span> for CacheEncoder<'enc, 'a, 'tcx, E>
     where E: 'enc + ty_codec::TyEncoder
 {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index be27e3d51529b..63494438f7d82 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -26,12 +26,13 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte
 use middle::privacy::AccessLevels;
 use middle::resolve_lifetime::ObjectLifetimeDefault;
 use mir::Mir;
+use mir::interpret::{GlobalId, Value, PrimVal};
 use mir::GeneratorLayout;
 use session::CrateDisambiguator;
 use traits;
 use ty;
 use ty::subst::{Subst, Substs};
-use ty::util::IntTypeExt;
+use ty::util::{IntTypeExt, Discr};
 use ty::walk::TypeWalker;
 use util::common::ErrorReported;
 use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
@@ -52,7 +53,6 @@ use syntax::attr;
 use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::symbol::{Symbol, InternedString};
 use syntax_pos::{DUMMY_SP, Span};
-use rustc_const_math::ConstInt;
 
 use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
 use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
@@ -79,7 +79,7 @@ pub use self::binding::BindingMode;
 pub use self::binding::BindingMode::*;
 
 pub use self::context::{TyCtxt, GlobalArenas, AllArenas, tls, keep_local};
-pub use self::context::{Lift, TypeckTables};
+pub use self::context::{Lift, TypeckTables, InterpretInterner};
 
 pub use self::instance::{Instance, InstanceDef};
 
@@ -528,9 +528,9 @@ impl<'tcx> TyS<'tcx> {
     }
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::TyS<'gcx> {
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::TyS<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let ty::TyS {
             ref sty,
@@ -1439,11 +1439,11 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> {
     }
 }
 
-impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for ParamEnvAnd<'gcx, T>
-    where T: HashStable<StableHashingContext<'gcx>>
+impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for ParamEnvAnd<'gcx, T>
+    where T: HashStable<StableHashingContext<'a>>
 {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let ParamEnvAnd {
             ref param_env,
@@ -1544,9 +1544,9 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef {
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {}
 
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for AdtDef {
+impl<'a> HashStable<StableHashingContext<'a>> for AdtDef {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         thread_local! {
             static CACHE: RefCell<FxHashMap<usize, Fingerprint>> =
@@ -1824,27 +1824,79 @@ impl<'a, 'gcx, 'tcx> AdtDef {
     }
 
     #[inline]
-    pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-                         -> impl Iterator<Item=ConstInt> + 'a {
+    pub fn eval_explicit_discr(
+        &self,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        expr_did: DefId,
+    ) -> Option<Discr<'tcx>> {
         let param_env = ParamEnv::empty(traits::Reveal::UserFacing);
         let repr_type = self.repr.discr_type();
+        let bit_size = layout::Integer::from_attr(tcx, repr_type).size().bits();
+        let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
+        let instance = ty::Instance::new(expr_did, substs);
+        let cid = GlobalId {
+            instance,
+            promoted: None
+        };
+        match tcx.const_eval(param_env.and(cid)) {
+            Ok(&ty::Const {
+                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
+                ..
+            }) => {
+                trace!("discriminants: {} ({:?})", b, repr_type);
+                let ty = repr_type.to_ty(tcx);
+                if repr_type.is_signed() {
+                    let val = b as i128;
+                    // sign extend to i128
+                    let amt = 128 - bit_size;
+                    let val = (val << amt) >> amt;
+                    Some(Discr {
+                        val: val as u128,
+                        ty,
+                    })
+                } else {
+                    Some(Discr {
+                        val: b,
+                        ty,
+                    })
+                }
+            },
+            Ok(&ty::Const {
+                val: ConstVal::Value(other),
+                ..
+            }) => {
+                info!("invalid enum discriminant: {:#?}", other);
+                ::middle::const_val::struct_error(
+                    tcx,
+                    tcx.def_span(expr_did),
+                    "constant evaluation of enum discriminant resulted in non-integer",
+                ).emit();
+                None
+            }
+            Err(err) => {
+                err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
+                if !expr_did.is_local() {
+                    span_bug!(tcx.def_span(expr_did),
+                        "variant discriminant evaluation succeeded \
+                            in its crate but failed locally");
+                }
+                None
+            }
+            _ => span_bug!(tcx.def_span(expr_did), "const eval "),
+        }
+    }
+
+    #[inline]
+    pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
+                         -> impl Iterator<Item=Discr<'tcx>> + 'a {
+        let repr_type = self.repr.discr_type();
         let initial = repr_type.initial_discriminant(tcx.global_tcx());
-        let mut prev_discr = None::<ConstInt>;
+        let mut prev_discr = None::<Discr<'tcx>>;
         self.variants.iter().map(move |v| {
-            let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
+            let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
             if let VariantDiscr::Explicit(expr_did) = v.discr {
-                let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
-                match tcx.const_eval(param_env.and((expr_did, substs))) {
-                    Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => {
-                        discr = v;
-                    }
-                    err => {
-                        if !expr_did.is_local() {
-                            span_bug!(tcx.def_span(expr_did),
-                                "variant discriminant evaluation succeeded \
-                                 in its crate but failed locally: {:?}", err);
-                        }
-                    }
+                if let Some(new_discr) = self.eval_explicit_discr(tcx, expr_did) {
+                    discr = new_discr;
                 }
             }
             prev_discr = Some(discr);
@@ -1861,8 +1913,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
     pub fn discriminant_for_variant(&self,
                                     tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                     variant_index: usize)
-                                    -> ConstInt {
-        let param_env = ParamEnv::empty(traits::Reveal::UserFacing);
+                                    -> Discr<'tcx> {
         let repr_type = self.repr.discr_type();
         let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx());
         let mut explicit_index = variant_index;
@@ -1873,18 +1924,12 @@ impl<'a, 'gcx, 'tcx> AdtDef {
                     explicit_index -= distance;
                 }
                 ty::VariantDiscr::Explicit(expr_did) => {
-                    let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
-                    match tcx.const_eval(param_env.and((expr_did, substs))) {
-                        Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => {
-                            explicit_value = v;
+                    match self.eval_explicit_discr(tcx, expr_did) {
+                        Some(discr) => {
+                            explicit_value = discr;
                             break;
-                        }
-                        err => {
-                            if !expr_did.is_local() {
-                                span_bug!(tcx.def_span(expr_did),
-                                    "variant discriminant evaluation succeeded \
-                                     in its crate but failed locally: {:?}", err);
-                            }
+                        },
+                        None => {
                             if explicit_index == 0 {
                                 break;
                             }
@@ -1894,18 +1939,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
                 }
             }
         }
-        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.usize_ty)
-            }
-            attr::SignedInt(ty) => {
-                ConstInt::new_signed_truncating(discr as i128, ty,
-                                                tcx.sess.target.isize_ty)
-            }
-        }
+        explicit_value.checked_add(tcx, (variant_index - explicit_index) as u128).0
     }
 
     pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index b9927c7eeb2fa..bae1ce31a5e77 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -20,6 +20,7 @@ use ty::subst::{UnpackedKind, Substs};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::fold::{TypeVisitor, TypeFolder};
 use ty::error::{ExpectedFound, TypeError};
+use mir::interpret::{GlobalId, Value, PrimVal};
 use util::common::ErrorReported;
 use std::rc::Rc;
 use std::iter;
@@ -482,19 +483,35 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
             assert_eq!(sz_b.ty, tcx.types.usize);
             let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
                 match x.val {
-                    ConstVal::Integral(x) => Ok(x.to_u64().unwrap()),
+                    ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()),
                     ConstVal::Unevaluated(def_id, substs) => {
                         // FIXME(eddyb) get the right param_env.
                         let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
                         match tcx.lift_to_global(&substs) {
                             Some(substs) => {
-                                match tcx.const_eval(param_env.and((def_id, substs))) {
-                                    Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => {
-                                        return Ok(x.to_u64().unwrap());
+                                let instance = ty::Instance::resolve(
+                                    tcx.global_tcx(),
+                                    param_env,
+                                    def_id,
+                                    substs,
+                                );
+                                if let Some(instance) = instance {
+                                    let cid = GlobalId {
+                                        instance,
+                                        promoted: None
+                                    };
+                                    match tcx.const_eval(param_env.and(cid)) {
+                                        Ok(&ty::Const {
+                                            val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
+                                            ..
+                                        }) => {
+                                            assert_eq!(b as u64 as u128, b);
+                                            return Ok(b as u64);
+                                        }
+                                        _ => {}
                                     }
-                                    _ => {}
                                 }
-                            }
+                            },
                             None => {}
                         }
                         tcx.sess.delay_span_bug(tcx.def_span(def_id),
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 055835ed69c1d..78fccaa113106 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -13,11 +13,12 @@
 //! hand, though we've recently added some macros (e.g.,
 //! `BraceStructLiftImpl!`) to help with the tedium.
 
-use middle::const_val::{self, ConstVal, ConstAggregate, ConstEvalErr};
+use middle::const_val::{self, ConstVal, ConstEvalErr};
 use ty::{self, Lift, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use mir::interpret;
 
 use std::rc::Rc;
 
@@ -56,6 +57,7 @@ CopyImpls! {
     ::syntax::abi::Abi,
     ::hir::def_id::DefId,
     ::mir::Local,
+    ::mir::Promoted,
     ::traits::Reveal,
     ::syntax_pos::Span,
 }
@@ -576,44 +578,139 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
 impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> {
     type Lifted = ConstEvalErr<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.kind).map(|kind| {
+        tcx.lift(&*self.kind).map(|kind| {
             ConstEvalErr {
                 span: self.span,
-                kind,
+                kind: Rc::new(kind),
             }
         })
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
+    type Lifted = interpret::EvalError<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        use ::mir::interpret::EvalErrorKind::*;
+        let kind = match self.kind {
+            MachineError(ref err) => MachineError(err.clone()),
+            FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch(
+                tcx.lift(&a)?,
+                tcx.lift(&b)?,
+            ),
+            NoMirFor(ref s) => NoMirFor(s.clone()),
+            UnterminatedCString(ptr) => UnterminatedCString(ptr),
+            DanglingPointerDeref => DanglingPointerDeref,
+            DoubleFree => DoubleFree,
+            InvalidMemoryAccess => InvalidMemoryAccess,
+            InvalidFunctionPointer => InvalidFunctionPointer,
+            InvalidBool => InvalidBool,
+            InvalidDiscriminant => InvalidDiscriminant,
+            PointerOutOfBounds {
+                ptr,
+                access,
+                allocation_size,
+            } => PointerOutOfBounds { ptr, access, allocation_size },
+            InvalidNullPointerUsage => InvalidNullPointerUsage,
+            ReadPointerAsBytes => ReadPointerAsBytes,
+            ReadBytesAsPointer => ReadBytesAsPointer,
+            InvalidPointerMath => InvalidPointerMath,
+            ReadUndefBytes => ReadUndefBytes,
+            DeadLocal => DeadLocal,
+            InvalidBoolOp(bop) => InvalidBoolOp(bop),
+            Unimplemented(ref s) => Unimplemented(s.clone()),
+            DerefFunctionPointer => DerefFunctionPointer,
+            ExecuteMemory => ExecuteMemory,
+            ArrayIndexOutOfBounds(sp, a, b) => ArrayIndexOutOfBounds(sp, a, b),
+            Math(sp, ref err) => Math(sp, err.clone()),
+            Intrinsic(ref s) => Intrinsic(s.clone()),
+            OverflowingMath => OverflowingMath,
+            InvalidChar(c) => InvalidChar(c),
+            ExecutionTimeLimitReached => ExecutionTimeLimitReached,
+            StackFrameLimitReached => StackFrameLimitReached,
+            OutOfTls => OutOfTls,
+            TlsOutOfBounds => TlsOutOfBounds,
+            AbiViolation(ref s) => AbiViolation(s.clone()),
+            AlignmentCheckFailed {
+                required,
+                has,
+            } => AlignmentCheckFailed { required, has },
+            MemoryLockViolation {
+                ptr,
+                len,
+                frame,
+                access,
+                ref lock,
+            } => MemoryLockViolation { ptr, len, frame, access, lock: lock.clone() },
+            MemoryAcquireConflict {
+                ptr,
+                len,
+                kind,
+                ref lock,
+            } => MemoryAcquireConflict { ptr, len, kind, lock: lock.clone() },
+            InvalidMemoryLockRelease {
+                ptr,
+                len,
+                frame,
+                ref lock,
+            } => InvalidMemoryLockRelease { ptr, len, frame, lock: lock.clone() },
+            DeallocatedLockedMemory {
+                ptr,
+                ref lock,
+            } => DeallocatedLockedMemory { ptr, lock: lock.clone() },
+            ValidationFailure(ref s) => ValidationFailure(s.clone()),
+            CalledClosureAsFunction => CalledClosureAsFunction,
+            VtableForArgumentlessMethod => VtableForArgumentlessMethod,
+            ModifiedConstantMemory => ModifiedConstantMemory,
+            AssumptionNotHeld => AssumptionNotHeld,
+            InlineAsm => InlineAsm,
+            TypeNotPrimitive(ty) => TypeNotPrimitive(tcx.lift(&ty)?),
+            ReallocatedWrongMemoryKind(ref a, ref b) => {
+                ReallocatedWrongMemoryKind(a.clone(), b.clone())
+            },
+            DeallocatedWrongMemoryKind(ref a, ref b) => {
+                DeallocatedWrongMemoryKind(a.clone(), b.clone())
+            },
+            ReallocateNonBasePtr => ReallocateNonBasePtr,
+            DeallocateNonBasePtr => DeallocateNonBasePtr,
+            IncorrectAllocationInformation(a, b, c, d) => {
+                IncorrectAllocationInformation(a, b, c, d)
+            },
+            Layout(lay) => Layout(tcx.lift(&lay)?),
+            HeapAllocZeroBytes => HeapAllocZeroBytes,
+            HeapAllocNonPowerOfTwoAlignment(n) => HeapAllocNonPowerOfTwoAlignment(n),
+            Unreachable => Unreachable,
+            Panic => Panic,
+            ReadFromReturnPointer => ReadFromReturnPointer,
+            PathNotFound(ref v) => PathNotFound(v.clone()),
+            UnimplementedTraitSelection => UnimplementedTraitSelection,
+            TypeckError => TypeckError,
+            ReferencedConstant => ReferencedConstant,
+        };
+        Some(interpret::EvalError {
+            kind: kind,
+            backtrace: self.backtrace.clone(),
+        })
+    }
+}
+
 impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> {
     type Lifted = const_val::ErrKind<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
         use middle::const_val::ErrKind::*;
 
         Some(match *self {
-            CannotCast => CannotCast,
-            MissingStructField => MissingStructField,
             NonConstPath => NonConstPath,
             UnimplementedConstVal(s) => UnimplementedConstVal(s),
-            ExpectedConstTuple => ExpectedConstTuple,
-            ExpectedConstStruct => ExpectedConstStruct,
-            IndexedNonVec => IndexedNonVec,
-            IndexNotUsize => IndexNotUsize,
             IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index },
-            MiscBinaryOp => MiscBinaryOp,
-            MiscCatchAll => MiscCatchAll,
-            IndexOpFeatureGated => IndexOpFeatureGated,
             Math(ref e) => Math(e.clone()),
 
             LayoutError(ref e) => {
                 return tcx.lift(e).map(LayoutError)
             }
-            ErroneousReferencedConstant(ref e) => {
-                return tcx.lift(e).map(ErroneousReferencedConstant)
-            }
 
             TypeckError => TypeckError,
             CheckMatchError => CheckMatchError,
+            Miri(ref e, ref frames) => return tcx.lift(e).map(|e| Miri(e, frames.clone())),
         })
     }
 }
@@ -632,6 +729,42 @@ impl<'a, 'tcx> Lift<'tcx> for ty::layout::LayoutError<'a> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
+    type Lifted = ty::InstanceDef<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        match *self {
+            ty::InstanceDef::Item(def_id) =>
+                Some(ty::InstanceDef::Item(def_id)),
+            ty::InstanceDef::Intrinsic(def_id) =>
+                Some(ty::InstanceDef::Intrinsic(def_id)),
+            ty::InstanceDef::FnPtrShim(def_id, ref ty) =>
+                Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?)),
+            ty::InstanceDef::Virtual(def_id, n) =>
+                Some(ty::InstanceDef::Virtual(def_id, n)),
+            ty::InstanceDef::ClosureOnceShim { call_once } =>
+                Some(ty::InstanceDef::ClosureOnceShim { call_once }),
+            ty::InstanceDef::DropGlue(def_id, ref ty) =>
+                Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?)),
+            ty::InstanceDef::CloneShim(def_id, ref ty) =>
+                Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?)),
+        }
+    }
+}
+
+BraceStructLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for ty::Instance<'a> {
+        type Lifted = ty::Instance<'tcx>;
+        def, substs
+    }
+}
+
+BraceStructLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for interpret::GlobalId<'a> {
+        type Lifted = interpret::GlobalId<'tcx>;
+        instance, promoted
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // TypeFoldable implementations.
 //
@@ -778,6 +911,74 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<Ty<'tcx>> {
     }
 }
 
+impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        use ty::InstanceDef::*;
+        Self {
+            substs: self.substs.fold_with(folder),
+            def: match self.def {
+                Item(did) => Item(did.fold_with(folder)),
+                Intrinsic(did) => Intrinsic(did.fold_with(folder)),
+                FnPtrShim(did, ty) => FnPtrShim(
+                    did.fold_with(folder),
+                    ty.fold_with(folder),
+                ),
+                Virtual(did, i) => Virtual(
+                    did.fold_with(folder),
+                    i,
+                ),
+                ClosureOnceShim { call_once } => ClosureOnceShim {
+                    call_once: call_once.fold_with(folder),
+                },
+                DropGlue(did, ty) => DropGlue(
+                    did.fold_with(folder),
+                    ty.fold_with(folder),
+                ),
+                CloneShim(did, ty) => CloneShim(
+                    did.fold_with(folder),
+                    ty.fold_with(folder),
+                ),
+            },
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        use ty::InstanceDef::*;
+        self.substs.visit_with(visitor) ||
+        match self.def {
+            Item(did) => did.visit_with(visitor),
+            Intrinsic(did) => did.visit_with(visitor),
+            FnPtrShim(did, ty) => {
+                did.visit_with(visitor) ||
+                ty.visit_with(visitor)
+            },
+            Virtual(did, _) => did.visit_with(visitor),
+            ClosureOnceShim { call_once } => call_once.visit_with(visitor),
+            DropGlue(did, ty) => {
+                did.visit_with(visitor) ||
+                ty.visit_with(visitor)
+            },
+            CloneShim(did, ty) => {
+                did.visit_with(visitor) ||
+                ty.visit_with(visitor)
+            },
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        Self {
+            instance: self.instance.fold_with(folder),
+            promoted: self.promoted
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.instance.visit_with(visitor)
+    }
+}
+
 impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         let sty = match self.sty {
@@ -1243,53 +1444,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
 impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
-            ConstVal::Integral(i) => ConstVal::Integral(i),
-            ConstVal::Float(f) => ConstVal::Float(f),
-            ConstVal::Str(s) => ConstVal::Str(s),
-            ConstVal::ByteStr(b) => ConstVal::ByteStr(b),
-            ConstVal::Bool(b) => ConstVal::Bool(b),
-            ConstVal::Char(c) => ConstVal::Char(c),
-            ConstVal::Variant(def_id) => ConstVal::Variant(def_id),
-            ConstVal::Function(def_id, substs) => {
-                ConstVal::Function(def_id, substs.fold_with(folder))
-            }
-            ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
-                let new_fields: Vec<_> = fields.iter().map(|&(name, v)| {
-                    (name, v.fold_with(folder))
-                }).collect();
-                let fields = if new_fields == fields {
-                    fields
-                } else {
-                    folder.tcx().alloc_name_const_slice(&new_fields)
-                };
-                ConstVal::Aggregate(ConstAggregate::Struct(fields))
-            }
-            ConstVal::Aggregate(ConstAggregate::Tuple(fields)) => {
-                let new_fields: Vec<_> = fields.iter().map(|v| {
-                    v.fold_with(folder)
-                }).collect();
-                let fields = if new_fields == fields {
-                    fields
-                } else {
-                    folder.tcx().alloc_const_slice(&new_fields)
-                };
-                ConstVal::Aggregate(ConstAggregate::Tuple(fields))
-            }
-            ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
-                let new_fields: Vec<_> = fields.iter().map(|v| {
-                    v.fold_with(folder)
-                }).collect();
-                let fields = if new_fields == fields {
-                    fields
-                } else {
-                    folder.tcx().alloc_const_slice(&new_fields)
-                };
-                ConstVal::Aggregate(ConstAggregate::Array(fields))
-            }
-            ConstVal::Aggregate(ConstAggregate::Repeat(v, count)) => {
-                let v = v.fold_with(folder);
-                ConstVal::Aggregate(ConstAggregate::Repeat(v, count))
-            }
+            ConstVal::Value(v) => ConstVal::Value(v),
             ConstVal::Unevaluated(def_id, substs) => {
                 ConstVal::Unevaluated(def_id, substs.fold_with(folder))
             }
@@ -1298,24 +1453,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> {
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         match *self {
-            ConstVal::Integral(_) |
-            ConstVal::Float(_) |
-            ConstVal::Str(_) |
-            ConstVal::ByteStr(_) |
-            ConstVal::Bool(_) |
-            ConstVal::Char(_) |
-            ConstVal::Variant(_) => false,
-            ConstVal::Function(_, substs) => substs.visit_with(visitor),
-            ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
-                fields.iter().any(|&(_, v)| v.visit_with(visitor))
-            }
-            ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
-            ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
-                fields.iter().any(|v| v.visit_with(visitor))
-            }
-            ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
-                v.visit_with(visitor)
-            }
+            ConstVal::Value(_) => false,
             ConstVal::Unevaluated(_, substs) => substs.visit_with(visitor),
         }
     }
diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs
index 62d3c8dc87da3..32f0d3384c4dc 100644
--- a/src/librustc/ty/trait_def.rs
+++ b/src/librustc/ty/trait_def.rs
@@ -186,9 +186,9 @@ pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     })
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for TraitImpls {
+impl<'a> HashStable<StableHashingContext<'a>> for TraitImpls {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let TraitImpls {
             ref blanket_impls,
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 785035ee5f4f0..cbd9a1b8d4f93 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -22,60 +22,98 @@ use ty::fold::TypeVisitor;
 use ty::subst::{Subst, UnpackedKind};
 use ty::maps::TyCtxtAt;
 use ty::TypeVariants::*;
+use ty::layout::Integer;
 use util::common::ErrorReported;
 use middle::lang_items;
+use mir::interpret::{Value, PrimVal};
 
-use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
 use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
                                            HashStable};
 use rustc_data_structures::fx::FxHashMap;
-use std::cmp;
+use std::{cmp, fmt};
 use std::hash::Hash;
 use std::intrinsics;
 use syntax::ast::{self, Name};
 use syntax::attr::{self, SignedInt, UnsignedInt};
 use syntax_pos::{Span, DUMMY_SP};
 
-type Disr = ConstInt;
-
-pub trait IntTypeExt {
-    fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
-    fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
-                           -> Option<Disr>;
-    fn assert_ty_matches(&self, val: Disr);
-    fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
+#[derive(Copy, Clone, Debug)]
+pub struct Discr<'tcx> {
+    pub val: u128,
+    pub ty: Ty<'tcx>
 }
 
+impl<'tcx> fmt::Display for Discr<'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        if self.ty.is_signed() {
+            write!(fmt, "{}", self.val as i128)
+        } else {
+            write!(fmt, "{}", self.val)
+        }
+    }
+}
 
-macro_rules! typed_literal {
-    ($tcx:expr, $ty:expr, $lit:expr) => {
-        match $ty {
-            SignedInt(ast::IntTy::I8)    => ConstInt::I8($lit),
-            SignedInt(ast::IntTy::I16)   => ConstInt::I16($lit),
-            SignedInt(ast::IntTy::I32)   => ConstInt::I32($lit),
-            SignedInt(ast::IntTy::I64)   => ConstInt::I64($lit),
-            SignedInt(ast::IntTy::I128)   => ConstInt::I128($lit),
-            SignedInt(ast::IntTy::Isize) => match $tcx.sess.target.isize_ty {
-                ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16($lit)),
-                ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32($lit)),
-                ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64($lit)),
-                _ => bug!(),
-            },
-            UnsignedInt(ast::UintTy::U8)  => ConstInt::U8($lit),
-            UnsignedInt(ast::UintTy::U16) => ConstInt::U16($lit),
-            UnsignedInt(ast::UintTy::U32) => ConstInt::U32($lit),
-            UnsignedInt(ast::UintTy::U64) => ConstInt::U64($lit),
-            UnsignedInt(ast::UintTy::U128) => ConstInt::U128($lit),
-            UnsignedInt(ast::UintTy::Usize) => match $tcx.sess.target.usize_ty {
-                ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16($lit)),
-                ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32($lit)),
-                ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64($lit)),
-                _ => bug!(),
-            },
+impl<'tcx> Discr<'tcx> {
+    /// Adds 1 to the value and wraps around if the maximum for the type is reached
+    pub fn wrap_incr<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
+        self.checked_add(tcx, 1).0
+    }
+    pub fn checked_add<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, n: u128) -> (Self, bool) {
+        let (int, signed) = match self.ty.sty {
+            TyInt(ity) => (Integer::from_attr(tcx, SignedInt(ity)), true),
+            TyUint(uty) => (Integer::from_attr(tcx, UnsignedInt(uty)), false),
+            _ => bug!("non integer discriminant"),
+        };
+        if signed {
+            let (min, max) = match int {
+                Integer::I8 => (i8::min_value() as i128, i8::max_value() as i128),
+                Integer::I16 => (i16::min_value() as i128, i16::max_value() as i128),
+                Integer::I32 => (i32::min_value() as i128, i32::max_value() as i128),
+                Integer::I64 => (i64::min_value() as i128, i64::max_value() as i128),
+                Integer::I128 => (i128::min_value(), i128::max_value()),
+            };
+            let val = self.val as i128;
+            let n = n as i128;
+            let oflo = val > max - n;
+            let val = if oflo {
+                min + (n - (max - val) - 1)
+            } else {
+                val + n
+            };
+            (Self {
+                val: val as u128,
+                ty: self.ty,
+            }, oflo)
+        } else {
+            let (min, max) = match int {
+                Integer::I8 => (u8::min_value() as u128, u8::max_value() as u128),
+                Integer::I16 => (u16::min_value() as u128, u16::max_value() as u128),
+                Integer::I32 => (u32::min_value() as u128, u32::max_value() as u128),
+                Integer::I64 => (u64::min_value() as u128, u64::max_value() as u128),
+                Integer::I128 => (u128::min_value(), u128::max_value()),
+            };
+            let val = self.val;
+            let oflo = val > max - n;
+            let val = if oflo {
+                min + (n - (max - val) - 1)
+            } else {
+                val + n
+            };
+            (Self {
+                val: val,
+                ty: self.ty,
+            }, oflo)
         }
     }
 }
 
+pub trait IntTypeExt {
+    fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
+    fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Discr<'tcx>>)
+                           -> Option<Discr<'tcx>>;
+    fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Discr<'tcx>;
+}
+
 impl IntTypeExt for attr::IntType {
     fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
         match *self {
@@ -94,33 +132,26 @@ impl IntTypeExt for attr::IntType {
         }
     }
 
-    fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
-        typed_literal!(tcx, *self, 0)
-    }
-
-    fn assert_ty_matches(&self, val: Disr) {
-        match (*self, val) {
-            (SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
-            (SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
-            (SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
-            (SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
-            (SignedInt(ast::IntTy::I128), ConstInt::I128(_)) => {},
-            (SignedInt(ast::IntTy::Isize), ConstInt::Isize(_)) => {},
-            (UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
-            (UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
-            (UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
-            (UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
-            (UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) => {},
-            (UnsignedInt(ast::UintTy::Usize), ConstInt::Usize(_)) => {},
-            _ => bug!("disr type mismatch: {:?} vs {:?}", self, val),
+    fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Discr<'tcx> {
+        Discr {
+            val: 0,
+            ty: self.to_ty(tcx)
         }
     }
 
-    fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
-                           -> Option<Disr> {
+    fn disr_incr<'a, 'tcx>(
+        &self,
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        val: Option<Discr<'tcx>>,
+    ) -> Option<Discr<'tcx>> {
         if let Some(val) = val {
-            self.assert_ty_matches(val);
-            (val + typed_literal!(tcx, *self, 1)).ok()
+            assert_eq!(self.to_ty(tcx), val.ty);
+            let (new, oflo) = val.checked_add(tcx, 1);
+            if oflo {
+                None
+            } else {
+                Some(new)
+            }
         } else {
             Some(self.initial_discriminant(tcx))
         }
@@ -681,31 +712,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         })
     }
 
-    pub fn const_usize(&self, val: u16) -> ConstInt {
-        match self.sess.target.usize_ty {
-            ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(val as u16)),
-            ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(val as u32)),
-            ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(val as u64)),
-            _ => bug!(),
-        }
-    }
-
-    /// Check if the node pointed to by def_id is a mutable static item
-    pub fn is_static_mut(&self, def_id: DefId) -> bool {
+    /// Return whether the node pointed to by def_id is a static item, and its mutability
+    pub fn is_static(&self, def_id: DefId) -> Option<hir::Mutability> {
         if let Some(node) = self.hir.get_if_local(def_id) {
             match node {
                 Node::NodeItem(&hir::Item {
-                    node: hir::ItemStatic(_, hir::MutMutable, _), ..
-                }) => true,
+                    node: hir::ItemStatic(_, mutbl, _), ..
+                }) => Some(mutbl),
                 Node::NodeForeignItem(&hir::ForeignItem {
-                    node: hir::ForeignItemStatic(_, mutbl), ..
-                }) => mutbl,
-                _ => false
+                    node: hir::ForeignItemStatic(_, is_mutbl), ..
+                }) =>
+                    Some(if is_mutbl {
+                        hir::Mutability::MutMutable
+                    } else {
+                        hir::Mutability::MutImmutable
+                    }),
+                _ => None
             }
         } else {
             match self.describe_def(def_id) {
-                Some(Def::Static(_, mutbl)) => mutbl,
-                _ => false
+                Some(Def::Static(_, is_mutbl)) =>
+                    Some(if is_mutbl {
+                        hir::Mutability::MutMutable
+                    } else {
+                        hir::Mutability::MutImmutable
+                    }),
+                _ => None
             }
         }
     }
@@ -764,7 +796,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
             TyArray(_, n) => {
                 self.hash_discriminant_u8(&n.val);
                 match n.val {
-                    ConstVal::Integral(x) => self.hash(x.to_u64().unwrap()),
+                    ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b),
                     ConstVal::Unevaluated(def_id, _) => self.def_id(def_id),
                     _ => bug!("arrays should not have {:?} as length", n)
                 }
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index 45f0ad1cf1a5f..722fdfe773a98 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -11,7 +11,7 @@
 //! An iterator over the type substructure.
 //! WARNING: this does not keep track of the region depth.
 
-use middle::const_val::{ConstVal, ConstAggregate};
+use middle::const_val::ConstVal;
 use ty::{self, Ty};
 use rustc_data_structures::small_vec::SmallVec;
 use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
@@ -140,30 +140,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
 
 fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const<'tcx>) {
     match constant.val {
-        ConstVal::Integral(_) |
-        ConstVal::Float(_) |
-        ConstVal::Str(_) |
-        ConstVal::ByteStr(_) |
-        ConstVal::Bool(_) |
-        ConstVal::Char(_) |
-        ConstVal::Variant(_) => {}
-        ConstVal::Function(_, substs) => {
-            stack.extend(substs.types().rev());
-        }
-        ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
-            for &(_, v) in fields.iter().rev() {
-                push_const(stack, v);
-            }
-        }
-        ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
-        ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
-            for v in fields.iter().rev() {
-                push_const(stack, v);
-            }
-        }
-        ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
-            push_const(stack, v);
-        }
+        ConstVal::Value(_) => {}
         ConstVal::Unevaluated(_, substs) => {
             stack.extend(substs.types().rev());
         }
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index ea99bd39e8792..49ae79ae9c92c 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use hir::def_id::DefId;
-use middle::const_val::{ConstVal, ConstAggregate};
+use middle::const_val::ConstVal;
 use infer::InferCtxt;
 use ty::subst::Substs;
 use traits;
@@ -217,28 +217,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
     fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) {
         self.require_sized(constant.ty, traits::ConstSized);
         match constant.val {
-            ConstVal::Integral(_) |
-            ConstVal::Float(_) |
-            ConstVal::Str(_) |
-            ConstVal::ByteStr(_) |
-            ConstVal::Bool(_) |
-            ConstVal::Char(_) |
-            ConstVal::Variant(_) |
-            ConstVal::Function(..) => {}
-            ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
-                for &(_, v) in fields {
-                    self.compute_const(v);
-                }
-            }
-            ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
-            ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
-                for v in fields {
-                    self.compute_const(v);
-                }
-            }
-            ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
-                self.compute_const(v);
-            }
+            ConstVal::Value(_) => {}
             ConstVal::Unevaluated(def_id, substs) => {
                 let obligations = self.nominal_obligations(def_id, substs);
                 self.out.extend(obligations);
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index a2620da4c10ca..5e2792ee6410e 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -21,12 +21,12 @@ use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, Ty
 use ty::{TyDynamic, TyInt, TyUint, TyInfer};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use util::nodemap::FxHashSet;
+use mir::interpret::{Value, PrimVal};
 
 use std::cell::Cell;
 use std::fmt;
 use std::usize;
 
-use rustc_const_math::ConstInt;
 use rustc_data_structures::indexed_vec::Idx;
 use syntax::abi::Abi;
 use syntax::ast::CRATE_NODE_ID;
@@ -1165,7 +1165,7 @@ define_print! {
                 TyArray(ty, sz) => {
                     print!(f, cx, write("["), print(ty), write("; "))?;
                     match sz.val {
-                        ConstVal::Integral(ConstInt::Usize(sz)) => {
+                        ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => {
                             write!(f, "{}", sz)?;
                         }
                         ConstVal::Unevaluated(_def_id, substs) => {
diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml
deleted file mode 100644
index 53b8402ab2ad5..0000000000000
--- a/src/librustc_const_eval/Cargo.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-[package]
-authors = ["The Rust Project Developers"]
-name = "rustc_const_eval"
-version = "0.0.0"
-
-[lib]
-name = "rustc_const_eval"
-path = "lib.rs"
-crate-type = ["dylib"]
-
-[dependencies]
-arena = { path = "../libarena" }
-log = "0.4"
-rustc = { path = "../librustc" }
-rustc_const_math = { path = "../librustc_const_math" }
-rustc_data_structures = { path = "../librustc_data_structures" }
-rustc_errors = { path = "../librustc_errors" }
-syntax = { path = "../libsyntax" }
-syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs
deleted file mode 100644
index d01b3c45f7fd1..0000000000000
--- a/src/librustc_const_eval/diagnostics.rs
+++ /dev/null
@@ -1,571 +0,0 @@
-// Copyright 2014 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.
-
-#![allow(non_snake_case)]
-
-// Error messages for EXXXX errors.
-// Each message should start and end with a new line, and be wrapped to 80 characters.
-// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
-register_long_diagnostics! {
-
-E0001: r##"
-#### Note: this error code is no longer emitted by the compiler.
-
-This error suggests that the expression arm corresponding to the noted pattern
-will never be reached as for all possible values of the expression being
-matched, one of the preceding patterns will match.
-
-This means that perhaps some of the preceding patterns are too general, this
-one is too specific or the ordering is incorrect.
-
-For example, the following `match` block has too many arms:
-
-```
-match Some(0) {
-    Some(bar) => {/* ... */}
-    x => {/* ... */} // This handles the `None` case
-    _ => {/* ... */} // All possible cases have already been handled
-}
-```
-
-`match` blocks have their patterns matched in order, so, for example, putting
-a wildcard arm above a more specific arm will make the latter arm irrelevant.
-
-Ensure the ordering of the match arm is correct and remove any superfluous
-arms.
-"##,
-
-E0002: r##"
-#### Note: this error code is no longer emitted by the compiler.
-
-This error indicates that an empty match expression is invalid because the type
-it is matching on is non-empty (there exist values of this type). In safe code
-it is impossible to create an instance of an empty type, so empty match
-expressions are almost never desired. This error is typically fixed by adding
-one or more cases to the match expression.
-
-An example of an empty type is `enum Empty { }`. So, the following will work:
-
-```
-enum Empty {}
-
-fn foo(x: Empty) {
-    match x {
-        // empty
-    }
-}
-```
-
-However, this won't:
-
-```compile_fail
-fn foo(x: Option<String>) {
-    match x {
-        // empty
-    }
-}
-```
-"##,
-
-E0003: r##"
-#### Note: this error code is no longer emitted by the compiler.
-
-Not-a-Number (NaN) values cannot be compared for equality and hence can never
-match the input to a match expression. So, the following will not compile:
-
-```compile_fail
-const NAN: f32 = 0.0 / 0.0;
-
-let number = 0.1f32;
-
-match number {
-    NAN => { /* ... */ },
-    _ => {}
-}
-```
-
-To match against NaN values, you should instead use the `is_nan()` method in a
-guard, like so:
-
-```
-let number = 0.1f32;
-
-match number {
-    x if x.is_nan() => { /* ... */ }
-    _ => {}
-}
-```
-"##,
-
-E0004: r##"
-This error indicates that the compiler cannot guarantee a matching pattern for
-one or more possible inputs to a match expression. Guaranteed matches are
-required in order to assign values to match expressions, or alternatively,
-determine the flow of execution. Erroneous code example:
-
-```compile_fail,E0004
-enum Terminator {
-    HastaLaVistaBaby,
-    TalkToMyHand,
-}
-
-let x = Terminator::HastaLaVistaBaby;
-
-match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered
-    Terminator::TalkToMyHand => {}
-}
-```
-
-If you encounter this error you must alter your patterns so that every possible
-value of the input type is matched. For types with a small number of variants
-(like enums) you should probably cover all cases explicitly. Alternatively, the
-underscore `_` wildcard pattern can be added after all other patterns to match
-"anything else". Example:
-
-```
-enum Terminator {
-    HastaLaVistaBaby,
-    TalkToMyHand,
-}
-
-let x = Terminator::HastaLaVistaBaby;
-
-match x {
-    Terminator::TalkToMyHand => {}
-    Terminator::HastaLaVistaBaby => {}
-}
-
-// or:
-
-match x {
-    Terminator::TalkToMyHand => {}
-    _ => {}
-}
-```
-"##,
-
-E0005: r##"
-Patterns used to bind names must be irrefutable, that is, they must guarantee
-that a name will be extracted in all cases. Erroneous code example:
-
-```compile_fail,E0005
-let x = Some(1);
-let Some(y) = x;
-// error: refutable pattern in local binding: `None` not covered
-```
-
-If you encounter this error you probably need to use a `match` or `if let` to
-deal with the possibility of failure. Example:
-
-```
-let x = Some(1);
-
-match x {
-    Some(y) => {
-        // do something
-    },
-    None => {}
-}
-
-// or:
-
-if let Some(y) = x {
-    // do something
-}
-```
-"##,
-
-E0007: r##"
-This error indicates that the bindings in a match arm would require a value to
-be moved into more than one location, thus violating unique ownership. Code
-like the following is invalid as it requires the entire `Option<String>` to be
-moved into a variable called `op_string` while simultaneously requiring the
-inner `String` to be moved into a variable called `s`.
-
-```compile_fail,E0007
-let x = Some("s".to_string());
-
-match x {
-    op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings
-    None => {},
-}
-```
-
-See also the error E0303.
-"##,
-
-E0008: r##"
-Names bound in match arms retain their type in pattern guards. As such, if a
-name is bound by move in a pattern, it should also be moved to wherever it is
-referenced in the pattern guard code. Doing so however would prevent the name
-from being available in the body of the match arm. Consider the following:
-
-```compile_fail,E0008
-match Some("hi".to_string()) {
-    Some(s) if s.len() == 0 => {}, // use s.
-    _ => {},
-}
-```
-
-The variable `s` has type `String`, and its use in the guard is as a variable of
-type `String`. The guard code effectively executes in a separate scope to the
-body of the arm, so the value would be moved into this anonymous scope and
-therefore becomes unavailable in the body of the arm.
-
-The problem above can be solved by using the `ref` keyword.
-
-```
-match Some("hi".to_string()) {
-    Some(ref s) if s.len() == 0 => {},
-    _ => {},
-}
-```
-
-Though this example seems innocuous and easy to solve, the problem becomes clear
-when it encounters functions which consume the value:
-
-```compile_fail,E0008
-struct A{}
-
-impl A {
-    fn consume(self) -> usize {
-        0
-    }
-}
-
-fn main() {
-    let a = Some(A{});
-    match a {
-        Some(y) if y.consume() > 0 => {}
-        _ => {}
-    }
-}
-```
-
-In this situation, even the `ref` keyword cannot solve it, since borrowed
-content cannot be moved. This problem cannot be solved generally. If the value
-can be cloned, here is a not-so-specific solution:
-
-```
-#[derive(Clone)]
-struct A{}
-
-impl A {
-    fn consume(self) -> usize {
-        0
-    }
-}
-
-fn main() {
-    let a = Some(A{});
-    match a{
-        Some(ref y) if y.clone().consume() > 0 => {}
-        _ => {}
-    }
-}
-```
-
-If the value will be consumed in the pattern guard, using its clone will not
-move its ownership, so the code works.
-"##,
-
-E0009: r##"
-In a pattern, all values that don't implement the `Copy` trait have to be bound
-the same way. The goal here is to avoid binding simultaneously by-move and
-by-ref.
-
-This limitation may be removed in a future version of Rust.
-
-Erroneous code example:
-
-```compile_fail,E0009
-struct X { x: (), }
-
-let x = Some((X { x: () }, X { x: () }));
-match x {
-    Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the
-                            //        same pattern
-    None => panic!()
-}
-```
-
-You have two solutions:
-
-Solution #1: Bind the pattern's values the same way.
-
-```
-struct X { x: (), }
-
-let x = Some((X { x: () }, X { x: () }));
-match x {
-    Some((ref y, ref z)) => {},
-    // or Some((y, z)) => {}
-    None => panic!()
-}
-```
-
-Solution #2: Implement the `Copy` trait for the `X` structure.
-
-However, please keep in mind that the first solution should be preferred.
-
-```
-#[derive(Clone, Copy)]
-struct X { x: (), }
-
-let x = Some((X { x: () }, X { x: () }));
-match x {
-    Some((y, ref z)) => {},
-    None => panic!()
-}
-```
-"##,
-
-E0158: r##"
-`const` and `static` mean different things. A `const` is a compile-time
-constant, an alias for a literal value. This property means you can match it
-directly within a pattern.
-
-The `static` keyword, on the other hand, guarantees a fixed location in memory.
-This does not always mean that the value is constant. For example, a global
-mutex can be declared `static` as well.
-
-If you want to match against a `static`, consider using a guard instead:
-
-```
-static FORTY_TWO: i32 = 42;
-
-match Some(42) {
-    Some(x) if x == FORTY_TWO => {}
-    _ => {}
-}
-```
-"##,
-
-E0162: r##"
-An if-let pattern attempts to match the pattern, and enters the body if the
-match was successful. If the match is irrefutable (when it cannot fail to
-match), use a regular `let`-binding instead. For instance:
-
-```compile_fail,E0162
-struct Irrefutable(i32);
-let irr = Irrefutable(0);
-
-// This fails to compile because the match is irrefutable.
-if let Irrefutable(x) = irr {
-    // This body will always be executed.
-    // ...
-}
-```
-
-Try this instead:
-
-```
-struct Irrefutable(i32);
-let irr = Irrefutable(0);
-
-let Irrefutable(x) = irr;
-println!("{}", x);
-```
-"##,
-
-E0165: r##"
-A while-let pattern attempts to match the pattern, and enters the body if the
-match was successful. If the match is irrefutable (when it cannot fail to
-match), use a regular `let`-binding inside a `loop` instead. For instance:
-
-```compile_fail,E0165
-struct Irrefutable(i32);
-let irr = Irrefutable(0);
-
-// This fails to compile because the match is irrefutable.
-while let Irrefutable(x) = irr {
-    // ...
-}
-```
-
-Try this instead:
-
-```no_run
-struct Irrefutable(i32);
-let irr = Irrefutable(0);
-
-loop {
-    let Irrefutable(x) = irr;
-    // ...
-}
-```
-"##,
-
-E0170: r##"
-Enum variants are qualified by default. For example, given this type:
-
-```
-enum Method {
-    GET,
-    POST,
-}
-```
-
-You would match it using:
-
-```
-enum Method {
-    GET,
-    POST,
-}
-
-let m = Method::GET;
-
-match m {
-    Method::GET => {},
-    Method::POST => {},
-}
-```
-
-If you don't qualify the names, the code will bind new variables named "GET" and
-"POST" instead. This behavior is likely not what you want, so `rustc` warns when
-that happens.
-
-Qualified names are good practice, and most code works well with them. But if
-you prefer them unqualified, you can import the variants into scope:
-
-```
-use Method::*;
-enum Method { GET, POST }
-# fn main() {}
-```
-
-If you want others to be able to import variants from your module directly, use
-`pub use`:
-
-```
-pub use Method::*;
-pub enum Method { GET, POST }
-# fn main() {}
-```
-"##,
-
-
-E0297: r##"
-#### Note: this error code is no longer emitted by the compiler.
-
-Patterns used to bind names must be irrefutable. That is, they must guarantee
-that a name will be extracted in all cases. Instead of pattern matching the
-loop variable, consider using a `match` or `if let` inside the loop body. For
-instance:
-
-```compile_fail,E0005
-let xs : Vec<Option<i32>> = vec![Some(1), None];
-
-// This fails because `None` is not covered.
-for Some(x) in xs {
-    // ...
-}
-```
-
-Match inside the loop instead:
-
-```
-let xs : Vec<Option<i32>> = vec![Some(1), None];
-
-for item in xs {
-    match item {
-        Some(x) => {},
-        None => {},
-    }
-}
-```
-
-Or use `if let`:
-
-```
-let xs : Vec<Option<i32>> = vec![Some(1), None];
-
-for item in xs {
-    if let Some(x) = item {
-        // ...
-    }
-}
-```
-"##,
-
-E0301: r##"
-Mutable borrows are not allowed in pattern guards, because matching cannot have
-side effects. Side effects could alter the matched object or the environment
-on which the match depends in such a way, that the match would not be
-exhaustive. For instance, the following would not match any arm if mutable
-borrows were allowed:
-
-```compile_fail,E0301
-match Some(()) {
-    None => { },
-    option if option.take().is_none() => {
-        /* impossible, option is `Some` */
-    },
-    Some(_) => { } // When the previous match failed, the option became `None`.
-}
-```
-"##,
-
-E0302: r##"
-Assignments are not allowed in pattern guards, because matching cannot have
-side effects. Side effects could alter the matched object or the environment
-on which the match depends in such a way, that the match would not be
-exhaustive. For instance, the following would not match any arm if assignments
-were allowed:
-
-```compile_fail,E0302
-match Some(()) {
-    None => { },
-    option if { option = None; false } => { },
-    Some(_) => { } // When the previous match failed, the option became `None`.
-}
-```
-"##,
-
-E0303: r##"
-In certain cases it is possible for sub-bindings to violate memory safety.
-Updates to the borrow checker in a future version of Rust may remove this
-restriction, but for now patterns must be rewritten without sub-bindings.
-
-Before:
-
-```compile_fail,E0303
-match Some("hi".to_string()) {
-    ref op_string_ref @ Some(s) => {},
-    None => {},
-}
-```
-
-After:
-
-```
-match Some("hi".to_string()) {
-    Some(ref s) => {
-        let op_string_ref = &Some(s);
-        // ...
-    },
-    None => {},
-}
-```
-
-The `op_string_ref` binding has type `&Option<&String>` in both cases.
-
-See also https://github.com/rust-lang/rust/issues/14587
-"##,
-
-}
-
-
-register_diagnostics! {
-//  E0298, // cannot compare constants
-//  E0299, // mismatched types between arms
-//  E0471, // constant evaluation error (in pattern)
-}
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
deleted file mode 100644
index 2a571fa82643b..0000000000000
--- a/src/librustc_const_eval/eval.rs
+++ /dev/null
@@ -1,687 +0,0 @@
-// Copyright 2012-2016 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::middle::const_val::ConstAggregate::*;
-use rustc::middle::const_val::ErrKind::*;
-use rustc::middle::const_val::{ByteArray, ConstVal, ConstEvalErr, EvalResult, ErrKind};
-
-use rustc::hir::map::blocks::FnLikeNode;
-use rustc::hir::def::{Def, CtorKind};
-use rustc::hir::def_id::DefId;
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::util::IntTypeExt;
-use rustc::ty::subst::{Substs, Subst};
-use rustc::util::common::ErrorReported;
-use rustc::util::nodemap::NodeMap;
-
-use syntax::abi::Abi;
-use syntax::ast;
-use syntax::attr;
-use rustc::hir::{self, Expr};
-use syntax_pos::Span;
-
-use std::cmp::Ordering;
-
-use rustc_const_math::*;
-macro_rules! signal {
-    ($e:expr, $exn:expr) => {
-        return Err(ConstEvalErr { span: $e.span, kind: $exn })
-    }
-}
-
-macro_rules! math {
-    ($e:expr, $op:expr) => {
-        match $op {
-            Ok(val) => val,
-            Err(e) => signal!($e, ErrKind::from(e)),
-        }
-    }
-}
-
-/// * `DefId` is the id of the constant.
-/// * `Substs` is the monomorphized substitutions for the expression.
-pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
-                                    -> Option<(DefId, &'tcx Substs<'tcx>)> {
-    ty::Instance::resolve(
-        tcx,
-        key.param_env,
-        key.value.0,
-        key.value.1,
-    ).map(|instance| (instance.def_id(), instance.substs))
-}
-
-pub struct ConstContext<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    tables: &'a ty::TypeckTables<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    substs: &'tcx Substs<'tcx>,
-    fn_args: Option<NodeMap<&'tcx ty::Const<'tcx>>>
-}
-
-impl<'a, 'tcx> ConstContext<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-               param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
-               tables: &'a ty::TypeckTables<'tcx>)
-               -> Self {
-        ConstContext {
-            tcx,
-            param_env: param_env_and_substs.param_env,
-            tables,
-            substs: param_env_and_substs.value,
-            fn_args: None
-        }
-    }
-
-    /// Evaluate a constant expression in a context where the expression isn't
-    /// guaranteed to be evaluable.
-    pub fn eval(&self, e: &'tcx Expr) -> EvalResult<'tcx> {
-        if self.tables.tainted_by_errors {
-            signal!(e, TypeckError);
-        }
-        eval_const_expr_partial(self, e)
-    }
-}
-
-type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
-
-fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
-                                     e: &'tcx Expr) -> EvalResult<'tcx> {
-    trace!("eval_const_expr_partial: {:?}", e);
-    let tcx = cx.tcx;
-    let ty = cx.tables.expr_ty(e).subst(tcx, cx.substs);
-    let mk_const = |val| tcx.mk_const(ty::Const { val, ty });
-
-    let result = match e.node {
-      hir::ExprUnary(hir::UnNeg, ref inner) => {
-        // unary neg literals already got their sign during creation
-        if let hir::ExprLit(ref lit) = inner.node {
-            use syntax::ast::*;
-            use syntax::ast::LitIntType::*;
-            const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128;
-            const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128;
-            const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
-            const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
-            const I128_OVERFLOW: u128 = i128::min_value() as u128;
-            let negated = match (&lit.node, &ty.sty) {
-                (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
-                (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
-                    Some(I8(i8::min_value()))
-                },
-                (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
-                (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
-                    Some(I16(i16::min_value()))
-                },
-                (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
-                (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
-                    Some(I32(i32::min_value()))
-                },
-                (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
-                (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
-                    Some(I64(i64::min_value()))
-                },
-                (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
-                (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
-                    Some(I128(i128::min_value()))
-                },
-                (&LitKind::Int(n, _), &ty::TyInt(IntTy::Isize)) |
-                (&LitKind::Int(n, Signed(IntTy::Isize)), _) => {
-                    match tcx.sess.target.isize_ty {
-                        IntTy::I16 => if n == I16_OVERFLOW {
-                            Some(Isize(Is16(i16::min_value())))
-                        } else {
-                            None
-                        },
-                        IntTy::I32 => if n == I32_OVERFLOW {
-                            Some(Isize(Is32(i32::min_value())))
-                        } else {
-                            None
-                        },
-                        IntTy::I64 => if n == I64_OVERFLOW {
-                            Some(Isize(Is64(i64::min_value())))
-                        } else {
-                            None
-                        },
-                        _ => span_bug!(e.span, "typeck error")
-                    }
-                },
-                _ => None
-            };
-            if let Some(i) = negated {
-                return Ok(mk_const(Integral(i)));
-            }
-        }
-        mk_const(match cx.eval(inner)?.val {
-          Float(f) => Float(-f),
-          Integral(i) => Integral(math!(e, -i)),
-          _ => signal!(e, TypeckError)
-        })
-      }
-      hir::ExprUnary(hir::UnNot, ref inner) => {
-        mk_const(match cx.eval(inner)?.val {
-          Integral(i) => Integral(math!(e, !i)),
-          Bool(b) => Bool(!b),
-          _ => signal!(e, TypeckError)
-        })
-      }
-      hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
-      hir::ExprBinary(op, ref a, ref b) => {
-        // technically, if we don't have type hints, but integral eval
-        // gives us a type through a type-suffix, cast or const def type
-        // we need to re-eval the other value of the BinOp if it was
-        // not inferred
-        mk_const(match (cx.eval(a)?.val, cx.eval(b)?.val) {
-          (Float(a), Float(b)) => {
-            use std::cmp::Ordering::*;
-            match op.node {
-              hir::BiAdd => Float(math!(e, a + b)),
-              hir::BiSub => Float(math!(e, a - b)),
-              hir::BiMul => Float(math!(e, a * b)),
-              hir::BiDiv => Float(math!(e, a / b)),
-              hir::BiRem => Float(math!(e, a % b)),
-              hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
-              hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
-              hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
-              hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
-              hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
-              hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
-              _ => span_bug!(e.span, "typeck error"),
-            }
-          }
-          (Integral(a), Integral(b)) => {
-            use std::cmp::Ordering::*;
-            match op.node {
-              hir::BiAdd => Integral(math!(e, a + b)),
-              hir::BiSub => Integral(math!(e, a - b)),
-              hir::BiMul => Integral(math!(e, a * b)),
-              hir::BiDiv => Integral(math!(e, a / b)),
-              hir::BiRem => Integral(math!(e, a % b)),
-              hir::BiBitAnd => Integral(math!(e, a & b)),
-              hir::BiBitOr => Integral(math!(e, a | b)),
-              hir::BiBitXor => Integral(math!(e, a ^ b)),
-              hir::BiShl => Integral(math!(e, a << b)),
-              hir::BiShr => Integral(math!(e, a >> b)),
-              hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
-              hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
-              hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
-              hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
-              hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
-              hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
-              _ => span_bug!(e.span, "typeck error"),
-            }
-          }
-          (Bool(a), Bool(b)) => {
-            Bool(match op.node {
-              hir::BiAnd => a && b,
-              hir::BiOr => a || b,
-              hir::BiBitXor => a ^ b,
-              hir::BiBitAnd => a & b,
-              hir::BiBitOr => a | b,
-              hir::BiEq => a == b,
-              hir::BiNe => a != b,
-              hir::BiLt => a < b,
-              hir::BiLe => a <= b,
-              hir::BiGe => a >= b,
-              hir::BiGt => a > b,
-              _ => span_bug!(e.span, "typeck error"),
-             })
-          }
-          (Char(a), Char(b)) => {
-            Bool(match op.node {
-              hir::BiEq => a == b,
-              hir::BiNe => a != b,
-              hir::BiLt => a < b,
-              hir::BiLe => a <= b,
-              hir::BiGe => a >= b,
-              hir::BiGt => a > b,
-              _ => span_bug!(e.span, "typeck error"),
-             })
-          }
-
-          _ => signal!(e, MiscBinaryOp),
-        })
-      }
-      hir::ExprCast(ref base, _) => {
-        let base_val = cx.eval(base)?;
-        let base_ty = cx.tables.expr_ty(base).subst(tcx, cx.substs);
-        if ty == base_ty {
-            base_val
-        } else {
-            match cast_const(tcx, base_val.val, ty) {
-                Ok(val) => mk_const(val),
-                Err(kind) => signal!(e, kind),
-            }
-        }
-      }
-      hir::ExprPath(ref qpath) => {
-        let substs = cx.tables.node_substs(e.hir_id).subst(tcx, cx.substs);
-          match cx.tables.qpath_def(qpath, e.hir_id) {
-              Def::Const(def_id) |
-              Def::AssociatedConst(def_id) => {
-                    let substs = tcx.normalize_associated_type_in_env(&substs, cx.param_env);
-                    match tcx.at(e.span).const_eval(cx.param_env.and((def_id, substs))) {
-                        Ok(val) => val,
-                        Err(ConstEvalErr { kind: TypeckError, .. }) => {
-                            signal!(e, TypeckError);
-                        }
-                        Err(err) => {
-                            debug!("bad reference: {:?}, {:?}", err.description(), err.span);
-                            signal!(e, ErroneousReferencedConstant(box err))
-                        },
-                    }
-              },
-              Def::VariantCtor(variant_def, CtorKind::Const) => {
-                mk_const(Variant(variant_def))
-              }
-              Def::VariantCtor(_, CtorKind::Fn) => {
-                  signal!(e, UnimplementedConstVal("enum variants"));
-              }
-              Def::StructCtor(_, CtorKind::Const) => {
-                  mk_const(Aggregate(Struct(&[])))
-              }
-              Def::StructCtor(_, CtorKind::Fn) => {
-                  signal!(e, UnimplementedConstVal("tuple struct constructors"))
-              }
-              Def::Local(id) => {
-                  debug!("Def::Local({:?}): {:?}", id, cx.fn_args);
-                  if let Some(&val) = cx.fn_args.as_ref().and_then(|args| args.get(&id)) {
-                      val
-                  } else {
-                      signal!(e, NonConstPath);
-                  }
-              },
-              Def::Method(id) | Def::Fn(id) => mk_const(Function(id, substs)),
-              Def::Err => span_bug!(e.span, "typeck error"),
-              _ => signal!(e, NonConstPath),
-          }
-      }
-      hir::ExprCall(ref callee, ref args) => {
-          let (def_id, substs) = match cx.eval(callee)?.val {
-              Function(def_id, substs) => (def_id, substs),
-              _ => signal!(e, TypeckError),
-          };
-
-          if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic {
-            let layout_of = |ty: Ty<'tcx>| {
-                let ty = tcx.erase_regions(&ty);
-                tcx.at(e.span).layout_of(cx.param_env.and(ty)).map_err(|err| {
-                    ConstEvalErr { span: e.span, kind: LayoutError(err) }
-                })
-            };
-            match &tcx.item_name(def_id)[..] {
-                "size_of" => {
-                    let size = layout_of(substs.type_at(0))?.size.bytes();
-                    return Ok(mk_const(Integral(Usize(ConstUsize::new(size,
-                        tcx.sess.target.usize_ty).unwrap()))));
-                }
-                "min_align_of" => {
-                    let align = layout_of(substs.type_at(0))?.align.abi();
-                    return Ok(mk_const(Integral(Usize(ConstUsize::new(align,
-                        tcx.sess.target.usize_ty).unwrap()))));
-                }
-                "type_id" => {
-                    let type_id = tcx.type_id_hash(substs.type_at(0));
-                    return Ok(mk_const(Integral(U64(type_id))));
-                }
-                _ => signal!(e, TypeckError)
-            }
-          }
-
-          let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
-            if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
-                if fn_like.constness() == hir::Constness::Const {
-                    tcx.hir.body(fn_like.body())
-                } else {
-                    signal!(e, TypeckError)
-                }
-            } else {
-                signal!(e, TypeckError)
-            }
-          } else {
-            if tcx.is_const_fn(def_id) {
-                tcx.extern_const_body(def_id).body
-            } else {
-                signal!(e, TypeckError)
-            }
-          };
-
-          let arg_ids = body.arguments.iter().map(|arg| match arg.pat.node {
-               hir::PatKind::Binding(_, canonical_id, _, _) => Some(canonical_id),
-               _ => None
-           }).collect::<Vec<_>>();
-          assert_eq!(arg_ids.len(), args.len());
-
-          let mut call_args = NodeMap();
-          for (arg, arg_expr) in arg_ids.into_iter().zip(args.iter()) {
-              let arg_val = cx.eval(arg_expr)?;
-              debug!("const call arg: {:?}", arg);
-              if let Some(id) = arg {
-                assert!(call_args.insert(id, arg_val).is_none());
-              }
-          }
-          debug!("const call({:?})", call_args);
-          let callee_cx = ConstContext {
-            tcx,
-            param_env: cx.param_env,
-            tables: tcx.typeck_tables_of(def_id),
-            substs,
-            fn_args: Some(call_args)
-          };
-          callee_cx.eval(&body.value)?
-      },
-      hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty) {
-          Ok(val) => mk_const(val),
-          Err(err) => signal!(e, err),
-      },
-      hir::ExprBlock(ref block) => {
-        match block.expr {
-            Some(ref expr) => cx.eval(expr)?,
-            None => mk_const(Aggregate(Tuple(&[]))),
-        }
-      }
-      hir::ExprType(ref e, _) => cx.eval(e)?,
-      hir::ExprTup(ref fields) => {
-        let values = fields.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
-        mk_const(Aggregate(Tuple(tcx.alloc_const_slice(&values))))
-      }
-      hir::ExprStruct(_, ref fields, _) => {
-        mk_const(Aggregate(Struct(tcx.alloc_name_const_slice(&fields.iter().map(|f| {
-            cx.eval(&f.expr).map(|v| (f.name.node, v))
-        }).collect::<Result<Vec<_>, _>>()?))))
-      }
-      hir::ExprIndex(ref arr, ref idx) => {
-        if !tcx.features().const_indexing {
-            signal!(e, IndexOpFeatureGated);
-        }
-        let arr = cx.eval(arr)?;
-        let idx = match cx.eval(idx)?.val {
-            Integral(Usize(i)) => i.as_u64(),
-            _ => signal!(idx, IndexNotUsize),
-        };
-        assert_eq!(idx as usize as u64, idx);
-        match arr.val {
-            Aggregate(Array(v)) => {
-                if let Some(&elem) = v.get(idx as usize) {
-                    elem
-                } else {
-                    let n = v.len() as u64;
-                    signal!(e, IndexOutOfBounds { len: n, index: idx })
-                }
-            }
-
-            Aggregate(Repeat(.., n)) if idx >= n => {
-                signal!(e, IndexOutOfBounds { len: n, index: idx })
-            }
-            Aggregate(Repeat(elem, _)) => elem,
-
-            ByteStr(b) if idx >= b.data.len() as u64 => {
-                signal!(e, IndexOutOfBounds { len: b.data.len() as u64, index: idx })
-            }
-            ByteStr(b) => {
-                mk_const(Integral(U8(b.data[idx as usize])))
-            },
-
-            _ => signal!(e, IndexedNonVec),
-        }
-      }
-      hir::ExprArray(ref v) => {
-        let values = v.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
-        mk_const(Aggregate(Array(tcx.alloc_const_slice(&values))))
-      }
-      hir::ExprRepeat(ref elem, _) => {
-          let n = match ty.sty {
-            ty::TyArray(_, n) => n.val.to_const_int().unwrap().to_u64().unwrap(),
-            _ => span_bug!(e.span, "typeck error")
-          };
-          mk_const(Aggregate(Repeat(cx.eval(elem)?, n)))
-      },
-      hir::ExprTupField(ref base, index) => {
-        if let Aggregate(Tuple(fields)) = cx.eval(base)?.val {
-            fields[index.node]
-        } else {
-            signal!(base, ExpectedConstTuple);
-        }
-      }
-      hir::ExprField(ref base, field_name) => {
-        if let Aggregate(Struct(fields)) = cx.eval(base)?.val {
-            if let Some(&(_, f)) = fields.iter().find(|&&(name, _)| name == field_name.node) {
-                f
-            } else {
-                signal!(e, MissingStructField);
-            }
-        } else {
-            signal!(base, ExpectedConstStruct);
-        }
-      }
-      hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),
-      _ => signal!(e, MiscCatchAll)
-    };
-
-    Ok(result)
-}
-
-fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            val: ConstInt,
-                            ty: Ty<'tcx>)
-                            -> CastResult<'tcx> {
-    let v = val.to_u128_unchecked();
-    match ty.sty {
-        ty::TyBool if v == 0 => Ok(Bool(false)),
-        ty::TyBool if v == 1 => Ok(Bool(true)),
-        ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i128 as i8))),
-        ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i128 as i16))),
-        ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i128 as i32))),
-        ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))),
-        ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))),
-        ty::TyInt(ast::IntTy::Isize) => {
-            Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.isize_ty))))
-        },
-        ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
-        ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
-        ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
-        ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
-        ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))),
-        ty::TyUint(ast::UintTy::Usize) => {
-            Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.usize_ty))))
-        },
-        ty::TyFloat(fty) => {
-            if let Some(i) = val.to_u128() {
-                Ok(Float(ConstFloat::from_u128(i, fty)))
-            } else {
-                // The value must be negative, go through signed integers.
-                let i = val.to_u128_unchecked() as i128;
-                Ok(Float(ConstFloat::from_i128(i, fty)))
-            }
-        }
-        ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
-        ty::TyChar => match val {
-            U8(u) => Ok(Char(u as char)),
-            _ => bug!(),
-        },
-        _ => Err(CannotCast),
-    }
-}
-
-fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                              val: ConstFloat,
-                              ty: Ty<'tcx>) -> CastResult<'tcx> {
-    let int_width = |ty| {
-        ty::layout::Integer::from_attr(tcx, ty).size().bits() as usize
-    };
-    match ty.sty {
-        ty::TyInt(ity) => {
-            if let Some(i) = val.to_i128(int_width(attr::SignedInt(ity))) {
-                cast_const_int(tcx, I128(i), ty)
-            } else {
-                Err(CannotCast)
-            }
-        }
-        ty::TyUint(uty) => {
-            if let Some(i) = val.to_u128(int_width(attr::UnsignedInt(uty))) {
-                cast_const_int(tcx, U128(i), ty)
-            } else {
-                Err(CannotCast)
-            }
-        }
-        ty::TyFloat(fty) => Ok(Float(val.convert(fty))),
-        _ => Err(CannotCast),
-    }
-}
-
-fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                        val: ConstVal<'tcx>,
-                        ty: Ty<'tcx>)
-                        -> CastResult<'tcx> {
-    match val {
-        Integral(i) => cast_const_int(tcx, i, ty),
-        Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
-        Float(f) => cast_const_float(tcx, f, ty),
-        Char(c) => cast_const_int(tcx, U32(c as u32), ty),
-        Variant(v) => {
-            let adt = tcx.adt_def(tcx.parent_def_id(v).unwrap());
-            let idx = adt.variant_index_with_id(v);
-            cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty)
-        }
-        Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
-        ByteStr(b) => match ty.sty {
-            ty::TyRawPtr(_) => {
-                Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
-            },
-            ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
-                ty::TyArray(ty, n) => {
-                    let n = n.val.to_const_int().unwrap().to_u64().unwrap();
-                    if ty == tcx.types.u8 && n == b.data.len() as u64 {
-                        Ok(val)
-                    } else {
-                        Err(CannotCast)
-                    }
-                }
-                ty::TySlice(_) => {
-                    Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
-                },
-                _ => Err(CannotCast),
-            },
-            _ => Err(CannotCast),
-        },
-        Str(s) => match ty.sty {
-            ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
-            ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
-                ty::TyStr => Ok(Str(s)),
-                _ => Err(CannotCast),
-            },
-            _ => Err(CannotCast),
-        },
-        _ => Err(CannotCast),
-    }
-}
-
-fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
-                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          mut ty: Ty<'tcx>)
-                          -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
-    use syntax::ast::*;
-    use syntax::ast::LitIntType::*;
-
-    if let ty::TyAdt(adt, _) = ty.sty {
-        if adt.is_enum() {
-            ty = adt.repr.discr_type().to_ty(tcx)
-        }
-    }
-
-    match *lit {
-        LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
-        LitKind::ByteStr(ref data) => Ok(ByteStr(ByteArray { data })),
-        LitKind::Byte(n) => Ok(Integral(U8(n))),
-        LitKind::Int(n, hint) => {
-            match (&ty.sty, hint) {
-                (&ty::TyInt(ity), _) |
-                (_, Signed(ity)) => {
-                    Ok(Integral(ConstInt::new_signed_truncating(n as i128,
-                        ity, tcx.sess.target.isize_ty)))
-                }
-                (&ty::TyUint(uty), _) |
-                (_, Unsigned(uty)) => {
-                    Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
-                        uty, tcx.sess.target.usize_ty)))
-                }
-                _ => bug!()
-            }
-        }
-        LitKind::Float(n, fty) => {
-            parse_float(&n.as_str(), fty).map(Float)
-        }
-        LitKind::FloatUnsuffixed(n) => {
-            let fty = match ty.sty {
-                ty::TyFloat(fty) => fty,
-                _ => bug!()
-            };
-            parse_float(&n.as_str(), fty).map(Float)
-        }
-        LitKind::Bool(b) => Ok(Bool(b)),
-        LitKind::Char(c) => Ok(Char(c)),
-    }
-}
-
-fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
-                     -> Result<ConstFloat, ErrKind<'tcx>> {
-    ConstFloat::from_str(num, fty).map_err(|_| {
-        // FIXME(#31407) this is only necessary because float parsing is buggy
-        UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
-    })
-}
-
-pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
-                          -> Result<Ordering, ErrorReported>
-{
-    let result = match (a, b) {
-        (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
-        (&Float(a), &Float(b)) => a.try_cmp(b).ok(),
-        (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
-        (&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
-        (&ByteStr(a), &ByteStr(b)) => Some(a.data.cmp(b.data)),
-        (&Char(a), &Char(b)) => Some(a.cmp(&b)),
-        _ => None,
-    };
-
-    match result {
-        Some(result) => Ok(result),
-        None => {
-            // FIXME: can this ever be reached?
-            tcx.sess.delay_span_bug(span,
-                &format!("type mismatch comparing {:?} and {:?}", a, b));
-            Err(ErrorReported)
-        }
-    }
-}
-
-impl<'a, 'tcx> ConstContext<'a, 'tcx> {
-    pub fn compare_lit_exprs(&self,
-                             span: Span,
-                             a: &'tcx Expr,
-                             b: &'tcx Expr) -> Result<Ordering, ErrorReported> {
-        let tcx = self.tcx;
-        let a = match self.eval(a) {
-            Ok(a) => a,
-            Err(e) => {
-                e.report(tcx, a.span, "expression");
-                return Err(ErrorReported);
-            }
-        };
-        let b = match self.eval(b) {
-            Ok(b) => b,
-            Err(e) => {
-                e.report(tcx, b.span, "expression");
-                return Err(ErrorReported);
-            }
-        };
-        compare_const_vals(tcx, span, &a.val, &b.val)
-    }
-}
diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs
deleted file mode 100644
index 4ec27d7ade560..0000000000000
--- a/src/librustc_const_math/int.rs
+++ /dev/null
@@ -1,590 +0,0 @@
-// Copyright 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 std::cmp::Ordering;
-use syntax::attr::IntType;
-use syntax::ast::{IntTy, UintTy};
-
-use super::isize::*;
-use super::usize::*;
-use super::err::*;
-
-#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
-pub enum ConstInt {
-    I8(i8),
-    I16(i16),
-    I32(i32),
-    I64(i64),
-    I128(i128),
-    Isize(ConstIsize),
-    U8(u8),
-    U16(u16),
-    U32(u32),
-    U64(u64),
-    U128(u128),
-    Usize(ConstUsize),
-}
-pub use self::ConstInt::*;
-
-
-macro_rules! bounds {
-    ($ct: ty, $($t:ident $min:ident $max:ident)*) => {
-        $(
-            pub const $min: $ct = $t::min_value() as $ct;
-            pub const $max: $ct = $t::max_value() as $ct;
-        )*
-    };
-    ($ct: ty: $min_val: expr, $($t:ident $min:ident $max:ident)*) => {
-        $(
-            pub const $min: $ct = $min_val;
-            pub const $max: $ct = $t::max_value() as $ct;
-        )*
-    }
-}
-
-mod ubounds {
-    #![allow(dead_code)]
-    bounds!{u128: 0,
-        i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX
-        u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX u128 U128MIN U128MAX
-        // do not add constants for isize/usize, because these are guaranteed to be wrong for
-        // arbitrary host/target combinations
-    }
-}
-
-mod ibounds {
-    #![allow(dead_code)]
-    bounds!(i128, u64 U64MIN U64MAX);
-
-    pub const U128MIN: i128 = 0;
-    pub const U128MAX: i128 = i128::max_value();
-
-    bounds!{i128,
-        i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX
-        u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX
-        // do not add constants for isize/usize, because these are guaranteed to be wrong for
-        // arbitrary host/target combinations
-    }
-}
-
-impl ConstInt {
-    /// Creates a new unsigned ConstInt with matching type while also checking that overflow does
-    /// not happen.
-    pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> {
-        match ty {
-            UintTy::U8 if val <= ubounds::U8MAX => Some(U8(val as u8)),
-            UintTy::U16 if val <= ubounds::U16MAX => Some(U16(val as u16)),
-            UintTy::U32 if val <= ubounds::U32MAX => Some(U32(val as u32)),
-            UintTy::U64 if val <= ubounds::U64MAX => Some(U64(val as u64)),
-            UintTy::Usize if val <= ubounds::U64MAX => ConstUsize::new(val as u64, usize_ty).ok()
-                .map(Usize),
-            UintTy::U128 => Some(U128(val)),
-            _ => None
-        }
-    }
-
-    /// Creates a new signed ConstInt with matching type while also checking that overflow does
-    /// not happen.
-    pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option<ConstInt> {
-        match ty {
-            IntTy::I8 if val <= ibounds::I8MAX => Some(I8(val as i8)),
-            IntTy::I16 if val <= ibounds::I16MAX => Some(I16(val as i16)),
-            IntTy::I32 if val <= ibounds::I32MAX => Some(I32(val as i32)),
-            IntTy::I64 if val <= ibounds::I64MAX => Some(I64(val as i64)),
-            IntTy::Isize if val <= ibounds::I64MAX => ConstIsize::new(val as i64, isize_ty).ok()
-                .map(Isize),
-            IntTy::I128 => Some(I128(val)),
-            _ => None
-        }
-    }
-
-    /// Creates a new unsigned ConstInt with matching type.
-    pub fn new_unsigned_truncating(val: u128, ty: UintTy, usize_ty: UintTy) -> ConstInt {
-        match ty {
-            UintTy::U8 => U8(val as u8),
-            UintTy::U16 => U16(val as u16),
-            UintTy::U32 => U32(val as u32),
-            UintTy::U64 => U64(val as u64),
-            UintTy::Usize => Usize(ConstUsize::new_truncating(val, usize_ty)),
-            UintTy::U128 => U128(val)
-        }
-    }
-
-    /// Creates a new signed ConstInt with matching type.
-    pub fn new_signed_truncating(val: i128, ty: IntTy, isize_ty: IntTy) -> ConstInt {
-        match ty {
-            IntTy::I8 => I8(val as i8),
-            IntTy::I16 => I16(val as i16),
-            IntTy::I32 => I32(val as i32),
-            IntTy::I64 => I64(val as i64),
-            IntTy::Isize => Isize(ConstIsize::new_truncating(val, isize_ty)),
-            IntTy::I128 => I128(val)
-        }
-    }
-
-    /// Description of the type, not the value
-    pub fn description(&self) -> &'static str {
-        match *self {
-            I8(_) => "i8",
-            I16(_) => "i16",
-            I32(_) => "i32",
-            I64(_) => "i64",
-            I128(_) => "i128",
-            Isize(_) => "isize",
-            U8(_) => "u8",
-            U16(_) => "u16",
-            U32(_) => "u32",
-            U64(_) => "u64",
-            U128(_) => "u128",
-            Usize(_) => "usize",
-        }
-    }
-
-    /// Erases the type and returns a u128.
-    /// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128`
-    pub fn to_u128_unchecked(self) -> u128 {
-        match self {
-            I8(i) => i as i128 as u128,
-            I16(i) => i as i128 as u128,
-            I32(i) => i as i128 as u128,
-            I64(i) => i as i128 as u128,
-            I128(i) => i as i128 as u128,
-            Isize(Is16(i)) => i as i128 as u128,
-            Isize(Is32(i)) => i as i128 as u128,
-            Isize(Is64(i)) => i as i128 as u128,
-            U8(i) => i as u128,
-            U16(i) => i as u128,
-            U32(i) => i as u128,
-            U64(i) => i as u128,
-            U128(i) => i as u128,
-            Usize(Us16(i)) => i as u128,
-            Usize(Us32(i)) => i as u128,
-            Usize(Us64(i)) => i as u128,
-        }
-    }
-
-    /// Converts the value to a `u32` if it's in the range 0...std::u32::MAX
-    pub fn to_u32(&self) -> Option<u32> {
-        self.to_u128().and_then(|v| if v <= u32::max_value() as u128 {
-            Some(v as u32)
-        } else {
-            None
-        })
-    }
-
-    /// Converts the value to a `u64` if it's in the range 0...std::u64::MAX
-    pub fn to_u64(&self) -> Option<u64> {
-        self.to_u128().and_then(|v| if v <= u64::max_value() as u128 {
-            Some(v as u64)
-        } else {
-            None
-        })
-    }
-
-    /// Converts the value to a `u128` if it's in the range 0...std::u128::MAX
-    pub fn to_u128(&self) -> Option<u128> {
-        match *self {
-            I8(v) if v >= 0 => Some(v as u128),
-            I16(v) if v >= 0 => Some(v as u128),
-            I32(v) if v >= 0 => Some(v as u128),
-            I64(v) if v >= 0 => Some(v as u128),
-            I128(v) if v >= 0 => Some(v as u128),
-            Isize(Is16(v)) if v >= 0 => Some(v as u128),
-            Isize(Is32(v)) if v >= 0 => Some(v as u128),
-            Isize(Is64(v)) if v >= 0 => Some(v as u128),
-            U8(v) => Some(v as u128),
-            U16(v) => Some(v as u128),
-            U32(v) => Some(v as u128),
-            U64(v) => Some(v as u128),
-            U128(v) => Some(v as u128),
-            Usize(Us16(v)) => Some(v as u128),
-            Usize(Us32(v)) => Some(v as u128),
-            Usize(Us64(v)) => Some(v as u128),
-            _ => None,
-        }
-    }
-
-    pub fn is_negative(&self) -> bool {
-        match *self {
-            I8(v) => v < 0,
-            I16(v) => v < 0,
-            I32(v) => v < 0,
-            I64(v) => v < 0,
-            I128(v) => v < 0,
-            Isize(Is16(v)) => v < 0,
-            Isize(Is32(v)) => v < 0,
-            Isize(Is64(v)) => v < 0,
-            _ => false,
-        }
-    }
-
-    /// Compares the values if they are of the same type
-    pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
-        match (self, rhs) {
-            (I8(a), I8(b)) => Ok(a.cmp(&b)),
-            (I16(a), I16(b)) => Ok(a.cmp(&b)),
-            (I32(a), I32(b)) => Ok(a.cmp(&b)),
-            (I64(a), I64(b)) => Ok(a.cmp(&b)),
-            (I128(a), I128(b)) => Ok(a.cmp(&b)),
-            (Isize(Is16(a)), Isize(Is16(b))) => Ok(a.cmp(&b)),
-            (Isize(Is32(a)), Isize(Is32(b))) => Ok(a.cmp(&b)),
-            (Isize(Is64(a)), Isize(Is64(b))) => Ok(a.cmp(&b)),
-            (U8(a), U8(b)) => Ok(a.cmp(&b)),
-            (U16(a), U16(b)) => Ok(a.cmp(&b)),
-            (U32(a), U32(b)) => Ok(a.cmp(&b)),
-            (U64(a), U64(b)) => Ok(a.cmp(&b)),
-            (U128(a), U128(b)) => Ok(a.cmp(&b)),
-            (Usize(Us16(a)), Usize(Us16(b))) => Ok(a.cmp(&b)),
-            (Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)),
-            (Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)),
-            _ => Err(CmpBetweenUnequalTypes),
-        }
-    }
-
-    /// Adds 1 to the value and wraps around if the maximum for the type is reached
-    pub fn wrap_incr(self) -> Self {
-        macro_rules! add1 {
-            ($e:expr) => { ($e).wrapping_add(1) }
-        }
-        match self {
-            ConstInt::I8(i) => ConstInt::I8(add1!(i)),
-            ConstInt::I16(i) => ConstInt::I16(add1!(i)),
-            ConstInt::I32(i) => ConstInt::I32(add1!(i)),
-            ConstInt::I64(i) => ConstInt::I64(add1!(i)),
-            ConstInt::I128(i) => ConstInt::I128(add1!(i)),
-            ConstInt::Isize(ConstIsize::Is16(i)) => ConstInt::Isize(ConstIsize::Is16(add1!(i))),
-            ConstInt::Isize(ConstIsize::Is32(i)) => ConstInt::Isize(ConstIsize::Is32(add1!(i))),
-            ConstInt::Isize(ConstIsize::Is64(i)) => ConstInt::Isize(ConstIsize::Is64(add1!(i))),
-            ConstInt::U8(i) => ConstInt::U8(add1!(i)),
-            ConstInt::U16(i) => ConstInt::U16(add1!(i)),
-            ConstInt::U32(i) => ConstInt::U32(add1!(i)),
-            ConstInt::U64(i) => ConstInt::U64(add1!(i)),
-            ConstInt::U128(i) => ConstInt::U128(add1!(i)),
-            ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))),
-            ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))),
-            ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))),
-        }
-    }
-
-    pub fn int_type(self) -> IntType {
-        match self {
-            ConstInt::I8(_) => IntType::SignedInt(IntTy::I8),
-            ConstInt::I16(_) => IntType::SignedInt(IntTy::I16),
-            ConstInt::I32(_) => IntType::SignedInt(IntTy::I32),
-            ConstInt::I64(_) => IntType::SignedInt(IntTy::I64),
-            ConstInt::I128(_) => IntType::SignedInt(IntTy::I128),
-            ConstInt::Isize(_) => IntType::SignedInt(IntTy::Isize),
-            ConstInt::U8(_) => IntType::UnsignedInt(UintTy::U8),
-            ConstInt::U16(_) => IntType::UnsignedInt(UintTy::U16),
-            ConstInt::U32(_) => IntType::UnsignedInt(UintTy::U32),
-            ConstInt::U64(_) => IntType::UnsignedInt(UintTy::U64),
-            ConstInt::U128(_) => IntType::UnsignedInt(UintTy::U128),
-            ConstInt::Usize(_) => IntType::UnsignedInt(UintTy::Usize),
-        }
-    }
-}
-
-impl ::std::cmp::PartialOrd for ConstInt {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        self.try_cmp(*other).ok()
-    }
-}
-
-impl ::std::cmp::Ord for ConstInt {
-    fn cmp(&self, other: &Self) -> Ordering {
-        self.try_cmp(*other).unwrap()
-    }
-}
-
-impl ::std::fmt::Display for ConstInt {
-    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
-        match *self {
-            I8(i) => write!(fmt, "{}i8", i),
-            I16(i) => write!(fmt, "{}i16", i),
-            I32(i) => write!(fmt, "{}i32", i),
-            I64(i) => write!(fmt, "{}i64", i),
-            I128(i) => write!(fmt, "{}i128", i),
-            Isize(i) => write!(fmt, "{}isize", i),
-            U8(i) => write!(fmt, "{}u8", i),
-            U16(i) => write!(fmt, "{}u16", i),
-            U32(i) => write!(fmt, "{}u32", i),
-            U64(i) => write!(fmt, "{}u64", i),
-            U128(i) => write!(fmt, "{}u128", i),
-            Usize(i) => write!(fmt, "{}usize", i),
-        }
-    }
-}
-
-macro_rules! overflowing {
-    ($e:expr, $err:expr) => {{
-        if $e.1 {
-            return Err(Overflow($err));
-        } else {
-            $e.0
-        }
-    }}
-}
-
-macro_rules! impl_binop {
-    ($op:ident, $func:ident, $checked_func:ident) => {
-        impl ::std::ops::$op for ConstInt {
-            type Output = Result<Self, ConstMathErr>;
-            fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
-                match (self, rhs) {
-                    (I8(a), I8(b)) => a.$checked_func(b).map(I8),
-                    (I16(a), I16(b)) => a.$checked_func(b).map(I16),
-                    (I32(a), I32(b)) => a.$checked_func(b).map(I32),
-                    (I64(a), I64(b)) => a.$checked_func(b).map(I64),
-                    (I128(a), I128(b)) => a.$checked_func(b).map(I128),
-                    (Isize(Is16(a)), Isize(Is16(b))) => a.$checked_func(b).map(Is16).map(Isize),
-                    (Isize(Is32(a)), Isize(Is32(b))) => a.$checked_func(b).map(Is32).map(Isize),
-                    (Isize(Is64(a)), Isize(Is64(b))) => a.$checked_func(b).map(Is64).map(Isize),
-                    (U8(a), U8(b)) => a.$checked_func(b).map(U8),
-                    (U16(a), U16(b)) => a.$checked_func(b).map(U16),
-                    (U32(a), U32(b)) => a.$checked_func(b).map(U32),
-                    (U64(a), U64(b)) => a.$checked_func(b).map(U64),
-                    (U128(a), U128(b)) => a.$checked_func(b).map(U128),
-                    (Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize),
-                    (Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize),
-                    (Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize),
-                    _ => return Err(UnequalTypes(Op::$op)),
-                }.ok_or(Overflow(Op::$op))
-            }
-        }
-    }
-}
-
-macro_rules! derive_binop {
-    ($op:ident, $func:ident) => {
-        impl ::std::ops::$op for ConstInt {
-            type Output = Result<Self, ConstMathErr>;
-            fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
-                match (self, rhs) {
-                    (I8(a), I8(b)) => Ok(I8(a.$func(b))),
-                    (I16(a), I16(b)) => Ok(I16(a.$func(b))),
-                    (I32(a), I32(b)) => Ok(I32(a.$func(b))),
-                    (I64(a), I64(b)) => Ok(I64(a.$func(b))),
-                    (I128(a), I128(b)) => Ok(I128(a.$func(b))),
-                    (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a.$func(b)))),
-                    (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a.$func(b)))),
-                    (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a.$func(b)))),
-                    (U8(a), U8(b)) => Ok(U8(a.$func(b))),
-                    (U16(a), U16(b)) => Ok(U16(a.$func(b))),
-                    (U32(a), U32(b)) => Ok(U32(a.$func(b))),
-                    (U64(a), U64(b)) => Ok(U64(a.$func(b))),
-                    (U128(a), U128(b)) => Ok(U128(a.$func(b))),
-                    (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a.$func(b)))),
-                    (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))),
-                    (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))),
-                    _ => Err(UnequalTypes(Op::$op)),
-                }
-            }
-        }
-    }
-}
-
-impl_binop!(Add, add, checked_add);
-impl_binop!(Sub, sub, checked_sub);
-impl_binop!(Mul, mul, checked_mul);
-derive_binop!(BitAnd, bitand);
-derive_binop!(BitOr, bitor);
-derive_binop!(BitXor, bitxor);
-
-const I128_MIN: i128 = ::std::i128::MIN;
-
-fn check_division(
-    lhs: ConstInt,
-    rhs: ConstInt,
-    op: Op,
-    zerr: ConstMathErr,
-) -> Result<(), ConstMathErr> {
-    match (lhs, rhs) {
-        (I8(_), I8(0)) => Err(zerr),
-        (I16(_), I16(0)) => Err(zerr),
-        (I32(_), I32(0)) => Err(zerr),
-        (I64(_), I64(0)) => Err(zerr),
-        (I128(_), I128(0)) => Err(zerr),
-        (Isize(_), Isize(Is16(0))) => Err(zerr),
-        (Isize(_), Isize(Is32(0))) => Err(zerr),
-        (Isize(_), Isize(Is64(0))) => Err(zerr),
-
-        (U8(_), U8(0)) => Err(zerr),
-        (U16(_), U16(0)) => Err(zerr),
-        (U32(_), U32(0)) => Err(zerr),
-        (U64(_), U64(0)) => Err(zerr),
-        (U128(_), U128(0)) => Err(zerr),
-        (Usize(_), Usize(Us16(0))) => Err(zerr),
-        (Usize(_), Usize(Us32(0))) => Err(zerr),
-        (Usize(_), Usize(Us64(0))) => Err(zerr),
-
-        (I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)),
-        (I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)),
-        (I32(::std::i32::MIN), I32(-1)) => Err(Overflow(op)),
-        (I64(::std::i64::MIN), I64(-1)) => Err(Overflow(op)),
-        (I128(I128_MIN), I128(-1)) => Err(Overflow(op)),
-        (Isize(Is16(::std::i16::MIN)), Isize(Is16(-1))) => Err(Overflow(op)),
-        (Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)),
-        (Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)),
-
-        _ => Ok(()),
-    }
-}
-
-impl ::std::ops::Div for ConstInt {
-    type Output = Result<Self, ConstMathErr>;
-    fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
-        let (lhs, rhs) = (self, rhs);
-        check_division(lhs, rhs, Op::Div, DivisionByZero)?;
-        match (lhs, rhs) {
-            (I8(a), I8(b)) => Ok(I8(a/b)),
-            (I16(a), I16(b)) => Ok(I16(a/b)),
-            (I32(a), I32(b)) => Ok(I32(a/b)),
-            (I64(a), I64(b)) => Ok(I64(a/b)),
-            (I128(a), I128(b)) => Ok(I128(a/b)),
-            (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))),
-            (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))),
-            (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))),
-
-            (U8(a), U8(b)) => Ok(U8(a/b)),
-            (U16(a), U16(b)) => Ok(U16(a/b)),
-            (U32(a), U32(b)) => Ok(U32(a/b)),
-            (U64(a), U64(b)) => Ok(U64(a/b)),
-            (U128(a), U128(b)) => Ok(U128(a/b)),
-            (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))),
-            (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))),
-            (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))),
-
-            _ => Err(UnequalTypes(Op::Div)),
-        }
-    }
-}
-
-impl ::std::ops::Rem for ConstInt {
-    type Output = Result<Self, ConstMathErr>;
-    fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
-        let (lhs, rhs) = (self, rhs);
-        // should INT_MIN%-1 be zero or an error?
-        check_division(lhs, rhs, Op::Rem, RemainderByZero)?;
-        match (lhs, rhs) {
-            (I8(a), I8(b)) => Ok(I8(a%b)),
-            (I16(a), I16(b)) => Ok(I16(a%b)),
-            (I32(a), I32(b)) => Ok(I32(a%b)),
-            (I64(a), I64(b)) => Ok(I64(a%b)),
-            (I128(a), I128(b)) => Ok(I128(a%b)),
-            (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))),
-            (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))),
-            (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))),
-
-            (U8(a), U8(b)) => Ok(U8(a%b)),
-            (U16(a), U16(b)) => Ok(U16(a%b)),
-            (U32(a), U32(b)) => Ok(U32(a%b)),
-            (U64(a), U64(b)) => Ok(U64(a%b)),
-            (U128(a), U128(b)) => Ok(U128(a%b)),
-            (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))),
-            (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))),
-            (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))),
-
-            _ => Err(UnequalTypes(Op::Rem)),
-        }
-    }
-}
-
-impl ::std::ops::Shl<ConstInt> for ConstInt {
-    type Output = Result<Self, ConstMathErr>;
-    fn shl(self, rhs: Self) -> Result<Self, ConstMathErr> {
-        let b = rhs.to_u32().ok_or(ShiftNegative)?;
-        match self {
-            I8(a) => Ok(I8(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            I16(a) => Ok(I16(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            I32(a) => Ok(I32(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            I64(a) => Ok(I64(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            I128(a) => Ok(I128(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shl(b), Op::Shl)))),
-            Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
-            Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
-            U8(a) => Ok(U8(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            U16(a) => Ok(U16(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            U32(a) => Ok(U32(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            U64(a) => Ok(U64(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            U128(a) => Ok(U128(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shl(b), Op::Shl)))),
-            Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
-            Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
-        }
-    }
-}
-
-impl ::std::ops::Shr<ConstInt> for ConstInt {
-    type Output = Result<Self, ConstMathErr>;
-    fn shr(self, rhs: Self) -> Result<Self, ConstMathErr> {
-        let b = rhs.to_u32().ok_or(ShiftNegative)?;
-        match self {
-            I8(a) => Ok(I8(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            I16(a) => Ok(I16(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            I32(a) => Ok(I32(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            I64(a) => Ok(I64(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            I128(a) => Ok(I128(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shr(b), Op::Shr)))),
-            Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
-            Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
-            U8(a) => Ok(U8(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            U16(a) => Ok(U16(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            U32(a) => Ok(U32(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            U64(a) => Ok(U64(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            U128(a) => Ok(U128(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shr(b), Op::Shr)))),
-            Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
-            Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
-        }
-    }
-}
-
-impl ::std::ops::Neg for ConstInt {
-    type Output = Result<Self, ConstMathErr>;
-    fn neg(self) -> Result<Self, ConstMathErr> {
-        match self {
-            I8(a) => Ok(I8(overflowing!(a.overflowing_neg(), Op::Neg))),
-            I16(a) => Ok(I16(overflowing!(a.overflowing_neg(), Op::Neg))),
-            I32(a) => Ok(I32(overflowing!(a.overflowing_neg(), Op::Neg))),
-            I64(a) => Ok(I64(overflowing!(a.overflowing_neg(), Op::Neg))),
-            I128(a) => Ok(I128(overflowing!(a.overflowing_neg(), Op::Neg))),
-            Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_neg(), Op::Neg)))),
-            Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_neg(), Op::Neg)))),
-            Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_neg(), Op::Neg)))),
-            a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) |
-            a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a),
-            U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation),
-        }
-    }
-}
-
-impl ::std::ops::Not for ConstInt {
-    type Output = Result<Self, ConstMathErr>;
-    fn not(self) -> Result<Self, ConstMathErr> {
-        match self {
-            I8(a) => Ok(I8(!a)),
-            I16(a) => Ok(I16(!a)),
-            I32(a) => Ok(I32(!a)),
-            I64(a) => Ok(I64(!a)),
-            I128(a) => Ok(I128(!a)),
-            Isize(Is16(a)) => Ok(Isize(Is16(!a))),
-            Isize(Is32(a)) => Ok(Isize(Is32(!a))),
-            Isize(Is64(a)) => Ok(Isize(Is64(!a))),
-            U8(a) => Ok(U8(!a)),
-            U16(a) => Ok(U16(!a)),
-            U32(a) => Ok(U32(!a)),
-            U64(a) => Ok(U64(!a)),
-            U128(a) => Ok(U128(!a)),
-            Usize(Us16(a)) => Ok(Usize(Us16(!a))),
-            Usize(Us32(a)) => Ok(Usize(Us32(!a))),
-            Usize(Us64(a)) => Ok(Usize(Us64(!a))),
-        }
-    }
-}
diff --git a/src/librustc_const_math/isize.rs b/src/librustc_const_math/isize.rs
deleted file mode 100644
index 18acc782775d8..0000000000000
--- a/src/librustc_const_math/isize.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 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 syntax::ast;
-use super::err::*;
-
-/// Depending on the target only one variant is ever used in a compilation.
-/// Anything else is an error. This invariant is checked at several locations
-#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
-pub enum ConstIsize {
-    Is16(i16),
-    Is32(i32),
-    Is64(i64),
-}
-pub use self::ConstIsize::*;
-
-impl ::std::fmt::Display for ConstIsize {
-    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
-        write!(fmt, "{}", self.as_i64())
-    }
-}
-
-impl ConstIsize {
-    pub fn as_i64(self) -> i64 {
-        match self {
-            Is16(i) => i as i64,
-            Is32(i) => i as i64,
-            Is64(i) => i,
-        }
-    }
-    pub fn new(i: i64, isize_ty: ast::IntTy) -> Result<Self, ConstMathErr> {
-        match isize_ty {
-            ast::IntTy::I16 if i as i16 as i64 == i => Ok(Is16(i as i16)),
-            ast::IntTy::I16 => Err(LitOutOfRange(ast::IntTy::Isize)),
-            ast::IntTy::I32 if i as i32 as i64 == i => Ok(Is32(i as i32)),
-            ast::IntTy::I32 => Err(LitOutOfRange(ast::IntTy::Isize)),
-            ast::IntTy::I64 => Ok(Is64(i)),
-            _ => unreachable!(),
-        }
-    }
-    pub fn new_truncating(i: i128, isize_ty: ast::IntTy) -> Self {
-        match isize_ty {
-            ast::IntTy::I16 => Is16(i as i16),
-            ast::IntTy::I32 => Is32(i as i32),
-            ast::IntTy::I64 => Is64(i as i64),
-            _ => unreachable!(),
-        }
-    }
-}
diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs
index 2d98bc48d2816..5555e727a9552 100644
--- a/src/librustc_const_math/lib.rs
+++ b/src/librustc_const_math/lib.rs
@@ -29,13 +29,7 @@ extern crate syntax;
 extern crate serialize as rustc_serialize; // used by deriving
 
 mod float;
-mod int;
-mod usize;
-mod isize;
 mod err;
 
 pub use float::*;
-pub use int::*;
-pub use usize::*;
-pub use isize::*;
 pub use err::{ConstMathErr, Op};
diff --git a/src/librustc_const_math/usize.rs b/src/librustc_const_math/usize.rs
deleted file mode 100644
index 56995f08f05b8..0000000000000
--- a/src/librustc_const_math/usize.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 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 syntax::ast;
-use super::err::*;
-
-/// Depending on the target only one variant is ever used in a compilation.
-/// Anything else is an error. This invariant is checked at several locations
-#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
-pub enum ConstUsize {
-    Us16(u16),
-    Us32(u32),
-    Us64(u64),
-}
-pub use self::ConstUsize::*;
-
-impl ::std::fmt::Display for ConstUsize {
-    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
-        write!(fmt, "{}", self.as_u64())
-    }
-}
-
-impl ConstUsize {
-    pub fn as_u64(self) -> u64 {
-        match self {
-            Us16(i) => i as u64,
-            Us32(i) => i as u64,
-            Us64(i) => i,
-        }
-    }
-    pub fn new(i: u64, usize_ty: ast::UintTy) -> Result<Self, ConstMathErr> {
-        match usize_ty {
-            ast::UintTy::U16 if i as u16 as u64 == i => Ok(Us16(i as u16)),
-            ast::UintTy::U16 => Err(ULitOutOfRange(ast::UintTy::Usize)),
-            ast::UintTy::U32 if i as u32 as u64 == i => Ok(Us32(i as u32)),
-            ast::UintTy::U32 => Err(ULitOutOfRange(ast::UintTy::Usize)),
-            ast::UintTy::U64 => Ok(Us64(i)),
-            _ => unreachable!(),
-        }
-    }
-    pub fn new_truncating(i: u128, usize_ty: ast::UintTy) -> Self {
-        match usize_ty {
-            ast::UintTy::U16 => Us16(i as u16),
-            ast::UintTy::U32 => Us32(i as u32),
-            ast::UintTy::U64 => Us64(i as u64),
-            _ => unreachable!(),
-        }
-    }
-}
diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs
index d82b712b5b14b..70733bc6aeda0 100644
--- a/src/librustc_data_structures/stable_hasher.rs
+++ b/src/librustc_data_structures/stable_hasher.rs
@@ -259,6 +259,14 @@ impl<CTX> HashStable<CTX> for f64 {
     }
 }
 
+impl<CTX> HashStable<CTX> for ::std::cmp::Ordering {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (*self as i8).hash_stable(ctx, hasher);
+    }
+}
+
 impl<T1: HashStable<CTX>, CTX> HashStable<CTX> for (T1,) {
     fn hash_stable<W: StableHasherResult>(&self,
                                           ctx: &mut CTX,
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index 802fe61d6f35b..6a1d9e5653428 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -17,7 +17,6 @@ rustc = { path = "../librustc" }
 rustc_allocator = { path = "../librustc_allocator" }
 rustc_back = { path = "../librustc_back" }
 rustc_borrowck = { path = "../librustc_borrowck" }
-rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_incremental = { path = "../librustc_incremental" }
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 571cc46bc6413..c9cf3f3b81fe6 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -36,8 +36,7 @@ use rustc_typeck as typeck;
 use rustc_privacy;
 use rustc_plugin::registry::Registry;
 use rustc_plugin as plugin;
-use rustc_passes::{self, ast_validation, loops, consts, hir_stats};
-use rustc_const_eval::{self, check_match};
+use rustc_passes::{self, ast_validation, loops, rvalue_promotion, hir_stats};
 use super::Compilation;
 
 use serialize::json;
@@ -942,7 +941,6 @@ pub fn default_provide(providers: &mut ty::maps::Providers) {
     ty::provide(providers);
     traits::provide(providers);
     reachable::provide(providers);
-    rustc_const_eval::provide(providers);
     rustc_passes::provide(providers);
     middle::region::provide(providers);
     cstore::provide(providers);
@@ -1038,8 +1036,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate,
         }
 
         time(time_passes,
-             "const checking",
-             || consts::check_crate(tcx));
+             "rvalue promotion",
+             || rvalue_promotion::check_crate(tcx));
 
         analysis.access_levels =
             time(time_passes, "privacy checking", || rustc_privacy::check_crate(tcx));
@@ -1050,7 +1048,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate,
 
         time(time_passes,
              "match checking",
-             || check_match::check_crate(tcx));
+             || mir::matchck_crate(tcx));
 
         // this must run before MIR dump, because
         // "not all control paths return a value" is reported here.
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 4b496fe3db65b..8c0e89716cffd 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -35,7 +35,6 @@ extern crate rustc;
 extern crate rustc_allocator;
 extern crate rustc_back;
 extern crate rustc_borrowck;
-extern crate rustc_const_eval;
 extern crate rustc_data_structures;
 extern crate rustc_errors as errors;
 extern crate rustc_passes;
@@ -1566,7 +1565,6 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
     // FIXME: need to figure out a way to get these back in here
     // all_errors.extend_from_slice(get_trans(sess).diagnostics());
     all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS);
-    all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS);
@@ -1576,8 +1574,14 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
     Registry::new(&all_errors)
 }
 
-pub fn main() {
+/// This allows tools to enable rust logging without having to magically match rustc's
+/// log crate version
+pub fn init_rustc_env_logger() {
     env_logger::init();
+}
+
+pub fn main() {
+    init_rustc_env_logger();
     let result = run(|| {
         let args = env::args_os().enumerate()
             .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| {
diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml
index 9fee2d54e4752..5ff891202dbc5 100644
--- a/src/librustc_lint/Cargo.toml
+++ b/src/librustc_lint/Cargo.toml
@@ -12,6 +12,6 @@ test = false
 [dependencies]
 log = "0.4"
 rustc = { path = "../librustc" }
-rustc_const_eval = { path = "../librustc_const_eval" }
+rustc_mir = { path = "../librustc_mir"}
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 62ac898337ca9..831d4fc755f8f 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -682,78 +682,6 @@ impl EarlyLintPass for DeprecatedAttr {
     }
 }
 
-declare_lint! {
-    pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
-    Warn,
-    "floating-point literals cannot be used in patterns"
-}
-
-/// Checks for floating point literals in patterns.
-#[derive(Clone)]
-pub struct IllegalFloatLiteralPattern;
-
-impl LintPass for IllegalFloatLiteralPattern {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN)
-    }
-}
-
-fn fl_lit_check_expr(cx: &EarlyContext, expr: &ast::Expr) {
-    use self::ast::{ExprKind, LitKind};
-    match expr.node {
-        ExprKind::Lit(ref l) => {
-            match l.node {
-                LitKind::FloatUnsuffixed(..) |
-                LitKind::Float(..) => {
-                    cx.span_lint(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
-                                 l.span,
-                                 "floating-point literals cannot be used in patterns");
-                    },
-                _ => (),
-            }
-        }
-        // These may occur in patterns
-        // and can maybe contain float literals
-        ExprKind::Unary(_, ref f) => fl_lit_check_expr(cx, f),
-        // Other kinds of exprs can't occur in patterns so we don't have to check them
-        // (ast_validation will emit an error if they occur)
-        _ => (),
-    }
-}
-
-impl EarlyLintPass for IllegalFloatLiteralPattern {
-    fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat) {
-        use self::ast::PatKind;
-        pat.walk(&mut |p| {
-            match p.node {
-                // Wildcard patterns and paths are uninteresting for the lint
-                PatKind::Wild |
-                PatKind::Path(..) => (),
-
-                // The walk logic recurses inside these
-                PatKind::Ident(..) |
-                PatKind::Struct(..) |
-                PatKind::Tuple(..) |
-                PatKind::TupleStruct(..) |
-                PatKind::Ref(..) |
-                PatKind::Box(..) |
-                PatKind::Paren(..) |
-                PatKind::Slice(..) => (),
-
-                // Extract the expressions and check them
-                PatKind::Lit(ref e) => fl_lit_check_expr(cx, e),
-                PatKind::Range(ref st, ref en, _) => {
-                    fl_lit_check_expr(cx, st);
-                    fl_lit_check_expr(cx, en);
-                },
-
-                PatKind::Mac(_) => bug!("lint must run post-expansion"),
-            }
-            true
-        });
-    }
-}
-
 declare_lint! {
     pub UNUSED_DOC_COMMENT,
     Warn,
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 9dc6d977851b1..e941f2e4e1c2a 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -39,11 +39,10 @@ extern crate syntax;
 extern crate rustc;
 #[macro_use]
 extern crate log;
-extern crate rustc_const_eval;
+extern crate rustc_mir;
 extern crate syntax_pos;
 
 use rustc::lint;
-use rustc::middle;
 use rustc::session;
 use rustc::util;
 
@@ -107,7 +106,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                        UnusedParens,
                        UnusedImportBraces,
                        AnonymousParameters,
-                       IllegalFloatLiteralPattern,
                        UnusedDocComment,
                        );
 
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 1c4bd0ff4c2ec..266f322e39777 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -14,8 +14,6 @@ use rustc::hir::map as hir_map;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, AdtKind, Ty, TyCtxt};
 use rustc::ty::layout::{self, LayoutOf};
-use middle::const_val::ConstVal;
-use rustc_const_eval::ConstContext;
 use util::nodemap::FxHashSet;
 use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass};
@@ -23,7 +21,7 @@ use lint::{LintPass, LateLintPass};
 use std::cmp;
 use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
 
-use syntax::ast;
+use syntax::{ast, attr};
 use syntax::abi::Abi;
 use syntax_pos::Span;
 use syntax::codemap;
@@ -42,12 +40,6 @@ declare_lint! {
     "literal out of range for its type"
 }
 
-declare_lint! {
-    EXCEEDING_BITSHIFTS,
-    Deny,
-    "shift exceeds the type's number of bits"
-}
-
 declare_lint! {
     VARIANT_SIZE_DIFFERENCES,
     Allow,
@@ -69,8 +61,7 @@ impl TypeLimits {
 impl LintPass for TypeLimits {
     fn get_lints(&self) -> LintArray {
         lint_array!(UNUSED_COMPARISONS,
-                    OVERFLOWING_LITERALS,
-                    EXCEEDING_BITSHIFTS)
+                    OVERFLOWING_LITERALS)
     }
 }
 
@@ -89,49 +80,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                                  e.span,
                                  "comparison is useless due to type limits");
                 }
-
-                if binop.node.is_shift() {
-                    let opt_ty_bits = match cx.tables.node_id_to_type(l.hir_id).sty {
-                        ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.isize_ty)),
-                        ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.usize_ty)),
-                        _ => None,
-                    };
-
-                    if let Some(bits) = opt_ty_bits {
-                        let exceeding = if let hir::ExprLit(ref lit) = r.node {
-                            if let ast::LitKind::Int(shift, _) = lit.node {
-                                shift as u64 >= bits
-                            } else {
-                                false
-                            }
-                        } else {
-                            // 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.param_env.and(substs),
-                                                             cx.tables);
-                            match const_cx.eval(&r) {
-                                Ok(&ty::Const { val: ConstVal::Integral(i), .. }) => {
-                                    i.is_negative() ||
-                                    i.to_u64()
-                                        .map(|i| i >= bits)
-                                        .unwrap_or(true)
-                                }
-                                _ => false,
-                            }
-                        };
-                        if exceeding {
-                            cx.span_lint(EXCEEDING_BITSHIFTS,
-                                         e.span,
-                                         "bitshift exceeds the type's number of bits");
-                        }
-                    };
-                }
             }
             hir::ExprLit(ref lit) => {
                 match cx.tables.node_id_to_type(e.hir_id).sty {
@@ -290,28 +238,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
             }
         }
 
-        fn int_ty_bits(int_ty: ast::IntTy, isize_ty: ast::IntTy) -> u64 {
-            match int_ty {
-                ast::IntTy::Isize => int_ty_bits(isize_ty, isize_ty),
-                ast::IntTy::I8 => 8,
-                ast::IntTy::I16 => 16 as u64,
-                ast::IntTy::I32 => 32,
-                ast::IntTy::I64 => 64,
-                ast::IntTy::I128 => 128,
-            }
-        }
-
-        fn uint_ty_bits(uint_ty: ast::UintTy, usize_ty: ast::UintTy) -> u64 {
-            match uint_ty {
-                ast::UintTy::Usize => uint_ty_bits(usize_ty, usize_ty),
-                ast::UintTy::U8 => 8,
-                ast::UintTy::U16 => 16,
-                ast::UintTy::U32 => 32,
-                ast::UintTy::U64 => 64,
-                ast::UintTy::U128 => 128,
-            }
-        }
-
         fn check_limits(cx: &LateContext,
                         binop: hir::BinOp,
                         l: &hir::Expr,
@@ -439,12 +365,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
         ) {
             let (t, actually) = match ty {
                 ty::TyInt(t) => {
-                    let bits = int_ty_bits(t, cx.sess().target.isize_ty);
+                    let ity = attr::IntType::SignedInt(t);
+                    let bits = layout::Integer::from_attr(cx.tcx, ity).size().bits();
                     let actually = (val << (128 - bits)) as i128 >> (128 - bits);
                     (format!("{:?}", t), actually.to_string())
                 }
                 ty::TyUint(t) => {
-                    let bits = uint_ty_bits(t, cx.sess().target.usize_ty);
+                    let ity = attr::IntType::UnsignedInt(t);
+                    let bits = layout::Integer::from_attr(cx.tcx, ity).size().bits();
                     let actually = (val << (128 - bits)) >> (128 - bits);
                     (format!("{:?}", t), actually.to_string())
                 }
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index e71bef512cf06..0ec5700f5f32a 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -664,6 +664,16 @@ extern "C" {
     pub fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
     pub fn LLVMConstLShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
     pub fn LLVMConstAShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
+    pub fn LLVMConstGEP(
+        ConstantVal: ValueRef,
+        ConstantIndices: *const ValueRef,
+        NumIndices: c_uint,
+    ) -> ValueRef;
+    pub fn LLVMConstInBoundsGEP(
+        ConstantVal: ValueRef,
+        ConstantIndices: *const ValueRef,
+        NumIndices: c_uint,
+    ) -> ValueRef;
     pub fn LLVMConstTrunc(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
     pub fn LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
     pub fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 60a0d4e03b54a..f44703b9335e2 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -21,14 +21,15 @@ use rustc::middle::cstore::{LinkagePreference, ExternConstBody,
 use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex,
-                         CRATE_DEF_INDEX, LOCAL_CRATE};
+                         CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId};
 use rustc::ich::Fingerprint;
 use rustc::middle::lang_items;
-use rustc::mir;
+use rustc::mir::{self, interpret};
 use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::codec::TyDecoder;
 use rustc::mir::Mir;
+use rustc::util::nodemap::FxHashMap;
 
 use std::cell::Ref;
 use std::collections::BTreeMap;
@@ -54,6 +55,9 @@ pub struct DecodeContext<'a, 'tcx: 'a> {
     last_filemap_index: usize,
 
     lazy_state: LazyState,
+
+    // interpreter allocation cache
+    interpret_alloc_cache: FxHashMap<usize, interpret::AllocId>,
 }
 
 /// Abstract over the various ways one can create metadata decoders.
@@ -72,6 +76,7 @@ pub trait Metadata<'a, 'tcx>: Copy {
             tcx,
             last_filemap_index: 0,
             lazy_state: LazyState::NoNode,
+            interpret_alloc_cache: FxHashMap::default(),
         }
     }
 }
@@ -268,6 +273,58 @@ impl<'a, 'tcx> SpecializedDecoder<DefIndex> for DecodeContext<'a, 'tcx> {
     }
 }
 
+impl<'a, 'tcx> SpecializedDecoder<LocalDefId> for DecodeContext<'a, 'tcx> {
+    #[inline]
+    fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> {
+        self.specialized_decode().map(|i| LocalDefId::from_def_id(i))
+    }
+}
+
+impl<'a, 'tcx> SpecializedDecoder<interpret::AllocId> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<interpret::AllocId, Self::Error> {
+        const MAX1: usize = usize::max_value() - 1;
+        let tcx = self.tcx.unwrap();
+        let pos = self.position();
+        match usize::decode(self)? {
+            ::std::usize::MAX => {
+                let alloc_id = tcx.interpret_interner.reserve();
+                trace!("creating alloc id {:?} at {}", alloc_id, pos);
+                // insert early to allow recursive allocs
+                self.interpret_alloc_cache.insert(pos, alloc_id);
+
+                let allocation = interpret::Allocation::decode(self)?;
+                trace!("decoded alloc {:?} {:#?}", alloc_id, allocation);
+                let allocation = self.tcx.unwrap().intern_const_alloc(allocation);
+                tcx.interpret_interner.intern_at_reserved(alloc_id, allocation);
+
+                if let Some(glob) = Option::<DefId>::decode(self)? {
+                    tcx.interpret_interner.cache(glob, alloc_id);
+                }
+
+                Ok(alloc_id)
+            },
+            MAX1 => {
+                trace!("creating fn alloc id at {}", pos);
+                let instance = ty::Instance::decode(self)?;
+                trace!("decoded fn alloc instance: {:?}", instance);
+                let id = tcx.interpret_interner.create_fn_alloc(instance);
+                trace!("created fn alloc id: {:?}", id);
+                self.interpret_alloc_cache.insert(pos, id);
+                Ok(id)
+            },
+            shorthand => {
+                trace!("loading shorthand {}", shorthand);
+                if let Some(&alloc_id) = self.interpret_alloc_cache.get(&shorthand) {
+                    return Ok(alloc_id);
+                }
+                trace!("shorthand {} not cached, loading entire allocation", shorthand);
+                // need to load allocation
+                self.with_position(shorthand, |this| interpret::AllocId::decode(this))
+            },
+        }
+    }
+}
+
 impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
         let tag = u8::decode(self)?;
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 830121b446fca..d959482417489 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -16,14 +16,14 @@ use schema::*;
 use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary,
                             EncodedMetadata};
 use rustc::hir::def::CtorKind;
-use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LOCAL_CRATE};
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LocalDefId, LOCAL_CRATE};
 use rustc::hir::map::definitions::DefPathTable;
 use rustc::ich::Fingerprint;
 use rustc::middle::dependency_format::Linkage;
 use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel,
                                       metadata_symbol_name};
 use rustc::middle::lang_items;
-use rustc::mir;
+use rustc::mir::{self, interpret};
 use rustc::traits::specialization_graph;
 use rustc::ty::{self, Ty, TyCtxt, ReprOptions, SymbolName};
 use rustc::ty::codec::{self as ty_codec, TyEncoder};
@@ -59,6 +59,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
     lazy_state: LazyState,
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
     predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
+    interpret_alloc_shorthands: FxHashMap<interpret::AllocId, usize>,
 
     // This is used to speed up Span encoding.
     filemap_cache: Lrc<FileMap>,
@@ -180,12 +181,48 @@ impl<'a, 'tcx> SpecializedEncoder<Span> for EncodeContext<'a, 'tcx> {
     }
 }
 
+impl<'a, 'tcx> SpecializedEncoder<LocalDefId> for EncodeContext<'a, 'tcx> {
+    #[inline]
+    fn specialized_encode(&mut self, def_id: &LocalDefId) -> Result<(), Self::Error> {
+        self.specialized_encode(&def_id.to_def_id())
+    }
+}
+
 impl<'a, 'tcx> SpecializedEncoder<Ty<'tcx>> for EncodeContext<'a, 'tcx> {
     fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> {
         ty_codec::encode_with_shorthand(self, ty, |ecx| &mut ecx.type_shorthands)
     }
 }
 
+impl<'a, 'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
+        trace!("encoding {:?} at {}", alloc_id, self.position());
+        if let Some(shorthand) = self.interpret_alloc_shorthands.get(alloc_id).cloned() {
+            trace!("encoding {:?} as shorthand to {}", alloc_id, shorthand);
+            return shorthand.encode(self);
+        }
+        let start = self.position();
+        // cache the allocation shorthand now, because the allocation itself might recursively
+        // point to itself.
+        self.interpret_alloc_shorthands.insert(*alloc_id, start);
+        if let Some(alloc) = self.tcx.interpret_interner.get_alloc(*alloc_id) {
+            trace!("encoding {:?} with {:#?}", alloc_id, alloc);
+            usize::max_value().encode(self)?;
+            alloc.encode(self)?;
+            self.tcx.interpret_interner
+                .get_corresponding_static_def_id(*alloc_id)
+                .encode(self)?;
+        } else if let Some(fn_instance) = self.tcx.interpret_interner.get_fn(*alloc_id) {
+            trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
+            (usize::max_value() - 1).encode(self)?;
+            fn_instance.encode(self)?;
+        } else {
+            bug!("alloc id without corresponding allocation: {}", alloc_id);
+        }
+        Ok(())
+    }
+}
+
 impl<'a, 'tcx> SpecializedEncoder<ty::GenericPredicates<'tcx>> for EncodeContext<'a, 'tcx> {
     fn specialized_encode(&mut self,
                           predicates: &ty::GenericPredicates<'tcx>)
@@ -1117,7 +1154,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
                 _ => None,
             },
             mir: match item.node {
-                hir::ItemStatic(..) if self.tcx.sess.opts.debugging_opts.always_encode_mir => {
+                hir::ItemStatic(..) => {
                     self.encode_optimized_mir(def_id)
                 }
                 hir::ItemConst(..) => self.encode_optimized_mir(def_id),
@@ -1699,6 +1736,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             type_shorthands: Default::default(),
             predicate_shorthands: Default::default(),
             filemap_cache: tcx.sess.codemap().files()[0].clone(),
+            interpret_alloc_shorthands: Default::default(),
         };
 
         // Encode the rustc version string in a predictable location.
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index ce94e4f912f4f..593f08e90bb3b 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -227,9 +227,9 @@ pub struct TraitImpls {
     pub impls: LazySeq<DefIndex>,
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for TraitImpls {
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TraitImpls {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let TraitImpls {
             trait_id: (krate, def_index),
@@ -310,9 +310,9 @@ pub enum EntryKind<'tcx> {
     AssociatedConst(AssociatedContainer, u8),
 }
 
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for EntryKind<'gcx> {
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for EntryKind<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml
index ea05a513f7e7d..90a0f18aba367 100644
--- a/src/librustc_mir/Cargo.toml
+++ b/src/librustc_mir/Cargo.toml
@@ -9,13 +9,13 @@ path = "lib.rs"
 crate-type = ["dylib"]
 
 [dependencies]
+arena = { path = "../libarena" }
 bitflags = "1.0"
 graphviz = { path = "../libgraphviz" }
 log = "0.4"
 log_settings = "0.1.1"
 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_errors = { path = "../librustc_errors" }
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 1ff0ffaaa68b3..028fc337967fa 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1635,11 +1635,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     Mutability::Mut => Ok(()),
                 }
             }
-            Place::Static(ref static_) => if !self.tcx.is_static_mut(static_.def_id) {
-                Err(place)
-            } else {
-                Ok(())
-            },
+            Place::Static(ref static_) =>
+                if self.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
+                    Err(place)
+                } else {
+                    Ok(())
+                },
             Place::Projection(ref proj) => {
                 match proj.elem {
                     ProjectionElem::Deref => {
@@ -1792,7 +1793,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 if static1.def_id != static2.def_id {
                     debug!("place_element_conflict: DISJOINT-STATIC");
                     Overlap::Disjoint
-                } else if self.tcx.is_static_mut(static1.def_id) {
+                } else if self.tcx.is_static(static1.def_id) == Some(hir::Mutability::MutMutable) {
                     // We ignore mutable statics - they can only be unsafe code.
                     debug!("place_element_conflict: IGNORE-STATIC-MUT");
                     Overlap::Disjoint
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index bbf4357e5b0f9..36e173dd5d640 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -24,7 +24,6 @@ use rustc::traits::{self, FulfillmentContext};
 use rustc::ty::error::TypeError;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
-use rustc::middle::const_val::ConstVal;
 use rustc::mir::*;
 use rustc::mir::tcx::PlaceTy;
 use rustc::mir::visit::{PlaceContext, Visitor};
@@ -258,7 +257,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                 // constraints on `'a` and `'b`. These constraints
                 // would be lost if we just look at the normalized
                 // value.
-                if let ConstVal::Function(def_id, ..) = value.val {
+                if let ty::TyFnDef(def_id, substs) = value.ty.sty {
                     let tcx = self.tcx();
                     let type_checker = &mut self.cx;
 
@@ -271,17 +270,6 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                     // are transitioning to the miri-based system, we
                     // don't have a handy function for that, so for
                     // now we just ignore `value.val` regions.
-                    let substs = match value.ty.sty {
-                        ty::TyFnDef(ty_def_id, substs) => {
-                            assert_eq!(def_id, ty_def_id);
-                            substs
-                        }
-                        _ => span_bug!(
-                            self.last_span,
-                            "unexpected type for constant function: {:?}",
-                            value.ty
-                        ),
-                    };
 
                     let instantiated_predicates =
                         tcx.predicates_of(def_id).instantiate(tcx, substs);
@@ -436,7 +424,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
                 ty: match base_ty.sty {
                     ty::TyArray(inner, size) => {
-                        let size = size.val.to_const_int().unwrap().to_u64().unwrap();
+                        let size = size.val.unwrap_u64();
                         let min_size = (from as u64) + (to as u64);
                         if let Some(rest_size) = size.checked_sub(min_size) {
                             tcx.mk_array(inner, rest_size)
@@ -1013,19 +1001,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
     }
 
     fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
-        match operand {
-            &Operand::Constant(box Constant {
-                literal:
-                    Literal::Value {
-                        value:
-                            &ty::Const {
-                                val: ConstVal::Function(def_id, _),
-                                ..
-                            },
-                        ..
-                    },
-                ..
-            }) => Some(def_id) == self.tcx().lang_items().box_free_fn(),
+        match *operand {
+            Operand::Constant(ref c) => match c.ty.sty {
+                ty::TyFnDef(ty_def_id, _) => {
+                    Some(ty_def_id) == self.tcx().lang_items().box_free_fn()
+                }
+                _ => false,
+            },
             _ => false,
         }
     }
@@ -1284,7 +1266,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 self.check_aggregate_rvalue(mir, rvalue, ak, ops, location)
             }
 
-            Rvalue::Repeat(operand, const_usize) => if const_usize.as_u64() > 1 {
+            Rvalue::Repeat(operand, len) => if *len > 1 {
                 let operand_ty = operand.ty(mir, tcx);
 
                 let trait_ref = ty::TraitRef {
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index d3cc952759058..1a9064aab1b2f 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -10,8 +10,6 @@
 
 //! See docs in build/expr/mod.rs
 
-use std;
-
 use rustc_const_math::{ConstMathErr, Op};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::indexed_vec::Idx;
@@ -19,12 +17,11 @@ use rustc_data_structures::indexed_vec::Idx;
 use build::{BlockAnd, BlockAndExtension, Builder};
 use build::expr::category::{Category, RvalueFunc};
 use hair::*;
-use rustc_const_math::{ConstInt, ConstIsize};
 use rustc::middle::const_val::ConstVal;
 use rustc::middle::region;
 use rustc::ty::{self, Ty};
 use rustc::mir::*;
-use syntax::ast;
+use rustc::mir::interpret::{Value, PrimVal};
 use syntax_pos::Span;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@@ -203,7 +200,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         ty: this.hir.tcx().types.u32,
                         literal: Literal::Value {
                             value: this.hir.tcx().mk_const(ty::Const {
-                                val: ConstVal::Integral(ConstInt::U32(0)),
+                                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
                                 ty: this.hir.tcx().types.u32
                             }),
                         },
@@ -384,31 +381,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     // Helper to get a `-1` value of the appropriate type
     fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        let literal = match ty.sty {
-            ty::TyInt(ity) => {
-                let val = match ity {
-                    ast::IntTy::I8  => ConstInt::I8(-1),
-                    ast::IntTy::I16 => ConstInt::I16(-1),
-                    ast::IntTy::I32 => ConstInt::I32(-1),
-                    ast::IntTy::I64 => ConstInt::I64(-1),
-                    ast::IntTy::I128 => ConstInt::I128(-1),
-                    ast::IntTy::Isize => {
-                        let int_ty = self.hir.tcx().sess.target.isize_ty;
-                        let val = ConstIsize::new(-1, int_ty).unwrap();
-                        ConstInt::Isize(val)
-                    }
-                };
-
-                Literal::Value {
-                    value: self.hir.tcx().mk_const(ty::Const {
-                        val: ConstVal::Integral(val),
-                        ty
-                    })
-                }
-            }
-            _ => {
-                span_bug!(span, "Invalid type for neg_1_literal: `{:?}`", ty)
-            }
+        let bits = self.hir.integer_bit_width(ty);
+        let n = (!0u128) >> (128 - bits);
+        let literal = Literal::Value {
+            value: self.hir.tcx().mk_const(ty::Const {
+                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
+                ty
+            })
         };
 
         self.literal_operand(span, ty, literal)
@@ -416,37 +395,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     // Helper to get the minimum value of the appropriate type
     fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        let literal = match ty.sty {
-            ty::TyInt(ity) => {
-                let val = match ity {
-                    ast::IntTy::I8  => ConstInt::I8(i8::min_value()),
-                    ast::IntTy::I16 => ConstInt::I16(i16::min_value()),
-                    ast::IntTy::I32 => ConstInt::I32(i32::min_value()),
-                    ast::IntTy::I64 => ConstInt::I64(i64::min_value()),
-                    ast::IntTy::I128 => ConstInt::I128(i128::min_value()),
-                    ast::IntTy::Isize => {
-                        let int_ty = self.hir.tcx().sess.target.isize_ty;
-                        let min = match int_ty {
-                            ast::IntTy::I16 => std::i16::MIN as i64,
-                            ast::IntTy::I32 => std::i32::MIN as i64,
-                            ast::IntTy::I64 => std::i64::MIN,
-                            _ => unreachable!()
-                        };
-                        let val = ConstIsize::new(min, int_ty).unwrap();
-                        ConstInt::Isize(val)
-                    }
-                };
-
-                Literal::Value {
-                    value: self.hir.tcx().mk_const(ty::Const {
-                        val: ConstVal::Integral(val),
-                        ty
-                    })
-                }
-            }
-            _ => {
-                span_bug!(span, "Invalid type for minval_literal: `{:?}`", ty)
-            }
+        assert!(ty.is_signed());
+        let bits = self.hir.integer_bit_width(ty);
+        let n = 1 << (bits - 1);
+        let literal = Literal::Value {
+            value: self.hir.tcx().mk_const(ty::Const {
+                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
+                ty
+            })
         };
 
         self.literal_operand(span, ty, literal)
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 58ce572ae8d88..229e33dcd7862 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -354,7 +354,7 @@ enum TestKind<'tcx> {
     // test the branches of enum
     SwitchInt {
         switch_ty: Ty<'tcx>,
-        options: Vec<&'tcx ty::Const<'tcx>>,
+        options: Vec<u128>,
         indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
     },
 
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index bdcbfc0bdd85e..09579eaecb2de 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -20,11 +20,10 @@ use build::matches::{Candidate, MatchPair, Test, TestKind};
 use hair::*;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::bitvec::BitVector;
-use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, Ty};
 use rustc::ty::util::IntTypeExt;
 use rustc::mir::*;
-use rustc::hir::RangeEnd;
+use rustc::hir::{RangeEnd, Mutability};
 use syntax_pos::Span;
 use std::cmp::Ordering;
 
@@ -112,7 +111,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                      test_place: &Place<'tcx>,
                                      candidate: &Candidate<'pat, 'tcx>,
                                      switch_ty: Ty<'tcx>,
-                                     options: &mut Vec<&'tcx ty::Const<'tcx>>,
+                                     options: &mut Vec<u128>,
                                      indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>)
                                      -> bool
     {
@@ -128,7 +127,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                 indices.entry(value)
                        .or_insert_with(|| {
-                           options.push(value);
+                           options.push(value.val.to_raw_bits().expect("switching on int"));
                            options.len() - 1
                        });
                 true
@@ -174,39 +173,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// Convert a byte array or byte slice to a byte slice.
-    fn to_slice_operand(&mut self,
-                        block: BasicBlock,
-                        source_info: SourceInfo,
-                        operand: Operand<'tcx>)
-                        -> Operand<'tcx>
-    {
-        let tcx = self.hir.tcx();
-        let ty = operand.ty(&self.local_decls, tcx);
-        debug!("to_slice_operand({:?}, {:?}: {:?})", block, operand, ty);
-        match ty.sty {
-            ty::TyRef(region, mt) => match mt.ty.sty {
-                ty::TyArray(ety, _) => {
-                    let ty = tcx.mk_imm_ref(region, tcx.mk_slice(ety));
-                    let temp = self.temp(ty, source_info.span);
-                    self.cfg.push_assign(block, source_info, &temp,
-                                         Rvalue::Cast(CastKind::Unsize, operand, ty));
-                    Operand::Move(temp)
-                }
-                ty::TySlice(_) => operand,
-                _ => {
-                    span_bug!(source_info.span,
-                              "bad operand {:?}: {:?} to `to_slice_operand`", operand, ty)
-                }
-            }
-            _ => {
-                span_bug!(source_info.span,
-                          "bad operand {:?}: {:?} to `to_slice_operand`", operand, ty)
-            }
-        }
-
-    }
-
     /// Generates the code to perform a test.
     pub fn perform_test(&mut self,
                         block: BasicBlock,
@@ -231,7 +197,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let tcx = self.hir.tcx();
                 for (idx, discr) in adt_def.discriminants(tcx).enumerate() {
                     target_blocks.place_back() <- if variants.contains(idx) {
-                        values.push(discr);
+                        values.push(discr.val);
                         *(targets.place_back() <- self.cfg.start_new_block())
                     } else {
                         if otherwise_block.is_none() {
@@ -266,9 +232,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     assert!(options.len() > 0 && options.len() <= 2);
                     let (true_bb, false_bb) = (self.cfg.start_new_block(),
                                                self.cfg.start_new_block());
-                    let ret = match options[0].val {
-                        ConstVal::Bool(true) => vec![true_bb, false_bb],
-                        ConstVal::Bool(false) => vec![false_bb, true_bb],
+                    let ret = match options[0] {
+                        1 => vec![true_bb, false_bb],
+                        0 => vec![false_bb, true_bb],
                         v => span_bug!(test.span, "expected boolean value but got {:?}", v)
                     };
                     (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place.clone()),
@@ -282,13 +248,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                .map(|_| self.cfg.start_new_block())
                                .chain(Some(otherwise))
                                .collect();
-                    let values: Vec<_> = options.iter().map(|v|
-                        v.val.to_const_int().expect("switching on integral")
-                    ).collect();
                     (targets.clone(), TerminatorKind::SwitchInt {
                         discr: Operand::Copy(place.clone()),
                         switch_ty,
-                        values: From::from(values),
+                        values: options.clone().into(),
                         targets,
                     })
                 };
@@ -296,41 +259,88 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 ret
             }
 
-            TestKind::Eq { value, ty } => {
-                let tcx = self.hir.tcx();
+            TestKind::Eq { value, mut ty } => {
                 let mut val = Operand::Copy(place.clone());
-
-                // If we're using b"..." as a pattern, we need to insert an
-                // unsizing coercion, as the byte string has the type &[u8; N].
-                //
-                // We want to do this even when the scrutinee is a reference to an
-                // array, so we can call `<[u8]>::eq` rather than having to find an
-                // `<[u8; N]>::eq`.
-                let (expect, val) = if let ConstVal::ByteStr(bytes) = value.val {
-                    let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len() as u64);
-                    let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty);
-                    let array = self.literal_operand(test.span, array_ref, Literal::Value {
-                        value
-                    });
-
-                    let val = self.to_slice_operand(block, source_info, val);
-                    let slice = self.to_slice_operand(block, source_info, array);
-                    (slice, val)
-                } else {
-                    (self.literal_operand(test.span, ty, Literal::Value {
-                        value
-                    }), val)
-                };
-
-                // Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq.
+                let mut expect = self.literal_operand(test.span, ty, Literal::Value {
+                    value
+                });
+                // Use PartialEq::eq instead of BinOp::Eq
+                // (the binop can only handle primitives)
                 let fail = self.cfg.start_new_block();
-                let ty = expect.ty(&self.local_decls, tcx);
-                if let ty::TyRef(_, mt) = ty.sty {
-                    assert!(ty.is_slice());
+                if !ty.is_scalar() {
+                    // If we're using b"..." as a pattern, we need to insert an
+                    // unsizing coercion, as the byte string has the type &[u8; N].
+                    //
+                    // We want to do this even when the scrutinee is a reference to an
+                    // array, so we can call `<[u8]>::eq` rather than having to find an
+                    // `<[u8; N]>::eq`.
+                    let unsize = |ty: Ty<'tcx>| match ty.sty {
+                        ty::TyRef(region, tam) => match tam.ty.sty {
+                            ty::TyArray(inner_ty, n) => Some((region, inner_ty, n)),
+                            _ => None,
+                        },
+                        _ => None,
+                    };
+                    let opt_ref_ty = unsize(ty);
+                    let opt_ref_test_ty = unsize(value.ty);
+                    let mut place = place.clone();
+                    match (opt_ref_ty, opt_ref_test_ty) {
+                        // nothing to do, neither is an array
+                        (None, None) => {},
+                        (Some((region, elem_ty, _)), _) |
+                        (None, Some((region, elem_ty, _))) => {
+                            let tcx = self.hir.tcx();
+                            // make both a slice
+                            ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
+                            if opt_ref_ty.is_some() {
+                                place = self.temp(ty, test.span);
+                                self.cfg.push_assign(block, source_info, &place,
+                                                    Rvalue::Cast(CastKind::Unsize, val, ty));
+                            }
+                            if opt_ref_test_ty.is_some() {
+                                let array = self.literal_operand(
+                                    test.span,
+                                    value.ty,
+                                    Literal::Value {
+                                        value
+                                    },
+                                );
+
+                                let slice = self.temp(ty, test.span);
+                                self.cfg.push_assign(block, source_info, &slice,
+                                                    Rvalue::Cast(CastKind::Unsize, array, ty));
+                                expect = Operand::Move(slice);
+                            }
+                        },
+                    }
                     let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap();
-                    let ty = mt.ty;
                     let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]);
 
+                    // take the argument by reference
+                    let region_scope = self.topmost_scope();
+                    let region = self.hir.tcx().mk_region(ty::ReScope(region_scope));
+                    let tam = ty::TypeAndMut {
+                        ty,
+                        mutbl: Mutability::MutImmutable,
+                    };
+                    let ref_ty = self.hir.tcx().mk_ref(region, tam);
+
+                    // let lhs_ref_place = &lhs;
+                    let ref_rvalue = Rvalue::Ref(region, BorrowKind::Shared, place.clone());
+                    let lhs_ref_place = self.temp(ref_ty, test.span);
+                    self.cfg.push_assign(block, source_info, &lhs_ref_place, ref_rvalue);
+                    let val = Operand::Move(lhs_ref_place);
+
+                    // let rhs_place = rhs;
+                    let rhs_place = self.temp(ty, test.span);
+                    self.cfg.push_assign(block, source_info, &rhs_place, Rvalue::Use(expect));
+
+                    // let rhs_ref_place = &rhs_place;
+                    let ref_rvalue = Rvalue::Ref(region, BorrowKind::Shared, rhs_place);
+                    let rhs_ref_place = self.temp(ref_ty, test.span);
+                    self.cfg.push_assign(block, source_info, &rhs_ref_place, ref_rvalue);
+                    let expect = Operand::Move(rhs_ref_place);
+
                     let bool_ty = self.hir.bool_ty();
                     let eq_result = self.temp(bool_ty, test.span);
                     let eq_block = self.cfg.start_new_block();
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index a3350cb1671d2..6e10c2307c8e6 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -13,12 +13,11 @@
 
 use build::Builder;
 
-use rustc_const_math::{ConstInt, ConstUsize, ConstIsize};
 use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, Ty};
+use rustc::mir::interpret::{Value, PrimVal};
 
 use rustc::mir::*;
-use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@@ -55,63 +54,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     // Returns a zero literal operand for the appropriate type, works for
     // bool, char and integers.
     pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        let literal = match ty.sty {
-            ty::TyBool => {
-                self.hir.false_literal()
-            }
-            ty::TyChar => {
-                Literal::Value {
-                    value: self.hir.tcx().mk_const(ty::Const {
-                        val: ConstVal::Char('\0'),
-                        ty
-                    })
-                }
-            }
-            ty::TyUint(ity) => {
-                let val = match ity {
-                    ast::UintTy::U8  => ConstInt::U8(0),
-                    ast::UintTy::U16 => ConstInt::U16(0),
-                    ast::UintTy::U32 => ConstInt::U32(0),
-                    ast::UintTy::U64 => ConstInt::U64(0),
-                    ast::UintTy::U128 => ConstInt::U128(0),
-                    ast::UintTy::Usize => {
-                        let uint_ty = self.hir.tcx().sess.target.usize_ty;
-                        let val = ConstUsize::new(0, uint_ty).unwrap();
-                        ConstInt::Usize(val)
-                    }
-                };
-
-                Literal::Value {
-                    value: self.hir.tcx().mk_const(ty::Const {
-                        val: ConstVal::Integral(val),
-                        ty
-                    })
-                }
-            }
-            ty::TyInt(ity) => {
-                let val = match ity {
-                    ast::IntTy::I8  => ConstInt::I8(0),
-                    ast::IntTy::I16 => ConstInt::I16(0),
-                    ast::IntTy::I32 => ConstInt::I32(0),
-                    ast::IntTy::I64 => ConstInt::I64(0),
-                    ast::IntTy::I128 => ConstInt::I128(0),
-                    ast::IntTy::Isize => {
-                        let int_ty = self.hir.tcx().sess.target.isize_ty;
-                        let val = ConstIsize::new(0, int_ty).unwrap();
-                        ConstInt::Isize(val)
-                    }
-                };
-
-                Literal::Value {
-                    value: self.hir.tcx().mk_const(ty::Const {
-                        val: ConstVal::Integral(val),
-                        ty
-                    })
-                }
-            }
+        match ty.sty {
+            ty::TyBool |
+            ty::TyChar |
+            ty::TyUint(_) |
+            ty::TyInt(_) => {}
             _ => {
                 span_bug!(span, "Invalid type for zero_literal: `{:?}`", ty)
             }
+        }
+        let literal = Literal::Value {
+            value: self.hir.tcx().mk_const(ty::Const {
+                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
+                ty
+            })
         };
 
         self.literal_operand(span, ty, literal)
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index a325cfe3eaae3..23c5499bb6396 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -11,7 +11,7 @@
 
 use build;
 use hair::cx::Cx;
-use hair::LintLevel;
+use hair::{LintLevel, BindingMode, PatternKind};
 use rustc::hir;
 use rustc::hir::def_id::{DefId, LocalDefId};
 use rustc::middle::region;
@@ -21,7 +21,6 @@ use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
 use rustc::util::nodemap::NodeMap;
 use rustc_back::PanicStrategy;
-use rustc_const_eval::pattern::{BindingMode, PatternKind};
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use shim;
 use std::mem;
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 533bad18c38a8..a150335a1ae4d 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -783,7 +783,7 @@ fn is_unsafe_place<'a, 'gcx: 'tcx, 'tcx: 'a>(
 
     match *place {
         Local(_) => false,
-        Static(ref static_) => tcx.is_static_mut(static_.def_id),
+        Static(ref static_) => tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable),
         Projection(ref proj) => {
             match proj.elem {
                 ProjectionElem::Field(..) |
diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs
index 3491faf9cdac0..2000ebea25d7e 100644
--- a/src/librustc_mir/diagnostics.rs
+++ b/src/librustc_mir/diagnostics.rs
@@ -12,6 +12,541 @@
 
 register_long_diagnostics! {
 
+
+E0001: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
+This error suggests that the expression arm corresponding to the noted pattern
+will never be reached as for all possible values of the expression being
+matched, one of the preceding patterns will match.
+
+This means that perhaps some of the preceding patterns are too general, this
+one is too specific or the ordering is incorrect.
+
+For example, the following `match` block has too many arms:
+
+```
+match Some(0) {
+    Some(bar) => {/* ... */}
+    x => {/* ... */} // This handles the `None` case
+    _ => {/* ... */} // All possible cases have already been handled
+}
+```
+
+`match` blocks have their patterns matched in order, so, for example, putting
+a wildcard arm above a more specific arm will make the latter arm irrelevant.
+
+Ensure the ordering of the match arm is correct and remove any superfluous
+arms.
+"##,
+
+E0002: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
+This error indicates that an empty match expression is invalid because the type
+it is matching on is non-empty (there exist values of this type). In safe code
+it is impossible to create an instance of an empty type, so empty match
+expressions are almost never desired. This error is typically fixed by adding
+one or more cases to the match expression.
+
+An example of an empty type is `enum Empty { }`. So, the following will work:
+
+```
+enum Empty {}
+
+fn foo(x: Empty) {
+    match x {
+        // empty
+    }
+}
+```
+
+However, this won't:
+
+```compile_fail
+fn foo(x: Option<String>) {
+    match x {
+        // empty
+    }
+}
+```
+"##,
+
+E0004: r##"
+This error indicates that the compiler cannot guarantee a matching pattern for
+one or more possible inputs to a match expression. Guaranteed matches are
+required in order to assign values to match expressions, or alternatively,
+determine the flow of execution. Erroneous code example:
+
+```compile_fail,E0004
+enum Terminator {
+    HastaLaVistaBaby,
+    TalkToMyHand,
+}
+
+let x = Terminator::HastaLaVistaBaby;
+
+match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered
+    Terminator::TalkToMyHand => {}
+}
+```
+
+If you encounter this error you must alter your patterns so that every possible
+value of the input type is matched. For types with a small number of variants
+(like enums) you should probably cover all cases explicitly. Alternatively, the
+underscore `_` wildcard pattern can be added after all other patterns to match
+"anything else". Example:
+
+```
+enum Terminator {
+    HastaLaVistaBaby,
+    TalkToMyHand,
+}
+
+let x = Terminator::HastaLaVistaBaby;
+
+match x {
+    Terminator::TalkToMyHand => {}
+    Terminator::HastaLaVistaBaby => {}
+}
+
+// or:
+
+match x {
+    Terminator::TalkToMyHand => {}
+    _ => {}
+}
+```
+"##,
+
+E0005: r##"
+Patterns used to bind names must be irrefutable, that is, they must guarantee
+that a name will be extracted in all cases. Erroneous code example:
+
+```compile_fail,E0005
+let x = Some(1);
+let Some(y) = x;
+// error: refutable pattern in local binding: `None` not covered
+```
+
+If you encounter this error you probably need to use a `match` or `if let` to
+deal with the possibility of failure. Example:
+
+```
+let x = Some(1);
+
+match x {
+    Some(y) => {
+        // do something
+    },
+    None => {}
+}
+
+// or:
+
+if let Some(y) = x {
+    // do something
+}
+```
+"##,
+
+E0007: r##"
+This error indicates that the bindings in a match arm would require a value to
+be moved into more than one location, thus violating unique ownership. Code
+like the following is invalid as it requires the entire `Option<String>` to be
+moved into a variable called `op_string` while simultaneously requiring the
+inner `String` to be moved into a variable called `s`.
+
+```compile_fail,E0007
+let x = Some("s".to_string());
+
+match x {
+    op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings
+    None => {},
+}
+```
+
+See also the error E0303.
+"##,
+
+E0008: r##"
+Names bound in match arms retain their type in pattern guards. As such, if a
+name is bound by move in a pattern, it should also be moved to wherever it is
+referenced in the pattern guard code. Doing so however would prevent the name
+from being available in the body of the match arm. Consider the following:
+
+```compile_fail,E0008
+match Some("hi".to_string()) {
+    Some(s) if s.len() == 0 => {}, // use s.
+    _ => {},
+}
+```
+
+The variable `s` has type `String`, and its use in the guard is as a variable of
+type `String`. The guard code effectively executes in a separate scope to the
+body of the arm, so the value would be moved into this anonymous scope and
+therefore becomes unavailable in the body of the arm.
+
+The problem above can be solved by using the `ref` keyword.
+
+```
+match Some("hi".to_string()) {
+    Some(ref s) if s.len() == 0 => {},
+    _ => {},
+}
+```
+
+Though this example seems innocuous and easy to solve, the problem becomes clear
+when it encounters functions which consume the value:
+
+```compile_fail,E0008
+struct A{}
+
+impl A {
+    fn consume(self) -> usize {
+        0
+    }
+}
+
+fn main() {
+    let a = Some(A{});
+    match a {
+        Some(y) if y.consume() > 0 => {}
+        _ => {}
+    }
+}
+```
+
+In this situation, even the `ref` keyword cannot solve it, since borrowed
+content cannot be moved. This problem cannot be solved generally. If the value
+can be cloned, here is a not-so-specific solution:
+
+```
+#[derive(Clone)]
+struct A{}
+
+impl A {
+    fn consume(self) -> usize {
+        0
+    }
+}
+
+fn main() {
+    let a = Some(A{});
+    match a{
+        Some(ref y) if y.clone().consume() > 0 => {}
+        _ => {}
+    }
+}
+```
+
+If the value will be consumed in the pattern guard, using its clone will not
+move its ownership, so the code works.
+"##,
+
+E0009: r##"
+In a pattern, all values that don't implement the `Copy` trait have to be bound
+the same way. The goal here is to avoid binding simultaneously by-move and
+by-ref.
+
+This limitation may be removed in a future version of Rust.
+
+Erroneous code example:
+
+```compile_fail,E0009
+struct X { x: (), }
+
+let x = Some((X { x: () }, X { x: () }));
+match x {
+    Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the
+                            //        same pattern
+    None => panic!()
+}
+```
+
+You have two solutions:
+
+Solution #1: Bind the pattern's values the same way.
+
+```
+struct X { x: (), }
+
+let x = Some((X { x: () }, X { x: () }));
+match x {
+    Some((ref y, ref z)) => {},
+    // or Some((y, z)) => {}
+    None => panic!()
+}
+```
+
+Solution #2: Implement the `Copy` trait for the `X` structure.
+
+However, please keep in mind that the first solution should be preferred.
+
+```
+#[derive(Clone, Copy)]
+struct X { x: (), }
+
+let x = Some((X { x: () }, X { x: () }));
+match x {
+    Some((y, ref z)) => {},
+    None => panic!()
+}
+```
+"##,
+
+E0030: r##"
+When matching against a range, the compiler verifies that the range is
+non-empty.  Range patterns include both end-points, so this is equivalent to
+requiring the start of the range to be less than or equal to the end of the
+range.
+
+For example:
+
+```compile_fail
+match 5u32 {
+    // This range is ok, albeit pointless.
+    1 ... 1 => {}
+    // This range is empty, and the compiler can tell.
+    1000 ... 5 => {}
+}
+```
+"##,
+
+E0158: r##"
+`const` and `static` mean different things. A `const` is a compile-time
+constant, an alias for a literal value. This property means you can match it
+directly within a pattern.
+
+The `static` keyword, on the other hand, guarantees a fixed location in memory.
+This does not always mean that the value is constant. For example, a global
+mutex can be declared `static` as well.
+
+If you want to match against a `static`, consider using a guard instead:
+
+```
+static FORTY_TWO: i32 = 42;
+
+match Some(42) {
+    Some(x) if x == FORTY_TWO => {}
+    _ => {}
+}
+```
+"##,
+
+E0162: r##"
+An if-let pattern attempts to match the pattern, and enters the body if the
+match was successful. If the match is irrefutable (when it cannot fail to
+match), use a regular `let`-binding instead. For instance:
+
+```compile_fail,E0162
+struct Irrefutable(i32);
+let irr = Irrefutable(0);
+
+// This fails to compile because the match is irrefutable.
+if let Irrefutable(x) = irr {
+    // This body will always be executed.
+    // ...
+}
+```
+
+Try this instead:
+
+```
+struct Irrefutable(i32);
+let irr = Irrefutable(0);
+
+let Irrefutable(x) = irr;
+println!("{}", x);
+```
+"##,
+
+E0165: r##"
+A while-let pattern attempts to match the pattern, and enters the body if the
+match was successful. If the match is irrefutable (when it cannot fail to
+match), use a regular `let`-binding inside a `loop` instead. For instance:
+
+```compile_fail,E0165
+struct Irrefutable(i32);
+let irr = Irrefutable(0);
+
+// This fails to compile because the match is irrefutable.
+while let Irrefutable(x) = irr {
+    // ...
+}
+```
+
+Try this instead:
+
+```no_run
+struct Irrefutable(i32);
+let irr = Irrefutable(0);
+
+loop {
+    let Irrefutable(x) = irr;
+    // ...
+}
+```
+"##,
+
+E0170: r##"
+Enum variants are qualified by default. For example, given this type:
+
+```
+enum Method {
+    GET,
+    POST,
+}
+```
+
+You would match it using:
+
+```
+enum Method {
+    GET,
+    POST,
+}
+
+let m = Method::GET;
+
+match m {
+    Method::GET => {},
+    Method::POST => {},
+}
+```
+
+If you don't qualify the names, the code will bind new variables named "GET" and
+"POST" instead. This behavior is likely not what you want, so `rustc` warns when
+that happens.
+
+Qualified names are good practice, and most code works well with them. But if
+you prefer them unqualified, you can import the variants into scope:
+
+```
+use Method::*;
+enum Method { GET, POST }
+# fn main() {}
+```
+
+If you want others to be able to import variants from your module directly, use
+`pub use`:
+
+```
+pub use Method::*;
+pub enum Method { GET, POST }
+# fn main() {}
+```
+"##,
+
+
+E0297: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
+Patterns used to bind names must be irrefutable. That is, they must guarantee
+that a name will be extracted in all cases. Instead of pattern matching the
+loop variable, consider using a `match` or `if let` inside the loop body. For
+instance:
+
+```compile_fail,E0005
+let xs : Vec<Option<i32>> = vec![Some(1), None];
+
+// This fails because `None` is not covered.
+for Some(x) in xs {
+    // ...
+}
+```
+
+Match inside the loop instead:
+
+```
+let xs : Vec<Option<i32>> = vec![Some(1), None];
+
+for item in xs {
+    match item {
+        Some(x) => {},
+        None => {},
+    }
+}
+```
+
+Or use `if let`:
+
+```
+let xs : Vec<Option<i32>> = vec![Some(1), None];
+
+for item in xs {
+    if let Some(x) = item {
+        // ...
+    }
+}
+```
+"##,
+
+E0301: r##"
+Mutable borrows are not allowed in pattern guards, because matching cannot have
+side effects. Side effects could alter the matched object or the environment
+on which the match depends in such a way, that the match would not be
+exhaustive. For instance, the following would not match any arm if mutable
+borrows were allowed:
+
+```compile_fail,E0301
+match Some(()) {
+    None => { },
+    option if option.take().is_none() => {
+        /* impossible, option is `Some` */
+    },
+    Some(_) => { } // When the previous match failed, the option became `None`.
+}
+```
+"##,
+
+E0302: r##"
+Assignments are not allowed in pattern guards, because matching cannot have
+side effects. Side effects could alter the matched object or the environment
+on which the match depends in such a way, that the match would not be
+exhaustive. For instance, the following would not match any arm if assignments
+were allowed:
+
+```compile_fail,E0302
+match Some(()) {
+    None => { },
+    option if { option = None; false } => { },
+    Some(_) => { } // When the previous match failed, the option became `None`.
+}
+```
+"##,
+
+E0303: r##"
+In certain cases it is possible for sub-bindings to violate memory safety.
+Updates to the borrow checker in a future version of Rust may remove this
+restriction, but for now patterns must be rewritten without sub-bindings.
+
+Before:
+
+```compile_fail,E0303
+match Some("hi".to_string()) {
+    ref op_string_ref @ Some(s) => {},
+    None => {},
+}
+```
+
+After:
+
+```
+match Some("hi".to_string()) {
+    Some(ref s) => {
+        let op_string_ref = &Some(s);
+        // ...
+    },
+    None => {},
+}
+```
+
+The `op_string_ref` binding has type `&Option<&String>` in both cases.
+
+See also https://github.com/rust-lang/rust/issues/14587
+"##,
+
 E0010: r##"
 The value of statics and constants must be known at compile time, and they live
 for the entire lifetime of a program. Creating a boxed value allocates memory on
@@ -1613,6 +2148,24 @@ fn main() {
 ```
 "##,
 
+E0579: r##"
+When matching against an exclusive range, the compiler verifies that the range
+is non-empty. Exclusive range patterns include the start point but not the end
+point, so this is equivalent to requiring the start of the range to be less
+than the end of the range.
+
+For example:
+
+```compile_fail
+match 5u32 {
+    // This range is ok, albeit pointless.
+    1 .. 2 => {}
+    // This range is empty, and the compiler can tell.
+    5 .. 5 => {}
+}
+```
+"##,
+
 E0595: r##"
 Closures cannot mutate immutable captured variables.
 
@@ -1771,6 +2324,9 @@ b.resume();
 }
 
 register_diagnostics! {
+//  E0298, // cannot compare constants
+//  E0299, // mismatched types between arms
+//  E0471, // constant evaluation error (in pattern)
 //    E0385, // {} in an aliasable location
     E0493, // destructors cannot be evaluated at compile-time
     E0524, // two closures require unique access to `..` at the same time
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 00ab2e4599528..da25969bf1177 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -10,12 +10,12 @@
 
 use hair::*;
 use rustc_data_structures::indexed_vec::Idx;
-use rustc_const_math::ConstInt;
 use hair::cx::Cx;
 use hair::cx::block;
 use hair::cx::to_ref::ToRef;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::middle::const_val::ConstVal;
+use rustc::mir::interpret::{GlobalId, Value, PrimVal};
 use rustc::ty::{self, AdtKind, VariantDef, Ty};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::cast::CastKind as TyCastKind;
@@ -100,7 +100,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             ExprKind::Deref { arg: expr.to_ref() }
         }
         Adjust::Deref(Some(deref)) => {
-            let call = deref.method_call(cx.tcx, expr.ty);
+            let call = deref.method_call(cx.tcx(), expr.ty);
 
             expr = Expr {
                 temp_lifetime,
@@ -314,7 +314,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             }
         }
 
-        hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) },
+        hir::ExprLit(ref lit) => ExprKind::Literal {
+            literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false),
+        },
 
         hir::ExprBinary(op, ref lhs, ref rhs) => {
             if cx.tables().is_method_call(expr) {
@@ -400,9 +402,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             if cx.tables().is_method_call(expr) {
                 overloaded_operator(cx, expr, vec![arg.to_ref()])
             } else {
-                // FIXME runtime-overflow
-                if let hir::ExprLit(_) = arg.node {
-                    ExprKind::Literal { literal: cx.const_eval_literal(expr) }
+                if let hir::ExprLit(ref lit) = arg.node {
+                    ExprKind::Literal {
+                        literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true),
+                    }
                 } else {
                     ExprKind::Unary {
                         op: UnOp::Neg,
@@ -508,10 +511,22 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let c = &cx.tcx.hir.body(count).value;
             let def_id = cx.tcx.hir.body_owner_def_id(count);
             let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id);
-            let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) {
-                Ok(&ty::Const { val: ConstVal::Integral(ConstInt::Usize(u)), .. }) => u,
-                Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
-                Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
+            let instance = ty::Instance::resolve(
+                cx.tcx.global_tcx(),
+                cx.param_env,
+                def_id,
+                substs,
+            ).unwrap();
+            let global_id = GlobalId {
+                instance,
+                promoted: None
+            };
+            let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) {
+                Ok(cv) => cv.val.unwrap_u64(),
+                Err(e) => {
+                    e.report(cx.tcx, cx.tcx.def_span(def_id), "array length");
+                    0
+                },
             };
 
             ExprKind::Repeat {
@@ -634,8 +649,8 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         span: expr.span,
         kind: ExprKind::Literal {
             literal: Literal::Value {
-                value: cx.tcx.mk_const(ty::Const {
-                    val: ConstVal::Function(def_id, substs),
+                value: cx.tcx().mk_const(ty::Const {
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
                     ty
                 }),
             },
@@ -682,13 +697,13 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     let substs = cx.tables().node_substs(expr.hir_id);
     match def {
         // A regular function, constructor function or a constant.
-        Def::Fn(def_id) |
-        Def::Method(def_id) |
-        Def::StructCtor(def_id, CtorKind::Fn) |
-        Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal {
+        Def::Fn(_) |
+        Def::Method(_) |
+        Def::StructCtor(_, CtorKind::Fn) |
+        Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
             literal: Literal::Value {
                 value: cx.tcx.mk_const(ty::Const {
-                    val: ConstVal::Function(def_id, substs),
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
                     ty: cx.tables().node_id_to_type(expr.hir_id)
                 }),
             },
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 44c413561175e..d8d5f5073abc1 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -16,22 +16,22 @@
 
 use hair::*;
 
-use rustc::middle::const_val::{ConstEvalErr, ConstVal};
-use rustc_const_eval::ConstContext;
+use rustc::middle::const_val::ConstVal;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::middle::region;
 use rustc::infer::InferCtxt;
 use rustc::ty::subst::Subst;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt, layout};
 use rustc::ty::subst::Substs;
-use syntax::ast;
+use syntax::ast::{self, LitKind};
 use syntax::attr;
 use syntax::symbol::Symbol;
 use rustc::hir;
-use rustc_const_math::{ConstInt, ConstUsize};
+use rustc_const_math::ConstFloat;
 use rustc_data_structures::sync::Lrc;
+use rustc::mir::interpret::{Value, PrimVal};
 
 #[derive(Clone)]
 pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
@@ -115,16 +115,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     }
 
     pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
-        match ConstUsize::new(value, self.tcx.sess.target.usize_ty) {
-            Ok(val) => {
-                Literal::Value {
-                    value: self.tcx.mk_const(ty::Const {
-                        val: ConstVal::Integral(ConstInt::Usize(val)),
-                        ty: self.tcx.types.usize
-                    })
-                }
-            }
-            Err(_) => bug!("usize literal out of range for target"),
+        Literal::Value {
+            value: self.tcx.mk_const(ty::Const {
+                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))),
+                ty: self.tcx.types.usize
+            })
         }
     }
 
@@ -139,7 +134,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     pub fn true_literal(&mut self) -> Literal<'tcx> {
         Literal::Value {
             value: self.tcx.mk_const(ty::Const {
-                val: ConstVal::Bool(true),
+                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))),
                 ty: self.tcx.types.bool
             })
         }
@@ -148,20 +143,104 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     pub fn false_literal(&mut self) -> Literal<'tcx> {
         Literal::Value {
             value: self.tcx.mk_const(ty::Const {
-                val: ConstVal::Bool(false),
+                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
                 ty: self.tcx.types.bool
             })
         }
     }
 
-    pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
+    pub fn integer_bit_width(
+        &self,
+        ty: Ty,
+    ) -> u64 {
+        let ty = match ty.sty {
+            ty::TyInt(ity) => attr::IntType::SignedInt(ity),
+            ty::TyUint(uty) => attr::IntType::UnsignedInt(uty),
+            _ => bug!("{} is not an integer", ty),
+        };
+        layout::Integer::from_attr(self.tcx, ty).size().bits()
+    }
+
+    pub fn const_eval_literal(
+        &mut self,
+        lit: &'tcx ast::LitKind,
+        ty: Ty<'tcx>,
+        sp: Span,
+        neg: bool,
+    ) -> Literal<'tcx> {
+        trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
         let tcx = self.tcx.global_tcx();
-        let const_cx = ConstContext::new(tcx,
-                                         self.param_env.and(self.identity_substs),
-                                         self.tables());
-        match const_cx.eval(tcx.hir.expect_expr(e.id)) {
-            Ok(value) => Literal::Value { value },
-            Err(s) => self.fatal_const_eval_err(&s, e.span, "expression")
+
+        let parse_float = |num: &str, fty| -> ConstFloat {
+            ConstFloat::from_str(num, fty).unwrap_or_else(|_| {
+                // FIXME(#31407) this is only necessary because float parsing is buggy
+                tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
+            })
+        };
+
+        let clamp = |n| {
+            let size = self.integer_bit_width(ty);
+            trace!("clamp {} with size {} and amt {}", n, size, 128 - size);
+            let amt = 128 - size;
+            let result = (n << amt) >> amt;
+            trace!("clamp result: {}", result);
+            result
+        };
+
+        use rustc::mir::interpret::*;
+        let lit = match *lit {
+            LitKind::Str(ref s, _) => {
+                let s = s.as_str();
+                let id = self.tcx.allocate_cached(s.as_bytes());
+                let ptr = MemoryPointer::new(id, 0);
+                Value::ByValPair(
+                    PrimVal::Ptr(ptr),
+                    PrimVal::from_u128(s.len() as u128),
+                )
+            },
+            LitKind::ByteStr(ref data) => {
+                let id = self.tcx.allocate_cached(data);
+                let ptr = MemoryPointer::new(id, 0);
+                Value::ByVal(PrimVal::Ptr(ptr))
+            },
+            LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
+            LitKind::Int(n, _) if neg => {
+                let n = n as i128;
+                let n = n.overflowing_neg().0;
+                let n = clamp(n as u128);
+                Value::ByVal(PrimVal::Bytes(n))
+            },
+            LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))),
+            LitKind::Float(n, fty) => {
+                let n = n.as_str();
+                let mut f = parse_float(&n, fty);
+                if neg {
+                    f = -f;
+                }
+                let bits = f.bits;
+                Value::ByVal(PrimVal::Bytes(bits))
+            }
+            LitKind::FloatUnsuffixed(n) => {
+                let fty = match ty.sty {
+                    ty::TyFloat(fty) => fty,
+                    _ => bug!()
+                };
+                let n = n.as_str();
+                let mut f = parse_float(&n, fty);
+                if neg {
+                    f = -f;
+                }
+                let bits = f.bits;
+                Value::ByVal(PrimVal::Bytes(bits))
+            }
+            LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
+            LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
+        };
+        Literal::Value {
+            value: self.tcx.mk_const(ty::Const {
+                val: ConstVal::Value(lit),
+                ty,
+            }),
         }
     }
 
@@ -177,17 +256,6 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                           p)
     }
 
-    pub fn fatal_const_eval_err(&mut 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,
@@ -203,7 +271,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                 return (method_ty,
                         Literal::Value {
                             value: self.tcx.mk_const(ty::Const {
-                                val: ConstVal::Function(item.def_id, substs),
+                                // ZST function type
+                                val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
                                 ty: method_ty
                             }),
                         });
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 09a31f9ab8fa5..5f60a134fb130 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -14,7 +14,6 @@
 //! unit-tested and separated from the Rust source and compiler data
 //! structures.
 
-use rustc_const_math::ConstUsize;
 use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp};
 use rustc::hir::def_id::DefId;
 use rustc::middle::region;
@@ -27,7 +26,8 @@ use self::cx::Cx;
 
 pub mod cx;
 
-pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
+pub mod pattern;
+pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
 
 #[derive(Copy, Clone, Debug)]
 pub enum LintLevel {
@@ -246,7 +246,7 @@ pub enum ExprKind<'tcx> {
     },
     Repeat {
         value: ExprRef<'tcx>,
-        count: ConstUsize,
+        count: u64,
     },
     Array {
         fields: Vec<ExprRef<'tcx>>,
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
similarity index 86%
rename from src/librustc_const_eval/_match.rs
rename to src/librustc_mir/hair/pattern/_match.rs
index 8e3b99f2dbfee..a3295aac80157 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -13,21 +13,19 @@ use self::Usefulness::*;
 use self::WitnessPreference::*;
 
 use rustc::middle::const_val::ConstVal;
-use eval::{compare_const_vals};
-
-use rustc_const_math::ConstInt;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::indexed_vec::Idx;
 
-use pattern::{FieldPattern, Pattern, PatternKind};
-use pattern::{PatternFoldable, PatternFolder};
+use super::{FieldPattern, Pattern, PatternKind};
+use super::{PatternFoldable, PatternFolder, compare_const_vals};
 
 use rustc::hir::def_id::DefId;
 use rustc::hir::RangeEnd;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 
 use rustc::mir::Field;
+use rustc::mir::interpret::{Value, PrimVal};
 use rustc::util::common::ErrorReported;
 
 use syntax_pos::{Span, DUMMY_SP};
@@ -182,18 +180,38 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
         self.byte_array_map.entry(pat).or_insert_with(|| {
             match pat.kind {
                 box PatternKind::Constant {
-                    value: &ty::Const { val: ConstVal::ByteStr(b), .. }
+                    value: &ty::Const { val: ConstVal::Value(b), ty }
                 } => {
-                    b.data.iter().map(|&b| &*pattern_arena.alloc(Pattern {
-                        ty: tcx.types.u8,
-                        span: pat.span,
-                        kind: box PatternKind::Constant {
-                            value: tcx.mk_const(ty::Const {
-                                val: ConstVal::Integral(ConstInt::U8(b)),
-                                ty: tcx.types.u8
-                            })
-                        }
-                    })).collect()
+                    match b {
+                        Value::ByVal(PrimVal::Ptr(ptr)) => {
+                            let is_array_ptr = ty
+                                .builtin_deref(true)
+                                .and_then(|t| t.ty.builtin_index())
+                                .map_or(false, |t| t == tcx.types.u8);
+                            assert!(is_array_ptr);
+                            let alloc = tcx
+                                .interpret_interner
+                                .get_alloc(ptr.alloc_id)
+                                .unwrap();
+                            assert_eq!(ptr.offset, 0);
+                            // FIXME: check length
+                            alloc.bytes.iter().map(|b| {
+                                &*pattern_arena.alloc(Pattern {
+                                    ty: tcx.types.u8,
+                                    span: pat.span,
+                                    kind: box PatternKind::Constant {
+                                        value: tcx.mk_const(ty::Const {
+                                            val: ConstVal::Value(Value::ByVal(
+                                                PrimVal::Bytes(*b as u128),
+                                            )),
+                                            ty: tcx.types.u8
+                                        })
+                                    }
+                                })
+                            }).collect()
+                        },
+                        _ => bug!("not a byte str: {:?}", b),
+                    }
                 }
                 _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
             }
@@ -422,13 +440,13 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
         ty::TyBool => {
             [true, false].iter().map(|&b| {
                 ConstantValue(cx.tcx.mk_const(ty::Const {
-                    val: ConstVal::Bool(b),
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))),
                     ty: cx.tcx.types.bool
                 }))
             }).collect()
         }
-        ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => {
-            let len = len.val.to_const_int().unwrap().to_u64().unwrap();
+        ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => {
+            let len = len.val.unwrap_u64();
             if len != 0 && cx.is_uninhabited(sub_ty) {
                 vec![]
             } else {
@@ -461,7 +479,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
 }
 
 fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
-    _cx: &mut MatchCheckCtxt<'a, 'tcx>,
+    cx: &mut MatchCheckCtxt<'a, 'tcx>,
     patterns: I) -> u64
     where I: Iterator<Item=&'p Pattern<'tcx>>
 {
@@ -535,8 +553,23 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
 
     for row in patterns {
         match *row.kind {
-            PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => {
-                max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64);
+            PatternKind::Constant {
+                value: &ty::Const {
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))),
+                    ty,
+                }
+            } => {
+                let is_array_ptr = ty
+                    .builtin_deref(true)
+                    .and_then(|t| t.ty.builtin_index())
+                    .map_or(false, |t| t == cx.tcx.types.u8);
+                if is_array_ptr {
+                    let alloc = cx.tcx
+                        .interpret_interner
+                        .get_alloc(ptr.alloc_id)
+                        .unwrap();
+                    max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
+                }
             }
             PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
                 let fixed_len = prefix.len() as u64 + suffix.len() as u64;
@@ -581,7 +614,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                                        witness: WitnessPreference)
                                        -> Usefulness<'tcx> {
     let &Matrix(ref rows) = matrix;
-    debug!("is_useful({:?}, {:?})", matrix, v);
+    debug!("is_useful({:#?}, {:#?})", matrix, v);
 
     // The base case. We are pattern-matching on () and the return value is
     // based on whether our matrix has a row or not.
@@ -626,10 +659,10 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
         max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0])))
     };
 
-    debug!("is_useful_expand_first_col: pcx={:?}, expanding {:?}", pcx, v[0]);
+    debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]);
 
     if let Some(constructors) = pat_constructors(cx, v[0], pcx) {
-        debug!("is_useful - expanding constructors: {:?}", constructors);
+        debug!("is_useful - expanding constructors: {:#?}", constructors);
         constructors.into_iter().map(|c|
             is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
         ).find(|result| result.is_useful()).unwrap_or(NotUseful)
@@ -639,9 +672,9 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
         let used_ctors: Vec<Constructor> = rows.iter().flat_map(|row| {
             pat_constructors(cx, row[0], pcx).unwrap_or(vec![])
         }).collect();
-        debug!("used_ctors = {:?}", used_ctors);
+        debug!("used_ctors = {:#?}", used_ctors);
         let all_ctors = all_constructors(cx, pcx);
-        debug!("all_ctors = {:?}", all_ctors);
+        debug!("all_ctors = {:#?}", all_ctors);
         let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| {
             !used_ctors.contains(*c)
         }).cloned().collect();
@@ -669,7 +702,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
             all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
         let is_declared_nonexhaustive =
             cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
-        debug!("missing_ctors={:?} is_privately_empty={:?} is_declared_nonexhaustive={:?}",
+        debug!("missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
                missing_ctors, is_privately_empty, is_declared_nonexhaustive);
 
         // For privately empty and non-exhaustive enums, we work as if there were an "extra"
@@ -769,7 +802,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
     lty: Ty<'tcx>,
     witness: WitnessPreference) -> Usefulness<'tcx>
 {
-    debug!("is_useful_specialized({:?}, {:?}, {:?})", v, ctor, lty);
+    debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
     let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty);
     let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| {
         Pattern {
@@ -821,7 +854,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
             Some(vec![ConstantRange(lo, hi, end)]),
         PatternKind::Array { .. } => match pcx.ty.sty {
             ty::TyArray(_, length) => Some(vec![
-                Slice(length.val.to_const_int().unwrap().to_u64().unwrap())
+                Slice(length.val.unwrap_u64())
             ]),
             _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
         },
@@ -842,7 +875,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
 /// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
 /// A struct pattern's arity is the number of fields it contains, etc.
 fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
-    debug!("constructor_arity({:?}, {:?})", ctor, ty);
+    debug!("constructor_arity({:#?}, {:?})", ctor, ty);
     match ty.sty {
         ty::TyTuple(ref fs, _) => fs.len() as u64,
         ty::TySlice(..) | ty::TyArray(..) => match *ctor {
@@ -866,7 +899,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
                                              ctor: &Constructor,
                                              ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
 {
-    debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty);
+    debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
     match ty.sty {
         ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(),
         ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor {
@@ -901,14 +934,28 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
     }
 }
 
-fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
+fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
                                     ctor: &Constructor,
                                     prefix: &[Pattern],
                                     slice: &Option<Pattern>,
                                     suffix: &[Pattern])
                                     -> Result<bool, ErrorReported> {
-    let data = match *ctor {
-        ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data,
+    let data: &[u8] = match *ctor {
+        ConstantValue(&ty::Const { val: ConstVal::Value(
+            Value::ByVal(PrimVal::Ptr(ptr))
+        ), ty }) => {
+            let is_array_ptr = ty
+                .builtin_deref(true)
+                .and_then(|t| t.ty.builtin_index())
+                .map_or(false, |t| t == tcx.types.u8);
+            assert!(is_array_ptr);
+            tcx
+                .interpret_interner
+                .get_alloc(ptr.alloc_id)
+                .unwrap()
+                .bytes
+                .as_ref()
+        }
         _ => bug!()
     };
 
@@ -923,11 +970,12 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
     {
         match pat.kind {
             box PatternKind::Constant { value } => match value.val {
-                ConstVal::Integral(ConstInt::U8(u)) => {
-                    if u != *ch {
+                ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
+                    assert_eq!(b as u8 as u128, b);
+                    if b as u8 != *ch {
                         return Ok(false);
                     }
-                },
+                }
                 _ => span_bug!(pat.span, "bad const u8 {:?}", value)
             },
             _ => {}
@@ -937,31 +985,41 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
     Ok(true)
 }
 
-fn constructor_covered_by_range(tcx: TyCtxt, span: Span,
-                                ctor: &Constructor,
+fn constructor_covered_by_range(ctor: &Constructor,
                                 from: &ConstVal, to: &ConstVal,
-                                end: RangeEnd)
+                                end: RangeEnd,
+                                ty: Ty)
                                 -> Result<bool, ErrorReported> {
-    let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less);
-    let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to);
+    trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty);
+    let cmp_from = |c_from| compare_const_vals(c_from, from, ty)
+        .map(|res| res != Ordering::Less);
+    let cmp_to = |c_to| compare_const_vals(c_to, to, ty);
+    macro_rules! some_or_ok {
+        ($e:expr) => {
+            match $e {
+                Some(to) => to,
+                None => return Ok(false), // not char or int
+            }
+        };
+    }
     match *ctor {
         ConstantValue(value) => {
-            let to = cmp_to(&value.val)?;
+            let to = some_or_ok!(cmp_to(&value.val));
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Included && to == Ordering::Equal);
-            Ok(cmp_from(&value.val)? && end)
+            Ok(some_or_ok!(cmp_from(&value.val)) && end)
         },
         ConstantRange(from, to, RangeEnd::Included) => {
-            let to = cmp_to(&to.val)?;
+            let to = some_or_ok!(cmp_to(&to.val));
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Included && to == Ordering::Equal);
-            Ok(cmp_from(&from.val)? && end)
+            Ok(some_or_ok!(cmp_from(&from.val)) && end)
         },
         ConstantRange(from, to, RangeEnd::Excluded) => {
-            let to = cmp_to(&to.val)?;
+            let to = some_or_ok!(cmp_to(&to.val));
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Excluded && to == Ordering::Equal);
-            Ok(cmp_from(&from.val)? && end)
+            Ok(some_or_ok!(cmp_from(&from.val)) && end)
         }
         Single => Ok(true),
         _ => bug!(),
@@ -979,7 +1037,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
         result[subpat.field.index()] = &subpat.pattern;
     }
 
-    debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, wild_patterns, result);
+    debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result);
     result
 }
 
@@ -994,7 +1052,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
 fn specialize<'p, 'a: 'p, 'tcx: 'a>(
     cx: &mut MatchCheckCtxt<'a, 'tcx>,
     r: &[&'p Pattern<'tcx>],
-    constructor: &Constructor,
+    constructor: &Constructor<'tcx>,
     wild_patterns: &[&'p Pattern<'tcx>])
     -> Option<Vec<&'p Pattern<'tcx>>>
 {
@@ -1024,8 +1082,19 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
         PatternKind::Constant { value } => {
             match *constructor {
                 Slice(..) => match value.val {
-                    ConstVal::ByteStr(b) => {
-                        if wild_patterns.len() == b.data.len() {
+                    ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => {
+                        let is_array_ptr = value.ty
+                            .builtin_deref(true)
+                            .and_then(|t| t.ty.builtin_index())
+                            .map_or(false, |t| t == cx.tcx.types.u8);
+                        assert!(is_array_ptr);
+                        let data_len = cx.tcx
+                            .interpret_interner
+                            .get_alloc(ptr.alloc_id)
+                            .unwrap()
+                            .bytes
+                            .len();
+                        if wild_patterns.len() == data_len {
                             Some(cx.lower_byte_str_pattern(pat))
                         } else {
                             None
@@ -1036,7 +1105,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                 },
                 _ => {
                     match constructor_covered_by_range(
-                        cx.tcx, pat.span, constructor, &value.val, &value.val, RangeEnd::Included
+                        constructor, &value.val, &value.val, RangeEnd::Included,
+                        value.ty,
                             ) {
                         Ok(true) => Some(vec![]),
                         Ok(false) => None,
@@ -1048,7 +1118,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
 
         PatternKind::Range { lo, hi, ref end } => {
             match constructor_covered_by_range(
-                cx.tcx, pat.span, constructor, &lo.val, &hi.val, end.clone()
+                constructor, &lo.val, &hi.val, end.clone(), lo.ty,
             ) {
                 Ok(true) => Some(vec![]),
                 Ok(false) => None,
@@ -1092,7 +1162,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
             }
         }
     };
-    debug!("specialize({:?}, {:?}) = {:?}", r[0], wild_patterns, head);
+    debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head);
 
     head.map(|mut head| {
         head.extend_from_slice(&r[1 ..]);
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
similarity index 96%
rename from src/librustc_const_eval/check_match.rs
rename to src/librustc_mir/hair/pattern/check_match.rs
index 6f7143c185cb3..69ed4e6064fcf 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -8,11 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
-use _match::Usefulness::*;
-use _match::WitnessPreference::*;
+use super::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
+use super::_match::Usefulness::*;
+use super::_match::WitnessPreference::*;
 
-use pattern::{Pattern, PatternContext, PatternError, PatternKind};
+use super::{Pattern, PatternContext, PatternError, PatternKind};
 
 use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
 use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
@@ -138,8 +138,18 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                 PatternError::AssociatedConstInPattern(span) => {
                     self.span_e0158(span, "associated consts cannot be referenced in patterns")
                 }
-                PatternError::ConstEval(ref err) => {
-                    err.report(self.tcx, pat_span, "pattern");
+                PatternError::FloatBug => {
+                    // FIXME(#31407) this is only necessary because float parsing is buggy
+                    ::rustc::middle::const_val::struct_error(
+                        self.tcx, pat_span,
+                        "could not evaluate float literal (see issue #31407)",
+                    ).emit();
+                }
+                PatternError::NonConstPath(span) => {
+                    ::rustc::middle::const_val::struct_error(
+                        self.tcx, span,
+                        "runtime values cannot be referenced in patterns",
+                    ).emit();
                 }
             }
         }
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_mir/hair/pattern/mod.rs
similarity index 64%
rename from src/librustc_const_eval/pattern.rs
rename to src/librustc_mir/hair/pattern/mod.rs
index bdb1001124de6..1774c95af0f05 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -8,10 +8,19 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use eval;
+//! Code to validate patterns/matches
 
-use rustc::middle::const_val::{ConstEvalErr, ConstVal};
+mod _match;
+mod check_match;
+
+pub use self::check_match::check_crate;
+pub(crate) use self::check_match::check_match;
+
+use interpret::{const_val_field, const_discr};
+
+use rustc::middle::const_val::ConstVal;
 use rustc::mir::{Field, BorrowKind, Mutability};
+use rustc::mir::interpret::{GlobalId, Value, PrimVal};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
 use rustc::ty::subst::{Substs, Kind};
 use rustc::hir::{self, PatKind, RangeEnd};
@@ -19,17 +28,20 @@ use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 
 use rustc_data_structures::indexed_vec::Idx;
+use rustc_const_math::ConstFloat;
 
+use std::cmp::Ordering;
 use std::fmt;
 use syntax::ast;
 use syntax::ptr::P;
 use syntax_pos::Span;
 
 #[derive(Clone, Debug)]
-pub enum PatternError<'tcx> {
+pub enum PatternError {
     AssociatedConstInPattern(Span),
     StaticInPattern(Span),
-    ConstEval(ConstEvalErr<'tcx>),
+    FloatBug,
+    NonConstPath(Span),
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -110,21 +122,26 @@ pub enum PatternKind<'tcx> {
     },
 }
 
-fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
-    match *value {
-        ConstVal::Float(ref x) => write!(f, "{}", x),
-        ConstVal::Integral(ref i) => write!(f, "{}", i),
-        ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]),
-        ConstVal::ByteStr(b) => write!(f, "{:?}", b.data),
-        ConstVal::Bool(b) => write!(f, "{:?}", b),
-        ConstVal::Char(c) => write!(f, "{:?}", c),
-        ConstVal::Variant(_) |
-        ConstVal::Function(..) |
-        ConstVal::Aggregate(_) |
+fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
+    match value.val {
+        ConstVal::Value(v) => print_miri_value(v, value.ty, f),
         ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
     }
 }
 
+fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result {
+    use rustc::ty::TypeVariants::*;
+    match (value, &ty.sty) {
+        (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
+        (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
+        (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n),
+        (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128),
+        (Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
+            write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
+        _ => bug!("{:?}: {} not printable in a pattern", value, ty),
+    }
+}
+
 impl<'tcx> fmt::Display for Pattern<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self.kind {
@@ -232,15 +249,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
                 write!(f, "{}", subpattern)
             }
             PatternKind::Constant { value } => {
-                print_const_val(&value.val, f)
+                print_const_val(value, f)
             }
             PatternKind::Range { lo, hi, end } => {
-                print_const_val(&lo.val, f)?;
+                print_const_val(lo, f)?;
                 match end {
                     RangeEnd::Included => write!(f, "...")?,
                     RangeEnd::Excluded => write!(f, "..")?,
                 }
-                print_const_val(&hi.val, f)
+                print_const_val(hi, f)
             }
             PatternKind::Slice { ref prefix, ref slice, ref suffix } |
             PatternKind::Array { ref prefix, ref slice, ref suffix } => {
@@ -272,7 +289,7 @@ pub struct PatternContext<'a, 'tcx: 'a> {
     pub param_env: ty::ParamEnv<'tcx>,
     pub tables: &'a ty::TypeckTables<'tcx>,
     pub substs: &'tcx Substs<'tcx>,
-    pub errors: Vec<PatternError<'tcx>>,
+    pub errors: Vec<PatternError>,
 }
 
 impl<'a, 'tcx> Pattern<'tcx> {
@@ -350,18 +367,53 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
 
             PatKind::Lit(ref value) => self.lower_lit(value),
 
-            PatKind::Range(ref lo, ref hi, end) => {
-                match (self.lower_lit(lo), self.lower_lit(hi)) {
+            PatKind::Range(ref lo_expr, ref hi_expr, end) => {
+                match (self.lower_lit(lo_expr), self.lower_lit(hi_expr)) {
                     (PatternKind::Constant { value: lo },
                      PatternKind::Constant { value: hi }) => {
-                        PatternKind::Range { lo, hi, end }
+                        use std::cmp::Ordering;
+                        match (end, compare_const_vals(&lo.val, &hi.val, ty).unwrap()) {
+                            (RangeEnd::Excluded, Ordering::Less) =>
+                                PatternKind::Range { lo, hi, end },
+                            (RangeEnd::Excluded, _) => {
+                                span_err!(
+                                    self.tcx.sess,
+                                    lo_expr.span,
+                                    E0579,
+                                    "lower range bound must be less than upper",
+                                );
+                                PatternKind::Wild
+                            },
+                            (RangeEnd::Included, Ordering::Greater) => {
+                                let mut err = struct_span_err!(
+                                    self.tcx.sess,
+                                    lo_expr.span,
+                                    E0030,
+                                    "lower range bound must be less than or equal to upper"
+                                );
+                                err.span_label(
+                                    lo_expr.span,
+                                    "lower bound larger than upper bound",
+                                );
+                                if self.tcx.sess.teach(&err.get_code().unwrap()) {
+                                    err.note("When matching against a range, the compiler \
+                                              verifies that the range is non-empty. Range \
+                                              patterns include both end-points, so this is \
+                                              equivalent to requiring the start of the range \
+                                              to be less than or equal to the end of the range.");
+                                }
+                                err.emit();
+                                PatternKind::Wild
+                            },
+                            (RangeEnd::Included, _) => PatternKind::Range { lo, hi, end },
+                        }
                     }
                     _ => PatternKind::Wild
                 }
             }
 
             PatKind::Path(ref qpath) => {
-                return self.lower_path(qpath, pat.hir_id, pat.id, pat.span);
+                return self.lower_path(qpath, pat.hir_id, pat.span);
             }
 
             PatKind::Ref(ref subpattern, _) |
@@ -471,7 +523,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                                        pattern: self.lower_pattern(field),
                                    })
                                    .collect();
-                self.lower_variant_or_leaf(def, ty, subpatterns)
+                self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
             }
 
             PatKind::Struct(ref qpath, ref fields, _) => {
@@ -503,7 +555,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                           })
                           .collect();
 
-                self.lower_variant_or_leaf(def, ty, subpatterns)
+                self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
             }
         };
 
@@ -580,7 +632,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
 
             ty::TyArray(_, len) => {
                 // fixed-length array
-                let len = len.val.to_const_int().unwrap().to_u64().unwrap();
+                let len = len.val.unwrap_u64();
                 assert!(len >= prefix.len() as u64 + suffix.len() as u64);
                 PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
             }
@@ -594,6 +646,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
     fn lower_variant_or_leaf(
         &mut self,
         def: Def,
+        span: Span,
         ty: Ty<'tcx>,
         subpatterns: Vec<FieldPattern<'tcx>>)
         -> PatternKind<'tcx>
@@ -624,14 +677,19 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                 PatternKind::Leaf { subpatterns: subpatterns }
             }
 
-            _ => bug!()
+            _ => {
+                self.errors.push(PatternError::NonConstPath(span));
+                PatternKind::Wild
+            }
         }
     }
 
+    /// Takes a HIR Path. If the path is a constant, evaluates it and feeds
+    /// it to `const_to_pat`. Any other path (like enum variants without fields)
+    /// is converted to the corresponding pattern via `lower_variant_or_leaf`
     fn lower_path(&mut self,
                   qpath: &hir::QPath,
                   id: hir::HirId,
-                  pat_id: ast::NodeId,
                   span: Span)
                   -> Pattern<'tcx> {
         let ty = self.tables.node_id_to_type(id);
@@ -643,23 +701,27 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
         let kind = match def {
             Def::Const(def_id) | Def::AssociatedConst(def_id) => {
                 let substs = self.tables.node_substs(id);
-                match eval::lookup_const_by_id(self.tcx, self.param_env.and((def_id, substs))) {
-                    Some((def_id, substs)) => {
-                        // Enter the inlined constant's tables&substs temporarily.
-                        let old_tables = self.tables;
-                        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 {
-                            self.tcx.extern_const_body(def_id).body
+                match ty::Instance::resolve(
+                    self.tcx,
+                    self.param_env,
+                    def_id,
+                    substs,
+                ) {
+                    Some(instance) => {
+                        let cid = GlobalId {
+                            instance,
+                            promoted: None,
                         };
-                        let pat = self.lower_const_expr(&body.value, pat_id, span);
-                        self.tables = old_tables;
-                        self.substs = old_substs;
-                        return pat;
-                    }
+                        match self.tcx.at(span).const_eval(self.param_env.and(cid)) {
+                            Ok(value) => {
+                                return self.const_to_pat(instance, value, id, span)
+                            },
+                            Err(err) => {
+                                err.report(self.tcx, span, "pattern");
+                                PatternKind::Wild
+                            },
+                        }
+                    },
                     None => {
                         self.errors.push(if is_associated_const {
                             PatternError::AssociatedConstInPattern(span)
@@ -667,10 +729,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                             PatternError::StaticInPattern(span)
                         });
                         PatternKind::Wild
-                    }
+                    },
                 }
             }
-            _ => self.lower_variant_or_leaf(def, ty, vec![]),
+            _ => self.lower_variant_or_leaf(def, span, ty, vec![]),
         };
 
         Pattern {
@@ -680,138 +742,167 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
         }
     }
 
+    /// Converts literals, paths and negation of literals to patterns.
+    /// The special case for negation exists to allow things like -128i8
+    /// which would overflow if we tried to evaluate 128i8 and then negate
+    /// afterwards.
     fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
-        let const_cx = eval::ConstContext::new(self.tcx,
-                                               self.param_env.and(self.substs),
-                                               self.tables);
-        match const_cx.eval(expr) {
-            Ok(value) => {
-                if let ConstVal::Variant(def_id) = value.val {
-                    let ty = self.tables.expr_ty(expr);
-                    self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![])
-                } else {
-                    PatternKind::Constant { value }
+        match expr.node {
+            hir::ExprLit(ref lit) => {
+                let ty = self.tables.expr_ty(expr);
+                match lit_to_const(&lit.node, self.tcx, ty, false) {
+                    Ok(val) => {
+                        let instance = ty::Instance::new(
+                            self.tables.local_id_root.expect("literal outside any scope"),
+                            self.substs,
+                        );
+                        let cv = self.tcx.mk_const(ty::Const { val, ty });
+                        *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+                    },
+                    Err(()) => {
+                        self.errors.push(PatternError::FloatBug);
+                        PatternKind::Wild
+                    },
+                }
+            },
+            hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind,
+            hir::ExprUnary(hir::UnNeg, ref expr) => {
+                let ty = self.tables.expr_ty(expr);
+                let lit = match expr.node {
+                    hir::ExprLit(ref lit) => lit,
+                    _ => span_bug!(expr.span, "not a literal: {:?}", expr),
+                };
+                match lit_to_const(&lit.node, self.tcx, ty, true) {
+                    Ok(val) => {
+                        let instance = ty::Instance::new(
+                            self.tables.local_id_root.expect("literal outside any scope"),
+                            self.substs,
+                        );
+                        let cv = self.tcx.mk_const(ty::Const { val, ty });
+                        *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+                    },
+                    Err(()) => {
+                        self.errors.push(PatternError::FloatBug);
+                        PatternKind::Wild
+                    },
                 }
             }
-            Err(e) => {
-                self.errors.push(PatternError::ConstEval(e));
-                PatternKind::Wild
-            }
+            _ => span_bug!(expr.span, "not a literal: {:?}", expr),
         }
     }
 
-    fn lower_const_expr(&mut self,
-                        expr: &'tcx hir::Expr,
-                        pat_id: ast::NodeId,
-                        span: Span)
-                        -> Pattern<'tcx> {
-        let pat_ty = self.tables.expr_ty(expr);
-        debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
-        match pat_ty.sty {
+    /// Converts an evaluated constant to a pattern (if possible).
+    /// This means aggregate values (like structs and enums) are converted
+    /// to a pattern that matches the value (as if you'd compare via eq).
+    fn const_to_pat(
+        &self,
+        instance: ty::Instance<'tcx>,
+        cv: &'tcx ty::Const<'tcx>,
+        id: hir::HirId,
+        span: Span,
+    ) -> Pattern<'tcx> {
+        debug!("const_to_pat: cv={:#?}", cv);
+        let adt_subpattern = |i, variant_opt| {
+            let field = Field::new(i);
+            let val = match cv.val {
+                ConstVal::Value(miri) => const_val_field(
+                    self.tcx, self.param_env, instance,
+                    variant_opt, field, miri, cv.ty,
+                ).unwrap(),
+                _ => bug!("{:#?} is not a valid adt", cv),
+            };
+            self.const_to_pat(instance, val, id, span)
+        };
+        let adt_subpatterns = |n, variant_opt| {
+            (0..n).map(|i| {
+                let field = Field::new(i);
+                FieldPattern {
+                    field,
+                    pattern: adt_subpattern(i, variant_opt),
+                }
+            }).collect::<Vec<_>>()
+        };
+        let kind = match cv.ty.sty {
             ty::TyFloat(_) => {
-                self.tcx.sess.span_err(span, "floating point constants cannot be used in patterns");
-            }
+                let id = self.tcx.hir.hir_to_node_id(id);
+                self.tcx.lint_node(
+                    ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+                    id,
+                    span,
+                    "floating-point types cannot be used in patterns",
+                );
+                PatternKind::Constant {
+                    value: cv,
+                }
+            },
             ty::TyAdt(adt_def, _) if adt_def.is_union() => {
                 // Matching on union fields is unsafe, we can't hide it in constants
                 self.tcx.sess.span_err(span, "cannot use unions in constant patterns");
+                PatternKind::Wild
             }
-            ty::TyAdt(adt_def, _) => {
-                if !self.tcx.has_attr(adt_def.did, "structural_match") {
-                    let msg = format!("to use a constant of type `{}` in a pattern, \
-                                       `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                                      self.tcx.item_path_str(adt_def.did),
-                                      self.tcx.item_path_str(adt_def.did));
-                    self.tcx.sess.span_err(span, &msg);
+            ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => {
+                let msg = format!("to use a constant of type `{}` in a pattern, \
+                                    `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
+                                    self.tcx.item_path_str(adt_def.did),
+                                    self.tcx.item_path_str(adt_def.did));
+                self.tcx.sess.span_err(span, &msg);
+                PatternKind::Wild
+            },
+            ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
+                match cv.val {
+                    ConstVal::Value(val) => {
+                        let discr = const_discr(
+                            self.tcx, self.param_env, instance, val, cv.ty
+                        ).unwrap();
+                        let variant_index = adt_def
+                            .discriminants(self.tcx)
+                            .position(|var| var.val == discr)
+                            .unwrap();
+                        let subpatterns = adt_subpatterns(
+                            adt_def.variants[variant_index].fields.len(),
+                            Some(variant_index),
+                        );
+                        PatternKind::Variant {
+                            adt_def,
+                            substs,
+                            variant_index,
+                            subpatterns,
+                        }
+                    },
+                    ConstVal::Unevaluated(..) =>
+                        span_bug!(span, "{:#?} is not a valid enum constant", cv),
                 }
-            }
-            _ => { }
-        }
-        let kind = match expr.node {
-            hir::ExprTup(ref exprs) => {
+            },
+            ty::TyAdt(adt_def, _) => {
+                let struct_var = adt_def.non_enum_variant();
                 PatternKind::Leaf {
-                    subpatterns: exprs.iter().enumerate().map(|(i, expr)| {
-                        FieldPattern {
-                            field: Field::new(i),
-                            pattern: self.lower_const_expr(expr, pat_id, span)
-                        }
-                    }).collect()
+                    subpatterns: adt_subpatterns(struct_var.fields.len(), None),
                 }
             }
-
-            hir::ExprCall(ref callee, ref args) => {
-                let qpath = match callee.node {
-                    hir::ExprPath(ref qpath) => qpath,
-                    _ => bug!()
-                };
-                let ty = self.tables.node_id_to_type(callee.hir_id);
-                let def = self.tables.qpath_def(qpath, callee.hir_id);
-                match def {
-                    Def::Fn(..) | Def::Method(..) => self.lower_lit(expr),
-                    _ => {
-                        let subpatterns = args.iter().enumerate().map(|(i, expr)| {
-                            FieldPattern {
-                                field: Field::new(i),
-                                pattern: self.lower_const_expr(expr, pat_id, span)
-                            }
-                        }).collect();
-                        self.lower_variant_or_leaf(def, ty, subpatterns)
-                    }
+            ty::TyTuple(fields, _) => {
+                PatternKind::Leaf {
+                    subpatterns: adt_subpatterns(fields.len(), None),
                 }
             }
-
-            hir::ExprStruct(ref qpath, ref fields, None) => {
-                let def = self.tables.qpath_def(qpath, expr.hir_id);
-                let adt_def = match pat_ty.sty {
-                    ty::TyAdt(adt_def, _) => adt_def,
-                    _ => {
-                        span_bug!(
-                            expr.span,
-                            "struct expr without ADT type");
-                    }
-                };
-                let variant_def = adt_def.variant_of_def(def);
-
-                let subpatterns =
-                    fields.iter()
-                          .map(|field| {
-                              let index = variant_def.index_of_field_named(field.name.node);
-                              let index = index.unwrap_or_else(|| {
-                                  span_bug!(
-                                      expr.span,
-                                      "no field with name {:?}",
-                                      field.name);
-                              });
-                              FieldPattern {
-                                  field: Field::new(index),
-                                  pattern: self.lower_const_expr(&field.expr, pat_id, span),
-                              }
-                          })
-                          .collect();
-
-                self.lower_variant_or_leaf(def, pat_ty, subpatterns)
-            }
-
-            hir::ExprArray(ref exprs) => {
-                let pats = exprs.iter()
-                                .map(|expr| self.lower_const_expr(expr, pat_id, span))
-                                .collect();
+            ty::TyArray(_, n) => {
                 PatternKind::Array {
-                    prefix: pats,
+                    prefix: (0..n.val.unwrap_u64())
+                        .map(|i| adt_subpattern(i as usize, None))
+                        .collect(),
                     slice: None,
-                    suffix: vec![]
+                    suffix: Vec::new(),
                 }
             }
-
-            hir::ExprPath(ref qpath) => {
-                return self.lower_path(qpath, expr.hir_id, pat_id, span);
-            }
-
-            _ => self.lower_lit(expr)
+            _ => {
+                PatternKind::Constant {
+                    value: cv,
+                }
+            },
         };
 
         Pattern {
             span,
-            ty: pat_ty,
+            ty: cv.ty,
             kind: Box::new(kind),
         }
     }
@@ -975,3 +1066,127 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
         }
     }
 }
+
+pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option<Ordering> {
+    use rustc_const_math::ConstFloat;
+    trace!("compare_const_vals: {:?}, {:?}", a, b);
+    use rustc::mir::interpret::{Value, PrimVal};
+    match (a, b) {
+        (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))),
+         &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => {
+            match ty.sty {
+                ty::TyFloat(ty) => {
+                    let l = ConstFloat {
+                        bits: a,
+                        ty,
+                    };
+                    let r = ConstFloat {
+                        bits: b,
+                        ty,
+                    };
+                    // FIXME(oli-obk): report cmp errors?
+                    l.try_cmp(r).ok()
+                },
+                ty::TyInt(_) => Some((a as i128).cmp(&(b as i128))),
+                _ => Some(a.cmp(&b)),
+            }
+        },
+        _ if a == b => Some(Ordering::Equal),
+        _ => None,
+    }
+}
+
+fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          ty: Ty<'tcx>,
+                          neg: bool)
+                          -> Result<ConstVal<'tcx>, ()> {
+    use syntax::ast::*;
+
+    use rustc::mir::interpret::*;
+    let lit = match *lit {
+        LitKind::Str(ref s, _) => {
+            let s = s.as_str();
+            let id = tcx.allocate_cached(s.as_bytes());
+            let ptr = MemoryPointer::new(id, 0);
+            Value::ByValPair(
+                PrimVal::Ptr(ptr),
+                PrimVal::from_u128(s.len() as u128),
+            )
+        },
+        LitKind::ByteStr(ref data) => {
+            let id = tcx.allocate_cached(data);
+            let ptr = MemoryPointer::new(id, 0);
+            Value::ByVal(PrimVal::Ptr(ptr))
+        },
+        LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
+        LitKind::Int(n, _) => {
+            enum Int {
+                Signed(IntTy),
+                Unsigned(UintTy),
+            }
+            let ty = match ty.sty {
+                ty::TyInt(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty),
+                ty::TyInt(other) => Int::Signed(other),
+                ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty),
+                ty::TyUint(other) => Int::Unsigned(other),
+                _ => bug!(),
+            };
+            let n = match ty {
+                // FIXME(oli-obk): are these casts correct?
+                Int::Signed(IntTy::I8) if neg =>
+                    (n as i128 as i8).overflowing_neg().0 as i128 as u128,
+                Int::Signed(IntTy::I16) if neg =>
+                    (n as i128 as i16).overflowing_neg().0 as i128 as u128,
+                Int::Signed(IntTy::I32) if neg =>
+                    (n as i128 as i32).overflowing_neg().0 as i128 as u128,
+                Int::Signed(IntTy::I64) if neg =>
+                    (n as i128 as i64).overflowing_neg().0 as i128 as u128,
+                Int::Signed(IntTy::I128) if neg =>
+                    (n as i128).overflowing_neg().0 as u128,
+                Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128,
+                Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128,
+                Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128,
+                Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128,
+                Int::Signed(IntTy::I128) => n,
+                Int::Unsigned(UintTy::U8) => n as u8 as u128,
+                Int::Unsigned(UintTy::U16) => n as u16 as u128,
+                Int::Unsigned(UintTy::U32) => n as u32 as u128,
+                Int::Unsigned(UintTy::U64) => n as u64 as u128,
+                Int::Unsigned(UintTy::U128) => n,
+                _ => bug!(),
+            };
+            Value::ByVal(PrimVal::Bytes(n))
+        },
+        LitKind::Float(n, fty) => {
+            let n = n.as_str();
+            let mut f = parse_float(&n, fty)?;
+            if neg {
+                f = -f;
+            }
+            let bits = f.bits;
+            Value::ByVal(PrimVal::Bytes(bits))
+        }
+        LitKind::FloatUnsuffixed(n) => {
+            let fty = match ty.sty {
+                ty::TyFloat(fty) => fty,
+                _ => bug!()
+            };
+            let n = n.as_str();
+            let mut f = parse_float(&n, fty)?;
+            if neg {
+                f = -f;
+            }
+            let bits = f.bits;
+            Value::ByVal(PrimVal::Bytes(bits))
+        }
+        LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
+        LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
+    };
+    Ok(ConstVal::Value(lit))
+}
+
+fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
+                     -> Result<ConstFloat, ()> {
+    ConstFloat::from_str(num, fty).map_err(|_| ())
+}
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index b476ea5685229..e654142d2164c 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -1,4 +1,5 @@
 use rustc::ty::Ty;
+use rustc::ty::layout::LayoutOf;
 use syntax::ast::{FloatTy, IntTy, UintTy};
 
 use rustc_const_math::ConstFloat;
@@ -7,115 +8,95 @@ use rustc::mir::interpret::{PrimVal, EvalResult, MemoryPointer, PointerArithmeti
 use rustc_apfloat::ieee::{Single, Double};
 use rustc_apfloat::Float;
 
-impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     pub(super) fn cast_primval(
         &self,
         val: PrimVal,
         src_ty: Ty<'tcx>,
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx, PrimVal> {
+        use rustc::ty::TypeVariants::*;
         trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
-        let src_kind = self.ty_to_primval_kind(src_ty)?;
 
         match val {
             PrimVal::Undef => Ok(PrimVal::Undef),
             PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
-            val @ PrimVal::Bytes(_) => {
-                use rustc::mir::interpret::PrimValKind::*;
-                match src_kind {
-                    F32 => self.cast_from_float(val.to_f32()?, dest_ty),
-                    F64 => self.cast_from_float(val.to_f64()?, dest_ty),
-
-                    I8 | I16 | I32 | I64 | I128 => {
-                        self.cast_from_signed_int(val.to_i128()?, dest_ty)
-                    }
-
-                    Bool | Char | U8 | U16 | U32 | U64 | U128 | FnPtr | Ptr => {
-                        self.cast_from_int(val.to_u128()?, dest_ty, false)
-                    }
+            PrimVal::Bytes(b) => {
+                match src_ty.sty {
+                    TyFloat(fty) => self.cast_from_float(b, fty, dest_ty),
+                    _ => self.cast_from_int(b, src_ty, dest_ty),
                 }
             }
         }
     }
 
-    fn cast_from_signed_int(&self, val: i128, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
-        self.cast_from_int(val as u128, ty, val < 0)
-    }
-
-    fn int_to_int(&self, v: i128, ty: IntTy) -> u128 {
-        match ty {
-            IntTy::I8 => v as i8 as u128,
-            IntTy::I16 => v as i16 as u128,
-            IntTy::I32 => v as i32 as u128,
-            IntTy::I64 => v as i64 as u128,
-            IntTy::I128 => v as u128,
-            IntTy::Isize => {
-                let ty = self.tcx.sess.target.isize_ty;
-                self.int_to_int(v, ty)
-            }
-        }
-    }
-    fn int_to_uint(&self, v: u128, ty: UintTy) -> u128 {
-        match ty {
-            UintTy::U8 => v as u8 as u128,
-            UintTy::U16 => v as u16 as u128,
-            UintTy::U32 => v as u32 as u128,
-            UintTy::U64 => v as u64 as u128,
-            UintTy::U128 => v,
-            UintTy::Usize => {
-                let ty = self.tcx.sess.target.usize_ty;
-                self.int_to_uint(v, ty)
-            }
-        }
-    }
-
     fn cast_from_int(
         &self,
         v: u128,
-        ty: Ty<'tcx>,
-        negative: bool,
+        src_ty: Ty<'tcx>,
+        dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx, PrimVal> {
-        trace!("cast_from_int: {}, {}, {}", v, ty, negative);
+        let signed = self.layout_of(src_ty)?.abi.is_signed();
+        let v = if signed {
+            self.sign_extend(v, src_ty)?
+        } else {
+            v
+        };
+        trace!("cast_from_int: {}, {}, {}", v, src_ty, dest_ty);
         use rustc::ty::TypeVariants::*;
-        match ty.sty {
-            // Casts to bool are not permitted by rustc, no need to handle them here.
-            TyInt(ty) => Ok(PrimVal::Bytes(self.int_to_int(v as i128, ty))),
-            TyUint(ty) => Ok(PrimVal::Bytes(self.int_to_uint(v, ty))),
+        match dest_ty.sty {
+            TyInt(_) | TyUint(_) => {
+                let v = self.truncate(v, dest_ty)?;
+                Ok(PrimVal::Bytes(v))
+            }
 
-            TyFloat(fty) if negative => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)),
+            TyFloat(fty) if signed => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)),
             TyFloat(fty) => Ok(PrimVal::Bytes(ConstFloat::from_u128(v, fty).bits)),
 
             TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
             TyChar => err!(InvalidChar(v)),
 
             // No alignment check needed for raw pointers.  But we have to truncate to target ptr size.
-            TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)),
+            TyRawPtr(_) => {
+                Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128))
+            },
 
-            _ => err!(Unimplemented(format!("int to {:?} cast", ty))),
+            // Casts to bool are not permitted by rustc, no need to handle them here.
+            _ => err!(Unimplemented(format!("int to {:?} cast", dest_ty))),
         }
     }
 
-    fn cast_from_float(&self, val: ConstFloat, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
+    fn cast_from_float(&self, bits: u128, fty: FloatTy, dest_ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
         use rustc::ty::TypeVariants::*;
-        match ty.sty {
+        use rustc_apfloat::FloatConvert;
+        match dest_ty.sty {
+            // float -> uint
             TyUint(t) => {
                 let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
-                match val.ty {
-                    FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(val.bits).to_u128(width).value)),
-                    FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(val.bits).to_u128(width).value)),
+                match fty {
+                    FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(bits).to_u128(width).value)),
+                    FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(bits).to_u128(width).value)),
                 }
             },
-
+            // float -> int
             TyInt(t) => {
                 let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
-                match val.ty {
-                    FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(val.bits).to_i128(width).value)),
-                    FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(val.bits).to_i128(width).value)),
+                match fty {
+                    FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(bits).to_i128(width).value)),
+                    FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(bits).to_i128(width).value)),
                 }
             },
-
-            TyFloat(fty) => Ok(PrimVal::from_float(val.convert(fty))),
-            _ => err!(Unimplemented(format!("float to {:?} cast", ty))),
+            // f64 -> f32
+            TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
+                Ok(PrimVal::Bytes(Single::to_bits(Double::from_bits(bits).convert(&mut false).value)))
+            },
+            // f32 -> f64
+            TyFloat(FloatTy::F64) if fty == FloatTy::F32 => {
+                Ok(PrimVal::Bytes(Double::to_bits(Single::from_bits(bits).convert(&mut false).value)))
+            },
+            // identity cast
+            TyFloat(_) => Ok(PrimVal::Bytes(bits)),
+            _ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
         }
     }
 
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index bc555368f0f5f..ee5874be9d70a 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/interpret/const_eval.rs
@@ -1,34 +1,49 @@
+use rustc::hir;
+use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
+use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError};
+use rustc::mir;
 use rustc::ty::{self, TyCtxt, Ty, Instance};
 use rustc::ty::layout::{self, LayoutOf};
-use rustc::ty::subst::Substs;
-use rustc::hir::def_id::DefId;
-use rustc::mir;
-use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError};
-use rustc::middle::const_val::{ConstEvalErr, ConstVal};
-use rustc_const_eval::{lookup_const_by_id, ConstContext};
-use rustc::mir::Field;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc::ty::subst::Subst;
 
 use syntax::ast::Mutability;
 use syntax::codemap::Span;
 
-use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal};
-use super::{Place, EvalContext, StackPopCleanup, ValTy};
-
-use rustc_const_math::ConstInt;
+use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal, AllocId};
+use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory};
 
 use std::fmt;
 use std::error::Error;
+use std::rc::Rc;
 
+pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    instance: Instance<'tcx>,
+    mir: &'mir mir::Mir<'tcx>,
+    span: Span,
+) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>> {
+    debug!("mk_borrowck_eval_cx: {:?}", instance);
+    let param_env = tcx.param_env(instance.def_id());
+    let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
+    // insert a stack frame so any queries have the correct substs
+    ecx.push_stack_frame(
+        instance,
+        span,
+        mir,
+        Place::undef(),
+        StackPopCleanup::None,
+    )?;
+    Ok(ecx)
+}
 
 pub fn mk_eval_cx<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     instance: Instance<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-) -> EvalResult<'tcx, EvalContext<'a, 'tcx, CompileTimeEvaluator>> {
+) -> EvalResult<'tcx, EvalContext<'a, 'tcx, 'tcx, CompileTimeEvaluator>> {
     debug!("mk_eval_cx: {:?}, {:?}", instance, param_env);
-    let limits = super::ResourceLimits::default();
-    let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ());
+    let span = tcx.def_span(instance.def_id());
+    let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
     let mir = ecx.load_mir(instance.def)?;
     // insert a stack frame so any queries have the correct substs
     ecx.push_stack_frame(
@@ -41,99 +56,115 @@ pub fn mk_eval_cx<'a, 'tcx>(
     Ok(ecx)
 }
 
-pub fn eval_body<'a, 'tcx>(
+pub fn eval_body_with_mir<'a, 'mir, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    instance: Instance<'tcx>,
+    cid: GlobalId<'tcx>,
+    mir: &'mir mir::Mir<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-) -> EvalResult<'tcx, (Pointer, Ty<'tcx>)> {
-    debug!("eval_body: {:?}, {:?}", instance, param_env);
-    let limits = super::ResourceLimits::default();
-    let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ());
-    let cid = GlobalId {
-        instance,
-        promoted: None,
-    };
-
-    if ecx.tcx.has_attr(instance.def_id(), "linkage") {
-        return Err(ConstEvalError::NotConst("extern global".to_string()).into());
+) -> Option<(Value, Pointer, Ty<'tcx>)> {
+    let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env);
+    match res {
+        Ok(val) => Some(val),
+        Err(mut err) => {
+            ecx.report(&mut err, true, None);
+            None
+        }
     }
-    let instance_ty = instance.ty(tcx);
-    if tcx.interpret_interner.borrow().get_cached(cid).is_none() {
-        let mir = ecx.load_mir(instance.def)?;
-        let layout = ecx.layout_of(instance_ty)?;
-        assert!(!layout.is_unsized());
-        let ptr = ecx.memory.allocate(
-            layout.size.bytes(),
-            layout.align,
-            None,
-        )?;
-        tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id);
-        let cleanup = StackPopCleanup::MarkStatic(Mutability::Immutable);
-        let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id()));
-        trace!("const_eval: pushing stack frame for global: {}", name);
-        ecx.push_stack_frame(
-            instance,
-            mir.span,
-            mir,
-            Place::from_ptr(ptr, layout.align),
-            cleanup.clone(),
-        )?;
+}
 
-        while ecx.step()? {}
+pub fn eval_body<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    cid: GlobalId<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> Option<(Value, Pointer, Ty<'tcx>)> {
+    let (res, ecx) = eval_body_and_ecx(tcx, cid, None, param_env);
+    match res {
+        Ok(val) => Some(val),
+        Err(mut err) => {
+            ecx.report(&mut err, true, None);
+            None
+        }
     }
-    let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached");
-    Ok((MemoryPointer::new(alloc, 0).into(), instance_ty))
 }
 
-pub fn eval_body_as_integer<'a, 'tcx>(
+fn eval_body_and_ecx<'a, 'mir, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    cid: GlobalId<'tcx>,
+    mir: Option<&'mir mir::Mir<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
-    instance: Instance<'tcx>,
-) -> EvalResult<'tcx, ConstInt> {
-    let ptr_ty = eval_body(tcx, instance, param_env);
-    let (ptr, ty) = ptr_ty?;
-    let ecx = mk_eval_cx(tcx, instance, param_env)?;
-    let prim = match ecx.try_read_value(ptr, ecx.layout_of(ty)?.align, ty)? {
-        Some(Value::ByVal(prim)) => prim.to_bytes()?,
-        _ => return err!(TypeNotPrimitive(ty)),
-    };
-    use syntax::ast::{IntTy, UintTy};
-    use rustc::ty::TypeVariants::*;
-    use rustc_const_math::{ConstIsize, ConstUsize};
-    Ok(match ty.sty {
-        TyInt(IntTy::I8) => ConstInt::I8(prim as i128 as i8),
-        TyInt(IntTy::I16) => ConstInt::I16(prim as i128 as i16),
-        TyInt(IntTy::I32) => ConstInt::I32(prim as i128 as i32),
-        TyInt(IntTy::I64) => ConstInt::I64(prim as i128 as i64),
-        TyInt(IntTy::I128) => ConstInt::I128(prim as i128),
-        TyInt(IntTy::Isize) => ConstInt::Isize(
-            ConstIsize::new(prim as i128 as i64, tcx.sess.target.isize_ty)
-                .expect("miri should already have errored"),
-        ),
-        TyUint(UintTy::U8) => ConstInt::U8(prim as u8),
-        TyUint(UintTy::U16) => ConstInt::U16(prim as u16),
-        TyUint(UintTy::U32) => ConstInt::U32(prim as u32),
-        TyUint(UintTy::U64) => ConstInt::U64(prim as u64),
-        TyUint(UintTy::U128) => ConstInt::U128(prim),
-        TyUint(UintTy::Usize) => ConstInt::Usize(
-            ConstUsize::new(prim as u64, tcx.sess.target.usize_ty)
-                .expect("miri should already have errored"),
-        ),
-        _ => {
-            return Err(
-                ConstEvalError::NeedsRfc(
-                    "evaluating anything other than isize/usize during typeck".to_string(),
-                ).into(),
-            )
+) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
+    debug!("eval_body: {:?}, {:?}", cid, param_env);
+    // we start out with the best span we have
+    // and try improving it down the road when more information is available
+    let span = tcx.def_span(cid.instance.def_id());
+    let mut span = mir.map(|mir| mir.span).unwrap_or(span);
+    let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
+    let res = (|| {
+        let mut mir = match mir {
+            Some(mir) => mir,
+            None => ecx.load_mir(cid.instance.def)?,
+        };
+        if let Some(index) = cid.promoted {
+            mir = &mir.promoted[index];
         }
-    })
+        span = mir.span;
+        let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
+        let alloc = tcx.interpret_interner.get_cached(cid.instance.def_id());
+        let alloc = match alloc {
+            Some(alloc) => {
+                assert!(cid.promoted.is_none());
+                assert!(param_env.caller_bounds.is_empty());
+                alloc
+            },
+            None => {
+                assert!(!layout.is_unsized());
+                let ptr = ecx.memory.allocate(
+                    layout.size.bytes(),
+                    layout.align,
+                    None,
+                )?;
+                if tcx.is_static(cid.instance.def_id()).is_some() {
+                    tcx.interpret_interner.cache(cid.instance.def_id(), ptr.alloc_id);
+                }
+                let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span);
+                let mutability = tcx.is_static(cid.instance.def_id());
+                let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable {
+                    Mutability::Mutable
+                } else {
+                    Mutability::Immutable
+                };
+                let cleanup = StackPopCleanup::MarkStatic(mutability);
+                let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id()));
+                let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p));
+                trace!("const_eval: pushing stack frame for global: {}{}", name, prom);
+                assert!(mir.arg_count == 0);
+                ecx.push_stack_frame(
+                    cid.instance,
+                    mir.span,
+                    mir,
+                    Place::from_ptr(ptr, layout.align),
+                    cleanup,
+                )?;
+
+                while ecx.step()? {}
+                ptr.alloc_id
+            }
+        };
+        let ptr = MemoryPointer::new(alloc, 0).into();
+        let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
+            Some(val) => val,
+            _ => Value::ByRef(ptr, layout.align),
+        };
+        Ok((value, ptr, layout.ty))
+    })();
+    (res, ecx)
 }
 
 pub struct CompileTimeEvaluator;
 
 impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
     fn into(self) -> EvalError<'tcx> {
-        EvalErrorKind::MachineError(Box::new(self)).into()
+        EvalErrorKind::MachineError(self.to_string()).into()
     }
 }
 
@@ -154,7 +185,7 @@ impl fmt::Display for ConstEvalError {
                     msg
                 )
             }
-            NotConst(ref msg) => write!(f, "Cannot evaluate within constants: \"{}\"", msg),
+            NotConst(ref msg) => write!(f, "{}", msg),
         }
     }
 }
@@ -173,33 +204,48 @@ impl Error for ConstEvalError {
     }
 }
 
-impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
+impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
     type MemoryData = ();
     type MemoryKinds = !;
     fn eval_fn_call<'a>(
-        ecx: &mut EvalContext<'a, 'tcx, Self>,
+        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         destination: Option<(Place, mir::BasicBlock)>,
-        _args: &[ValTy<'tcx>],
+        args: &[ValTy<'tcx>],
         span: Span,
-        _sig: ty::FnSig<'tcx>,
+        sig: ty::FnSig<'tcx>,
     ) -> EvalResult<'tcx, bool> {
         debug!("eval_fn_call: {:?}", instance);
         if !ecx.tcx.is_const_fn(instance.def_id()) {
-            return Err(
-                ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(),
-            );
+            let def_id = instance.def_id();
+            let (op, oflo) = if let Some(op) = ecx.tcx.is_binop_lang_item(def_id) {
+                op
+            } else {
+                return Err(
+                    ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(),
+                );
+            };
+            let (dest, bb) = destination.expect("128 lowerings can't diverge");
+            let dest_ty = sig.output();
+            if oflo {
+                ecx.intrinsic_with_overflow(op, args[0], args[1], dest, dest_ty)?;
+            } else {
+                ecx.intrinsic_overflowing(op, args[0], args[1], dest, dest_ty)?;
+            }
+            ecx.goto_block(bb);
+            return Ok(true);
         }
         let mir = match ecx.load_mir(instance.def) {
             Ok(mir) => mir,
-            Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => {
-                // some simple things like `malloc` might get accepted in the future
-                return Err(
-                    ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
-                        .into(),
-                );
+            Err(err) => {
+                if let EvalErrorKind::NoMirFor(ref path) = err.kind {
+                    return Err(
+                        ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
+                            .into(),
+                    );
+                }
+                return Err(err);
             }
-            Err(other) => return Err(other),
         };
         let (return_place, return_to_block) = match destination {
             Some((place, block)) => (place, StackPopCleanup::Goto(block)),
@@ -219,7 +265,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
 
 
     fn call_intrinsic<'a>(
-        ecx: &mut EvalContext<'a, 'tcx, Self>,
+        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         _args: &[ValTy<'tcx>],
         dest: Place,
@@ -261,7 +307,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
     }
 
     fn try_ptr_op<'a>(
-        _ecx: &EvalContext<'a, 'tcx, Self>,
+        _ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
         _bin_op: mir::BinOp,
         left: PrimVal,
         _left_ty: Ty<'tcx>,
@@ -277,12 +323,29 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
         }
     }
 
-    fn mark_static_initialized(m: !) -> EvalResult<'tcx> {
-        m
+    fn mark_static_initialized<'a>(
+        _mem: &mut Memory<'a, 'mir, 'tcx, Self>,
+        _id: AllocId,
+        _mutability: Mutability,
+    ) -> EvalResult<'tcx, bool> {
+        Ok(false)
+    }
+
+    fn init_static<'a>(
+        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        cid: GlobalId<'tcx>,
+    ) -> EvalResult<'tcx, AllocId> {
+        // ensure the static is computed
+        ecx.const_eval(cid)?;
+        Ok(ecx
+            .tcx
+            .interpret_interner
+            .get_cached(cid.instance.def_id())
+            .expect("uncached static"))
     }
 
     fn box_alloc<'a>(
-        _ecx: &mut EvalContext<'a, 'tcx, Self>,
+        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         _ty: Ty<'tcx>,
         _dest: Place,
     ) -> EvalResult<'tcx> {
@@ -292,7 +355,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
     }
 
     fn global_item_with_linkage<'a>(
-        _ecx: &mut EvalContext<'a, 'tcx, Self>,
+        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         _instance: ty::Instance<'tcx>,
         _mutability: Mutability,
     ) -> EvalResult<'tcx> {
@@ -302,275 +365,147 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
     }
 }
 
+pub fn const_val_field<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    instance: ty::Instance<'tcx>,
+    variant: Option<usize>,
+    field: mir::Field,
+    value: Value,
+    ty: Ty<'tcx>,
+) -> ::rustc::middle::const_val::EvalResult<'tcx> {
+    trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
+    let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
+    let result = (|| {
+        let (mut field, ty) = match value {
+            Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
+            Value::ByRef(ptr, align) => {
+                let place = Place::Ptr {
+                    ptr,
+                    align,
+                    extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant),
+                };
+                let layout = ecx.layout_of(ty)?;
+                let (place, layout) = ecx.place_field(place, field, layout)?;
+                let (ptr, align) = place.to_ptr_align();
+                (Value::ByRef(ptr, align), layout.ty)
+            }
+        };
+        if let Value::ByRef(ptr, align) = field {
+            if let Some(val) = ecx.try_read_value(ptr, align, ty)? {
+                field = val;
+            }
+        }
+        Ok((field, ty))
+    })();
+    match result {
+        Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
+            val: ConstVal::Value(field),
+            ty,
+        })),
+        Err(err) => {
+            let (trace, span) = ecx.generate_stacktrace(None);
+            let err = ErrKind::Miri(err, trace);
+            Err(ConstEvalErr {
+                kind: err.into(),
+                span,
+            })
+        },
+    }
+}
+
+pub fn const_discr<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    instance: ty::Instance<'tcx>,
+    value: Value,
+    ty: Ty<'tcx>,
+) -> EvalResult<'tcx, u128> {
+    trace!("const_discr: {:?}, {:?}, {:?}", instance, value, ty);
+    let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
+    let (ptr, align) = match value {
+        Value::ByValPair(..) | Value::ByVal(_) => {
+            let layout = ecx.layout_of(ty)?;
+            use super::MemoryKind;
+            let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
+            let ptr: Pointer = ptr.into();
+            ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
+            (ptr, layout.align)
+        },
+        Value::ByRef(ptr, align) => (ptr, align),
+    };
+    let place = Place::from_primval_ptr(ptr, align);
+    ecx.read_discriminant_value(place, ty)
+}
+
 pub fn const_eval_provider<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>,
+    key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
 ) -> ::rustc::middle::const_val::EvalResult<'tcx> {
     trace!("const eval: {:?}", key);
-    let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, key) {
-        resolved
-    } else {
-        return Err(ConstEvalErr {
-            span: tcx.def_span(key.value.0),
-            kind: TypeckError
-        });
-    };
+    let cid = key.value;
+    let def_id = cid.instance.def.def_id();
+
+    if tcx.is_foreign_item(def_id) {
+        let id = tcx.interpret_interner.get_cached(def_id);
+        let id = match id {
+            // FIXME: due to caches this shouldn't happen, add some assertions
+            Some(id) => id,
+            None => {
+                let id = tcx.interpret_interner.reserve();
+                tcx.interpret_interner.cache(def_id, id);
+                id
+            },
+        };
+        let ty = tcx.type_of(def_id);
+        let layout = tcx.layout_of(key.param_env.and(ty)).unwrap();
+        let ptr = MemoryPointer::new(id, 0);
+        return Ok(tcx.mk_const(ty::Const {
+            val: ConstVal::Value(Value::ByRef(ptr.into(), layout.align)),
+            ty,
+        }))
+    }
 
-    let tables = tcx.typeck_tables_of(def_id);
-    let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
-        let body_id = tcx.hir.body_owned_by(id);
+    if let Some(id) = tcx.hir.as_local_node_id(def_id) {
+        let tables = tcx.typeck_tables_of(def_id);
+        let span = tcx.def_span(def_id);
 
         // Do match-check before building MIR
         if tcx.check_match(def_id).is_err() {
             return Err(ConstEvalErr {
-                span: tcx.def_span(key.value.0),
-                kind: CheckMatchError,
+                kind: Rc::new(CheckMatchError),
+                span,
             });
         }
 
-        tcx.mir_const_qualif(def_id);
-        tcx.hir.body(body_id)
-    } else {
-        tcx.extern_const_body(def_id).body
-    };
-
-    // do not continue into miri if typeck errors occurred
-    // it will fail horribly
-    if tables.tainted_by_errors {
-        return Err(ConstEvalErr { span: body.value.span, kind: TypeckError })
-    }
-
-    trace!("running old const eval");
-    let old_result = ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value);
-    trace!("old const eval produced {:?}", old_result);
-    if tcx.sess.opts.debugging_opts.miri {
-        let instance = ty::Instance::new(def_id, substs);
-        trace!("const eval instance: {:?}, {:?}", instance, key.param_env);
-        let miri_result = ::interpret::eval_body(tcx, instance, key.param_env);
-        match (miri_result, old_result) {
-            (Err(err), Ok(ok)) => {
-                trace!("miri failed, ctfe returned {:?}", ok);
-                tcx.sess.span_warn(
-                    tcx.def_span(key.value.0),
-                    "miri failed to eval, while ctfe succeeded",
-                );
-                let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
-                let () = unwrap_miri(&ecx, Err(err));
-                Ok(ok)
-            },
-            (_, Err(err)) => Err(err),
-            (Ok((miri_val, miri_ty)), Ok(ctfe)) => {
-                let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
-                let layout = ecx.layout_of(miri_ty).unwrap();
-                let miri_place = Place::from_primval_ptr(miri_val, layout.align);
-                check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val);
-                Ok(ctfe)
-            }
+        if let hir::BodyOwnerKind::Const = tcx.hir.body_owner_kind(id) {
+            tcx.mir_const_qualif(def_id);
         }
-    } else {
-        old_result
-    }
-}
 
-fn check_ctfe_against_miri<'a, 'tcx>(
-    ecx: &mut EvalContext<'a, 'tcx, CompileTimeEvaluator>,
-    miri_place: Place,
-    miri_ty: Ty<'tcx>,
-    ctfe: ConstVal<'tcx>,
-) {
-    use rustc::middle::const_val::ConstAggregate::*;
-    use rustc_const_math::ConstFloat;
-    use rustc::ty::TypeVariants::*;
-    let miri_val = ValTy {
-        value: ecx.read_place(miri_place).unwrap(),
-        ty: miri_ty
+        // Do not continue into miri if typeck errors occurred; it will fail horribly
+        if tables.tainted_by_errors {
+            return Err(ConstEvalErr {
+                kind: Rc::new(TypeckError),
+                span,
+            });
+        }
     };
-    match miri_ty.sty {
-        TyInt(int_ty) => {
-            let prim = get_prim(ecx, miri_val);
-            let c = ConstInt::new_signed_truncating(prim as i128,
-                                                    int_ty,
-                                                    ecx.tcx.sess.target.isize_ty);
-            let c = ConstVal::Integral(c);
-            assert_eq!(c, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", c, ctfe);
-        },
-        TyUint(uint_ty) => {
-            let prim = get_prim(ecx, miri_val);
-            let c = ConstInt::new_unsigned_truncating(prim,
-                                                     uint_ty,
-                                                     ecx.tcx.sess.target.usize_ty);
-            let c = ConstVal::Integral(c);
-            assert_eq!(c, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", c, ctfe);
-        },
-        TyFloat(ty) => {
-            let prim = get_prim(ecx, miri_val);
-            let f = ConstVal::Float(ConstFloat { bits: prim, ty });
-            assert_eq!(f, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", f, ctfe);
-        },
-        TyBool => {
-            let bits = get_prim(ecx, miri_val);
-            if bits > 1 {
-                bug!("miri evaluated to {}, but expected a bool {:?}", bits, ctfe);
-            }
-            let b = ConstVal::Bool(bits == 1);
-            assert_eq!(b, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", b, ctfe);
-        },
-        TyChar => {
-            let bits = get_prim(ecx, miri_val);
-            if let Some(cm) = ::std::char::from_u32(bits as u32) {
-                assert_eq!(
-                    ConstVal::Char(cm), ctfe,
-                    "miri evaluated to {:?}, but expected {:?}", cm, ctfe,
-                );
-            } else {
-                bug!("miri evaluated to {}, but expected a char {:?}", bits, ctfe);
-            }
-        },
-        TyStr => {
-            let value = ecx.follow_by_ref_value(miri_val.value, miri_val.ty);
-            if let Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) = value {
-                let bytes = ecx
-                    .memory
-                    .read_bytes(ptr.into(), len as u64)
-                    .expect("bad miri memory for str");
-                if let Ok(s) = ::std::str::from_utf8(bytes) {
-                    if let ConstVal::Str(s2) = ctfe {
-                        assert_eq!(s, s2, "miri produced {:?}, but expected {:?}", s, s2);
-                    } else {
-                        bug!("miri produced {:?}, but expected {:?}", s, ctfe);
-                    }
-                } else {
-                    bug!(
-                        "miri failed to produce valid utf8 {:?}, while ctfe produced {:?}",
-                        bytes,
-                        ctfe,
-                    );
-                }
-            } else {
-                bug!("miri evaluated to {:?}, but expected a str {:?}", value, ctfe);
-            }
-        },
-        TyArray(elem_ty, n) => {
-            let n = n.val.to_const_int().unwrap().to_u64().unwrap();
-            let vec: Vec<(ConstVal, Ty<'tcx>)> = match ctfe {
-                ConstVal::ByteStr(arr) => arr.data.iter().map(|&b| {
-                    (ConstVal::Integral(ConstInt::U8(b)), ecx.tcx.types.u8)
-                }).collect(),
-                ConstVal::Aggregate(Array(v)) => {
-                    v.iter().map(|c| (c.val, c.ty)).collect()
-                },
-                ConstVal::Aggregate(Repeat(v, n)) => {
-                    vec![(v.val, v.ty); n as usize]
-                },
-                _ => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe),
-            };
-            let layout = ecx.layout_of(miri_ty).unwrap();
-            for (i, elem) in vec.into_iter().enumerate() {
-                assert!((i as u64) < n);
-                let (field_place, _) =
-                    ecx.place_field(miri_place, Field::new(i), layout).unwrap();
-                check_ctfe_against_miri(ecx, field_place, elem_ty, elem.0);
-            }
-        },
-        TyTuple(..) => {
-            let vec = match ctfe {
-                ConstVal::Aggregate(Tuple(v)) => v,
-                _ => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe),
-            };
-            let layout = ecx.layout_of(miri_ty).unwrap();
-            for (i, elem) in vec.into_iter().enumerate() {
-                let (field_place, _) =
-                    ecx.place_field(miri_place, Field::new(i), layout).unwrap();
-                check_ctfe_against_miri(ecx, field_place, elem.ty, elem.val);
-            }
-        },
-        TyAdt(def, _) => {
-            let mut miri_place = miri_place;
-            let struct_variant = if def.is_enum() {
-                let discr = ecx.read_discriminant_value(miri_place, miri_ty).unwrap();
-                let variant = def.discriminants(ecx.tcx).position(|variant_discr| {
-                    variant_discr.to_u128_unchecked() == discr
-                }).expect("miri produced invalid enum discriminant");
-                miri_place = ecx.place_downcast(miri_place, variant).unwrap();
-                &def.variants[variant]
-            } else {
-                def.non_enum_variant()
-            };
-            let vec = match ctfe {
-                ConstVal::Aggregate(Struct(v)) => v,
-                ConstVal::Variant(did) => {
-                    assert_eq!(struct_variant.fields.len(), 0);
-                    assert_eq!(did, struct_variant.did);
-                    return;
-                },
-                ctfe => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe),
-            };
-            let layout = ecx.layout_of(miri_ty).unwrap();
-            for &(name, elem) in vec.into_iter() {
-                let field = struct_variant.fields.iter().position(|f| f.name == name).unwrap();
-                let (field_place, _) =
-                    ecx.place_field(miri_place, Field::new(field), layout).unwrap();
-                check_ctfe_against_miri(ecx, field_place, elem.ty, elem.val);
-            }
-        },
-        TySlice(_) => bug!("miri produced a slice?"),
-        // not supported by ctfe
-        TyRawPtr(_) |
-        TyRef(..) => {}
-        TyDynamic(..) => bug!("miri produced a trait object"),
-        TyClosure(..) => bug!("miri produced a closure"),
-        TyGenerator(..) => bug!("miri produced a generator"),
-        TyGeneratorWitness(..) => bug!("miri produced a generator witness"),
-        TyNever => bug!("miri produced a value of the never type"),
-        TyProjection(_) => bug!("miri produced a projection"),
-        TyAnon(..) => bug!("miri produced an impl Trait type"),
-        TyParam(_) => bug!("miri produced an unmonomorphized type"),
-        TyInfer(_) => bug!("miri produced an uninferred type"),
-        TyError => bug!("miri produced a type error"),
-        TyForeign(_) => bug!("miri produced an extern type"),
-        // should be fine
-        TyFnDef(..) => {}
-        TyFnPtr(_) => {
-            let value = ecx.value_to_primval(miri_val);
-            let ptr = match value {
-                Ok(PrimVal::Ptr(ptr)) => ptr,
-                value => bug!("expected fn ptr, got {:?}", value),
-            };
-            let inst = ecx.memory.get_fn(ptr).unwrap();
-            match ctfe {
-                ConstVal::Function(did, substs) => {
-                    let ctfe = ty::Instance::resolve(
-                        ecx.tcx,
-                        ecx.param_env,
-                        did,
-                        substs,
-                    ).unwrap();
-                    assert_eq!(inst, ctfe, "expected fn ptr {:?}, but got {:?}", ctfe, inst);
-                },
-                _ => bug!("ctfe produced {:?}, but miri produced function {:?}", ctfe, inst),
-            }
-        },
-    }
-}
 
-fn get_prim<'a, 'tcx>(
-    ecx: &mut EvalContext<'a, 'tcx, CompileTimeEvaluator>,
-    val: ValTy<'tcx>,
-) -> u128 {
-    let res = ecx.value_to_primval(val).and_then(|prim| prim.to_bytes());
-    unwrap_miri(ecx, res)
-}
-
-fn unwrap_miri<'a, 'tcx, T>(
-    ecx: &EvalContext<'a, 'tcx, CompileTimeEvaluator>,
-    res: Result<T, EvalError<'tcx>>,
-) -> T {
-    match res {
-        Ok(val) => val,
-        Err(mut err) => {
-            ecx.report(&mut err);
-            ecx.tcx.sess.abort_if_errors();
-            bug!("{:#?}", err);
+    let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
+    res.map(|(miri_value, _, miri_ty)| {
+        tcx.mk_const(ty::Const {
+            val: ConstVal::Value(miri_value),
+            ty: miri_ty,
+        })
+    }).map_err(|mut err| {
+        if tcx.is_static(def_id).is_some() {
+            ecx.report(&mut err, true, None);
         }
-    }
+        let (trace, span) = ecx.generate_stacktrace(None);
+        let err = ErrKind::Miri(err, trace);
+        ConstEvalErr {
+            kind: err.into(),
+            span,
+        }
+    })
 }
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 25f933c5da6e7..13090ca53302b 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -3,14 +3,15 @@ use std::fmt::Write;
 
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::definitions::DefPathData;
-use rustc::middle::const_val::ConstVal;
+use rustc::middle::const_val::{ConstVal, ErrKind};
 use rustc::mir;
-use rustc::traits::Reveal;
 use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout};
 use rustc::ty::subst::{Subst, Substs};
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::maps::TyCtxtAt;
 use rustc_data_structures::indexed_vec::Idx;
-use syntax::codemap::{self, DUMMY_SP};
+use rustc::middle::const_val::FrameInfo;
+use syntax::codemap::{self, Span};
 use syntax::ast::Mutability;
 use rustc::mir::interpret::{
     GlobalId, Value, Pointer, PrimVal, PrimValKind,
@@ -18,41 +19,41 @@ use rustc::mir::interpret::{
 };
 
 use super::{Place, PlaceExtra, Memory,
-            HasMemory, MemoryKind, operator,
+            HasMemory, MemoryKind,
             Machine};
 
-pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> {
+pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
     /// Stores the `Machine` instance.
     pub machine: M,
 
     /// The results of the type checker, from rustc.
-    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
 
     /// Bounds in scope for polymorphic evaluations.
     pub param_env: ty::ParamEnv<'tcx>,
 
     /// The virtual memory system.
-    pub memory: Memory<'a, 'tcx, M>,
+    pub memory: Memory<'a, 'mir, 'tcx, M>,
 
     /// The virtual call stack.
-    pub(crate) stack: Vec<Frame<'tcx>>,
+    pub(crate) stack: Vec<Frame<'mir, 'tcx>>,
 
     /// The maximum number of stack frames allowed
     pub(crate) stack_limit: usize,
 
-    /// The maximum number of operations that may be executed.
+    /// The maximum number of terminators that may be evaluated.
     /// This prevents infinite loops and huge computations from freezing up const eval.
     /// Remove once halting problem is solved.
-    pub(crate) steps_remaining: u64,
+    pub(crate) steps_remaining: usize,
 }
 
 /// A stack frame.
-pub struct Frame<'tcx> {
+pub struct Frame<'mir, 'tcx: 'mir> {
     ////////////////////////////////////////////////////////////////////////////////
     // Function and callsite information
     ////////////////////////////////////////////////////////////////////////////////
     /// The MIR for the function called on this frame.
-    pub mir: &'tcx mir::Mir<'tcx>,
+    pub mir: &'mir mir::Mir<'tcx>,
 
     /// The def_id and substs of the current function
     pub instance: ty::Instance<'tcx>,
@@ -102,23 +103,6 @@ pub enum StackPopCleanup {
     None,
 }
 
-#[derive(Copy, Clone, Debug)]
-pub struct ResourceLimits {
-    pub memory_size: u64,
-    pub step_limit: u64,
-    pub stack_limit: usize,
-}
-
-impl Default for ResourceLimits {
-    fn default() -> Self {
-        ResourceLimits {
-            memory_size: 100 * 1024 * 1024, // 100 MB
-            step_limit: 1_000_000,
-            stack_limit: 100,
-        }
-    }
-}
-
 #[derive(Copy, Clone, Debug)]
 pub struct TyAndPacked<'tcx> {
     pub ty: Ty<'tcx>,
@@ -131,6 +115,15 @@ pub struct ValTy<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
+impl<'tcx> ValTy<'tcx> {
+    pub fn from(val: &ty::Const<'tcx>) -> Option<Self> {
+        match val.val {
+            ConstVal::Value(value) => Some(ValTy { value, ty: val.ty }),
+            ConstVal::Unevaluated { .. } => None,
+        }
+    }
+}
+
 impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
     type Target = Value;
     fn deref(&self) -> &Value {
@@ -138,37 +131,37 @@ impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
     }
 }
 
-impl<'a, 'tcx, M: Machine<'tcx>> HasDataLayout for &'a EvalContext<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a EvalContext<'a, 'mir, 'tcx, M> {
     #[inline]
     fn data_layout(&self) -> &layout::TargetDataLayout {
         &self.tcx.data_layout
     }
 }
 
-impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> HasDataLayout
-    for &'c &'b mut EvalContext<'a, 'tcx, M> {
+impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout
+    for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
     #[inline]
     fn data_layout(&self) -> &layout::TargetDataLayout {
         &self.tcx.data_layout
     }
 }
 
-impl<'a, 'tcx, M: Machine<'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'mir, 'tcx, M> {
     #[inline]
     fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
-        self.tcx
+        *self.tcx
     }
 }
 
-impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> layout::HasTyCtxt<'tcx>
-    for &'c &'b mut EvalContext<'a, 'tcx, M> {
+impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx>
+    for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
     #[inline]
     fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> {
-        self.tcx
+        *self.tcx
     }
 }
 
-impl<'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'mir, 'tcx, M> {
     type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
 
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
@@ -177,8 +170,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'tcx
     }
 }
 
-impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>>
-    for &'c &'b mut EvalContext<'a, 'tcx, M> {
+impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf<Ty<'tcx>>
+    for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
     type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
 
     #[inline]
@@ -187,11 +180,10 @@ impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>>
     }
 }
 
-impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     pub fn new(
-        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        limits: ResourceLimits,
         machine: M,
         memory_data: M::MemoryData,
     ) -> Self {
@@ -199,10 +191,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             machine,
             tcx,
             param_env,
-            memory: Memory::new(tcx, limits.memory_size, memory_data),
+            memory: Memory::new(tcx, memory_data),
             stack: Vec::new(),
-            stack_limit: limits.stack_limit,
-            steps_remaining: limits.step_limit,
+            stack_limit: tcx.sess.const_eval_stack_frame_limit.get(),
+            steps_remaining: tcx.sess.const_eval_step_limit.get(),
         }
     }
 
@@ -214,15 +206,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         self.memory.allocate(size, layout.align, Some(MemoryKind::Stack))
     }
 
-    pub fn memory(&self) -> &Memory<'a, 'tcx, M> {
+    pub fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
         &self.memory
     }
 
-    pub fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> {
+    pub fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
         &mut self.memory
     }
 
-    pub fn stack(&self) -> &[Frame<'tcx>] {
+    pub fn stack(&self) -> &[Frame<'mir, 'tcx>] {
         &self.stack
     }
 
@@ -240,45 +232,26 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         ))
     }
 
-    pub(super) fn const_to_value(&mut self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
-        use rustc::middle::const_val::ConstVal::*;
-
-        let primval = match *const_val {
-            Integral(const_int) => PrimVal::Bytes(const_int.to_u128_unchecked()),
-
-            Float(val) => PrimVal::Bytes(val.bits),
-
-            Bool(b) => PrimVal::from_bool(b),
-            Char(c) => PrimVal::from_char(c),
-
-            Str(ref s) => return self.str_to_value(s),
-
-            ByteStr(ref bs) => {
-                let ptr = self.memory.allocate_cached(bs.data);
-                PrimVal::Ptr(ptr)
-            }
-
-            Unevaluated(def_id, substs) => {
+    pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+        match *const_val {
+            ConstVal::Unevaluated(def_id, substs) => {
                 let instance = self.resolve(def_id, substs)?;
-                return Ok(self.read_global_as_value(GlobalId {
+                self.read_global_as_value(GlobalId {
                     instance,
                     promoted: None,
-                }, self.layout_of(ty)?));
+                }, ty)
             }
-
-            Aggregate(..) |
-            Variant(_) => bug!("should not have aggregate or variant constants in MIR"),
-            // function items are zero sized and thus have no readable value
-            Function(..) => PrimVal::Undef,
-        };
-
-        Ok(Value::ByVal(primval))
+            ConstVal::Value(val) => Ok(val),
+        }
     }
 
     pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> {
-        let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs);
+        trace!("resolve: {:?}, {:#?}", def_id, substs);
+        trace!("substs: {:#?}", self.substs());
+        trace!("param_env: {:#?}", self.param_env);
+        let substs = self.tcx.trans_apply_param_substs_env(self.substs(), self.param_env, &substs);
         ty::Instance::resolve(
-            self.tcx,
+            *self.tcx,
             self.param_env,
             def_id,
             substs,
@@ -286,7 +259,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
     }
 
     pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env)
+        ty.is_sized(self.tcx, self.param_env)
     }
 
     pub fn load_mir(
@@ -313,7 +286,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         // miri doesn't care about lifetimes, and will choke on some crazy ones
         // let's simply get rid of them
         let without_lifetimes = self.tcx.erase_regions(&ty);
-        let substituted = without_lifetimes.subst(self.tcx, substs);
+        let substituted = without_lifetimes.subst(*self.tcx, substs);
         let substituted = self.tcx.fully_normalize_monormophic_ty(&substituted);
         substituted
     }
@@ -402,14 +375,14 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         &mut self,
         instance: ty::Instance<'tcx>,
         span: codemap::Span,
-        mir: &'tcx mir::Mir<'tcx>,
+        mir: &'mir mir::Mir<'tcx>,
         return_place: Place,
         return_to_block: StackPopCleanup,
     ) -> EvalResult<'tcx> {
         ::log_settings::settings().indentation += 1;
 
         /// Return the set of locals that have a storage annotation anywhere
-        fn collect_storage_annotations<'tcx>(mir: &'tcx mir::Mir<'tcx>) -> HashSet<mir::Local> {
+        fn collect_storage_annotations<'mir, 'tcx>(mir: &'mir mir::Mir<'tcx>) -> HashSet<mir::Local> {
             use rustc::mir::StatementKind::*;
 
             let mut set = HashSet::new();
@@ -477,7 +450,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             StackPopCleanup::MarkStatic(mutable) => {
                 if let Place::Ptr { ptr, .. } = frame.return_place {
                     // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
-                    self.memory.mark_static_initalized(
+                    self.memory.mark_static_initialized(
                         ptr.to_ptr()?.alloc_id,
                         mutable,
                     )?
@@ -563,16 +536,16 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
             UnaryOp(un_op, ref operand) => {
                 let val = self.eval_operand_to_primval(operand)?;
-                let kind = self.ty_to_primval_kind(dest_ty)?;
+                let val = self.unary_op(un_op, val, dest_ty)?;
                 self.write_primval(
                     dest,
-                    operator::unary_op(un_op, val, kind)?,
+                    val,
                     dest_ty,
                 )?;
             }
 
             Aggregate(ref kind, ref operands) => {
-                self.inc_step_counter_and_check_limit(operands.len() as u64)?;
+                self.inc_step_counter_and_check_limit(operands.len())?;
 
                 let (dest, active_field_index) = match **kind {
                     mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
@@ -600,7 +573,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
             Repeat(ref operand, _) => {
                 let (elem_ty, length) = match dest_ty.sty {
-                    ty::TyArray(elem_ty, n) => (elem_ty, n.val.to_const_int().unwrap().to_u64().unwrap()),
+                    ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()),
                     _ => {
                         bug!(
                             "tried to assign array-repeat to non-array type {:?}",
@@ -720,8 +693,13 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                                     bug!("reifying a fn ptr that requires \
                                           const arguments");
                                 }
-                                let instance = self.resolve(def_id, substs)?;
-                                let fn_ptr = self.memory.create_fn_alloc(instance);
+                                let instance: EvalResult<'tcx, _> = ty::Instance::resolve(
+                                    *self.tcx,
+                                    self.param_env,
+                                    def_id,
+                                    substs,
+                                ).ok_or(EvalErrorKind::TypeckError.into());
+                                let fn_ptr = self.memory.create_fn_alloc(instance?);
                                 let valty = ValTy {
                                     value: Value::ByVal(PrimVal::Ptr(fn_ptr)),
                                     ty: dest_ty,
@@ -748,7 +726,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                             ty::TyClosure(def_id, substs) => {
                                 let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs);
                                 let instance = ty::Instance::resolve_closure(
-                                    self.tcx,
+                                    *self.tcx,
                                     def_id,
                                     substs,
                                     ty::ClosureKind::FnOnce,
@@ -771,9 +749,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 let place = self.eval_place(place)?;
                 let discr_val = self.read_discriminant_value(place, ty)?;
                 if let ty::TyAdt(adt_def, _) = ty.sty {
-                    trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(self.tcx).collect::<Vec<_>>());
-                    if adt_def.discriminants(self.tcx).all(|v| {
-                        discr_val != v.to_u128_unchecked()
+                    trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(*self.tcx).collect::<Vec<_>>());
+                    if adt_def.discriminants(*self.tcx).all(|v| {
+                        discr_val != v.val
                     })
                     {
                         return err!(InvalidDiscriminant);
@@ -820,7 +798,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
     pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> {
         use rustc::mir::Operand::*;
-        let ty = self.monomorphize(op.ty(self.mir(), self.tcx), self.substs());
+        let ty = self.monomorphize(op.ty(self.mir(), *self.tcx), self.substs());
         match *op {
             // FIXME: do some more logic on `move` to invalidate the old location
             Copy(ref place) |
@@ -841,7 +819,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                         self.read_global_as_value(GlobalId {
                             instance: self.frame().instance,
                             promoted: Some(index),
-                        }, self.layout_of(ty)?)
+                        }, ty)?
                     }
                 };
 
@@ -928,8 +906,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             }
             layout::Variants::Tagged { .. } => {
                 let discr_val = dest_ty.ty_adt_def().unwrap()
-                    .discriminant_for_variant(self.tcx, variant_index)
-                    .to_u128_unchecked();
+                    .discriminant_for_variant(*self.tcx, variant_index)
+                    .val;
 
                 let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?;
                 self.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?;
@@ -953,9 +931,38 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         Ok(())
     }
 
-    pub fn read_global_as_value(&self, gid: GlobalId, layout: TyLayout) -> Value {
-        let alloc = self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached");
-        Value::ByRef(MemoryPointer::new(alloc, 0).into(), layout.align)
+    pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+        if gid.promoted.is_none() {
+            let cached = self
+                .tcx
+                .interpret_interner
+                .get_cached(gid.instance.def_id());
+            if let Some(alloc_id) = cached {
+                let layout = self.layout_of(ty)?;
+                let ptr = MemoryPointer::new(alloc_id, 0);
+                return Ok(Value::ByRef(ptr.into(), layout.align))
+            }
+        }
+        let cv = self.const_eval(gid)?;
+        self.const_to_value(&cv.val, ty)
+    }
+
+    pub fn const_eval(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
+        let param_env = if self.tcx.is_static(gid.instance.def_id()).is_some() {
+            use rustc::traits;
+            ty::ParamEnv::empty(traits::Reveal::All)
+        } else {
+            self.param_env
+        };
+        self.tcx.const_eval(param_env.and(gid)).map_err(|err| match *err.kind {
+            ErrKind::Miri(ref err, _) => match err.kind {
+                EvalErrorKind::TypeckError |
+                EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(),
+                _ => EvalErrorKind::ReferencedConstant.into(),
+            },
+            ErrKind::TypeckError => EvalErrorKind::TypeckError.into(),
+            ref other => bug!("const eval returned {:?}", other),
+        })
     }
 
     pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> {
@@ -1121,20 +1128,22 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         dest_align: Align,
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx> {
-        trace!("write_value_to_ptr: {:#?}", value);
         let layout = self.layout_of(dest_ty)?;
+        trace!("write_value_to_ptr: {:#?}, {}, {:#?}", value, dest_ty, layout);
         match value {
             Value::ByRef(ptr, align) => {
                 self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size.bytes(), false)
             }
             Value::ByVal(primval) => {
-                match layout.abi {
-                    layout::Abi::Scalar(_) => {}
-                    _ if primval.is_undef() => {}
+                let signed = match layout.abi {
+                    layout::Abi::Scalar(ref scal) => match scal.value {
+                        layout::Primitive::Int(_, signed) => signed,
+                        _ => false,
+                    },
+                    _ if primval.is_undef() => false,
                     _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
-                }
-                // TODO: Do we need signedness?
-                self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), false)
+                };
+                self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), signed)
             }
             Value::ByValPair(a_val, b_val) => {
                 let ptr = dest.to_ptr()?;
@@ -1247,7 +1256,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         pointee_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx, Value> {
         let ptr_size = self.memory.pointer_size();
-        let p: Pointer = self.memory.read_ptr_sized_unsigned(ptr, ptr_align)?.into();
+        let p: Pointer = self.memory.read_ptr_sized(ptr, ptr_align)?.into();
         if self.type_is_sized(pointee_ty) {
             Ok(p.to_value())
         } else {
@@ -1255,11 +1264,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             let extra = ptr.offset(ptr_size, self)?;
             match self.tcx.struct_tail(pointee_ty).sty {
                 ty::TyDynamic(..) => Ok(p.to_value_with_vtable(
-                    self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_ptr()?,
+                    self.memory.read_ptr_sized(extra, ptr_align)?.to_ptr()?,
                 )),
-                ty::TySlice(..) | ty::TyStr => Ok(
-                    p.to_value_with_len(self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_bytes()? as u64),
-                ),
+                ty::TySlice(..) | ty::TyStr => {
+                    let len = self
+                        .memory
+                        .read_ptr_sized(extra, ptr_align)?
+                        .to_bytes()?;
+                    Ok(p.to_value_with_len(len as u64))
+                },
                 _ => bug!("unsized primval ptr read from {:?}", pointee_ty),
             }
         }
@@ -1271,7 +1284,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         let ptr = ptr.to_ptr()?;
         let val = match ty.sty {
             ty::TyBool => {
-                let val = self.memory.read_primval(ptr, ptr_align, 1, false)?;
+                let val = self.memory.read_primval(ptr, ptr_align, 1)?;
                 let val = match val {
                     PrimVal::Bytes(0) => false,
                     PrimVal::Bytes(1) => true,
@@ -1281,7 +1294,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 PrimVal::from_bool(val)
             }
             ty::TyChar => {
-                let c = self.memory.read_primval(ptr, ptr_align, 4, false)?.to_bytes()? as u32;
+                let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32;
                 match ::std::char::from_u32(c) {
                     Some(ch) => PrimVal::from_char(ch),
                     None => return err!(InvalidChar(c as u128)),
@@ -1298,7 +1311,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                     I128 => 16,
                     Isize => self.memory.pointer_size(),
                 };
-                self.memory.read_primval(ptr, ptr_align, size, true)?
+                self.memory.read_primval(ptr, ptr_align, size)?
             }
 
             ty::TyUint(uint_ty) => {
@@ -1311,17 +1324,17 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                     U128 => 16,
                     Usize => self.memory.pointer_size(),
                 };
-                self.memory.read_primval(ptr, ptr_align, size, false)?
+                self.memory.read_primval(ptr, ptr_align, size)?
             }
 
             ty::TyFloat(FloatTy::F32) => {
-                PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4, false)?.to_bytes()?)
+                PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()?)
             }
             ty::TyFloat(FloatTy::F64) => {
-                PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8, false)?.to_bytes()?)
+                PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8)?.to_bytes()?)
             }
 
-            ty::TyFnPtr(_) => self.memory.read_ptr_sized_unsigned(ptr, ptr_align)?,
+            ty::TyFnPtr(_) => self.memory.read_ptr_sized(ptr, ptr_align)?,
             ty::TyRef(_, ref tam) |
             ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, ptr_align, tam.ty).map(Some),
 
@@ -1331,12 +1344,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 }
 
                 if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
-                    let mut signed = false;
-                    if let layout::Int(_, s) = scalar.value {
-                        signed = s;
-                    }
                     let size = scalar.value.size(self).bytes();
-                    self.memory.read_primval(ptr, ptr_align, size, signed)?
+                    self.memory.read_primval(ptr, ptr_align, size)?
                 } else {
                     return Ok(None);
                 }
@@ -1348,15 +1357,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         Ok(Some(Value::ByVal(val)))
     }
 
-    pub fn frame(&self) -> &Frame<'tcx> {
+    pub fn frame(&self) -> &Frame<'mir, 'tcx> {
         self.stack.last().expect("no call frames exist")
     }
 
-    pub fn frame_mut(&mut self) -> &mut Frame<'tcx> {
+    pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> {
         self.stack.last_mut().expect("no call frames exist")
     }
 
-    pub(super) fn mir(&self) -> &'tcx mir::Mir<'tcx> {
+    pub(super) fn mir(&self) -> &'mir mir::Mir<'tcx> {
         self.frame().mir
     }
 
@@ -1385,7 +1394,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 let ptr = self.into_ptr(src)?;
                 // u64 cast is from usize to u64, which is always good
                 let valty = ValTy {
-                    value: ptr.to_value_with_len(length.val.to_const_int().unwrap().to_u64().unwrap() ),
+                    value: ptr.to_value_with_len(length.val.unwrap_u64() ),
                     ty: dest_ty,
                 };
                 self.write_value(valty, dest)
@@ -1402,7 +1411,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             }
             (_, &ty::TyDynamic(ref data, _)) => {
                 let trait_ref = data.principal().unwrap().with_self_ty(
-                    self.tcx,
+                    *self.tcx,
                     src_pointee_ty,
                 );
                 let trait_ref = self.tcx.erase_regions(&trait_ref);
@@ -1504,11 +1513,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 write!(msg, ":").unwrap();
 
                 match self.stack[frame].get_local(local) {
-                    Err(EvalError { kind: EvalErrorKind::DeadLocal, .. }) => {
-                        write!(msg, " is dead").unwrap();
-                    }
                     Err(err) => {
-                        panic!("Failed to access local: {:?}", err);
+                        if let EvalErrorKind::DeadLocal = err.kind {
+                            write!(msg, " is dead").unwrap();
+                        } else {
+                            panic!("Failed to access local: {:?}", err);
+                        }
                     }
                     Ok(Value::ByRef(ptr, align)) => {
                         match ptr.into_inner_primval() {
@@ -1566,7 +1576,40 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         Ok(())
     }
 
-    pub fn report(&self, e: &mut EvalError) {
+    pub fn generate_stacktrace(&self, explicit_span: Option<Span>) -> (Vec<FrameInfo>, Span) {
+        let mut last_span = None;
+        let mut frames = Vec::new();
+        // skip 1 because the last frame is just the environment of the constant
+        for &Frame { instance, span, .. } in self.stack().iter().skip(1).rev() {
+            // make sure we don't emit frames that are duplicates of the previous
+            if explicit_span == Some(span) {
+                last_span = Some(span);
+                continue;
+            }
+            if let Some(last) = last_span {
+                if last == span {
+                    continue;
+                }
+            } else {
+                last_span = Some(span);
+            }
+            let location = if self.tcx.def_key(instance.def_id()).disambiguated_data.data == DefPathData::ClosureExpr {
+                "closure".to_owned()
+            } else {
+                instance.to_string()
+            };
+            frames.push(FrameInfo { span, location });
+        }
+        trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
+        (frames, self.tcx.span)
+    }
+
+    pub fn report(&self, e: &mut EvalError, as_err: bool, explicit_span: Option<Span>) {
+        match e.kind {
+            EvalErrorKind::Layout(_) |
+            EvalErrorKind::TypeckError => return,
+            _ => {},
+        }
         if let Some(ref mut backtrace) = e.backtrace {
             let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
             backtrace.resolve();
@@ -1599,29 +1642,60 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         }
         if let Some(frame) = self.stack().last() {
             let block = &frame.mir.basic_blocks()[frame.block];
-            let span = if frame.stmt < block.statements.len() {
+            let span = explicit_span.unwrap_or_else(|| if frame.stmt < block.statements.len() {
                 block.statements[frame.stmt].source_info.span
             } else {
                 block.terminator().source_info.span
+            });
+            trace!("reporting const eval failure at {:?}", span);
+            let mut err = if as_err {
+                ::rustc::middle::const_val::struct_error(*self.tcx, span, "constant evaluation error")
+            } else {
+                let node_id = self
+                    .stack()
+                    .iter()
+                    .rev()
+                    .filter_map(|frame| self.tcx.hir.as_local_node_id(frame.instance.def_id()))
+                    .next()
+                    .expect("some part of a failing const eval must be local");
+                self.tcx.struct_span_lint_node(
+                    ::rustc::lint::builtin::CONST_ERR,
+                    node_id,
+                    span,
+                    "constant evaluation error",
+                )
             };
-            let mut err = self.tcx.sess.struct_span_err(span, &e.to_string());
-            for &Frame { instance, span, .. } in self.stack().iter().rev() {
-                if self.tcx.def_key(instance.def_id()).disambiguated_data.data ==
-                    DefPathData::ClosureExpr
-                {
-                    err.span_note(span, "inside call to closure");
-                    continue;
-                }
-                err.span_note(span, &format!("inside call to {}", instance));
+            let (frames, span) = self.generate_stacktrace(explicit_span);
+            err.span_label(span, e.to_string());
+            for FrameInfo { span, location } in frames {
+                err.span_note(span, &format!("inside call to `{}`", location));
             }
             err.emit();
         } else {
             self.tcx.sess.err(&e.to_string());
         }
     }
+
+    pub fn sign_extend(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
+        let layout = self.layout_of(ty)?;
+        let size = layout.size.bits();
+        assert!(layout.abi.is_signed());
+        // sign extend
+        let amt = 128 - size;
+        // shift the unsigned value to the left
+        // and back to the right as signed (essentially fills with FF on the left)
+        Ok((((value << amt) as i128) >> amt) as u128)
+    }
+
+    pub fn truncate(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
+        let size = self.layout_of(ty)?.size.bits();
+        let amt = 128 - size;
+        // truncate (shift left to drop out leftover values, shift right to fill with zeroes)
+        Ok((value << amt) >> amt)
+    }
 }
 
-impl<'tcx> Frame<'tcx> {
+impl<'mir, 'tcx> Frame<'mir, 'tcx> {
     pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> {
         // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
         self.locals[local.index() - 1].ok_or(EvalErrorKind::DeadLocal.into())
@@ -1655,14 +1729,3 @@ impl<'tcx> Frame<'tcx> {
         return Ok(old);
     }
 }
-
-// TODO(solson): Upstream these methods into rustc::ty::layout.
-
-pub fn resolve_drop_in_place<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    ty: Ty<'tcx>,
-) -> ty::Instance<'tcx> {
-    let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem);
-    let substs = tcx.intern_substs(&[ty.into()]);
-    ty::Instance::resolve(tcx, ty::ParamEnv::empty(Reveal::All), def_id, substs).unwrap()
-}
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index c2989dbaaf11f..5af0a053e9239 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -2,7 +2,7 @@
 //! This separation exists to ensure that no fancy miri features like
 //! interpreting common C functions leak into CTFE.
 
-use rustc::mir::interpret::{AllocId, EvalResult, PrimVal, MemoryPointer, AccessKind};
+use rustc::mir::interpret::{AllocId, EvalResult, PrimVal, MemoryPointer, AccessKind, GlobalId};
 use super::{EvalContext, Place, ValTy, Memory};
 
 use rustc::mir;
@@ -12,7 +12,7 @@ use syntax::ast::Mutability;
 
 /// Methods of this trait signifies a point where CTFE evaluation would fail
 /// and some use case dependent behaviour can instead be applied
-pub trait Machine<'tcx>: Sized {
+pub trait Machine<'mir, 'tcx>: Sized {
     /// Additional data that can be accessed via the Memory
     type MemoryData;
 
@@ -26,7 +26,7 @@ pub trait Machine<'tcx>: Sized {
     ///
     /// Returns Ok(false) if a new stack frame was pushed
     fn eval_fn_call<'a>(
-        ecx: &mut EvalContext<'a, 'tcx, Self>,
+        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         destination: Option<(Place, mir::BasicBlock)>,
         args: &[ValTy<'tcx>],
@@ -36,7 +36,7 @@ pub trait Machine<'tcx>: Sized {
 
     /// directly process an intrinsic without pushing a stack frame.
     fn call_intrinsic<'a>(
-        ecx: &mut EvalContext<'a, 'tcx, Self>,
+        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[ValTy<'tcx>],
         dest: Place,
@@ -51,7 +51,7 @@ pub trait Machine<'tcx>: Sized {
     ///
     /// Returns a (value, overflowed) pair if the operation succeeded
     fn try_ptr_op<'a>(
-        ecx: &EvalContext<'a, 'tcx, Self>,
+        ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
         bin_op: mir::BinOp,
         left: PrimVal,
         left_ty: Ty<'tcx>,
@@ -60,26 +60,37 @@ pub trait Machine<'tcx>: Sized {
     ) -> EvalResult<'tcx, Option<(PrimVal, bool)>>;
 
     /// Called when trying to mark machine defined `MemoryKinds` as static
-    fn mark_static_initialized(m: Self::MemoryKinds) -> EvalResult<'tcx>;
+    fn mark_static_initialized<'a>(
+        _mem: &mut Memory<'a, 'mir, 'tcx, Self>,
+        _id: AllocId,
+        _mutability: Mutability,
+    ) -> EvalResult<'tcx, bool>;
+
+    /// Called when requiring a pointer to a static. Non const eval can
+    /// create a mutable memory location for `static mut`
+    fn init_static<'a>(
+        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        cid: GlobalId<'tcx>,
+    ) -> EvalResult<'tcx, AllocId>;
 
     /// Heap allocations via the `box` keyword
     ///
     /// Returns a pointer to the allocated memory
     fn box_alloc<'a>(
-        ecx: &mut EvalContext<'a, 'tcx, Self>,
+        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         ty: Ty<'tcx>,
         dest: Place,
     ) -> EvalResult<'tcx>;
 
     /// Called when trying to access a global declared with a `linkage` attribute
     fn global_item_with_linkage<'a>(
-        ecx: &mut EvalContext<'a, 'tcx, Self>,
+        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         mutability: Mutability,
     ) -> EvalResult<'tcx>;
 
     fn check_locks<'a>(
-        _mem: &Memory<'a, 'tcx, Self>,
+        _mem: &Memory<'a, 'mir, 'tcx, Self>,
         _ptr: MemoryPointer,
         _size: u64,
         _access: AccessKind,
@@ -88,12 +99,12 @@ pub trait Machine<'tcx>: Sized {
     }
 
     fn add_lock<'a>(
-        _mem: &mut Memory<'a, 'tcx, Self>,
+        _mem: &mut Memory<'a, 'mir, 'tcx, Self>,
         _id: AllocId,
     ) {}
 
     fn free_lock<'a>(
-        _mem: &mut Memory<'a, 'tcx, Self>,
+        _mem: &mut Memory<'a, 'mir, 'tcx, Self>,
         _id: AllocId,
         _len: u64,
     ) -> EvalResult<'tcx> {
@@ -101,14 +112,14 @@ pub trait Machine<'tcx>: Sized {
     }
 
     fn end_region<'a>(
-        _ecx: &mut EvalContext<'a, 'tcx, Self>,
+        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         _reg: Option<::rustc::middle::region::Scope>,
     ) -> EvalResult<'tcx> {
         Ok(())
     }
 
     fn validation_op<'a>(
-        _ecx: &mut EvalContext<'a, 'tcx, Self>,
+        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         _op: ::rustc::mir::ValidationOp,
         _operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>,
     ) -> EvalResult<'tcx> {
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 7cc4ba8489525..b369f80e849b0 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -1,8 +1,9 @@
 use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
 use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque};
-use std::{ptr, mem, io};
+use std::{ptr, io};
 
-use rustc::ty::{Instance, TyCtxt};
+use rustc::ty::Instance;
+use rustc::ty::maps::TyCtxtAt;
 use rustc::ty::layout::{self, Align, TargetDataLayout};
 use syntax::ast::Mutability;
 
@@ -19,8 +20,6 @@ use super::{EvalContext, Machine};
 pub enum MemoryKind<T> {
     /// Error if deallocated except during a stack pop
     Stack,
-    /// A mutable Static. All the others are interned in the tcx
-    MutableStatic, // FIXME: move me into the machine, rustc const eval doesn't need them
     /// Additional memory kinds a machine wishes to distinguish from the builtin ones
     Machine(T),
 }
@@ -29,7 +28,7 @@ pub enum MemoryKind<T> {
 // Top-level interpreter memory
 ////////////////////////////////////////////////////////////////////////////////
 
-pub struct Memory<'a, 'tcx: 'a, M: Machine<'tcx>> {
+pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
     /// Additional data required by the Machine
     pub data: M::MemoryData,
 
@@ -44,28 +43,20 @@ pub struct Memory<'a, 'tcx: 'a, M: Machine<'tcx>> {
     /// Stores statics while they are being processed, before they are interned and thus frozen
     uninitialized_statics: HashMap<AllocId, Allocation>,
 
-    /// Number of virtual bytes allocated.
-    memory_usage: u64,
-
-    /// Maximum number of virtual bytes that may be allocated.
-    memory_size: u64,
-
     /// The current stack frame.  Used to check accesses against locks.
     pub cur_frame: usize,
 
-    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
 }
 
-impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
-    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, max_memory: u64, data: M::MemoryData) -> Self {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
+    pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
         Memory {
             data,
             alloc_kind: HashMap::new(),
             alloc_map: HashMap::new(),
             uninitialized_statics: HashMap::new(),
             tcx,
-            memory_size: max_memory,
-            memory_usage: 0,
             cur_frame: usize::max_value(),
         }
     }
@@ -77,7 +68,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
     }
 
     pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> MemoryPointer {
-        let id = self.tcx.interpret_interner.borrow_mut().create_fn_alloc(instance);
+        let id = self.tcx.interpret_interner.create_fn_alloc(instance);
         MemoryPointer::new(id, 0)
     }
 
@@ -93,22 +84,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         align: Align,
         kind: Option<MemoryKind<M::MemoryKinds>>,
     ) -> EvalResult<'tcx, MemoryPointer> {
-        if self.memory_size - self.memory_usage < size {
-            return err!(OutOfMemory {
-                allocation_size: size,
-                memory_size: self.memory_size,
-                memory_usage: self.memory_usage,
-            });
-        }
-        self.memory_usage += size;
         assert_eq!(size as usize as u64, size);
         let alloc = Allocation {
             bytes: vec![0; size as usize],
             relocations: BTreeMap::new(),
             undef_mask: UndefMask::new(size),
             align,
+            runtime_mutability: Mutability::Immutable,
         };
-        let id = self.tcx.interpret_interner.borrow_mut().reserve();
+        let id = self.tcx.interpret_interner.reserve();
         M::add_lock(self, id);
         match kind {
             Some(kind @ MemoryKind::Stack) |
@@ -119,7 +103,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             None => {
                 self.uninitialized_statics.insert(id, alloc);
             },
-            Some(MemoryKind::MutableStatic) => bug!("don't allocate mutable statics directly")
         }
         Ok(MemoryPointer::new(id, 0))
     }
@@ -164,10 +147,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
 
     pub fn deallocate_local(&mut self, ptr: MemoryPointer) -> EvalResult<'tcx> {
         match self.alloc_kind.get(&ptr.alloc_id).cloned() {
-            // for a constant like `const FOO: &i32 = &1;` the local containing
-            // the `1` is referred to by the global. We transitively marked everything
-            // the global refers to as static itself, so we don't free it here
-            Some(MemoryKind::MutableStatic) => Ok(()),
             Some(MemoryKind::Stack) => self.deallocate(ptr, None, MemoryKind::Stack),
             // Happens if the memory was interned into immutable memory
             None => Ok(()),
@@ -192,12 +171,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
                     "uninitializedstatic".to_string(),
                     format!("{:?}", kind),
                 ))
-            } else if self.tcx.interpret_interner.borrow().get_fn(ptr.alloc_id).is_some() {
+            } else if self.tcx.interpret_interner.get_fn(ptr.alloc_id).is_some() {
                 return err!(DeallocatedWrongMemoryKind(
                     "function".to_string(),
                     format!("{:?}", kind),
                 ))
-            } else if self.tcx.interpret_interner.borrow().get_alloc(ptr.alloc_id).is_some() {
+            } else if self.tcx.interpret_interner.get_alloc(ptr.alloc_id).is_some() {
                 return err!(DeallocatedWrongMemoryKind(
                     "static".to_string(),
                     format!("{:?}", kind),
@@ -228,7 +207,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             }
         }
 
-        self.memory_usage -= alloc.bytes.len() as u64;
         debug!("deallocated : {}", ptr.alloc_id);
 
         Ok(())
@@ -292,7 +270,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
 }
 
 /// Allocation accessors
-impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
         // normal alloc?
         match self.alloc_map.get(&id) {
@@ -301,11 +279,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             None => match self.uninitialized_statics.get(&id) {
                 Some(alloc) => Ok(alloc),
                 None => {
-                    let int = self.tcx.interpret_interner.borrow();
                     // static alloc?
-                    int.get_alloc(id)
+                    self.tcx.interpret_interner.get_alloc(id)
                         // no alloc? produce an error
-                        .ok_or_else(|| if int.get_fn(id).is_some() {
+                        .ok_or_else(|| if self.tcx.interpret_interner.get_fn(id).is_some() {
                             EvalErrorKind::DerefFunctionPointer.into()
                         } else {
                             EvalErrorKind::DanglingPointerDeref.into()
@@ -326,11 +303,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             None => match self.uninitialized_statics.get_mut(&id) {
                 Some(alloc) => Ok(alloc),
                 None => {
-                    let int = self.tcx.interpret_interner.borrow();
                     // no alloc or immutable alloc? produce an error
-                    if int.get_alloc(id).is_some() {
+                    if self.tcx.interpret_interner.get_alloc(id).is_some() {
                         err!(ModifiedConstantMemory)
-                    } else if int.get_fn(id).is_some() {
+                    } else if self.tcx.interpret_interner.get_fn(id).is_some() {
                         err!(DerefFunctionPointer)
                     } else {
                         err!(DanglingPointerDeref)
@@ -347,7 +323,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         debug!("reading fn ptr: {}", ptr.alloc_id);
         self.tcx
             .interpret_interner
-            .borrow()
             .get_fn(ptr.alloc_id)
             .ok_or(EvalErrorKind::ExecuteMemory.into())
     }
@@ -376,27 +351,25 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
                     Some(a) => (a, match self.alloc_kind[&id] {
                         MemoryKind::Stack => " (stack)".to_owned(),
                         MemoryKind::Machine(m) => format!(" ({:?})", m),
-                        MemoryKind::MutableStatic => " (static mut)".to_owned(),
                     }),
                     // uninitialized static alloc?
                     None => match self.uninitialized_statics.get(&id) {
                         Some(a) => (a, " (static in the process of initialization)".to_owned()),
                         None => {
-                            let int = self.tcx.interpret_interner.borrow();
                             // static alloc?
-                            match int.get_alloc(id) {
+                            match self.tcx.interpret_interner.get_alloc(id) {
                                 Some(a) => (a, "(immutable)".to_owned()),
-                                None => if let Some(func) = int.get_fn(id) {
+                                None => if let Some(func) = self.tcx.interpret_interner.get_fn(id) {
                                     trace!("{} {}", msg, func);
-                    continue;
+                                    continue;
                                 } else {
-                            trace!("{} (deallocated)", msg);
-                            continue;
+                                    trace!("{} (deallocated)", msg);
+                                    continue;
                                 },
-                }
+                            }
                         },
                     },
-            };
+                };
 
             for i in 0..(alloc.bytes.len() as u64) {
                 if let Some(&target_id) = alloc.relocations.get(&i) {
@@ -441,14 +414,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
 
     pub fn leak_report(&self) -> usize {
         trace!("### LEAK REPORT ###");
-        let kinds = &self.alloc_kind;
         let leaks: Vec<_> = self.alloc_map
             .keys()
-            .filter_map(|key| if kinds[key] != MemoryKind::MutableStatic {
-                Some(*key)
-            } else {
-                None
-            })
+            .cloned()
             .collect();
         let n = leaks.len();
         self.dump_allocs(leaks);
@@ -457,7 +425,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
 }
 
 /// Byte accessors
-impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     fn get_bytes_unchecked(
         &self,
         ptr: MemoryPointer,
@@ -521,7 +489,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
 }
 
 /// Reading and writing
-impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     /// mark an allocation pointed to by a static as static and initialized
     fn mark_inner_allocation_initialized(
         &mut self,
@@ -529,80 +497,47 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         mutability: Mutability,
     ) -> EvalResult<'tcx> {
         match self.alloc_kind.get(&alloc) {
-            // do not go into immutable statics
-            None |
-            // or mutable statics
-            Some(&MemoryKind::MutableStatic) => Ok(()),
+            // do not go into statics
+            None => Ok(()),
             // just locals and machine allocs
-            Some(_) => self.mark_static_initalized(alloc, mutability),
+            Some(_) => self.mark_static_initialized(alloc, mutability),
         }
     }
 
     /// mark an allocation as static and initialized, either mutable or not
-    pub fn mark_static_initalized(
+    pub fn mark_static_initialized(
         &mut self,
         alloc_id: AllocId,
         mutability: Mutability,
     ) -> EvalResult<'tcx> {
         trace!(
-            "mark_static_initalized {:?}, mutability: {:?}",
+            "mark_static_initialized {:?}, mutability: {:?}",
             alloc_id,
             mutability
         );
-        if mutability == Mutability::Immutable {
-            let alloc = self.alloc_map.remove(&alloc_id);
-            let kind = self.alloc_kind.remove(&alloc_id);
-            assert_ne!(kind, Some(MemoryKind::MutableStatic));
-            let uninit = self.uninitialized_statics.remove(&alloc_id);
-            if let Some(alloc) = alloc.or(uninit) {
-                let alloc = self.tcx.intern_const_alloc(alloc);
-                self.tcx.interpret_interner.borrow_mut().intern_at_reserved(alloc_id, alloc);
-                // recurse into inner allocations
-                for &alloc in alloc.relocations.values() {
-                    self.mark_inner_allocation_initialized(alloc, mutability)?;
-                }
-            }
-            return Ok(());
-        }
-        // We are marking the static as initialized, so move it out of the uninit map
-        if let Some(uninit) = self.uninitialized_statics.remove(&alloc_id) {
-            self.alloc_map.insert(alloc_id, uninit);
-        }
-        // do not use `self.get_mut(alloc_id)` here, because we might have already marked a
-        // sub-element or have circular pointers (e.g. `Rc`-cycles)
-        let relocations = match self.alloc_map.get_mut(&alloc_id) {
-            Some(&mut Allocation {
-                     ref mut relocations,
-                     ..
-                 }) => {
-                match self.alloc_kind.get(&alloc_id) {
-                    // const eval results can refer to "locals".
-                    // E.g. `const Foo: &u32 = &1;` refers to the temp local that stores the `1`
-                    None |
-                    Some(&MemoryKind::Stack) => {},
-                    Some(&MemoryKind::Machine(m)) => M::mark_static_initialized(m)?,
-                    Some(&MemoryKind::MutableStatic) => {
-                        trace!("mark_static_initalized: skipping already initialized static referred to by static currently being initialized");
-                        return Ok(());
-                    },
-                }
-                // overwrite or insert
-                self.alloc_kind.insert(alloc_id, MemoryKind::MutableStatic);
-                // take out the relocations vector to free the borrow on self, so we can call
-                // mark recursively
-                mem::replace(relocations, Default::default())
+        // The machine handled it
+        if M::mark_static_initialized(self, alloc_id, mutability)? {
+            return Ok(())
+        }
+        let alloc = self.alloc_map.remove(&alloc_id);
+        match self.alloc_kind.remove(&alloc_id) {
+            None => {},
+            Some(MemoryKind::Machine(_)) => bug!("machine didn't handle machine alloc"),
+            Some(MemoryKind::Stack) => {},
+        }
+        let uninit = self.uninitialized_statics.remove(&alloc_id);
+        if let Some(mut alloc) = alloc.or(uninit) {
+            // ensure llvm knows not to put this into immutable memroy
+            alloc.runtime_mutability = mutability;
+            let alloc = self.tcx.intern_const_alloc(alloc);
+            self.tcx.interpret_interner.intern_at_reserved(alloc_id, alloc);
+            // recurse into inner allocations
+            for &alloc in alloc.relocations.values() {
+                self.mark_inner_allocation_initialized(alloc, mutability)?;
             }
-            None => return err!(DanglingPointerDeref),
-        };
-        // recurse into inner allocations
-        for &alloc in relocations.values() {
-            self.mark_inner_allocation_initialized(alloc, mutability)?;
+        } else {
+            bug!("no allocation found for {:?}", alloc_id);
         }
-        // put back the relocations
-        self.alloc_map
-            .get_mut(&alloc_id)
-            .expect("checked above")
-            .relocations = relocations;
         Ok(())
     }
 
@@ -720,7 +655,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         Ok(())
     }
 
-    pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: u64, signed: bool) -> EvalResult<'tcx, PrimVal> {
+    pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: u64) -> EvalResult<'tcx, PrimVal> {
         self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer
         let endianness = self.endianness();
         let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?;
@@ -730,11 +665,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             return Ok(PrimVal::Undef.into());
         }
         // Now we do the actual reading
-        let bytes = if signed {
-            read_target_int(endianness, bytes).unwrap() as u128
-        } else {
-            read_target_uint(endianness, bytes).unwrap()
-        };
+        let bytes = read_target_uint(endianness, bytes).unwrap();
         // See if we got a pointer
         if size != self.pointer_size() {
             if self.relocations(ptr, size)?.count() != 0 {
@@ -751,8 +682,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         Ok(PrimVal::Bytes(bytes))
     }
 
-    pub fn read_ptr_sized_unsigned(&self, ptr: MemoryPointer, ptr_align: Align) -> EvalResult<'tcx, PrimVal> {
-        self.read_primval(ptr, ptr_align, self.pointer_size(), false)
+    pub fn read_ptr_sized(&self, ptr: MemoryPointer, ptr_align: Align) -> EvalResult<'tcx, PrimVal> {
+        self.read_primval(ptr, ptr_align, self.pointer_size())
     }
 
     pub fn write_primval(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> {
@@ -764,19 +695,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
                 val.offset as u128
             }
 
-            PrimVal::Bytes(bytes) => {
-                // We need to mask here, or the byteorder crate can die when given a u64 larger
-                // than fits in an integer of the requested size.
-                let mask = match size {
-                    1 => !0u8 as u128,
-                    2 => !0u16 as u128,
-                    4 => !0u32 as u128,
-                    8 => !0u64 as u128,
-                    16 => !0,
-                    n => bug!("unexpected PrimVal::Bytes size: {}", n),
-                };
-                bytes & mask
-            }
+            PrimVal::Bytes(bytes) => bytes,
 
             PrimVal::Undef => {
                 self.mark_definedness(PrimVal::Ptr(ptr).into(), size, false)?;
@@ -829,7 +748,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
 }
 
 /// Relocations
-impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     fn relocations(
         &self,
         ptr: MemoryPointer,
@@ -883,7 +802,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
 }
 
 /// Undefined bytes
-impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     // FIXME(solson): This is a very naive, slow version.
     fn copy_undef_mask(
         &mut self,
@@ -944,7 +863,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
 // Methods to access integers in the target endianness
 ////////////////////////////////////////////////////////////////////////////////
 
-fn write_target_uint(
+pub fn write_target_uint(
     endianness: layout::Endian,
     mut target: &mut [u8],
     data: u128,
@@ -955,7 +874,8 @@ fn write_target_uint(
         layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
     }
 }
-fn write_target_int(
+
+pub fn write_target_int(
     endianness: layout::Endian,
     mut target: &mut [u8],
     data: i128,
@@ -967,27 +887,20 @@ fn write_target_int(
     }
 }
 
-fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
+pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
     match endianness {
         layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
         layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
     }
 }
 
-fn read_target_int(endianness: layout::Endian, mut source: &[u8]) -> Result<i128, io::Error> {
-    match endianness {
-        layout::Endian::Little => source.read_int128::<LittleEndian>(source.len()),
-        layout::Endian::Big => source.read_int128::<BigEndian>(source.len()),
-    }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Unaligned accesses
 ////////////////////////////////////////////////////////////////////////////////
 
-pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
-    fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M>;
-    fn memory(&self) -> &Memory<'a, 'tcx, M>;
+pub trait HasMemory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
+    fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M>;
+    fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M>;
 
     /// Convert the value into a pointer (or a pointer-sized integer).  If the value is a ByRef,
     /// this may have to perform a load.
@@ -997,7 +910,7 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
     ) -> EvalResult<'tcx, Pointer> {
         Ok(match value {
             Value::ByRef(ptr, align) => {
-                self.memory().read_ptr_sized_unsigned(ptr.to_ptr()?, align)?
+                self.memory().read_ptr_sized(ptr.to_ptr()?, align)?
             }
             Value::ByVal(ptr) |
             Value::ByValPair(ptr, _) => ptr,
@@ -1011,8 +924,8 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
         match value {
             Value::ByRef(ref_ptr, align) => {
                 let mem = self.memory();
-                let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?, align)?.into();
-                let vtable = mem.read_ptr_sized_unsigned(
+                let ptr = mem.read_ptr_sized(ref_ptr.to_ptr()?, align)?.into();
+                let vtable = mem.read_ptr_sized(
                     ref_ptr.offset(mem.pointer_size(), &mem.tcx.data_layout)?.to_ptr()?,
                     align
                 )?.to_ptr()?;
@@ -1033,8 +946,8 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
         match value {
             Value::ByRef(ref_ptr, align) => {
                 let mem = self.memory();
-                let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?, align)?.into();
-                let len = mem.read_ptr_sized_unsigned(
+                let ptr = mem.read_ptr_sized(ref_ptr.to_ptr()?, align)?.into();
+                let len = mem.read_ptr_sized(
                     ref_ptr.offset(mem.pointer_size(), &mem.tcx.data_layout)?.to_ptr()?,
                     align
                 )?.to_bytes()? as u64;
@@ -1051,31 +964,31 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> {
     }
 }
 
-impl<'a, 'tcx, M: Machine<'tcx>> HasMemory<'a, 'tcx, M> for Memory<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasMemory<'a, 'mir, 'tcx, M> for Memory<'a, 'mir, 'tcx, M> {
     #[inline]
-    fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> {
+    fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
         self
     }
 
     #[inline]
-    fn memory(&self) -> &Memory<'a, 'tcx, M> {
+    fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
         self
     }
 }
 
-impl<'a, 'tcx, M: Machine<'tcx>> HasMemory<'a, 'tcx, M> for EvalContext<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasMemory<'a, 'mir, 'tcx, M> for EvalContext<'a, 'mir, 'tcx, M> {
     #[inline]
-    fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> {
+    fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
         &mut self.memory
     }
 
     #[inline]
-    fn memory(&self) -> &Memory<'a, 'tcx, M> {
+    fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> {
         &self.memory
     }
 }
 
-impl<'a, 'tcx, M: Machine<'tcx>> layout::HasDataLayout for &'a Memory<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasDataLayout for &'a Memory<'a, 'mir, 'tcx, M> {
     #[inline]
     fn data_layout(&self) -> &TargetDataLayout {
         &self.tcx.data_layout
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index fee62c8a82e2f..ae6337d82c3e3 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -11,13 +11,23 @@ mod step;
 mod terminator;
 mod traits;
 
-pub use self::eval_context::{EvalContext, Frame, ResourceLimits, StackPopCleanup,
+pub use self::eval_context::{EvalContext, Frame, StackPopCleanup,
                              TyAndPacked, ValTy};
 
 pub use self::place::{Place, PlaceExtra};
 
 pub use self::memory::{Memory, MemoryKind, HasMemory};
 
-pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider};
+pub use self::const_eval::{
+    eval_body_with_mir,
+    mk_borrowck_eval_cx,
+    eval_body,
+    CompileTimeEvaluator,
+    const_eval_provider,
+    const_val_field,
+    const_discr,
+};
 
 pub use self::machine::Machine;
+
+pub use self::memory::{write_target_uint, write_target_int, read_target_uint};
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index 6ab1aec38b863..dfc0c4a824a84 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -1,14 +1,15 @@
 use rustc::mir;
-use rustc::ty::Ty;
+use rustc::ty::{self, Ty};
 use rustc_const_math::ConstFloat;
 use syntax::ast::FloatTy;
 use std::cmp::Ordering;
+use rustc::ty::layout::LayoutOf;
 
 use super::{EvalContext, Place, Machine, ValTy};
 
-use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, bytes_to_f32, bytes_to_f64};
+use rustc::mir::interpret::{EvalResult, PrimVal, Value};
 
-impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     fn binop_with_overflow(
         &mut self,
         op: mir::BinOp,
@@ -55,57 +56,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
     }
 }
 
-macro_rules! overflow {
-    ($op:ident, $l:expr, $r:expr) => ({
-        let (val, overflowed) = $l.$op($r);
-        let primval = PrimVal::Bytes(val as u128);
-        Ok((primval, overflowed))
-    })
-}
-
-macro_rules! int_arithmetic {
-    ($kind:expr, $int_op:ident, $l:expr, $r:expr) => ({
-        let l = $l;
-        let r = $r;
-        use rustc::mir::interpret::PrimValKind::*;
-        match $kind {
-            I8  => overflow!($int_op, l as i8,  r as i8),
-            I16 => overflow!($int_op, l as i16, r as i16),
-            I32 => overflow!($int_op, l as i32, r as i32),
-            I64 => overflow!($int_op, l as i64, r as i64),
-            I128 => overflow!($int_op, l as i128, r as i128),
-            U8  => overflow!($int_op, l as u8,  r as u8),
-            U16 => overflow!($int_op, l as u16, r as u16),
-            U32 => overflow!($int_op, l as u32, r as u32),
-            U64 => overflow!($int_op, l as u64, r as u64),
-            U128 => overflow!($int_op, l as u128, r as u128),
-            _ => bug!("int_arithmetic should only be called on int primvals"),
-        }
-    })
-}
-
-macro_rules! int_shift {
-    ($kind:expr, $int_op:ident, $l:expr, $r:expr) => ({
-        let l = $l;
-        let r = $r;
-        let r_wrapped = r as u32;
-        match $kind {
-            I8  => overflow!($int_op, l as i8,  r_wrapped),
-            I16 => overflow!($int_op, l as i16, r_wrapped),
-            I32 => overflow!($int_op, l as i32, r_wrapped),
-            I64 => overflow!($int_op, l as i64, r_wrapped),
-            I128 => overflow!($int_op, l as i128, r_wrapped),
-            U8  => overflow!($int_op, l as u8,  r_wrapped),
-            U16 => overflow!($int_op, l as u16, r_wrapped),
-            U32 => overflow!($int_op, l as u32, r_wrapped),
-            U64 => overflow!($int_op, l as u64, r_wrapped),
-            U128 => overflow!($int_op, l as u128, r_wrapped),
-            _ => bug!("int_shift should only be called on int primvals"),
-        }.map(|(val, over)| (val, over || r != r_wrapped as u128))
-    })
-}
-
-impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     /// Returns the result of the specified operation and whether it overflowed.
     pub fn binary_op(
         &self,
@@ -116,11 +67,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         right_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx, (PrimVal, bool)> {
         use rustc::mir::BinOp::*;
-        use rustc::mir::interpret::PrimValKind::*;
 
         let left_kind = self.ty_to_primval_kind(left_ty)?;
         let right_kind = self.ty_to_primval_kind(right_ty)?;
-        //trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, left, left_kind, right, right_kind);
+        trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, left, left_kind, right, right_kind);
 
         // I: Handle operations that support pointers
         if !left_kind.is_float() && !right_kind.is_float() {
@@ -133,13 +83,34 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         let l = left.to_bytes()?;
         let r = right.to_bytes()?;
 
+        let left_layout = self.layout_of(left_ty)?;
+
         // These ops can have an RHS with a different numeric type.
         if right_kind.is_int() && (bin_op == Shl || bin_op == Shr) {
-            return match bin_op {
-                Shl => int_shift!(left_kind, overflowing_shl, l, r),
-                Shr => int_shift!(left_kind, overflowing_shr, l, r),
-                _ => bug!("it has already been checked that this is a shift op"),
+            let signed = left_layout.abi.is_signed();
+            let mut r = r as u32;
+            let size = left_layout.size.bits() as u32;
+            let oflo = r >= size;
+            if oflo {
+                r %= size;
+            }
+            let result = if signed {
+                let l = self.sign_extend(l, left_ty)? as i128;
+                let result = match bin_op {
+                    Shl => l << r,
+                    Shr => l >> r,
+                    _ => bug!("it has already been checked that this is a shift op"),
+                };
+                result as u128
+            } else {
+                match bin_op {
+                    Shl => l << r,
+                    Shr => l >> r,
+                    _ => bug!("it has already been checked that this is a shift op"),
+                }
             };
+            let truncated = self.truncate(result, left_ty)?;
+            return Ok((PrimVal::Bytes(truncated), oflo));
         }
 
         if left_kind != right_kind {
@@ -179,41 +150,95 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             }
         };
 
-        let val = match (bin_op, left_kind) {
-            (_, F32) => float_op(bin_op, l, r, FloatTy::F32),
-            (_, F64) => float_op(bin_op, l, r, FloatTy::F64),
-
-
-            (Eq, _) => PrimVal::from_bool(l == r),
-            (Ne, _) => PrimVal::from_bool(l != r),
-
-            (Lt, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) < (r as i128)),
-            (Lt, _) => PrimVal::from_bool(l < r),
-            (Le, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) <= (r as i128)),
-            (Le, _) => PrimVal::from_bool(l <= r),
-            (Gt, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) > (r as i128)),
-            (Gt, _) => PrimVal::from_bool(l > r),
-            (Ge, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) >= (r as i128)),
-            (Ge, _) => PrimVal::from_bool(l >= r),
+        if left_layout.abi.is_signed() {
+            let op: Option<fn(&i128, &i128) -> bool> = match bin_op {
+                Lt => Some(i128::lt),
+                Le => Some(i128::le),
+                Gt => Some(i128::gt),
+                Ge => Some(i128::ge),
+                _ => None,
+            };
+            if let Some(op) = op {
+                let l = self.sign_extend(l, left_ty)? as i128;
+                let r = self.sign_extend(r, right_ty)? as i128;
+                return Ok((PrimVal::from_bool(op(&l, &r)), false));
+            }
+            let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
+                Rem | Div if r == 0 => return Ok((PrimVal::Bytes(l), true)),
+                Div => Some(i128::overflowing_div),
+                Rem => Some(i128::overflowing_rem),
+                Add => Some(i128::overflowing_add),
+                Sub => Some(i128::overflowing_sub),
+                Mul => Some(i128::overflowing_mul),
+                _ => None,
+            };
+            if let Some(op) = op {
+                let l128 = self.sign_extend(l, left_ty)? as i128;
+                let r = self.sign_extend(r, right_ty)? as i128;
+                let size = left_layout.size.bits();
+                match bin_op {
+                    Rem | Div => {
+                        // int_min / -1
+                        if r == -1 && l == (1 << (size - 1)) {
+                            return Ok((PrimVal::Bytes(l), true));
+                        }
+                    },
+                    _ => {},
+                }
+                trace!("{}, {}, {}", l, l128, r);
+                let (result, mut oflo) = op(l128, r);
+                trace!("{}, {}", result, oflo);
+                if !oflo && size != 128 {
+                    let max = 1 << (size - 1);
+                    oflo = result >= max || result < -max;
+                }
+                let result = result as u128;
+                let truncated = self.truncate(result, left_ty)?;
+                return Ok((PrimVal::Bytes(truncated), oflo));
+            }
+        }
 
-            (BitOr, _) => PrimVal::Bytes(l | r),
-            (BitAnd, _) => PrimVal::Bytes(l & r),
-            (BitXor, _) => PrimVal::Bytes(l ^ r),
+        if let ty::TyFloat(fty) = left_ty.sty {
+            return Ok((float_op(bin_op, l, r, fty), false));
+        }
 
-            (Add, k) if k.is_int() => return int_arithmetic!(k, overflowing_add, l, r),
-            (Sub, k) if k.is_int() => return int_arithmetic!(k, overflowing_sub, l, r),
-            (Mul, k) if k.is_int() => return int_arithmetic!(k, overflowing_mul, l, r),
-            (Div, k) if k.is_int() => return int_arithmetic!(k, overflowing_div, l, r),
-            (Rem, k) if k.is_int() => return int_arithmetic!(k, overflowing_rem, l, r),
+        // only ints left
+        let val = match bin_op {
+            Eq => PrimVal::from_bool(l == r),
+            Ne => PrimVal::from_bool(l != r),
+
+            Lt => PrimVal::from_bool(l < r),
+            Le => PrimVal::from_bool(l <= r),
+            Gt => PrimVal::from_bool(l > r),
+            Ge => PrimVal::from_bool(l >= r),
+
+            BitOr => PrimVal::Bytes(l | r),
+            BitAnd => PrimVal::Bytes(l & r),
+            BitXor => PrimVal::Bytes(l ^ r),
+
+            Add | Sub | Mul | Rem | Div => {
+                let op: fn(u128, u128) -> (u128, bool) = match bin_op {
+                    Add => u128::overflowing_add,
+                    Sub => u128::overflowing_sub,
+                    Mul => u128::overflowing_mul,
+                    Rem | Div if r == 0 => return Ok((PrimVal::Bytes(l), true)),
+                    Div => u128::overflowing_div,
+                    Rem => u128::overflowing_rem,
+                    _ => bug!(),
+                };
+                let (result, oflo) = op(l, r);
+                let truncated = self.truncate(result, left_ty)?;
+                return Ok((PrimVal::Bytes(truncated), oflo || truncated != result));
+            }
 
             _ => {
                 let msg = format!(
                     "unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})",
                     bin_op,
                     left,
-                    left_kind,
+                    left_ty,
                     right,
-                    right_kind
+                    right_ty,
                 );
                 return err!(Unimplemented(msg));
             }
@@ -221,47 +246,33 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
         Ok((val, false))
     }
-}
 
-pub fn unary_op<'tcx>(
-    un_op: mir::UnOp,
-    val: PrimVal,
-    val_kind: PrimValKind,
-) -> EvalResult<'tcx, PrimVal> {
-    use rustc::mir::UnOp::*;
-    use rustc::mir::interpret::PrimValKind::*;
-
-    let bytes = val.to_bytes()?;
+    pub fn unary_op(
+        &self,
+        un_op: mir::UnOp,
+        val: PrimVal,
+        ty: Ty<'tcx>,
+    ) -> EvalResult<'tcx, PrimVal> {
+        use rustc::mir::UnOp::*;
+        use rustc_apfloat::ieee::{Single, Double};
+        use rustc_apfloat::Float;
 
-    let result_bytes = match (un_op, val_kind) {
-        (Not, Bool) => !val.to_bool()? as u128,
+        let bytes = val.to_bytes()?;
+        let size = self.layout_of(ty)?.size.bits();
 
-        (Not, U8) => !(bytes as u8) as u128,
-        (Not, U16) => !(bytes as u16) as u128,
-        (Not, U32) => !(bytes as u32) as u128,
-        (Not, U64) => !(bytes as u64) as u128,
-        (Not, U128) => !bytes,
+        let result_bytes = match (un_op, &ty.sty) {
 
-        (Not, I8) => !(bytes as i8) as u128,
-        (Not, I16) => !(bytes as i16) as u128,
-        (Not, I32) => !(bytes as i32) as u128,
-        (Not, I64) => !(bytes as i64) as u128,
-        (Not, I128) => !(bytes as i128) as u128,
+            (Not, ty::TyBool) => !val.to_bool()? as u128,
 
-        (Neg, I8) => -(bytes as i8) as u128,
-        (Neg, I16) => -(bytes as i16) as u128,
-        (Neg, I32) => -(bytes as i32) as u128,
-        (Neg, I64) => -(bytes as i64) as u128,
-        (Neg, I128) => -(bytes as i128) as u128,
+            (Not, _) => !bytes,
 
-        (Neg, F32) => (-bytes_to_f32(bytes)).bits,
-        (Neg, F64) => (-bytes_to_f64(bytes)).bits,
+            (Neg, ty::TyFloat(FloatTy::F32)) => Single::to_bits(-Single::from_bits(bytes)),
+            (Neg, ty::TyFloat(FloatTy::F64)) => Double::to_bits(-Double::from_bits(bytes)),
 
-        _ => {
-            let msg = format!("unimplemented unary op: {:?}, {:?}", un_op, val);
-            return err!(Unimplemented(msg));
-        }
-    };
+            (Neg, _) if bytes == (1 << (size - 1)) => return err!(OverflowingMath),
+            (Neg, _) => (-(bytes as i128)) as u128,
+        };
 
-    Ok(PrimVal::Bytes(result_bytes))
+        Ok(PrimVal::Bytes(self.truncate(result_bytes, ty)?))
+    }
 }
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 701b7a07ac988..d27de3ef6bfc4 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -71,7 +71,7 @@ impl<'tcx> Place {
 
     pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
         match ty.sty {
-            ty::TyArray(elem, n) => (elem, n.val.to_const_int().unwrap().to_u64().unwrap() as u64),
+            ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64),
 
             ty::TySlice(elem) => {
                 match self {
@@ -90,7 +90,7 @@ impl<'tcx> Place {
     }
 }
 
-impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     /// Reads a value from the place without going through the intermediate step of obtaining
     /// a `miri::Place`
     pub fn try_read_place(
@@ -103,18 +103,43 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             Local(mir::RETURN_PLACE) => err!(ReadFromReturnPointer),
             // Directly reading a local will always succeed
             Local(local) => self.frame().get_local(local).map(Some),
-            // Directly reading a static will always succeed
-            Static(ref static_) => {
-                let instance = ty::Instance::mono(self.tcx, static_.def_id);
-                Ok(Some(self.read_global_as_value(GlobalId {
-                    instance,
-                    promoted: None,
-                }, self.layout_of(self.place_ty(place))?)))
-            }
+            // No fast path for statics. Reading from statics is rare and would require another
+            // Machine function to handle differently in miri.
+            Static(_) => Ok(None),
             Projection(ref proj) => self.try_read_place_projection(proj),
         }
     }
 
+    pub fn read_field(
+        &self,
+        base: Value,
+        variant: Option<usize>,
+        field: mir::Field,
+        base_ty: Ty<'tcx>,
+    ) -> EvalResult<'tcx, Option<(Value, Ty<'tcx>)>> {
+        let mut base_layout = self.layout_of(base_ty)?;
+        if let Some(variant_index) = variant {
+            base_layout = base_layout.for_variant(self, variant_index);
+        }
+        let field_index = field.index();
+        let field = base_layout.field(self, field_index)?;
+        if field.size.bytes() == 0 {
+            return Ok(Some((Value::ByVal(PrimVal::Undef), field.ty)))
+        }
+        let offset = base_layout.fields.offset(field_index);
+        match base {
+            // the field covers the entire type
+            Value::ByValPair(..) |
+            Value::ByVal(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some((base, field.ty))),
+            // split fat pointers, 2 element tuples, ...
+            Value::ByValPair(a, b) if base_layout.fields.count() == 2 => {
+                let val = [a, b][field_index];
+                Ok(Some((Value::ByVal(val), field.ty)))
+            },
+            _ => Ok(None),
+        }
+    }
+
     fn try_read_place_projection(
         &mut self,
         proj: &mir::PlaceProjection<'tcx>,
@@ -126,23 +151,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         };
         let base_ty = self.place_ty(&proj.base);
         match proj.elem {
-            Field(field, _) => {
-                let base_layout = self.layout_of(base_ty)?;
-                let field_index = field.index();
-                let field = base_layout.field(&self, field_index)?;
-                let offset = base_layout.fields.offset(field_index);
-                match base {
-                    // the field covers the entire type
-                    Value::ByValPair(..) |
-                    Value::ByVal(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some(base)),
-                    // split fat pointers, 2 element tuples, ...
-                    Value::ByValPair(a, b) if base_layout.fields.count() == 2 => {
-                        let val = [a, b][field_index];
-                        Ok(Some(Value::ByVal(val)))
-                    },
-                    _ => Ok(None),
-                }
-            },
+            Field(field, _) => Ok(self.read_field(base, None, field, base_ty)?.map(|(f, _)| f)),
             // The NullablePointer cases should work fine, need to take care for normal enums
             Downcast(..) |
             Subslice { .. } |
@@ -188,17 +197,29 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             },
 
             Static(ref static_) => {
-                let instance = ty::Instance::mono(self.tcx, static_.def_id);
-                let gid = GlobalId {
-                    instance,
-                    promoted: None,
-                };
+                let alloc = self
+                    .tcx
+                    .interpret_interner
+                    .get_cached(static_.def_id);
                 let layout = self.layout_of(self.place_ty(mir_place))?;
-                let alloc = self.tcx.interpret_interner.borrow().get_cached(gid).expect("uncached global");
-                Place::Ptr {
-                    ptr: MemoryPointer::new(alloc, 0).into(),
-                    align: layout.align,
-                    extra: PlaceExtra::None,
+                if let Some(alloc) = alloc {
+                    Place::Ptr {
+                        ptr: MemoryPointer::new(alloc, 0).into(),
+                        align: layout.align,
+                        extra: PlaceExtra::None,
+                    }
+                } else {
+                    let instance = ty::Instance::mono(*self.tcx, static_.def_id);
+                    let cid = GlobalId {
+                        instance,
+                        promoted: None
+                    };
+                    let alloc = Machine::init_static(self, cid)?;
+                    Place::Ptr {
+                        ptr: MemoryPointer::new(alloc, 0).into(),
+                        align: layout.align,
+                        extra: PlaceExtra::None,
+                    }
                 }
             }
 
@@ -424,7 +445,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
     pub fn place_ty(&self, place: &mir::Place<'tcx>) -> Ty<'tcx> {
         self.monomorphize(
-            place.ty(self.mir(), self.tcx).to_ty(self.tcx),
+            place.ty(self.mir(), *self.tcx).to_ty(*self.tcx),
             self.substs(),
         )
     }
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 2b0f9041d5115..4e1750caf26ba 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -2,22 +2,13 @@
 //!
 //! The main entry point is the `step` method.
 
-use rustc::hir;
-use rustc::mir::visit::{Visitor, PlaceContext};
 use rustc::mir;
-use rustc::ty::{self, Instance};
-use rustc::ty::layout::LayoutOf;
-use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::GlobalId;
 
-use rustc::mir::interpret::{EvalResult, EvalErrorKind};
-use super::{EvalContext, StackPopCleanup, Place, Machine};
+use rustc::mir::interpret::EvalResult;
+use super::{EvalContext, Machine};
 
-use syntax::codemap::Span;
-use syntax::ast::Mutability;
-
-impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
-    pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+    pub fn inc_step_counter_and_check_limit(&mut self, n: usize) -> EvalResult<'tcx> {
         self.steps_remaining = self.steps_remaining.saturating_sub(n);
         if self.steps_remaining > 0 {
             Ok(())
@@ -28,7 +19,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
     /// Returns true as long as there are more things to do.
     pub fn step(&mut self) -> EvalResult<'tcx, bool> {
-        self.inc_step_counter_and_check_limit(1)?;
         if self.stack.is_empty() {
             return Ok(false);
         }
@@ -41,52 +31,16 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         let old_frames = self.cur_frame();
 
         if let Some(stmt) = basic_block.statements.get(stmt_id) {
-            let mut new = Ok(false);
-            ConstantExtractor {
-                span: stmt.source_info.span,
-                instance: self.frame().instance,
-                ecx: self,
-                mir,
-                new_constant: &mut new,
-            }.visit_statement(
-                block,
-                stmt,
-                mir::Location {
-                    block,
-                    statement_index: stmt_id,
-                },
-            );
-            // if ConstantExtractor added a new frame, we don't execute anything here
-            // but await the next call to step
-            if !new? {
-                assert_eq!(old_frames, self.cur_frame());
-                self.statement(stmt)?;
-            }
+            assert_eq!(old_frames, self.cur_frame());
+            self.statement(stmt)?;
             return Ok(true);
         }
 
+        self.inc_step_counter_and_check_limit(1)?;
+
         let terminator = basic_block.terminator();
-        let mut new = Ok(false);
-        ConstantExtractor {
-            span: terminator.source_info.span,
-            instance: self.frame().instance,
-            ecx: self,
-            mir,
-            new_constant: &mut new,
-        }.visit_terminator(
-            block,
-            terminator,
-            mir::Location {
-                block,
-                statement_index: stmt_id,
-            },
-        );
-        // if ConstantExtractor added a new frame, we don't execute anything here
-        // but await the next call to step
-        if !new? {
-            assert_eq!(old_frames, self.cur_frame());
-            self.terminator(terminator)?;
-        }
+        assert_eq!(old_frames, self.cur_frame());
+        self.terminator(terminator)?;
         Ok(true)
     }
 
@@ -98,6 +52,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         // Some statements (e.g. box) push new stack frames.  We have to record the stack frame number
         // *before* executing the statement.
         let frame_idx = self.cur_frame();
+        self.tcx.span = stmt.source_info.span;
+        self.memory.tcx.span = stmt.source_info.span;
 
         match stmt.kind {
             Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?,
@@ -146,190 +102,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
     fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> {
         trace!("{:?}", terminator.kind);
+        self.tcx.span = terminator.source_info.span;
+        self.memory.tcx.span = terminator.source_info.span;
         self.eval_terminator(terminator)?;
         if !self.stack.is_empty() {
             trace!("// {:?}", self.frame().block);
         }
         Ok(())
     }
-
-    /// returns `true` if a stackframe was pushed
-    fn global_item(
-        &mut self,
-        instance: Instance<'tcx>,
-        span: Span,
-        mutability: Mutability,
-    ) -> EvalResult<'tcx, bool> {
-        debug!("global_item: {:?}", instance);
-        let cid = GlobalId {
-            instance,
-            promoted: None,
-        };
-        if self.tcx.interpret_interner.borrow().get_cached(cid).is_some() {
-            return Ok(false);
-        }
-        if self.tcx.has_attr(instance.def_id(), "linkage") {
-            M::global_item_with_linkage(self, cid.instance, mutability)?;
-            return Ok(false);
-        }
-        let instance_ty = instance.ty(self.tcx);
-        let layout = self.layout_of(instance_ty)?;
-        assert!(!layout.is_unsized());
-        let ptr = self.memory.allocate(
-            layout.size.bytes(),
-            layout.align,
-            None,
-        )?;
-        self.tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id);
-        let internally_mutable = !layout.ty.is_freeze(self.tcx, self.param_env, span);
-        let mutability = if mutability == Mutability::Mutable || internally_mutable {
-            Mutability::Mutable
-        } else {
-            Mutability::Immutable
-        };
-        let cleanup = StackPopCleanup::MarkStatic(mutability);
-        let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id()));
-        trace!("pushing stack frame for global: {}", name);
-        let mir = self.load_mir(instance.def)?;
-        self.push_stack_frame(
-            instance,
-            span,
-            mir,
-            Place::from_ptr(ptr, layout.align),
-            cleanup,
-        )?;
-        Ok(true)
-    }
-}
-
-struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b, M: Machine<'tcx> + 'a> {
-    span: Span,
-    ecx: &'a mut EvalContext<'b, 'tcx, M>,
-    mir: &'tcx mir::Mir<'tcx>,
-    instance: ty::Instance<'tcx>,
-    // Whether a stackframe for a new constant has been pushed
-    new_constant: &'a mut EvalResult<'tcx, bool>,
-}
-
-impl<'a, 'b, 'tcx, M: Machine<'tcx>> ConstantExtractor<'a, 'b, 'tcx, M> {
-    fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx, bool>>(&mut self, f: F) {
-        match *self.new_constant {
-            // already computed a constant, don't do more than one per iteration
-            Ok(true) => {},
-            // no constants computed yet
-            Ok(false) => *self.new_constant = f(self),
-            // error happened, abort the visitor traversing
-            Err(_) => {},
-        }
-    }
-}
-
-impl<'a, 'b, 'tcx, M: Machine<'tcx>> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx, M> {
-    fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Location) {
-        self.super_constant(constant, location);
-        self.try(|this| {
-            match constant.literal {
-                // already computed by rustc
-                mir::Literal::Value { value: &ty::Const { val: ConstVal::Unevaluated(def_id, substs), .. } } => {
-                    debug!("global_item: {:?}, {:#?}", def_id, substs);
-                    let substs = this.ecx.tcx.trans_apply_param_substs(this.instance.substs, &substs);
-                    debug!("global_item_new_substs: {:#?}", substs);
-                    debug!("global_item_param_env: {:#?}", this.ecx.param_env);
-                    let instance = Instance::resolve(
-                        this.ecx.tcx,
-                        this.ecx.param_env,
-                        def_id,
-                        substs,
-                    ).ok_or(EvalErrorKind::TypeckError)?; // turn error prop into a panic to expose associated type in const issue
-                    this.ecx.global_item(
-                        instance,
-                        constant.span,
-                        Mutability::Immutable,
-                    )
-                }
-                mir::Literal::Value { .. } => Ok(false),
-                mir::Literal::Promoted { index } => {
-                    let cid = GlobalId {
-                        instance: this.instance,
-                        promoted: Some(index),
-                    };
-                    if this.ecx.tcx.interpret_interner.borrow().get_cached(cid).is_some() {
-                        return Ok(false);
-                    }
-                    let mir = &this.mir.promoted[index];
-                    let ty = this.ecx.monomorphize(mir.return_ty(), this.instance.substs);
-                    let layout = this.ecx.layout_of(ty)?;
-                    assert!(!layout.is_unsized());
-                    let ptr = this.ecx.memory.allocate(
-                        layout.size.bytes(),
-                        layout.align,
-                        None,
-                    )?;
-                    this.ecx.tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id);
-                    trace!("pushing stack frame for {:?}", index);
-                    this.ecx.push_stack_frame(
-                        this.instance,
-                        constant.span,
-                        mir,
-                        Place::from_ptr(ptr, layout.align),
-                        StackPopCleanup::MarkStatic(Mutability::Immutable),
-                    )?;
-                    Ok(true)
-                }
-            }
-        });
-    }
-
-    fn visit_place(
-        &mut self,
-        place: &mir::Place<'tcx>,
-        context: PlaceContext<'tcx>,
-        location: mir::Location,
-    ) {
-        self.super_place(place, context, location);
-        self.try(|this| {
-            if let mir::Place::Static(ref static_) = *place {
-                let def_id = static_.def_id;
-                let span = this.span;
-                if let Some(node_item) = this.ecx.tcx.hir.get_if_local(def_id) {
-                    if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item {
-                        if let hir::ItemStatic(_, m, _) = *node {
-                            let instance = Instance::mono(this.ecx.tcx, def_id);
-                            this.ecx.global_item(
-                                instance,
-                                span,
-                                if m == hir::MutMutable {
-                                    Mutability::Mutable
-                                } else {
-                                    Mutability::Immutable
-                                },
-                            )
-                        } else {
-                            bug!("static def id doesn't point to static");
-                        }
-                    } else {
-                        bug!("static def id doesn't point to item");
-                    }
-                } else {
-                    let def = this.ecx.tcx.describe_def(def_id).expect("static not found");
-                    if let hir::def::Def::Static(_, mutable) = def {
-                        let instance = Instance::mono(this.ecx.tcx, def_id);
-                        this.ecx.global_item(
-                            instance,
-                            span,
-                            if mutable {
-                                Mutability::Mutable
-                            } else {
-                                Mutability::Immutable
-                            },
-                        )
-                    } else {
-                        bug!("static found but isn't a static: {:?}", def);
-                    }
-                }
-            } else {
-                Ok(false)
-            }
-        });
-    }
 }
diff --git a/src/librustc_mir/interpret/terminator/drop.rs b/src/librustc_mir/interpret/terminator/drop.rs
index c5942712b87dd..fbc0c499e59de 100644
--- a/src/librustc_mir/interpret/terminator/drop.rs
+++ b/src/librustc_mir/interpret/terminator/drop.rs
@@ -5,7 +5,7 @@ use syntax::codemap::Span;
 use rustc::mir::interpret::{EvalResult, PrimVal, Value};
 use interpret::{Machine, ValTy, EvalContext, Place, PlaceExtra};
 
-impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     pub(crate) fn drop_place(
         &mut self,
         place: Place,
diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs
index 606bda51edb1f..babc784701475 100644
--- a/src/librustc_mir/interpret/terminator/mod.rs
+++ b/src/librustc_mir/interpret/terminator/mod.rs
@@ -5,15 +5,14 @@ use syntax::codemap::Span;
 use syntax::abi::Abi;
 
 use rustc::mir::interpret::{EvalResult, PrimVal, Value};
-use super::{EvalContext, eval_context,
-            Place, Machine, ValTy};
+use super::{EvalContext, Place, Machine, ValTy};
 
 use rustc_data_structures::indexed_vec::Idx;
 use interpret::memory::HasMemory;
 
 mod drop;
 
-impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     pub fn goto_block(&mut self, target: mir::BasicBlock) {
         self.frame_mut().block = target;
         self.frame_mut().stmt = 0;
@@ -45,8 +44,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 // Branch to the `otherwise` case by default, if no match is found.
                 let mut target_block = targets[targets.len() - 1];
 
-                for (index, const_int) in values.iter().enumerate() {
-                    let prim = PrimVal::Bytes(const_int.to_u128_unchecked());
+                for (index, &const_int) in values.iter().enumerate() {
+                    let prim = PrimVal::Bytes(const_int);
                     if discr_prim.to_bytes()? == prim.to_bytes()? {
                         target_block = targets[index];
                         break;
@@ -72,10 +71,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                     ty::TyFnPtr(sig) => {
                         let fn_ptr = self.value_to_primval(func)?.to_ptr()?;
                         let instance = self.memory.get_fn(fn_ptr)?;
-                        let instance_ty = instance.ty(self.tcx);
+                        let instance_ty = instance.ty(*self.tcx);
                         match instance_ty.sty {
                             ty::TyFnDef(..) => {
-                                let real_sig = instance_ty.fn_sig(self.tcx);
+                                let real_sig = instance_ty.fn_sig(*self.tcx);
                                 let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig);
                                 let real_sig = self.tcx.erase_late_bound_regions_and_normalize(&real_sig);
                                 if !self.check_sig_compat(sig, real_sig)? {
@@ -88,7 +87,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                     }
                     ty::TyFnDef(def_id, substs) => (
                         self.resolve(def_id, substs)?,
-                        func.ty.fn_sig(self.tcx),
+                        func.ty.fn_sig(*self.tcx),
                     ),
                     _ => {
                         let msg = format!("can't handle callee of type {:?}", func.ty);
@@ -117,7 +116,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 let ty = self.tcx.trans_apply_param_substs(self.substs(), &ty);
                 trace!("TerminatorKind::drop: {:?}, type {}", location, ty);
 
-                let instance = eval_context::resolve_drop_in_place(self.tcx, ty);
+                let instance = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
                 self.drop_place(
                     place,
                     instance,
@@ -402,7 +401,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 let ptr_size = self.memory.pointer_size();
                 let ptr_align = self.tcx.data_layout.pointer_align;
                 let (ptr, vtable) = self.into_ptr_vtable_pair(args[0].value)?;
-                let fn_ptr = self.memory.read_ptr_sized_unsigned(
+                let fn_ptr = self.memory.read_ptr_sized(
                     vtable.offset(ptr_size * (idx as u64 + 3), &self)?,
                     ptr_align
                 )?.to_ptr()?;
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index 22417201f0dc5..ded27108e716a 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -3,10 +3,9 @@ use rustc::ty::layout::{Size, Align, LayoutOf};
 use syntax::ast::Mutability;
 
 use rustc::mir::interpret::{PrimVal, Value, MemoryPointer, EvalResult};
-use super::{EvalContext, eval_context,
-            Machine};
+use super::{EvalContext, Machine};
 
-impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
     /// objects.
     ///
@@ -34,7 +33,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             None,
         )?;
 
-        let drop = eval_context::resolve_drop_in_place(self.tcx, ty);
+        let drop = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
         let drop = self.memory.create_fn_alloc(drop);
         self.memory.write_ptr_sized_unsigned(vtable, ptr_align, PrimVal::Ptr(drop))?;
 
@@ -52,9 +51,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             }
         }
 
-        self.memory.mark_static_initalized(
+        self.memory.mark_static_initialized(
             vtable.alloc_id,
-            Mutability::Mutable,
+            Mutability::Immutable,
         )?;
 
         Ok(vtable)
@@ -80,8 +79,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
     ) -> EvalResult<'tcx, (Size, Align)> {
         let pointer_size = self.memory.pointer_size();
         let pointer_align = self.tcx.data_layout.pointer_align;
-        let size = self.memory.read_ptr_sized_unsigned(vtable.offset(pointer_size, self)?, pointer_align)?.to_bytes()? as u64;
-        let align = self.memory.read_ptr_sized_unsigned(
+        let size = self.memory.read_ptr_sized(vtable.offset(pointer_size, self)?, pointer_align)?.to_bytes()? as u64;
+        let align = self.memory.read_ptr_sized(
             vtable.offset(pointer_size * 2, self)?,
             pointer_align
         )?.to_bytes()? as u64;
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 8c15d1cf8b03a..c31e95fd826c6 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -16,6 +16,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 
 #![deny(warnings)]
 
+#![feature(slice_patterns)]
+#![feature(from_ref)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(catch_expr)]
@@ -38,6 +40,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 #![feature(nonzero)]
 #![feature(underscore_lifetimes)]
 
+extern crate arena;
 #[macro_use]
 extern crate bitflags;
 #[macro_use] extern crate log;
@@ -52,7 +55,6 @@ extern crate syntax;
 extern crate syntax_pos;
 extern crate rustc_back;
 extern crate rustc_const_math;
-extern crate rustc_const_eval;
 extern crate core; // for NonZero
 extern crate log_settings;
 extern crate rustc_apfloat;
@@ -70,6 +72,7 @@ pub mod util;
 pub mod interpret;
 pub mod monomorphize;
 
+pub use hair::pattern::check_crate as matchck_crate;
 use rustc::ty::maps::Providers;
 
 pub fn provide(providers: &mut Providers) {
@@ -77,6 +80,7 @@ pub fn provide(providers: &mut Providers) {
     shim::provide(providers);
     transform::provide(providers);
     providers.const_eval = interpret::const_eval_provider;
+    providers.check_match = hair::pattern::check_match;
 }
 
 __build_diagnostic_array! { librustc_mir, DIAGNOSTICS }
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 0f512569adf97..f6b47efca31cd 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -194,15 +194,17 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
 use rustc::middle::const_val::ConstVal;
+use rustc::mir::interpret::{Value, PrimVal, AllocId, Pointer};
 use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
 use rustc::traits;
 use rustc::ty::subst::{Substs, Kind};
 use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
 use rustc::ty::adjustment::CustomCoerceUnsized;
 use rustc::session::config;
-use rustc::mir::{self, Location};
+use rustc::mir::{self, Location, Promoted};
 use rustc::mir::visit::Visitor as MirVisitor;
 use rustc::mir::mono::MonoItem;
+use rustc::mir::interpret::GlobalId;
 
 use monomorphize::{self, Instance};
 use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
@@ -377,7 +379,19 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             recursion_depth_reset = None;
 
-            collect_neighbours(tcx, instance, true, &mut neighbors);
+            let cid = GlobalId {
+                instance,
+                promoted: None,
+            };
+            let param_env = ty::ParamEnv::empty(traits::Reveal::All);
+
+            match tcx.const_eval(param_env.and(cid)) {
+                Ok(val) => collect_const(tcx, val, instance.substs, &mut neighbors),
+                Err(err) => {
+                    let span = tcx.def_span(def_id);
+                    err.report(tcx, span, "static");
+                }
+            }
         }
         MonoItem::Fn(instance) => {
             // Sanity check whether this ended up being collected accidentally
@@ -389,7 +403,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                                recursion_depths));
             check_type_length_limit(tcx, instance);
 
-            collect_neighbours(tcx, instance, false, &mut neighbors);
+            collect_neighbours(tcx, instance, &mut neighbors);
         }
         MonoItem::GlobalAsm(..) => {
             recursion_depth_reset = None;
@@ -498,7 +512,6 @@ struct MirNeighborCollector<'a, 'tcx: 'a> {
     mir: &'a mir::Mir<'tcx>,
     output: &'a mut Vec<MonoItem<'tcx>>,
     param_substs: &'tcx Substs<'tcx>,
-    const_context: bool,
 }
 
 impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
@@ -568,15 +581,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
     fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
         debug!("visiting const {:?} @ {:?}", *constant, location);
 
-        if let ConstVal::Unevaluated(def_id, substs) = constant.val {
-            let substs = self.tcx.trans_apply_param_substs(self.param_substs,
-                                                           &substs);
-            let instance = ty::Instance::resolve(self.tcx,
-                                                 ty::ParamEnv::empty(traits::Reveal::All),
-                                                 def_id,
-                                                 substs).unwrap();
-            collect_neighbours(self.tcx, instance, true, self.output);
-        }
+        collect_const(self.tcx, constant, self.param_substs, self.output);
 
         self.super_const(constant);
     }
@@ -592,30 +597,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
             mir::TerminatorKind::Call { ref func, .. } => {
                 let callee_ty = func.ty(self.mir, tcx);
                 let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty);
-
-                let constness = match (self.const_context, &callee_ty.sty) {
-                    (true, &ty::TyFnDef(def_id, substs)) if self.tcx.is_const_fn(def_id) => {
-                        let instance =
-                            ty::Instance::resolve(self.tcx,
-                                                  ty::ParamEnv::empty(traits::Reveal::All),
-                                                  def_id,
-                                                  substs).unwrap();
-                        Some(instance)
-                    }
-                    _ => None
-                };
-
-                if let Some(const_fn_instance) = constness {
-                    // If this is a const fn, called from a const context, we
-                    // have to visit its body in order to find any fn reifications
-                    // it might contain.
-                    collect_neighbours(self.tcx,
-                                       const_fn_instance,
-                                       true,
-                                       self.output);
-                } else {
-                    visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
-                }
+                visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
             }
             mir::TerminatorKind::Drop { ref location, .. } |
             mir::TerminatorKind::DropAndReplace { ref location, .. } => {
@@ -1098,26 +1080,59 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
+/// Scan the miri alloc in order to find function calls, closures, and drop-glue
+fn collect_miri<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    alloc_id: AllocId,
+    output: &mut Vec<MonoItem<'tcx>>,
+) {
+    if let Some(did) = tcx.interpret_interner.get_corresponding_static_def_id(alloc_id) {
+        let instance = Instance::mono(tcx, did);
+        if should_monomorphize_locally(tcx, &instance) {
+            trace!("collecting static {:?}", did);
+            output.push(MonoItem::Static(did));
+        }
+    } else if let Some(alloc) = tcx.interpret_interner.get_alloc(alloc_id) {
+        trace!("collecting {:?} with {:#?}", alloc_id, alloc);
+        for &inner in alloc.relocations.values() {
+            collect_miri(tcx, inner, output);
+        }
+    } else if let Some(fn_instance) = tcx.interpret_interner.get_fn(alloc_id) {
+        if should_monomorphize_locally(tcx, &fn_instance) {
+            trace!("collecting {:?} with {:#?}", alloc_id, fn_instance);
+            output.push(create_fn_mono_item(fn_instance));
+        }
+    } else {
+        bug!("alloc id without corresponding allocation: {}", alloc_id);
+    }
+}
+
 /// Scan the MIR in order to find function calls, closures, and drop-glue
 fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 instance: Instance<'tcx>,
-                                const_context: bool,
                                 output: &mut Vec<MonoItem<'tcx>>)
 {
     let mir = tcx.instance_mir(instance.def);
 
-    let mut visitor = MirNeighborCollector {
+    MirNeighborCollector {
         tcx,
         mir: &mir,
         output,
         param_substs: instance.substs,
-        const_context,
-    };
-
-    visitor.visit_mir(&mir);
-    for promoted in &mir.promoted {
-        visitor.mir = promoted;
-        visitor.visit_mir(promoted);
+    }.visit_mir(&mir);
+    let param_env = ty::ParamEnv::empty(traits::Reveal::All);
+    for (i, promoted) in mir.promoted.iter().enumerate() {
+        use rustc_data_structures::indexed_vec::Idx;
+        let cid = GlobalId {
+            instance,
+            promoted: Some(Promoted::new(i)),
+        };
+        match tcx.const_eval(param_env.and(cid)) {
+            Ok(val) => collect_const(tcx, val, instance.substs, output),
+            Err(err) => {
+                err.report(tcx, promoted.span, "promoted");
+            }
+        }
     }
 }
 
@@ -1129,3 +1144,60 @@ fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     printer.push_def_path(def_id, &mut output);
     output
 }
+
+fn collect_const<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    constant: &ty::Const<'tcx>,
+    param_substs: &'tcx Substs<'tcx>,
+    output: &mut Vec<MonoItem<'tcx>>,
+) {
+    debug!("visiting const {:?}", *constant);
+
+    let val = match constant.val {
+        ConstVal::Unevaluated(def_id, substs) => {
+            let param_env = ty::ParamEnv::empty(traits::Reveal::All);
+            let substs = tcx.trans_apply_param_substs(param_substs,
+                                                        &substs);
+            let instance = ty::Instance::resolve(tcx,
+                                                param_env,
+                                                def_id,
+                                                substs).unwrap();
+
+            let cid = GlobalId {
+                instance,
+                promoted: None,
+            };
+            match tcx.const_eval(param_env.and(cid)) {
+                Ok(val) => val.val,
+                Err(err) => {
+                    let span = tcx.def_span(def_id);
+                    err.report(tcx, span, "constant");
+                    return;
+                }
+            }
+        },
+        _ => constant.val,
+    };
+    match val {
+        ConstVal::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
+        ConstVal::Value(Value::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => {
+            collect_miri(tcx, a.alloc_id, output);
+            collect_miri(tcx, b.alloc_id, output);
+        }
+        ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) |
+        ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) |
+        ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) =>
+            collect_miri(tcx, ptr.alloc_id, output),
+        ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) => {
+            // by ref should only collect the inner allocation, not the value itself
+            let alloc = tcx
+                .interpret_interner
+                .get_alloc(ptr.alloc_id)
+                .expect("ByRef to extern static is not allowed");
+            for &inner in alloc.relocations.values() {
+                collect_miri(tcx, inner, output);
+            }
+        }
+        _ => {},
+    }
+}
diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs
index 38b8ffc6b9c80..1f7f1237ba789 100644
--- a/src/librustc_mir/monomorphize/item.rs
+++ b/src/librustc_mir/monomorphize/item.rs
@@ -314,7 +314,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
                 output.push('[');
                 self.push_type_name(inner_type, output);
                 write!(output, "; {}",
-                    len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap();
+                    len.val.unwrap_u64()).unwrap();
                 output.push(']');
             },
             ty::TySlice(inner_type) => {
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index e6ebdd3d6c167..9aff7fa2a2c71 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -16,7 +16,7 @@ use rustc::mir::*;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::ty::maps::Providers;
-use rustc_const_math::{ConstInt, ConstUsize};
+use rustc::mir::interpret::{Value, PrimVal};
 
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
@@ -303,7 +303,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     match self_ty.sty {
         _ if is_copy => builder.copy_shim(),
         ty::TyArray(ty, len) => {
-            let len = len.val.to_const_int().unwrap().to_u64().unwrap();
+            let len = len.val.unwrap_u64();
             builder.array_shim(dest, src, ty, len)
         }
         ty::TyClosure(def_id, substs) => {
@@ -443,7 +443,8 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
             ty: func_ty,
             literal: Literal::Value {
                 value: tcx.mk_const(ty::Const {
-                    val: ConstVal::Function(self.def_id, substs),
+                    // ZST function type
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
                     ty: func_ty
                 }),
             },
@@ -501,13 +502,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
     }
 
     fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
-        let value = ConstUsize::new(value, self.tcx.sess.target.usize_ty).unwrap();
         box Constant {
             span: self.span,
             ty: self.tcx.types.usize,
             literal: Literal::Value {
                 value: self.tcx.mk_const(ty::Const {
-                    val: ConstVal::Integral(ConstInt::Usize(value)),
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))),
                     ty: self.tcx.types.usize,
                 })
             }
@@ -739,8 +739,8 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 ty,
                 literal: Literal::Value {
                     value: tcx.mk_const(ty::Const {
-                        val: ConstVal::Function(def_id,
-                            Substs::identity_for_item(tcx, def_id)),
+                        // ZST function type
+                        val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
                         ty
                     }),
                 },
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 0bef9f0602d86..86d08dec2b9c3 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -213,7 +213,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                 // locals are safe
             }
             &Place::Static(box Static { def_id, ty: _ }) => {
-                if self.tcx.is_static_mut(def_id) {
+                if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) {
                     self.require_unsafe("use of mutable static");
                 } else if self.tcx.is_foreign_item(def_id) {
                     let source_info = self.source_info;
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
new file mode 100644
index 0000000000000..f133d6e9c6dee
--- /dev/null
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -0,0 +1,517 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Propagates constants for early reporting of statically known
+//! assertion failures
+
+
+use rustc::hir::def::Def;
+use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local};
+use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind};
+use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
+use rustc::mir::visit::{Visitor, PlaceContext};
+use rustc::middle::const_val::ConstVal;
+use rustc::ty::{TyCtxt, self, Instance};
+use rustc::mir::interpret::{Value, PrimVal, GlobalId};
+use interpret::{eval_body_with_mir, mk_borrowck_eval_cx, ValTy};
+use transform::{MirPass, MirSource};
+use syntax::codemap::Span;
+use rustc::ty::subst::Substs;
+use rustc_data_structures::indexed_vec::IndexVec;
+use rustc::ty::ParamEnv;
+use rustc::ty::layout::{
+    LayoutOf, TyLayout, LayoutError,
+    HasTyCtxt, TargetDataLayout, HasDataLayout,
+};
+
+pub struct ConstProp;
+
+impl MirPass for ConstProp {
+    fn run_pass<'a, 'tcx>(&self,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          source: MirSource,
+                          mir: &mut Mir<'tcx>) {
+        // will be evaluated by miri and produce its errors there
+        if source.promoted.is_some() {
+            return;
+        }
+        match tcx.describe_def(source.def_id) {
+            // skip statics because they'll be evaluated by miri anyway
+            Some(Def::Static(..)) => return,
+            _ => {},
+        }
+        trace!("ConstProp starting for {:?}", source.def_id);
+
+        // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
+        // constants, instead of just checking for const-folding succeeding.
+        // That would require an uniform one-def no-mutation analysis
+        // and RPO (or recursing when needing the value of a local).
+        let mut optimization_finder = ConstPropagator::new(mir, tcx, source);
+        optimization_finder.visit_mir(mir);
+
+        trace!("ConstProp done for {:?}", source.def_id);
+    }
+}
+
+type Const<'tcx> = (Value, ty::Ty<'tcx>, Span);
+
+/// Finds optimization opportunities on the MIR.
+struct ConstPropagator<'b, 'a, 'tcx:'a+'b> {
+    mir: &'b Mir<'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    source: MirSource,
+    places: IndexVec<Local, Option<Const<'tcx>>>,
+    can_const_prop: IndexVec<Local, bool>,
+    param_env: ParamEnv<'tcx>,
+}
+
+impl<'a, 'b, 'tcx> LayoutOf<ty::Ty<'tcx>> for &'a ConstPropagator<'a, 'b, 'tcx> {
+    type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
+
+    fn layout_of(self, ty: ty::Ty<'tcx>) -> Self::TyLayout {
+        self.tcx.layout_of(self.param_env.and(ty))
+    }
+}
+
+impl<'a, 'b, 'tcx> HasDataLayout for &'a ConstPropagator<'a, 'b, 'tcx> {
+    #[inline]
+    fn data_layout(&self) -> &TargetDataLayout {
+        &self.tcx.data_layout
+    }
+}
+
+impl<'a, 'b, 'tcx> HasTyCtxt<'tcx> for &'a ConstPropagator<'a, 'b, 'tcx> {
+    #[inline]
+    fn tcx<'c>(&'c self) -> TyCtxt<'c, 'tcx, 'tcx> {
+        self.tcx
+    }
+}
+
+impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
+    fn new(
+        mir: &'b Mir<'tcx>,
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        source: MirSource,
+    ) -> ConstPropagator<'b, 'a, 'tcx> {
+        let param_env = tcx.param_env(source.def_id);
+        ConstPropagator {
+            mir,
+            tcx,
+            source,
+            param_env,
+            can_const_prop: CanConstProp::check(mir),
+            places: IndexVec::from_elem(None, &mir.local_decls),
+        }
+    }
+
+    fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
+        let value = match self.tcx.const_eval(self.param_env.and(cid)) {
+            Ok(val) => val,
+            Err(err) => {
+                err.report(self.tcx, err.span, "constant propagated");
+                return None;
+            },
+        };
+        let val = match value.val {
+            ConstVal::Value(v) => v,
+            _ => bug!("eval produced: {:?}", value),
+        };
+        let val = (val, value.ty, span);
+        trace!("evaluated {:?} to {:?}", cid, val);
+        Some(val)
+    }
+
+    fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
+        match c.literal {
+            Literal::Value { value } => match value.val {
+                ConstVal::Value(v) => Some((v, value.ty, c.span)),
+                ConstVal::Unevaluated(did, substs) => {
+                    let instance = Instance::resolve(
+                        self.tcx,
+                        self.param_env,
+                        did,
+                        substs,
+                    )?;
+                    let cid = GlobalId {
+                        instance,
+                        promoted: None,
+                    };
+                    self.const_eval(cid, c.span)
+                },
+            },
+            // evaluate the promoted and replace the constant with the evaluated result
+            Literal::Promoted { index } => {
+                let generics = self.tcx.generics_of(self.source.def_id);
+                if generics.parent_types as usize + generics.types.len() > 0 {
+                    // FIXME: can't handle code with generics
+                    return None;
+                }
+                let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
+                let instance = Instance::new(self.source.def_id, substs);
+                let cid = GlobalId {
+                    instance,
+                    promoted: Some(index),
+                };
+                // cannot use `const_eval` here, because that would require having the MIR
+                // for the current function available, but we're producing said MIR right now
+                let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, self.param_env)?;
+                let val = (value, ty, c.span);
+                trace!("evaluated {:?} to {:?}", c, val);
+                Some(val)
+            }
+        }
+    }
+
+    fn eval_place(&mut self, place: &Place<'tcx>) -> Option<Const<'tcx>> {
+        match *place {
+            Place::Local(loc) => self.places[loc].clone(),
+            Place::Projection(ref proj) => match proj.elem {
+                ProjectionElem::Field(field, _) => {
+                    trace!("field proj on {:?}", proj.base);
+                    let (base, ty, span) = self.eval_place(&proj.base)?;
+                    match base {
+                        Value::ByValPair(a, b) => {
+                            trace!("by val pair: {:?}, {:?}", a, b);
+                            let base_layout = self.tcx.layout_of(self.param_env.and(ty)).ok()?;
+                            trace!("layout computed");
+                            use rustc_data_structures::indexed_vec::Idx;
+                            let field_index = field.index();
+                            let val = [a, b][field_index];
+                            let field = base_layout.field(&*self, field_index).ok()?;
+                            trace!("projection resulted in: {:?}", val);
+                            Some((Value::ByVal(val), field.ty, span))
+                        },
+                        _ => None,
+                    }
+                },
+                _ => None,
+            },
+            _ => None,
+        }
+    }
+
+    fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option<Const<'tcx>> {
+        match *op {
+            Operand::Constant(ref c) => self.eval_constant(c),
+            Operand::Move(ref place) | Operand::Copy(ref place) => self.eval_place(place),
+        }
+    }
+
+    fn const_prop(
+        &mut self,
+        rvalue: &Rvalue<'tcx>,
+        place_ty: ty::Ty<'tcx>,
+        source_info: SourceInfo,
+    ) -> Option<Const<'tcx>> {
+        let span = source_info.span;
+        match *rvalue {
+            // No need to overwrite an already evaluated constant
+            Rvalue::Use(Operand::Constant(box Constant {
+                literal: Literal::Value {
+                    value: &ty::Const {
+                        val: ConstVal::Value(_),
+                        ..
+                    },
+                },
+                ..
+            })) => None,
+            // This branch exists for the sanity type check
+            Rvalue::Use(Operand::Constant(ref c)) => {
+                assert_eq!(c.ty, place_ty);
+                self.eval_constant(c)
+            },
+            Rvalue::Use(ref op) => {
+                self.eval_operand(op)
+            },
+            Rvalue::Repeat(..) |
+            Rvalue::Ref(..) |
+            Rvalue::Cast(..) |
+            Rvalue::Aggregate(..) |
+            Rvalue::NullaryOp(NullOp::Box, _) |
+            Rvalue::Discriminant(..) => None,
+            // FIXME(oli-obk): evaluate static/constant slice lengths
+            Rvalue::Len(_) => None,
+            Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
+                let param_env = self.tcx.param_env(self.source.def_id);
+                type_size_of(self.tcx, param_env, ty).map(|n| (
+                    Value::ByVal(PrimVal::Bytes(n as u128)),
+                    self.tcx.types.usize,
+                    span,
+                ))
+            }
+            Rvalue::UnaryOp(op, ref arg) => {
+                let def_id = if self.tcx.is_closure(self.source.def_id) {
+                    self.tcx.closure_base_def_id(self.source.def_id)
+                } else {
+                    self.source.def_id
+                };
+                let generics = self.tcx.generics_of(def_id);
+                if generics.parent_types as usize + generics.types.len() > 0 {
+                    // FIXME: can't handle code with generics
+                    return None;
+                }
+                let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
+                let instance = Instance::new(self.source.def_id, substs);
+                let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
+
+                let val = self.eval_operand(arg)?;
+                let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?;
+                match ecx.unary_op(op, prim, val.1) {
+                    Ok(val) => Some((Value::ByVal(val), place_ty, span)),
+                    Err(mut err) => {
+                        ecx.report(&mut err, false, Some(span));
+                        None
+                    },
+                }
+            }
+            Rvalue::CheckedBinaryOp(op, ref left, ref right) |
+            Rvalue::BinaryOp(op, ref left, ref right) => {
+                trace!("rvalue binop {:?} for {:?} and {:?}", op, left, right);
+                let right = self.eval_operand(right)?;
+                let def_id = if self.tcx.is_closure(self.source.def_id) {
+                    self.tcx.closure_base_def_id(self.source.def_id)
+                } else {
+                    self.source.def_id
+                };
+                let generics = self.tcx.generics_of(def_id);
+                let has_generics = generics.parent_types as usize + generics.types.len() > 0;
+                if has_generics {
+                    // FIXME: can't handle code with generics
+                    return None;
+                }
+                let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
+                let instance = Instance::new(self.source.def_id, substs);
+                let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
+
+                let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?;
+                if op == BinOp::Shr || op == BinOp::Shl {
+                    let param_env = self.tcx.param_env(self.source.def_id);
+                    let left_ty = left.ty(self.mir, self.tcx);
+                    let bits = self.tcx.layout_of(param_env.and(left_ty)).unwrap().size.bits();
+                    if r.to_bytes().ok().map_or(false, |b| b >= bits as u128) {
+                        let scope_info = match self.mir.visibility_scope_info {
+                            ClearCrossCrate::Set(ref data) => data,
+                            ClearCrossCrate::Clear => return None,
+                        };
+                        let dir = if op == BinOp::Shr {
+                            "right"
+                        } else {
+                            "left"
+                        };
+                        let node_id = scope_info[source_info.scope].lint_root;
+                        self.tcx.lint_node(
+                            ::rustc::lint::builtin::EXCEEDING_BITSHIFTS,
+                            node_id,
+                            span,
+                            &format!("attempt to shift {} with overflow", dir));
+                        return None;
+                    }
+                }
+                let left = self.eval_operand(left)?;
+                let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?;
+                trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
+                match ecx.binary_op(op, l, left.1, r, right.1) {
+                    Ok((val, overflow)) => {
+                        let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
+                            Value::ByValPair(
+                                val,
+                                PrimVal::from_bool(overflow),
+                            )
+                        } else {
+                            if overflow {
+                                use rustc::mir::interpret::EvalErrorKind;
+                                let mut err = EvalErrorKind::OverflowingMath.into();
+                                ecx.report(&mut err, false, Some(span));
+                                return None;
+                            }
+                            Value::ByVal(val)
+                        };
+                        Some((val, place_ty, span))
+                    },
+                    Err(mut err) => {
+                        ecx.report(&mut err, false, Some(span));
+                        None
+                    },
+                }
+            },
+        }
+    }
+}
+
+fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          param_env: ty::ParamEnv<'tcx>,
+                          ty: ty::Ty<'tcx>) -> Option<u64> {
+    tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes())
+}
+
+struct CanConstProp {
+    can_const_prop: IndexVec<Local, bool>,
+    // false at the beginning, once set, there are not allowed to be any more assignments
+    found_assignment: IndexVec<Local, bool>,
+}
+
+impl CanConstProp {
+    /// returns true if `local` can be propagated
+    fn check(mir: &Mir) -> IndexVec<Local, bool> {
+        let mut cpv = CanConstProp {
+            can_const_prop: IndexVec::from_elem(true, &mir.local_decls),
+            found_assignment: IndexVec::from_elem(false, &mir.local_decls),
+        };
+        for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
+            // cannot use args at all
+            // cannot use locals because if x < y { y - x } else { x - y } would
+            //        lint for x != y
+            // FIXME(oli-obk): lint variables until they are used in a condition
+            // FIXME(oli-obk): lint if return value is constant
+            *val = mir.local_kind(local) == LocalKind::Temp;
+        }
+        cpv.visit_mir(mir);
+        cpv.can_const_prop
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for CanConstProp {
+    fn visit_local(
+        &mut self,
+        &local: &Local,
+        context: PlaceContext<'tcx>,
+        _: Location,
+    ) {
+        use rustc::mir::visit::PlaceContext::*;
+        match context {
+            // Constants must have at most one write
+            // FIXME(oli-obk): we could be more powerful here, if the multiple writes
+            // only occur in independent execution paths
+            Store => if self.found_assignment[local] {
+                self.can_const_prop[local] = false;
+            } else {
+                self.found_assignment[local] = true
+            },
+            // Reading constants is allowed an arbitrary number of times
+            Copy | Move |
+            StorageDead | StorageLive |
+            Validate |
+            Projection(_) |
+            Inspect => {},
+            _ => self.can_const_prop[local] = false,
+        }
+    }
+}
+
+impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
+    fn visit_constant(
+        &mut self,
+        constant: &Constant<'tcx>,
+        location: Location,
+    ) {
+        trace!("visit_constant: {:?}", constant);
+        self.super_constant(constant, location);
+        self.eval_constant(constant);
+    }
+
+    fn visit_statement(
+        &mut self,
+        block: BasicBlock,
+        statement: &Statement<'tcx>,
+        location: Location,
+    ) {
+        trace!("visit_statement: {:?}", statement);
+        if let StatementKind::Assign(ref place, ref rval) = statement.kind {
+            let place_ty = place
+                .ty(&self.mir.local_decls, self.tcx)
+                .to_ty(self.tcx);
+            if let Some(value) = self.const_prop(rval, place_ty, statement.source_info) {
+                if let Place::Local(local) = *place {
+                    trace!("checking whether {:?} can be stored to {:?}", value, local);
+                    if self.can_const_prop[local] {
+                        trace!("storing {:?} to {:?}", value, local);
+                        assert!(self.places[local].is_none());
+                        self.places[local] = Some(value);
+                    }
+                }
+            }
+        }
+        self.super_statement(block, statement, location);
+    }
+
+    fn visit_terminator_kind(
+        &mut self,
+        block: BasicBlock,
+        kind: &TerminatorKind<'tcx>,
+        location: Location,
+    ) {
+        self.super_terminator_kind(block, kind, location);
+        if let TerminatorKind::Assert { expected, msg, cond, .. } = kind {
+            if let Some(value) = self.eval_operand(cond) {
+                trace!("assertion on {:?} should be {:?}", value, expected);
+                if Value::ByVal(PrimVal::from_bool(*expected)) != value.0 {
+                    // poison all places this operand references so that further code
+                    // doesn't use the invalid value
+                    match cond {
+                        Operand::Move(ref place) | Operand::Copy(ref place) => {
+                            let mut place = place;
+                            while let Place::Projection(ref proj) = *place {
+                                place = &proj.base;
+                            }
+                            if let Place::Local(local) = *place {
+                                self.places[local] = None;
+                            }
+                        },
+                        Operand::Constant(_) => {}
+                    }
+                    let span = self.mir[block]
+                        .terminator
+                        .as_ref()
+                        .unwrap()
+                        .source_info
+                        .span;
+                    let node_id = self
+                        .tcx
+                        .hir
+                        .as_local_node_id(self.source.def_id)
+                        .expect("some part of a failing const eval must be local");
+                    use rustc::mir::AssertMessage::*;
+                    let msg = match msg {
+                        // Need proper const propagator for these
+                        GeneratorResumedAfterReturn |
+                        GeneratorResumedAfterPanic => return,
+                        Math(ref err) => err.description().to_owned(),
+                        BoundsCheck { ref len, ref index } => {
+                            let len = self.eval_operand(len).expect("len must be const");
+                            let len = match len.0 {
+                                Value::ByVal(PrimVal::Bytes(n)) => n,
+                                _ => bug!("const len not primitive: {:?}", len),
+                            };
+                            let index = self
+                                .eval_operand(index)
+                                .expect("index must be const");
+                            let index = match index.0 {
+                                Value::ByVal(PrimVal::Bytes(n)) => n,
+                                _ => bug!("const index not primitive: {:?}", index),
+                            };
+                            format!(
+                                "index out of bounds: \
+                                the len is {} but the index is {}",
+                                len,
+                                index,
+                            )
+                        },
+                    };
+                    self.tcx.lint_node(
+                        ::rustc::lint::builtin::CONST_ERR,
+                        node_id,
+                        span,
+                        &msg,
+                    );
+                }
+            }
+        }
+    }
+}
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index 9eca343cb5edc..2e8dd623d744d 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -19,6 +19,7 @@ use rustc::hir;
 use rustc::ty::{self, TyCtxt};
 use rustc::mir::*;
 use rustc::middle::const_val::ConstVal;
+use rustc::mir::interpret::{Value, PrimVal};
 use rustc::util::nodemap::FxHashMap;
 use rustc_data_structures::indexed_set::IdxSetBuf;
 use rustc_data_structures::indexed_vec::Idx;
@@ -541,7 +542,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             ty: self.tcx.types.bool,
             literal: Literal::Value {
                 value: self.tcx.mk_const(ty::Const {
-                    val: ConstVal::Bool(val),
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))),
                     ty: self.tcx.types.bool
                 })
             }
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 04ebaa031fe5a..0ff7356943388 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -68,7 +68,6 @@ use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior};
 use rustc::ty::subst::Substs;
 use util::dump_mir;
 use util::liveness::{self, LivenessMode};
-use rustc_const_math::ConstInt;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::indexed_set::IdxSetBuf;
 use std::collections::HashMap;
@@ -80,6 +79,7 @@ use transform::simplify;
 use transform::no_landing_pads::no_landing_pads;
 use dataflow::{do_dataflow, DebugFormatted, state_for_location};
 use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
+use rustc::mir::interpret::{Value, PrimVal};
 
 pub struct StateTransform;
 
@@ -181,7 +181,7 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
             ty: self.tcx.types.u32,
             literal: Literal::Value {
                 value: self.tcx.mk_const(ty::Const {
-                    val: ConstVal::Integral(ConstInt::U32(state_disc)),
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))),
                     ty: self.tcx.types.u32
                 }),
             },
@@ -534,7 +534,7 @@ fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let switch = TerminatorKind::SwitchInt {
         discr: Operand::Copy(transform.make_field(transform.state_field, tcx.types.u32)),
         switch_ty: tcx.types.u32,
-        values: Cow::from(cases.iter().map(|&(i, _)| ConstInt::U32(i)).collect::<Vec<_>>()),
+        values: Cow::from(cases.iter().map(|&(i, _)| i.into()).collect::<Vec<_>>()),
         targets: cases.iter().map(|&(_, d)| d).chain(once(default_block)).collect(),
     };
 
@@ -698,7 +698,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             ty: tcx.types.bool,
             literal: Literal::Value {
                 value: tcx.mk_const(ty::Const {
-                    val: ConstVal::Bool(false),
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
                     ty: tcx.types.bool
                 }),
             },
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 64c702b99cdb3..b8a0e0f89073d 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -207,6 +207,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
             return false;
         }
 
+        // Do not inline {u,i}128 lang items, trans const eval depends
+        // on detecting calls to these lang items and intercepting them
+        if tcx.is_binop_lang_item(callsite.callee).is_some() {
+            debug!("    not inlining 128bit integer lang item");
+            return false;
+        }
+
         let trans_fn_attrs = tcx.trans_fn_attrs(callsite.callee);
 
         let hinted = match trans_fn_attrs.inline {
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 9d1f76313759b..81b740c917b5e 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -41,6 +41,7 @@ pub mod dump_mir;
 pub mod deaggregator;
 pub mod instcombine;
 pub mod copy_prop;
+pub mod const_prop;
 pub mod generator;
 pub mod inline;
 pub mod lower_128bit;
@@ -265,6 +266,8 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
         generator::StateTransform,
 
         instcombine::InstCombine,
+        const_prop::ConstProp,
+        simplify_branches::SimplifyBranches::new("after-const-prop"),
         deaggregator::Deaggregator,
         copy_prop::CopyPropagation,
         remove_noop_landing_pads::RemoveNoopLandingPads,
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 8f5831270d6e5..88618122e4f11 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -690,7 +690,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                             _ => false
                         }
                     } else if let ty::TyArray(_, len) = ty.sty {
-                        len.val.to_const_int().unwrap().to_u64().unwrap() == 0 &&
+                        len.val.unwrap_u64() == 0 &&
                             self.mode == Mode::Fn
                     } else {
                         false
diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs
index 41089f567bd71..9dd48952208a9 100644
--- a/src/librustc_mir/transform/simplify_branches.rs
+++ b/src/librustc_mir/transform/simplify_branches.rs
@@ -13,6 +13,7 @@
 use rustc::ty::{self, TyCtxt};
 use rustc::middle::const_val::ConstVal;
 use rustc::mir::*;
+use rustc::mir::interpret::{Value, PrimVal};
 use transform::{MirPass, MirSource};
 
 use std::borrow::Cow;
@@ -40,10 +41,10 @@ impl MirPass for SimplifyBranches {
                 TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
                     literal: Literal::Value { ref value }, ..
                 }), ref values, ref targets, .. } => {
-                    if let Some(ref constint) = value.val.to_const_int() {
+                    if let Some(constint) = value.val.to_raw_bits() {
                         let (otherwise, targets) = targets.split_last().unwrap();
                         let mut ret = TerminatorKind::Goto { target: *otherwise };
-                        for (v, t) in values.iter().zip(targets.iter()) {
+                        for (&v, t) in values.iter().zip(targets.iter()) {
                             if v == constint {
                                 ret = TerminatorKind::Goto { target: *t };
                                 break;
@@ -56,9 +57,12 @@ impl MirPass for SimplifyBranches {
                 },
                 TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
                     literal: Literal::Value {
-                        value: &ty::Const { val: ConstVal::Bool(cond), .. }
+                        value: &ty::Const {
+                            val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))),
+                        .. }
                     }, ..
-                }), expected, .. } if cond == expected => {
+                }), expected, .. } if (cond == 1) == expected => {
+                    assert!(cond <= 1);
                     TerminatorKind::Goto { target: target }
                 },
                 TerminatorKind::FalseEdges { real_target, .. } => {
diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs
index e46de17047986..9cc3ffb30638f 100644
--- a/src/librustc_mir/transform/uniform_array_move_out.rs
+++ b/src/librustc_mir/transform/uniform_array_move_out.rs
@@ -81,8 +81,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
                 } else {
                     let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
                     if let ty::TyArray(item_ty, const_size) = place_ty.sty {
-                        if let Some(size) = const_size.val.to_const_int().and_then(|v| v.to_u64()) {
-                            assert!(size <= (u32::max_value() as u64),
+                        if let Some(size) = const_size.val.to_raw_bits() {
+                            assert!(size <= (u32::max_value() as u128),
                                     "unform array move out doesn't supported
                                      for array bigger then u32");
                             self.uniform(location, dst_place, proj, item_ty, size as u32);
@@ -203,7 +203,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut {
                         let opt_size = opt_src_place.and_then(|src_place| {
                             let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
                             if let ty::TyArray(_, ref size_o) = src_ty.sty {
-                                size_o.val.to_const_int().and_then(|v| v.to_u64())
+                                size_o.val.to_raw_bits().map(|n| n as u64)
                             } else {
                                 None
                             }
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index e2feb0ed39054..458dd488409e4 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -11,13 +11,14 @@
 use std::fmt;
 use rustc::hir;
 use rustc::mir::*;
-use rustc::middle::const_val::{ConstInt, ConstVal};
+use rustc::middle::const_val::ConstVal;
 use rustc::middle::lang_items;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::{Kind, Substs};
 use rustc::ty::util::IntTypeExt;
 use rustc_data_structures::indexed_vec::Idx;
 use util::patch::MirPatch;
+use rustc::mir::interpret::{Value, PrimVal};
 
 use std::{iter, u32};
 
@@ -425,7 +426,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
                     variant_path,
                     &adt.variants[variant_index],
                     substs);
-                values.push(discr);
+                values.push(discr.val);
                 if let Unwind::To(unwind) = unwind {
                     // We can't use the half-ladder from the original
                     // drop ladder, because this breaks the
@@ -480,7 +481,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
     fn adt_switch_block(&mut self,
                         adt: &'tcx ty::AdtDef,
                         blocks: Vec<BasicBlock>,
-                        values: &[ConstInt],
+                        values: &[u128],
                         succ: BasicBlock,
                         unwind: Unwind)
                         -> BasicBlock {
@@ -803,7 +804,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
                 self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
             }
             ty::TyArray(ety, size) => self.open_drop_for_array(
-                ety, size.val.to_const_int().and_then(|v| v.to_u64())),
+                ety, size.val.to_raw_bits().map(|i| i as u64)),
             ty::TySlice(ety) => self.open_drop_for_array(ety, None),
 
             _ => bug!("open drop from non-ADT `{:?}`", ty)
@@ -949,7 +950,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
             ty: self.tcx().types.usize,
             literal: Literal::Value {
                 value: self.tcx().mk_const(ty::Const {
-                    val: ConstVal::Integral(self.tcx().const_usize(val)),
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))),
                     ty: self.tcx().types.usize
                 })
             }
diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml
index e87e976eac3eb..4bab24ae1392c 100644
--- a/src/librustc_passes/Cargo.toml
+++ b/src/librustc_passes/Cargo.toml
@@ -11,7 +11,7 @@ crate-type = ["dylib"]
 [dependencies]
 log = "0.4"
 rustc = { path = "../librustc" }
-rustc_const_eval = { path = "../librustc_const_eval" }
+rustc_mir = { path = "../librustc_mir"}
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 syntax = { path = "../libsyntax" }
diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs
index 184fab778c601..7a54fc72d53cc 100644
--- a/src/librustc_passes/diagnostics.rs
+++ b/src/librustc_passes/diagnostics.rs
@@ -31,23 +31,6 @@ const FOO2: i32 = { 0 }; // but brackets are useless here
 ```
 "##,
 */
-E0030: r##"
-When matching against a range, the compiler verifies that the range is
-non-empty.  Range patterns include both end-points, so this is equivalent to
-requiring the start of the range to be less than or equal to the end of the
-range.
-
-For example:
-
-```compile_fail
-match 5u32 {
-    // This range is ok, albeit pointless.
-    1 ... 1 => {}
-    // This range is empty, and the compiler can tell.
-    1000 ... 5 => {}
-}
-```
-"##,
 
 E0130: r##"
 You declared a pattern as an argument in a foreign function declaration.
@@ -228,24 +211,6 @@ impl Foo for Bar {
 "##,
 
 
-E0579: r##"
-When matching against an exclusive range, the compiler verifies that the range
-is non-empty. Exclusive range patterns include the start point but not the end
-point, so this is equivalent to requiring the start of the range to be less
-than the end of the range.
-
-For example:
-
-```compile_fail
-match 5u32 {
-    // This range is ok, albeit pointless.
-    1 .. 2 => {}
-    // This range is empty, and the compiler can tell.
-    5 .. 5 => {}
-}
-```
-"##,
-
 E0590: r##"
 `break` or `continue` must include a label when used in the condition of a
 `while` loop.
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index 8bd9598288770..1f6cc1f71fc08 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -23,7 +23,7 @@
 
 #[macro_use]
 extern crate rustc;
-extern crate rustc_const_eval;
+extern crate rustc_mir;
 extern crate rustc_const_math;
 extern crate rustc_data_structures;
 
@@ -39,7 +39,7 @@ use rustc::ty::maps::Providers;
 mod diagnostics;
 
 pub mod ast_validation;
-pub mod consts;
+pub mod rvalue_promotion;
 pub mod hir_stats;
 pub mod loops;
 mod mir_stats;
@@ -47,5 +47,5 @@ mod mir_stats;
 __build_diagnostic_array! { librustc_passes, DIAGNOSTICS }
 
 pub fn provide(providers: &mut Providers) {
-    consts::provide(providers);
+    rvalue_promotion::provide(providers);
 }
diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs
index e4705674e2292..4a4ce63cc1d4e 100644
--- a/src/librustc_passes/mir_stats.rs
+++ b/src/librustc_passes/mir_stats.rs
@@ -12,7 +12,6 @@
 // pieces of MIR. The resulting numbers are good approximations but not
 // completely accurate (some things might be counted twice, others missed).
 
-use rustc_const_math::{ConstUsize};
 use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData};
 use rustc::mir::{Constant, Literal, Location, Local, LocalDecl};
 use rustc::mir::{Place, PlaceElem, PlaceProjection};
@@ -265,13 +264,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
         self.super_const(constant);
     }
 
-    fn visit_const_usize(&mut self,
-                         const_usize: &ConstUsize,
-                         _: Location) {
-        self.record("ConstUsize", const_usize);
-        self.super_const_usize(const_usize);
-    }
-
     fn visit_local_decl(&mut self,
                         local: Local,
                         local_decl: &LocalDecl<'tcx>) {
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/rvalue_promotion.rs
similarity index 77%
rename from src/librustc_passes/consts.rs
rename to src/librustc_passes/rvalue_promotion.rs
index b93b759fdf869..16278c37a0cc0 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/rvalue_promotion.rs
@@ -25,12 +25,6 @@
 // by borrowck::gather_loans
 
 use rustc::ty::cast::CastKind;
-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, LayoutError};
-use rustc_const_math::{ConstMathErr, Op};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::blocks::FnLikeNode;
@@ -38,20 +32,16 @@ use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::maps::{queries, Providers};
+use rustc::ty::maps::Providers;
 use rustc::ty::subst::Substs;
 use rustc::traits::Reveal;
-use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::{ItemLocalSet, NodeSet};
-use rustc::lint::builtin::CONST_ERR;
-use rustc::hir::{self, PatKind, RangeEnd};
+use rustc::hir;
 use rustc_data_structures::sync::Lrc;
 use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 
-use std::cmp::Ordering;
-
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         rvalue_promotable_map,
@@ -124,29 +114,6 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
-    fn const_cx(&self) -> ConstContext<'a, 'gcx> {
-        ConstContext::new(self.tcx, self.param_env.and(self.identity_substs), self.tables)
-    }
-
-    fn check_const_eval(&self, expr: &'gcx hir::Expr) {
-        if let Err(err) = self.const_cx().eval(expr) {
-            match err.kind {
-                UnimplementedConstVal(_) => {}
-                IndexOpFeatureGated => {}
-                ErroneousReferencedConstant(_) => {}
-                TypeckError => {}
-                MiscCatchAll => {}
-                _ => {
-                    self.tcx.lint_node(CONST_ERR,
-                                       expr.id,
-                                       expr.span,
-                                       &format!("constant evaluation error: {}",
-                                                err.description().into_oneline()));
-                }
-            }
-        }
-    }
-
     // Returns true iff all the values of the type are promotable.
     fn type_has_only_promotable_values(&mut self, ty: Ty<'gcx>) -> bool {
         ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) &&
@@ -196,9 +163,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
         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 tcx = self.tcx;
         let param_env = self.param_env;
@@ -214,52 +178,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
         self.identity_substs = outer_identity_substs;
     }
 
-    fn visit_pat(&mut self, p: &'tcx hir::Pat) {
-        match p.node {
-            PatKind::Lit(ref lit) => {
-                self.check_const_eval(lit);
-            }
-            PatKind::Range(ref start, ref end, RangeEnd::Excluded) => {
-                match self.const_cx().compare_lit_exprs(p.span, start, end) {
-                    Ok(Ordering::Less) => {}
-                    Ok(Ordering::Equal) |
-                    Ok(Ordering::Greater) => {
-                        span_err!(self.tcx.sess,
-                                  start.span,
-                                  E0579,
-                                  "lower range bound must be less than upper");
-                    }
-                    Err(ErrorReported) => {}
-                }
-            }
-            PatKind::Range(ref start, ref end, RangeEnd::Included) => {
-                match self.const_cx().compare_lit_exprs(p.span, start, end) {
-                    Ok(Ordering::Less) |
-                    Ok(Ordering::Equal) => {}
-                    Ok(Ordering::Greater) => {
-                        let mut err = struct_span_err!(
-                            self.tcx.sess,
-                            start.span,
-                            E0030,
-                            "lower range bound must be less than or equal to upper"
-                        );
-                        err.span_label(start.span, "lower bound larger than upper bound");
-                        if self.tcx.sess.teach(&err.get_code().unwrap()) {
-                            err.note("When matching against a range, the compiler verifies that \
-                                      the range is non-empty. Range patterns include both \
-                                      end-points, so this is equivalent to requiring the start of \
-                                      the range to be less than or equal to the end of the range.");
-                        }
-                        err.emit();
-                    }
-                    Err(ErrorReported) => {}
-                }
-            }
-            _ => {}
-        }
-        intravisit::walk_pat(self, p);
-    }
-
     fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) {
         match stmt.node {
             hir::StmtDecl(ref decl, _) => {
@@ -308,30 +226,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
             self.promotable = false;
         }
 
-        if self.in_fn && self.promotable {
-            match self.const_cx().eval(ex) {
-                Ok(_) => {}
-                Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
-                Err(ConstEvalErr { kind: MiscCatchAll, .. }) |
-                Err(ConstEvalErr { kind: MiscBinaryOp, .. }) |
-                Err(ConstEvalErr { kind: NonConstPath, .. }) |
-                Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), .. }) |
-                Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), .. }) |
-                Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), .. }) |
-                Err(ConstEvalErr { kind: IndexOpFeatureGated, .. }) => {}
-                Err(ConstEvalErr { kind: TypeckError, .. }) => {}
-                Err(ConstEvalErr {
-                    kind: LayoutError(ty::layout::LayoutError::Unknown(_)), ..
-                }) => {}
-                Err(msg) => {
-                    self.tcx.lint_node(CONST_ERR,
-                                       ex.id,
-                                       msg.span,
-                                       &msg.description().into_oneline().into_owned());
-                }
-            }
-        }
-
         if self.promotable {
             self.result.insert(ex.hir_id.local_id);
         }
@@ -397,7 +291,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
 
                 // References to a static that are themselves within a static
                 // are inherently promotable with the exception
-                //  of "#[thread_loca]" statics, which may not
+                //  of "#[thread_local]" statics, which may not
                 // outlive the current function
                 Def::Static(did, _) => {
 
@@ -431,16 +325,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
                         // Don't peek inside trait associated constants.
                         false
                     } else {
-                        queries::const_is_rvalue_promotable_to_static::try_get(v.tcx, e.span, did)
-                            .unwrap_or_else(|mut err| {
-                                // A cycle between constants ought to be reported elsewhere.
-                                err.cancel();
-                                v.tcx.sess.delay_span_bug(
-                                    e.span,
-                                    &format!("cycle encountered during const qualification: {:?}",
-                                             did));
-                                false
-                            })
+                        v.tcx.at(e.span).const_is_rvalue_promotable_to_static(did)
                     };
 
                     // Just in case the type is more specific than the definition,
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 3708f6f6ec4fc..49a5b7ac8b907 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -195,7 +195,7 @@ pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>,
     let (source, target) = cx.tcx.struct_lockstep_tails(source, target);
     match (&source.sty, &target.sty) {
         (&ty::TyArray(_, len), &ty::TySlice(_)) => {
-            C_usize(cx, len.val.to_const_int().unwrap().to_u64().unwrap())
+            C_usize(cx, len.val.unwrap_u64())
         }
         (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
             // For now, upcasts are limited to changes in marker
@@ -334,14 +334,6 @@ pub fn cast_shift_expr_rhs(
     cast_shift_rhs(op, lhs, rhs, |a, b| cx.trunc(a, b), |a, b| cx.zext(a, b))
 }
 
-pub fn cast_shift_const_rhs(op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
-    cast_shift_rhs(op,
-                   lhs,
-                   rhs,
-                   |a, b| unsafe { llvm::LLVMConstTrunc(a, b.to_ref()) },
-                   |a, b| unsafe { llvm::LLVMConstZExt(a, b.to_ref()) })
-}
-
 fn cast_shift_rhs<F, G>(op: hir::BinOp_,
                         lhs: ValueRef,
                         rhs: ValueRef,
@@ -980,6 +972,8 @@ fn collect_and_partition_translation_items<'a, 'tcx>(
             collector::collect_crate_mono_items(tcx, collection_mode)
     });
 
+    tcx.sess.abort_if_errors();
+
     ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx, items.iter());
 
     let strategy = if tcx.sess.opts.incremental.is_some() {
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 0ce3f729305b4..122b51dbbb778 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -13,7 +13,6 @@ use llvm::{SetUnnamedAddr};
 use llvm::{ValueRef, True};
 use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
-use rustc::middle::const_val::ConstEvalErr;
 use debuginfo;
 use base;
 use monomorphize::MonoItem;
@@ -247,12 +246,15 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
 pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
                               def_id: DefId,
                               is_mutable: bool,
-                              attrs: &[ast::Attribute])
-                              -> Result<ValueRef, ConstEvalErr<'tcx>> {
+                              attrs: &[ast::Attribute]) {
     unsafe {
         let g = get_static(cx, def_id);
 
-        let v = ::mir::trans_static_initializer(cx, def_id)?;
+        let v = match ::mir::trans_static_initializer(cx, def_id) {
+            Ok(v) => v,
+            // Error has already been reported
+            Err(_) => return,
+        };
 
         // boolean SSA values are i1, but they have to be stored in i8 slots,
         // otherwise some LLVM optimization passes don't work as expected
@@ -316,7 +318,5 @@ pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
             let cast = llvm::LLVMConstPointerCast(g, Type::i8p(cx).to_ref());
             cx.used_statics.borrow_mut().push(cast);
         }
-
-        Ok(g)
     }
 }
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 2c430d03c968e..d20b51ca0fdf4 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -276,7 +276,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
 
     let upper_bound = match array_or_slice_type.sty {
         ty::TyArray(_, len) => {
-            len.val.to_const_int().unwrap().to_u64().unwrap() as c_longlong
+            len.val.unwrap_u64() as c_longlong
         }
         _ => -1
     };
@@ -1378,7 +1378,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
                     DIB(cx),
                     name.as_ptr(),
                     // FIXME: what if enumeration has i128 discriminant?
-                    discr.to_u128_unchecked() as u64)
+                    discr.val as u64)
             }
         })
         .collect();
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index 6490d109f2936..a88eb9ae35471 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -97,7 +97,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
         ty::TyArray(inner_type, len) => {
             output.push('[');
             push_debuginfo_type_name(cx, inner_type, true, output);
-            output.push_str(&format!("; {}", len.val.to_const_int().unwrap().to_u64().unwrap()));
+            output.push_str(&format!("; {}", len.val.unwrap_u64()));
             output.push(']');
         },
         ty::TySlice(inner_type) => {
diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs
index f683703ce6d53..dd34dc0345886 100644
--- a/src/librustc_trans/mir/analyze.rs
+++ b/src/librustc_trans/mir/analyze.rs
@@ -13,8 +13,7 @@
 
 use rustc_data_structures::bitvec::BitVector;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use rustc::middle::const_val::ConstVal;
-use rustc::mir::{self, Location, TerminatorKind, Literal};
+use rustc::mir::{self, Location, TerminatorKind};
 use rustc::mir::visit::{Visitor, PlaceContext};
 use rustc::mir::traversal;
 use rustc::ty;
@@ -109,15 +108,18 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
                              block: mir::BasicBlock,
                              kind: &mir::TerminatorKind<'tcx>,
                              location: Location) {
-        match *kind {
+        let check = match *kind {
             mir::TerminatorKind::Call {
-                func: mir::Operand::Constant(box mir::Constant {
-                    literal: Literal::Value {
-                        value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, ..
-                    }, ..
-                }),
+                func: mir::Operand::Constant(ref c),
                 ref args, ..
-            } if Some(def_id) == self.fx.cx.tcx.lang_items().box_free_fn() => {
+            } => match c.ty.sty {
+                ty::TyFnDef(did, _) => Some((did, args)),
+                _ => None,
+            },
+            _ => None,
+        };
+        if let Some((def_id, args)) = check {
+            if Some(def_id) == self.fx.cx.tcx.lang_items().box_free_fn() {
                 // box_free(x) shares with `drop x` the property that it
                 // is not guaranteed to be statically dominated by the
                 // definition of x, so x must always be in an alloca.
@@ -125,7 +127,6 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
                     self.visit_place(place, PlaceContext::Drop, location);
                 }
             }
-            _ => {}
         }
 
         self.super_terminator_kind(block, kind, location);
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index bb2a7840faee7..efb5338f680af 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -10,7 +10,6 @@
 
 use llvm::{self, ValueRef, BasicBlockRef};
 use rustc::middle::lang_items;
-use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind};
 use rustc::ty::{self, TypeFoldable};
 use rustc::ty::layout::{self, LayoutOf};
 use rustc::traits;
@@ -19,7 +18,7 @@ use abi::{Abi, FnType, ArgType, PassMode};
 use base;
 use callee;
 use builder::Builder;
-use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_undef};
+use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_uint_big, C_undef};
 use consts;
 use meth;
 use monomorphize;
@@ -30,7 +29,6 @@ use syntax::symbol::Symbol;
 use syntax_pos::Pos;
 
 use super::{FunctionCx, LocalRef};
-use super::constant::Const;
 use super::place::PlaceRef;
 use super::operand::OperandRef;
 use super::operand::OperandValue::{Pair, Ref, Immediate};
@@ -196,19 +194,21 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                 if switch_ty == bx.tcx().types.bool {
                     let lltrue = llblock(self, targets[0]);
                     let llfalse = llblock(self, targets[1]);
-                    if let [ConstInt::U8(0)] = values[..] {
+                    if let [0] = values[..] {
                         bx.cond_br(discr.immediate(), llfalse, lltrue);
                     } else {
+                        assert_eq!(&values[..], &[1]);
                         bx.cond_br(discr.immediate(), lltrue, llfalse);
                     }
                 } else {
                     let (otherwise, targets) = targets.split_last().unwrap();
                     let switch = bx.switch(discr.immediate(),
                                             llblock(self, *otherwise), values.len());
-                    for (value, target) in values.iter().zip(targets) {
-                        let val = Const::from_constint(bx.cx, value);
+                    let switch_llty = bx.cx.layout_of(switch_ty).immediate_llvm_type(bx.cx);
+                    for (&value, target) in values.iter().zip(targets) {
+                        let llval = C_uint_big(switch_llty, value);
                         let llbb = llblock(self, *target);
-                        bx.add_case(switch, val.llval, llbb)
+                        bx.add_case(switch, llval, llbb)
                     }
                 }
             }
@@ -351,26 +351,18 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                     .max(tcx.data_layout.pointer_align);
 
                 // Put together the arguments to the panic entry point.
-                let (lang_item, args, const_err) = match *msg {
+                let (lang_item, args) = match *msg {
                     mir::AssertMessage::BoundsCheck { ref len, ref index } => {
                         let len = self.trans_operand(&mut bx, len).immediate();
                         let index = self.trans_operand(&mut bx, index).immediate();
 
-                        let const_err = common::const_to_opt_u128(len, false)
-                            .and_then(|len| common::const_to_opt_u128(index, false)
-                                .map(|index| ErrKind::IndexOutOfBounds {
-                                    len: len as u64,
-                                    index: index as u64
-                                }));
-
                         let file_line_col = C_struct(bx.cx, &[filename, line, col], false);
                         let file_line_col = consts::addr_of(bx.cx,
                                                             file_line_col,
                                                             align,
                                                             "panic_bounds_check_loc");
                         (lang_items::PanicBoundsCheckFnLangItem,
-                         vec![file_line_col, index, len],
-                         const_err)
+                         vec![file_line_col, index, len])
                     }
                     mir::AssertMessage::Math(ref err) => {
                         let msg_str = Symbol::intern(err.description()).as_str();
@@ -383,8 +375,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                                                                 align,
                                                                 "panic_loc");
                         (lang_items::PanicFnLangItem,
-                         vec![msg_file_line_col],
-                         Some(ErrKind::Math(err.clone())))
+                         vec![msg_file_line_col])
                     }
                     mir::AssertMessage::GeneratorResumedAfterReturn |
                     mir::AssertMessage::GeneratorResumedAfterPanic => {
@@ -403,23 +394,10 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                                                                 align,
                                                                 "panic_loc");
                         (lang_items::PanicFnLangItem,
-                         vec![msg_file_line_col],
-                         None)
+                         vec![msg_file_line_col])
                     }
                 };
 
-                // If we know we always panic, and the error message
-                // is also constant, then we can produce a warning.
-                if const_cond == Some(!expected) {
-                    if let Some(err) = const_err {
-                        let err = ConstEvalErr{ span: span, kind: err };
-                        let mut diag = bx.tcx().sess.struct_span_warn(
-                            span, "this expression will panic at run-time");
-                        err.note(bx.tcx(), span, "expression", &mut diag);
-                        diag.emit();
-                    }
-                }
-
                 // Obtain the panic entry point.
                 let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
                 let instance = ty::Instance::mono(bx.tcx(), def_id);
@@ -529,10 +507,13 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                                     span_bug!(span, "shuffle indices must be constant");
                                 }
                                 mir::Operand::Constant(ref constant) => {
-                                    let val = self.trans_constant(&bx, constant);
+                                    let (llval, ty) = self.simd_shuffle_indices(
+                                        &bx,
+                                        constant,
+                                    );
                                     return OperandRef {
-                                        val: Immediate(val.llval),
-                                        layout: bx.cx.layout_of(val.ty)
+                                        val: Immediate(llval),
+                                        layout: bx.cx.layout_of(ty)
                                     };
                                 }
                             }
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index d470f92b75231..6aa8b7e5449fd 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -9,1341 +9,229 @@
 // except according to those terms.
 
 use llvm::{self, ValueRef};
-use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
-use rustc_const_math::ConstInt::*;
-use rustc_const_math::{ConstInt, ConstMathErr, MAX_F32_PLUS_HALF_ULP};
+use rustc::middle::const_val::{ConstVal, ConstEvalErr};
+use rustc_mir::interpret::{read_target_uint, const_val_field};
 use rustc::hir::def_id::DefId;
-use rustc::infer::TransNormalize;
 use rustc::traits;
 use rustc::mir;
-use rustc::mir::tcx::PlaceTy;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::layout::{self, LayoutOf, Size};
-use rustc::ty::cast::{CastTy, IntTy};
-use rustc::ty::subst::{Kind, Substs};
-use rustc_apfloat::{ieee, Float, Status};
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use base;
-use abi::{self, Abi};
-use callee;
+use rustc_data_structures::indexed_vec::Idx;
+use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue};
+use rustc::ty::{self, Ty};
+use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
 use builder::Builder;
-use common::{self, CodegenCx, const_get_elt, val_ty};
-use common::{C_array, C_bool, C_bytes, C_int, C_uint, C_uint_big, C_u32, C_u64};
-use common::{C_null, C_struct, C_str_slice, C_undef, C_usize, C_vector, C_fat_ptr};
-use common::const_to_opt_u128;
+use common::{CodegenCx};
+use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize};
 use consts;
 use type_of::LayoutLlvmExt;
 use type_::Type;
-use value::Value;
+use syntax::ast::Mutability;
 
-use syntax_pos::Span;
-use syntax::ast;
-
-use std::fmt;
-use std::ptr;
-
-use super::operand::{OperandRef, OperandValue};
+use super::super::callee;
 use super::FunctionCx;
 
-/// A sized constant rvalue.
-/// The LLVM type might not be the same for a single Rust type,
-/// e.g. each enum variant would have its own LLVM struct type.
-#[derive(Copy, Clone)]
-pub struct Const<'tcx> {
-    pub llval: ValueRef,
-    pub ty: Ty<'tcx>
-}
-
-impl<'a, 'tcx> Const<'tcx> {
-    pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> {
-        Const {
-            llval,
-            ty,
-        }
-    }
-
-    pub fn from_constint(cx: &CodegenCx<'a, 'tcx>, ci: &ConstInt) -> Const<'tcx> {
-        let tcx = cx.tcx;
-        let (llval, ty) = match *ci {
-            I8(v) => (C_int(Type::i8(cx), v as i64), tcx.types.i8),
-            I16(v) => (C_int(Type::i16(cx), v as i64), tcx.types.i16),
-            I32(v) => (C_int(Type::i32(cx), v as i64), tcx.types.i32),
-            I64(v) => (C_int(Type::i64(cx), v as i64), tcx.types.i64),
-            I128(v) => (C_uint_big(Type::i128(cx), v as u128), tcx.types.i128),
-            Isize(v) => (C_int(Type::isize(cx), v.as_i64()), tcx.types.isize),
-            U8(v) => (C_uint(Type::i8(cx), v as u64), tcx.types.u8),
-            U16(v) => (C_uint(Type::i16(cx), v as u64), tcx.types.u16),
-            U32(v) => (C_uint(Type::i32(cx), v as u64), tcx.types.u32),
-            U64(v) => (C_uint(Type::i64(cx), v), tcx.types.u64),
-            U128(v) => (C_uint_big(Type::i128(cx), v), tcx.types.u128),
-            Usize(v) => (C_uint(Type::isize(cx), v.as_u64()), tcx.types.usize),
-        };
-        Const { llval: llval, ty: ty }
-    }
-
-    /// Translate ConstVal into a LLVM constant value.
-    pub fn from_constval(cx: &CodegenCx<'a, 'tcx>,
-                         cv: &ConstVal,
-                         ty: Ty<'tcx>)
-                         -> Const<'tcx> {
-        let llty = cx.layout_of(ty).llvm_type(cx);
-        let val = match *cv {
-            ConstVal::Float(v) => {
-                let bits = match v.ty {
-                    ast::FloatTy::F32 => C_u32(cx, v.bits as u32),
-                    ast::FloatTy::F64 => C_u64(cx, v.bits as u64)
-                };
-                consts::bitcast(bits, llty)
-            }
-            ConstVal::Bool(v) => C_bool(cx, v),
-            ConstVal::Integral(ref i) => return Const::from_constint(cx, i),
-            ConstVal::Str(ref v) => C_str_slice(cx, v.clone()),
-            ConstVal::ByteStr(v) => {
-                consts::addr_of(cx, C_bytes(cx, v.data), cx.align_of(ty), "byte_str")
-            }
-            ConstVal::Char(c) => C_uint(Type::char(cx), c as u64),
-            ConstVal::Function(..) => C_undef(llty),
-            ConstVal::Variant(_) |
-            ConstVal::Aggregate(..) |
-            ConstVal::Unevaluated(..) => {
-                bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv)
-            }
-        };
-
-        assert!(!ty.has_erasable_regions());
-
-        Const::new(val, ty)
-    }
-
-    fn get_field(&self, cx: &CodegenCx<'a, 'tcx>, i: usize) -> ValueRef {
-        let layout = cx.layout_of(self.ty);
-        let field = layout.field(cx, i);
-        if field.is_zst() {
-            return C_undef(field.immediate_llvm_type(cx));
-        }
-        let offset = layout.fields.offset(i);
-        match layout.abi {
-            layout::Abi::Scalar(_) |
-            layout::Abi::ScalarPair(..) |
-            layout::Abi::Vector { .. }
-                if offset.bytes() == 0 && field.size == layout.size => self.llval,
-
-            layout::Abi::ScalarPair(ref a, ref b) => {
-                if offset.bytes() == 0 {
-                    assert_eq!(field.size, a.value.size(cx));
-                    const_get_elt(self.llval, 0)
-                } else {
-                    assert_eq!(offset, a.value.size(cx)
-                        .abi_align(b.value.align(cx)));
-                    assert_eq!(field.size, b.value.size(cx));
-                    const_get_elt(self.llval, 1)
-                }
-            }
-            _ => {
-                match layout.fields {
-                    layout::FieldPlacement::Union(_) => self.llval,
-                    _ => const_get_elt(self.llval, layout.llvm_field_index(i)),
-                }
-            }
-        }
-    }
-
-    fn get_pair(&self, cx: &CodegenCx<'a, 'tcx>) -> (ValueRef, ValueRef) {
-        (self.get_field(cx, 0), self.get_field(cx, 1))
-    }
-
-    fn get_fat_ptr(&self, cx: &CodegenCx<'a, 'tcx>) -> (ValueRef, ValueRef) {
-        assert_eq!(abi::FAT_PTR_ADDR, 0);
-        assert_eq!(abi::FAT_PTR_EXTRA, 1);
-        self.get_pair(cx)
-    }
-
-    fn as_place(&self) -> ConstPlace<'tcx> {
-        ConstPlace {
-            base: Base::Value(self.llval),
-            llextra: ptr::null_mut(),
-            ty: self.ty
-        }
-    }
-
-    pub fn to_operand(&self, cx: &CodegenCx<'a, 'tcx>) -> OperandRef<'tcx> {
-        let layout = cx.layout_of(self.ty);
-        let llty = layout.immediate_llvm_type(cx);
-        let llvalty = val_ty(self.llval);
-
-        let val = if llty == llvalty && layout.is_llvm_scalar_pair() {
-            OperandValue::Pair(
-                const_get_elt(self.llval, 0),
-                const_get_elt(self.llval, 1))
-        } else if llty == llvalty && layout.is_llvm_immediate() {
-            // If the types match, we can use the value directly.
-            OperandValue::Immediate(self.llval)
-        } else {
-            // Otherwise, or if the value is not immediate, we create
-            // a constant LLVM global and cast its address if necessary.
-            let align = cx.align_of(self.ty);
-            let ptr = consts::addr_of(cx, self.llval, align, "const");
-            OperandValue::Ref(consts::ptrcast(ptr, layout.llvm_type(cx).ptr_to()),
-                              layout.align)
-        };
-
-        OperandRef {
-            val,
-            layout
-        }
-    }
-}
-
-impl<'tcx> fmt::Debug for Const<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Const({:?}: {:?})", Value(self.llval), self.ty)
-    }
-}
-
-#[derive(Copy, Clone)]
-enum Base {
-    /// A constant value without an unique address.
-    Value(ValueRef),
-
-    /// String literal base pointer (cast from array).
-    Str(ValueRef),
-
-    /// The address of a static.
-    Static(ValueRef)
-}
-
-/// A place as seen from a constant.
-#[derive(Copy, Clone)]
-struct ConstPlace<'tcx> {
-    base: Base,
-    llextra: ValueRef,
-    ty: Ty<'tcx>
-}
-
-impl<'tcx> ConstPlace<'tcx> {
-    fn to_const(&self, span: Span) -> Const<'tcx> {
-        match self.base {
-            Base::Value(val) => Const::new(val, self.ty),
-            Base::Str(ptr) => {
-                span_bug!(span, "loading from `str` ({:?}) in constant",
-                          Value(ptr))
-            }
-            Base::Static(val) => {
-                span_bug!(span, "loading from `static` ({:?}) in constant",
-                          Value(val))
-            }
-        }
-    }
-
-    pub fn len<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> ValueRef {
-        match self.ty.sty {
-            ty::TyArray(_, n) => {
-                C_usize(cx, n.val.to_const_int().unwrap().to_u64().unwrap())
-            }
-            ty::TySlice(_) | ty::TyStr => {
-                assert!(self.llextra != ptr::null_mut());
-                self.llextra
-            }
-            _ => bug!("unexpected type `{}` in ConstPlace::len", self.ty)
-        }
-    }
-}
-
-/// Machinery for translating a constant's MIR to LLVM values.
-/// FIXME(eddyb) use miri and lower its allocations to LLVM.
-struct MirConstContext<'a, 'tcx: 'a> {
-    cx: &'a CodegenCx<'a, 'tcx>,
-    mir: &'a mir::Mir<'tcx>,
-
-    /// Type parameters for const fn and associated constants.
-    substs: &'tcx Substs<'tcx>,
-
-    /// Values of locals in a constant or const fn.
-    locals: IndexVec<mir::Local, Option<Result<Const<'tcx>, ConstEvalErr<'tcx>>>>
-}
-
-fn add_err<'tcx, U, V>(failure: &mut Result<U, ConstEvalErr<'tcx>>,
-                       value: &Result<V, ConstEvalErr<'tcx>>)
-{
-    if let &Err(ref err) = value {
-        if failure.is_ok() {
-            *failure = Err(err.clone());
-        }
-    }
-}
-
-impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
-    fn new(cx: &'a CodegenCx<'a, 'tcx>,
-           mir: &'a mir::Mir<'tcx>,
-           substs: &'tcx Substs<'tcx>,
-           args: IndexVec<mir::Local, Result<Const<'tcx>, ConstEvalErr<'tcx>>>)
-           -> MirConstContext<'a, 'tcx> {
-        let mut context = MirConstContext {
-            cx,
-            mir,
-            substs,
-            locals: (0..mir.local_decls.len()).map(|_| None).collect(),
-        };
-        for (i, arg) in args.into_iter().enumerate() {
-            // Locals after local 0 are the function arguments
-            let index = mir::Local::new(i + 1);
-            context.locals[index] = Some(arg);
-        }
-        context
-    }
-
-    fn trans_def(cx: &'a CodegenCx<'a, 'tcx>,
-                 def_id: DefId,
-                 substs: &'tcx Substs<'tcx>,
-                 args: IndexVec<mir::Local, Result<Const<'tcx>, ConstEvalErr<'tcx>>>)
-                 -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
-        let instance = ty::Instance::resolve(cx.tcx,
-                                             ty::ParamEnv::empty(traits::Reveal::All),
-                                             def_id,
-                                             substs).unwrap();
-        let mir = cx.tcx.instance_mir(instance.def);
-        MirConstContext::new(cx, &mir, instance.substs, args).trans()
-    }
-
-    fn monomorphize<T>(&self, value: &T) -> T
-        where T: TransNormalize<'tcx>
-    {
-        self.cx.tcx.trans_apply_param_substs(self.substs, value)
-    }
-
-    fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
-        let tcx = self.cx.tcx;
-        let mut bb = mir::START_BLOCK;
-
-        // Make sure to evaluate all statemenets to
-        // report as many errors as we possibly can.
-        let mut failure = Ok(());
-
-        loop {
-            let data = &self.mir[bb];
-            for statement in &data.statements {
-                let span = statement.source_info.span;
-                match statement.kind {
-                    mir::StatementKind::Assign(ref dest, ref rvalue) => {
-                        let ty = dest.ty(self.mir, tcx);
-                        let ty = self.monomorphize(&ty).to_ty(tcx);
-                        let value = self.const_rvalue(rvalue, ty, span);
-                        add_err(&mut failure, &value);
-                        self.store(dest, value, span);
-                    }
-                    mir::StatementKind::StorageLive(_) |
-                    mir::StatementKind::StorageDead(_) |
-                    mir::StatementKind::Validate(..) |
-                    mir::StatementKind::EndRegion(_) |
-                    mir::StatementKind::Nop => {}
-                    mir::StatementKind::InlineAsm { .. } |
-                    mir::StatementKind::SetDiscriminant{ .. } => {
-                        span_bug!(span, "{:?} should not appear in constants?", statement.kind);
-                    }
-                }
+pub fn primval_to_llvm(cx: &CodegenCx,
+                       cv: PrimVal,
+                       scalar: &Scalar,
+                       llty: Type) -> ValueRef {
+    let bits = if scalar.is_bool() { 1 } else { scalar.value.size(cx).bits() };
+    match cv {
+        PrimVal::Undef => C_undef(Type::ix(cx, bits)),
+        PrimVal::Bytes(b) => {
+            let llval = C_uint_big(Type::ix(cx, bits), b);
+            if scalar.value == layout::Pointer {
+                unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) }
+            } else {
+                consts::bitcast(llval, llty)
             }
-
-            let terminator = data.terminator();
-            let span = terminator.source_info.span;
-            bb = match terminator.kind {
-                mir::TerminatorKind::Drop { target, .. } | // No dropping.
-                mir::TerminatorKind::Goto { target } => target,
-                mir::TerminatorKind::Return => {
-                    failure?;
-                    return self.locals[mir::RETURN_PLACE].clone().unwrap_or_else(|| {
-                        span_bug!(span, "no returned value in constant");
-                    });
-                }
-
-                mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, .. } => {
-                    let cond = self.const_operand(cond, span)?;
-                    let cond_bool = common::const_to_uint(cond.llval) != 0;
-                    if cond_bool != expected {
-                        let err = match *msg {
-                            mir::AssertMessage::BoundsCheck { ref len, ref index } => {
-                                let len = self.const_operand(len, span)?;
-                                let index = self.const_operand(index, span)?;
-                                ErrKind::IndexOutOfBounds {
-                                    len: common::const_to_uint(len.llval),
-                                    index: common::const_to_uint(index.llval)
-                                }
-                            }
-                            mir::AssertMessage::Math(ref err) => {
-                                ErrKind::Math(err.clone())
-                            }
-                            mir::AssertMessage::GeneratorResumedAfterReturn |
-                            mir::AssertMessage::GeneratorResumedAfterPanic =>
-                                span_bug!(span, "{:?} should not appear in constants?", msg),
-                        };
-
-                        let err = ConstEvalErr { span: span, kind: err };
-                        err.report(tcx, span, "expression");
-                        failure = Err(err);
-                    }
-                    target
-                }
-
-                mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
-                    let fn_ty = func.ty(self.mir, tcx);
-                    let fn_ty = self.monomorphize(&fn_ty);
-                    let (def_id, substs) = match fn_ty.sty {
-                        ty::TyFnDef(def_id, substs) => (def_id, substs),
-                        _ => span_bug!(span, "calling {:?} (of type {}) in constant",
-                                       func, fn_ty)
-                    };
-
-                    let mut arg_vals = IndexVec::with_capacity(args.len());
-                    for arg in args {
-                        let arg_val = self.const_operand(arg, span);
-                        add_err(&mut failure, &arg_val);
-                        arg_vals.push(arg_val);
-                    }
-                    if let Some((ref dest, target)) = *destination {
-                        let result = if fn_ty.fn_sig(tcx).abi() == Abi::RustIntrinsic {
-                            match &tcx.item_name(def_id)[..] {
-                                "size_of" => {
-                                    let llval = C_usize(self.cx,
-                                        self.cx.size_of(substs.type_at(0)).bytes());
-                                    Ok(Const::new(llval, tcx.types.usize))
-                                }
-                                "min_align_of" => {
-                                    let llval = C_usize(self.cx,
-                                        self.cx.align_of(substs.type_at(0)).abi());
-                                    Ok(Const::new(llval, tcx.types.usize))
-                                }
-                                "type_id" => {
-                                    let llval = C_u64(self.cx,
-                                        self.cx.tcx.type_id_hash(substs.type_at(0)));
-                                    Ok(Const::new(llval, tcx.types.u64))
-                                }
-                                _ => span_bug!(span, "{:?} in constant", terminator.kind)
-                            }
-                        } else if let Some((op, is_checked)) = self.is_binop_lang_item(def_id) {
-                            (||{
-                                assert_eq!(arg_vals.len(), 2);
-                                let rhs = arg_vals.pop().unwrap()?;
-                                let lhs = arg_vals.pop().unwrap()?;
-                                if !is_checked {
-                                    let binop_ty = op.ty(tcx, lhs.ty, rhs.ty);
-                                    let (lhs, rhs) = (lhs.llval, rhs.llval);
-                                    Ok(Const::new(const_scalar_binop(op, lhs, rhs, binop_ty),
-                                                  binop_ty))
-                                } else {
-                                    let ty = lhs.ty;
-                                    let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
-                                    let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false);
-                                    let (lhs, rhs) = (lhs.llval, rhs.llval);
-                                    assert!(!ty.is_fp());
-
-                                    match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
-                                        Some((llval, of)) => {
-                                            Ok(trans_const_adt(
-                                                self.cx,
-                                                binop_ty,
-                                                &mir::AggregateKind::Tuple,
-                                                &[
-                                                    Const::new(llval, val_ty),
-                                                    Const::new(C_bool(self.cx, of), tcx.types.bool)
-                                                ]))
-                                        }
-                                        None => {
-                                            span_bug!(span,
-                                                "{:?} got non-integer operands: {:?} and {:?}",
-                                                op, Value(lhs), Value(rhs));
-                                        }
-                                    }
-                                }
-                            })()
-                        } else {
-                            MirConstContext::trans_def(self.cx, def_id, substs, arg_vals)
-                        };
-                        add_err(&mut failure, &result);
-                        self.store(dest, result, span);
-                        target
+        },
+        PrimVal::Ptr(ptr) => {
+            if let Some(fn_instance) = cx.tcx.interpret_interner.get_fn(ptr.alloc_id) {
+                callee::get_fn(cx, fn_instance)
+            } else {
+                let static_ = cx
+                    .tcx
+                    .interpret_interner
+                    .get_corresponding_static_def_id(ptr.alloc_id);
+                let base_addr = if let Some(def_id) = static_ {
+                    assert!(cx.tcx.is_static(def_id).is_some());
+                    consts::get_static(cx, def_id)
+                } else if let Some(alloc) = cx.tcx.interpret_interner
+                                              .get_alloc(ptr.alloc_id) {
+                    let init = global_initializer(cx, alloc);
+                    if alloc.runtime_mutability == Mutability::Mutable {
+                        consts::addr_of_mut(cx, init, alloc.align, "byte_str")
                     } else {
-                        span_bug!(span, "diverging {:?} in constant", terminator.kind);
-                    }
-                }
-                _ => span_bug!(span, "{:?} in constant", terminator.kind)
-            };
-        }
-    }
-
-    fn is_binop_lang_item(&mut self, def_id: DefId) -> Option<(mir::BinOp, bool)> {
-        let tcx = self.cx.tcx;
-        let items = tcx.lang_items();
-        let def_id = Some(def_id);
-        if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
-        else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
-        else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
-        else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
-        else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
-        else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
-        else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
-        else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
-        else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
-        else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
-        else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
-        else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
-        else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
-        else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
-        else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
-        else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
-        else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
-        else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
-        else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
-        else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
-        else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
-        else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
-        else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
-        else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
-        else { None }
-    }
-
-    fn store(&mut self,
-             dest: &mir::Place<'tcx>,
-             value: Result<Const<'tcx>, ConstEvalErr<'tcx>>,
-             span: Span) {
-        if let mir::Place::Local(index) = *dest {
-            self.locals[index] = Some(value);
-        } else {
-            span_bug!(span, "assignment to {:?} in constant", dest);
-        }
-    }
-
-    fn const_place(&self, place: &mir::Place<'tcx>, span: Span)
-                    -> Result<ConstPlace<'tcx>, ConstEvalErr<'tcx>> {
-        let tcx = self.cx.tcx;
-
-        if let mir::Place::Local(index) = *place {
-            return self.locals[index].clone().unwrap_or_else(|| {
-                span_bug!(span, "{:?} not initialized", place)
-            }).map(|v| v.as_place());
-        }
-
-        let place = match *place {
-            mir::Place::Local(_)  => bug!(), // handled above
-            mir::Place::Static(box mir::Static { def_id, ty }) => {
-                ConstPlace {
-                    base: Base::Static(consts::get_static(self.cx, def_id)),
-                    llextra: ptr::null_mut(),
-                    ty: self.monomorphize(&ty),
-                }
-            }
-            mir::Place::Projection(ref projection) => {
-                let tr_base = self.const_place(&projection.base, span)?;
-                let projected_ty = PlaceTy::Ty { ty: tr_base.ty }
-                    .projection_ty(tcx, &projection.elem);
-                let base = tr_base.to_const(span);
-                let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx);
-                let has_metadata = self.cx.type_has_metadata(projected_ty);
-
-                let (projected, llextra) = match projection.elem {
-                    mir::ProjectionElem::Deref => {
-                        let (base, extra) = if !has_metadata {
-                            (base.llval, ptr::null_mut())
-                        } else {
-                            base.get_fat_ptr(self.cx)
-                        };
-                        if self.cx.statics.borrow().contains_key(&base) {
-                            (Base::Static(base), extra)
-                        } else if let ty::TyStr = projected_ty.sty {
-                            (Base::Str(base), extra)
-                        } else {
-                            let v = base;
-                            let v = self.cx.const_unsized.borrow().get(&v).map_or(v, |&v| v);
-                            let mut val = unsafe { llvm::LLVMGetInitializer(v) };
-                            if val.is_null() {
-                                span_bug!(span, "dereference of non-constant pointer `{:?}`",
-                                          Value(base));
-                            }
-                            let layout = self.cx.layout_of(projected_ty);
-                            if let layout::Abi::Scalar(ref scalar) = layout.abi {
-                                let i1_type = Type::i1(self.cx);
-                                if scalar.is_bool() && val_ty(val) != i1_type {
-                                    unsafe {
-                                        val = llvm::LLVMConstTrunc(val, i1_type.to_ref());
-                                    }
-                                }
-                            }
-                            (Base::Value(val), extra)
-                        }
-                    }
-                    mir::ProjectionElem::Field(ref field, _) => {
-                        let llprojected = base.get_field(self.cx, field.index());
-                        let llextra = if !has_metadata {
-                            ptr::null_mut()
-                        } else {
-                            tr_base.llextra
-                        };
-                        (Base::Value(llprojected), llextra)
-                    }
-                    mir::ProjectionElem::Index(index) => {
-                        let index = &mir::Operand::Copy(mir::Place::Local(index));
-                        let llindex = self.const_operand(index, span)?.llval;
-
-                        let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
-                            iv
-                        } else {
-                            span_bug!(span, "index is not an integer-constant expression")
-                        };
-
-                        // Produce an undef instead of a LLVM assertion on OOB.
-                        let len = common::const_to_uint(tr_base.len(self.cx));
-                        let llelem = if iv < len as u128 {
-                            const_get_elt(base.llval, iv as u64)
-                        } else {
-                            C_undef(self.cx.layout_of(projected_ty).llvm_type(self.cx))
-                        };
-
-                        (Base::Value(llelem), ptr::null_mut())
-                    }
-                    _ => span_bug!(span, "{:?} in constant", projection.elem)
-                };
-                ConstPlace {
-                    base: projected,
-                    llextra,
-                    ty: projected_ty
-                }
-            }
-        };
-        Ok(place)
-    }
-
-    fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
-                     -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
-        debug!("const_operand({:?} @ {:?})", operand, span);
-        let result = match *operand {
-            mir::Operand::Copy(ref place) |
-            mir::Operand::Move(ref place) => {
-                Ok(self.const_place(place, span)?.to_const(span))
-            }
-
-            mir::Operand::Constant(ref constant) => {
-                let ty = self.monomorphize(&constant.ty);
-                match constant.literal.clone() {
-                    mir::Literal::Promoted { index } => {
-                        let mir = &self.mir.promoted[index];
-                        MirConstContext::new(self.cx, mir, self.substs, IndexVec::new()).trans()
-                    }
-                    mir::Literal::Value { value } => {
-                        if let ConstVal::Unevaluated(def_id, substs) = value.val {
-                            let substs = self.monomorphize(&substs);
-                            MirConstContext::trans_def(self.cx, def_id, substs, IndexVec::new())
-                        } else {
-                            Ok(Const::from_constval(self.cx, &value.val, ty))
-                        }
-                    }
-                }
-            }
-        };
-        debug!("const_operand({:?} @ {:?}) = {:?}", operand, span,
-               result.as_ref().ok());
-        result
-    }
-
-    fn const_array(&self, array_ty: Ty<'tcx>, fields: &[ValueRef])
-                   -> Const<'tcx>
-    {
-        let elem_ty = array_ty.builtin_index().unwrap_or_else(|| {
-            bug!("bad array type {:?}", array_ty)
-        });
-        let llunitty = self.cx.layout_of(elem_ty).llvm_type(self.cx);
-        // If the array contains enums, an LLVM array won't work.
-        let val = if fields.iter().all(|&f| val_ty(f) == llunitty) {
-            C_array(llunitty, fields)
-        } else {
-            C_struct(self.cx, fields, false)
-        };
-        Const::new(val, array_ty)
-    }
-
-    fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
-                    dest_ty: Ty<'tcx>, span: Span)
-                    -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
-        let tcx = self.cx.tcx;
-        debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span);
-        let val = match *rvalue {
-            mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?,
-
-            mir::Rvalue::Repeat(ref elem, count) => {
-                let elem = self.const_operand(elem, span)?;
-                let size = count.as_u64();
-                assert_eq!(size as usize as u64, size);
-                let fields = vec![elem.llval; size as usize];
-                self.const_array(dest_ty, &fields)
-            }
-
-            mir::Rvalue::Aggregate(box mir::AggregateKind::Array(_), ref operands) => {
-                // Make sure to evaluate all operands to
-                // report as many errors as we possibly can.
-                let mut fields = Vec::with_capacity(operands.len());
-                let mut failure = Ok(());
-                for operand in operands {
-                    match self.const_operand(operand, span) {
-                        Ok(val) => fields.push(val.llval),
-                        Err(err) => if failure.is_ok() { failure = Err(err); }
-                    }
-                }
-                failure?;
-
-                self.const_array(dest_ty, &fields)
-            }
-
-            mir::Rvalue::Aggregate(ref kind, ref operands) => {
-                // Make sure to evaluate all operands to
-                // report as many errors as we possibly can.
-                let mut fields = Vec::with_capacity(operands.len());
-                let mut failure = Ok(());
-                for operand in operands {
-                    match self.const_operand(operand, span) {
-                        Ok(val) => fields.push(val),
-                        Err(err) => if failure.is_ok() { failure = Err(err); }
-                    }
-                }
-                failure?;
-
-                trans_const_adt(self.cx, dest_ty, kind, &fields)
-            }
-
-            mir::Rvalue::Cast(ref kind, ref source, cast_ty) => {
-                let operand = self.const_operand(source, span)?;
-                let cast_ty = self.monomorphize(&cast_ty);
-
-                let val = match *kind {
-                    mir::CastKind::ReifyFnPointer => {
-                        match operand.ty.sty {
-                            ty::TyFnDef(def_id, substs) => {
-                                if tcx.has_attr(def_id, "rustc_args_required_const") {
-                                    bug!("reifying a fn ptr that requires \
-                                          const arguments");
-                                }
-                                callee::resolve_and_get_fn(self.cx, def_id, substs)
-                            }
-                            _ => {
-                                span_bug!(span, "{} cannot be reified to a fn ptr",
-                                          operand.ty)
-                            }
-                        }
-                    }
-                    mir::CastKind::ClosureFnPointer => {
-                        match operand.ty.sty {
-                            ty::TyClosure(def_id, substs) => {
-                                // Get the def_id for FnOnce::call_once
-                                let fn_once = tcx.lang_items().fn_once_trait().unwrap();
-                                let call_once = tcx
-                                    .global_tcx().associated_items(fn_once)
-                                    .find(|it| it.kind == ty::AssociatedKind::Method)
-                                    .unwrap().def_id;
-                                // Now create its substs [Closure, Tuple]
-                                let input = substs.closure_sig(def_id, tcx).input(0);
-                                let input = tcx.erase_late_bound_regions_and_normalize(&input);
-                                let substs = tcx.mk_substs([operand.ty, input]
-                                    .iter().cloned().map(Kind::from));
-                                callee::resolve_and_get_fn(self.cx, call_once, substs)
-                            }
-                            _ => {
-                                bug!("{} cannot be cast to a fn ptr", operand.ty)
-                            }
-                        }
+                        consts::addr_of(cx, init, alloc.align, "byte_str")
                     }
-                    mir::CastKind::UnsafeFnPointer => {
-                        // this is a no-op at the LLVM level
-                        operand.llval
-                    }
-                    mir::CastKind::Unsize => {
-                        let pointee_ty = operand.ty.builtin_deref(true)
-                            .expect("consts: unsizing got non-pointer type").ty;
-                        let (base, old_info) = if !self.cx.type_is_sized(pointee_ty) {
-                            // Normally, the source is a thin pointer and we are
-                            // adding extra info to make a fat pointer. The exception
-                            // is when we are upcasting an existing object fat pointer
-                            // to use a different vtable. In that case, we want to
-                            // load out the original data pointer so we can repackage
-                            // it.
-                            let (base, extra) = operand.get_fat_ptr(self.cx);
-                            (base, Some(extra))
-                        } else {
-                            (operand.llval, None)
-                        };
-
-                        let unsized_ty = cast_ty.builtin_deref(true)
-                            .expect("consts: unsizing got non-pointer target type").ty;
-                        let ptr_ty = self.cx.layout_of(unsized_ty).llvm_type(self.cx).ptr_to();
-                        let base = consts::ptrcast(base, ptr_ty);
-                        let info = base::unsized_info(self.cx, pointee_ty,
-                                                      unsized_ty, old_info);
-
-                        if old_info.is_none() {
-                            let prev_const = self.cx.const_unsized.borrow_mut()
-                                                     .insert(base, operand.llval);
-                            assert!(prev_const.is_none() || prev_const == Some(operand.llval));
-                        }
-                        C_fat_ptr(self.cx, base, info)
-                    }
-                    mir::CastKind::Misc if self.cx.layout_of(operand.ty).is_llvm_immediate() => {
-                        let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast");
-                        let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
-                        let cast_layout = self.cx.layout_of(cast_ty);
-                        assert!(cast_layout.is_llvm_immediate());
-                        let ll_t_out = cast_layout.immediate_llvm_type(self.cx);
-                        let llval = operand.llval;
-
-                        let mut signed = false;
-                        let l = self.cx.layout_of(operand.ty);
-                        if let layout::Abi::Scalar(ref scalar) = l.abi {
-                            if let layout::Int(_, true) = scalar.value {
-                                signed = true;
-                            }
-                        }
-
-                        unsafe {
-                            match (r_t_in, r_t_out) {
-                                (CastTy::Int(_), CastTy::Int(_)) => {
-                                    let s = signed as llvm::Bool;
-                                    llvm::LLVMConstIntCast(llval, ll_t_out.to_ref(), s)
-                                }
-                                (CastTy::Int(_), CastTy::Float) => {
-                                    cast_const_int_to_float(self.cx, llval, signed, ll_t_out)
-                                }
-                                (CastTy::Float, CastTy::Float) => {
-                                    llvm::LLVMConstFPCast(llval, ll_t_out.to_ref())
-                                }
-                                (CastTy::Float, CastTy::Int(IntTy::I)) => {
-                                    cast_const_float_to_int(self.cx, &operand,
-                                                            true, ll_t_out, span)
-                                }
-                                (CastTy::Float, CastTy::Int(_)) => {
-                                    cast_const_float_to_int(self.cx, &operand,
-                                                            false, ll_t_out, span)
-                                }
-                                (CastTy::Ptr(_), CastTy::Ptr(_)) |
-                                (CastTy::FnPtr, CastTy::Ptr(_)) |
-                                (CastTy::RPtr(_), CastTy::Ptr(_)) => {
-                                    consts::ptrcast(llval, ll_t_out)
-                                }
-                                (CastTy::Int(_), CastTy::Ptr(_)) => {
-                                    let s = signed as llvm::Bool;
-                                    let usize_llval = llvm::LLVMConstIntCast(llval,
-                                        self.cx.isize_ty.to_ref(), s);
-                                    llvm::LLVMConstIntToPtr(usize_llval, ll_t_out.to_ref())
-                                }
-                                (CastTy::Ptr(_), CastTy::Int(_)) |
-                                (CastTy::FnPtr, CastTy::Int(_)) => {
-                                    llvm::LLVMConstPtrToInt(llval, ll_t_out.to_ref())
-                                }
-                                _ => bug!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty)
-                            }
-                        }
-                    }
-                    mir::CastKind::Misc => { // Casts from a fat-ptr.
-                        let l = self.cx.layout_of(operand.ty);
-                        let cast = self.cx.layout_of(cast_ty);
-                        if l.is_llvm_scalar_pair() {
-                            let (data_ptr, meta) = operand.get_fat_ptr(self.cx);
-                            if cast.is_llvm_scalar_pair() {
-                                let data_cast = consts::ptrcast(data_ptr,
-                                    cast.scalar_pair_element_llvm_type(self.cx, 0));
-                                C_fat_ptr(self.cx, data_cast, meta)
-                            } else { // cast to thin-ptr
-                                // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
-                                // pointer-cast of that pointer to desired pointer type.
-                                let llcast_ty = cast.immediate_llvm_type(self.cx);
-                                consts::ptrcast(data_ptr, llcast_ty)
-                            }
-                        } else {
-                            bug!("Unexpected non-fat-pointer operand")
-                        }
-                    }
-                };
-                Const::new(val, cast_ty)
-            }
-
-            mir::Rvalue::Ref(_, bk, ref place) => {
-                let tr_place = self.const_place(place, span)?;
-
-                let ty = tr_place.ty;
-                let ref_ty = tcx.mk_ref(tcx.types.re_erased,
-                    ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() });
-
-                let base = match tr_place.base {
-                    Base::Value(llval) => {
-                        // FIXME: may be wrong for &*(&simd_vec as &fmt::Debug)
-                        let align = if self.cx.type_is_sized(ty) {
-                            self.cx.align_of(ty)
-                        } else {
-                            self.cx.tcx.data_layout.pointer_align
-                        };
-                        if let mir::BorrowKind::Mut { .. } = bk {
-                            consts::addr_of_mut(self.cx, llval, align, "ref_mut")
-                        } else {
-                            consts::addr_of(self.cx, llval, align, "ref")
-                        }
-                    }
-                    Base::Str(llval) |
-                    Base::Static(llval) => llval
-                };
-
-                let ptr = if self.cx.type_is_sized(ty) {
-                    base
                 } else {
-                    C_fat_ptr(self.cx, base, tr_place.llextra)
+                    bug!("missing allocation {:?}", ptr.alloc_id);
                 };
-                Const::new(ptr, ref_ty)
-            }
-
-            mir::Rvalue::Len(ref place) => {
-                let tr_place = self.const_place(place, span)?;
-                Const::new(tr_place.len(self.cx), tcx.types.usize)
-            }
-
-            mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
-                let lhs = self.const_operand(lhs, span)?;
-                let rhs = self.const_operand(rhs, span)?;
-                let ty = lhs.ty;
-                let binop_ty = op.ty(tcx, lhs.ty, rhs.ty);
-                let (lhs, rhs) = (lhs.llval, rhs.llval);
-                Const::new(const_scalar_binop(op, lhs, rhs, ty), binop_ty)
-            }
-
-            mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
-                let lhs = self.const_operand(lhs, span)?;
-                let rhs = self.const_operand(rhs, span)?;
-                let ty = lhs.ty;
-                let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
-                let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false);
-                let (lhs, rhs) = (lhs.llval, rhs.llval);
-                assert!(!ty.is_fp());
-
-                match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
-                    Some((llval, of)) => {
-                        trans_const_adt(self.cx, binop_ty, &mir::AggregateKind::Tuple, &[
-                            Const::new(llval, val_ty),
-                            Const::new(C_bool(self.cx, of), tcx.types.bool)
-                        ])
-                    }
-                    None => {
-                        span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}",
-                                  rvalue, Value(lhs), Value(rhs));
-                    }
-                }
-            }
-
-            mir::Rvalue::UnaryOp(op, ref operand) => {
-                let operand = self.const_operand(operand, span)?;
-                let lloperand = operand.llval;
-                let llval = match op {
-                    mir::UnOp::Not => {
-                        unsafe {
-                            llvm::LLVMConstNot(lloperand)
-                        }
-                    }
-                    mir::UnOp::Neg => {
-                        let is_float = operand.ty.is_fp();
-                        unsafe {
-                            if is_float {
-                                llvm::LLVMConstFNeg(lloperand)
-                            } else {
-                                llvm::LLVMConstNeg(lloperand)
-                            }
-                        }
-                    }
-                };
-                Const::new(llval, operand.ty)
-            }
-
-            mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => {
-                assert!(self.cx.type_is_sized(ty));
-                let llval = C_usize(self.cx, self.cx.size_of(ty).bytes());
-                Const::new(llval, tcx.types.usize)
-            }
-
-            _ => span_bug!(span, "{:?} in constant", rvalue)
-        };
-
-        debug!("const_rvalue({:?}: {:?} @ {:?}) = {:?}", rvalue, dest_ty, span, val);
-
-        Ok(val)
-    }
-
-}
-
-fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
-    match t.sty {
-        ty::TyInt(int_type) => const_to_opt_u128(value, true)
-            .and_then(|input| ConstInt::new_signed(input as i128, int_type,
-                                                   tcx.sess.target.isize_ty)),
-        ty::TyUint(uint_type) => const_to_opt_u128(value, false)
-            .and_then(|input| ConstInt::new_unsigned(input, uint_type,
-                                                     tcx.sess.target.usize_ty)),
-        _ => None
-
-    }
-}
-
-pub fn const_scalar_binop(op: mir::BinOp,
-                          lhs: ValueRef,
-                          rhs: ValueRef,
-                          input_ty: Ty) -> ValueRef {
-    assert!(!input_ty.is_simd());
-    let is_float = input_ty.is_fp();
-    let signed = input_ty.is_signed();
-
-    unsafe {
-        match op {
-            mir::BinOp::Add if is_float => llvm::LLVMConstFAdd(lhs, rhs),
-            mir::BinOp::Add             => llvm::LLVMConstAdd(lhs, rhs),
-
-            mir::BinOp::Sub if is_float => llvm::LLVMConstFSub(lhs, rhs),
-            mir::BinOp::Sub             => llvm::LLVMConstSub(lhs, rhs),
-
-            mir::BinOp::Mul if is_float => llvm::LLVMConstFMul(lhs, rhs),
-            mir::BinOp::Mul             => llvm::LLVMConstMul(lhs, rhs),
 
-            mir::BinOp::Div if is_float => llvm::LLVMConstFDiv(lhs, rhs),
-            mir::BinOp::Div if signed   => llvm::LLVMConstSDiv(lhs, rhs),
-            mir::BinOp::Div             => llvm::LLVMConstUDiv(lhs, rhs),
-
-            mir::BinOp::Rem if is_float => llvm::LLVMConstFRem(lhs, rhs),
-            mir::BinOp::Rem if signed   => llvm::LLVMConstSRem(lhs, rhs),
-            mir::BinOp::Rem             => llvm::LLVMConstURem(lhs, rhs),
-
-            mir::BinOp::BitXor => llvm::LLVMConstXor(lhs, rhs),
-            mir::BinOp::BitAnd => llvm::LLVMConstAnd(lhs, rhs),
-            mir::BinOp::BitOr  => llvm::LLVMConstOr(lhs, rhs),
-            mir::BinOp::Shl    => {
-                let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
-                llvm::LLVMConstShl(lhs, rhs)
-            }
-            mir::BinOp::Shr    => {
-                let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
-                if signed { llvm::LLVMConstAShr(lhs, rhs) }
-                else      { llvm::LLVMConstLShr(lhs, rhs) }
-            }
-            mir::BinOp::Eq | mir::BinOp::Ne |
-            mir::BinOp::Lt | mir::BinOp::Le |
-            mir::BinOp::Gt | mir::BinOp::Ge => {
-                if is_float {
-                    let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop());
-                    llvm::LLVMConstFCmp(cmp, lhs, rhs)
+                let llval = unsafe { llvm::LLVMConstInBoundsGEP(
+                    consts::bitcast(base_addr, Type::i8p(cx)),
+                    &C_usize(cx, ptr.offset),
+                    1,
+                ) };
+                if scalar.value != layout::Pointer {
+                    unsafe { llvm::LLVMConstPtrToInt(llval, llty.to_ref()) }
                 } else {
-                    let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(),
-                                                                signed);
-                    llvm::LLVMConstICmp(cmp, lhs, rhs)
+                    consts::bitcast(llval, llty)
                 }
             }
-            mir::BinOp::Offset => unreachable!("BinOp::Offset in const-eval!")
         }
     }
 }
 
-pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                            op: mir::BinOp,
-                                            lllhs: ValueRef,
-                                            llrhs: ValueRef,
-                                            input_ty: Ty<'tcx>)
-                                            -> Option<(ValueRef, bool)> {
-    if let (Some(lhs), Some(rhs)) = (to_const_int(lllhs, input_ty, tcx),
-                                     to_const_int(llrhs, input_ty, tcx)) {
-        let result = match op {
-            mir::BinOp::Add => lhs + rhs,
-            mir::BinOp::Sub => lhs - rhs,
-            mir::BinOp::Mul => lhs * rhs,
-            mir::BinOp::Shl => lhs << rhs,
-            mir::BinOp::Shr => lhs >> rhs,
-            _ => {
-                bug!("Operator `{:?}` is not a checkable operator", op)
-            }
-        };
+pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
+    let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
+    let layout = cx.data_layout();
+    let pointer_size = layout.pointer_size.bytes() as usize;
 
-        let of = match result {
-            Ok(_) => false,
-            Err(ConstMathErr::Overflow(_)) |
-            Err(ConstMathErr::ShiftNegative) => true,
-            Err(err) => {
-                bug!("Operator `{:?}` on `{:?}` and `{:?}` errored: {}",
-                     op, lhs, rhs, err.description());
-            }
-        };
-
-        Some((const_scalar_binop(op, lllhs, llrhs, input_ty), of))
-    } else {
-        None
+    let mut next_offset = 0;
+    for (&offset, &alloc_id) in &alloc.relocations {
+        assert_eq!(offset as usize as u64, offset);
+        let offset = offset as usize;
+        if offset > next_offset {
+            llvals.push(C_bytes(cx, &alloc.bytes[next_offset..offset]));
+        }
+        let ptr_offset = read_target_uint(
+            layout.endian,
+            &alloc.bytes[offset..(offset + pointer_size)],
+        ).expect("global_initializer: could not read relocation pointer") as u64;
+        llvals.push(primval_to_llvm(
+            cx,
+            PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
+            &Scalar {
+                value: layout::Primitive::Pointer,
+                valid_range: 0..=!0
+            },
+            Type::i8p(cx)
+        ));
+        next_offset = offset + pointer_size;
     }
-}
-
-unsafe fn cast_const_float_to_int(cx: &CodegenCx,
-                                  operand: &Const,
-                                  signed: bool,
-                                  int_ty: Type,
-                                  span: Span) -> ValueRef {
-    let llval = operand.llval;
-    let float_bits = match operand.ty.sty {
-        ty::TyFloat(fty) => fty.bit_width(),
-        _ => bug!("cast_const_float_to_int: operand not a float"),
-    };
-    // Note: this breaks if llval is a complex constant expression rather than a simple constant.
-    // One way that might happen would be if addresses could be turned into integers in constant
-    // expressions, but that doesn't appear to be possible?
-    // In any case, an ICE is better than producing undef.
-    let llval_bits = consts::bitcast(llval, Type::ix(cx, float_bits as u64));
-    let bits = const_to_opt_u128(llval_bits, false).unwrap_or_else(|| {
-        panic!("could not get bits of constant float {:?}",
-               Value(llval));
-    });
-    let int_width = int_ty.int_width() as usize;
-    // Try to convert, but report an error for overflow and NaN. This matches HIR const eval.
-    let cast_result = match float_bits {
-        32 if signed => ieee::Single::from_bits(bits).to_i128(int_width).map(|v| v as u128),
-        64 if signed => ieee::Double::from_bits(bits).to_i128(int_width).map(|v| v as u128),
-        32 => ieee::Single::from_bits(bits).to_u128(int_width),
-        64 => ieee::Double::from_bits(bits).to_u128(int_width),
-        n => bug!("unsupported float width {}", n),
-    };
-    if cast_result.status.contains(Status::INVALID_OP) {
-        let err = ConstEvalErr { span: span, kind: ErrKind::CannotCast };
-        err.report(cx.tcx, span, "expression");
+    if alloc.bytes.len() >= next_offset {
+        llvals.push(C_bytes(cx, &alloc.bytes[next_offset ..]));
     }
-    C_uint_big(int_ty, cast_result.value)
-}
 
-unsafe fn cast_const_int_to_float(cx: &CodegenCx,
-                                  llval: ValueRef,
-                                  signed: bool,
-                                  float_ty: Type) -> ValueRef {
-    // Note: this breaks if llval is a complex constant expression rather than a simple constant.
-    // One way that might happen would be if addresses could be turned into integers in constant
-    // expressions, but that doesn't appear to be possible?
-    // In any case, an ICE is better than producing undef.
-    let value = const_to_opt_u128(llval, signed).unwrap_or_else(|| {
-        panic!("could not get z128 value of constant integer {:?}",
-               Value(llval));
-    });
-    if signed {
-        llvm::LLVMConstSIToFP(llval, float_ty.to_ref())
-    } else if float_ty.float_width() == 32 && value >= MAX_F32_PLUS_HALF_ULP {
-        // We're casting to f32 and the value is > f32::MAX + 0.5 ULP -> round up to infinity.
-        let infinity_bits = C_u32(cx, ieee::Single::INFINITY.to_bits() as u32);
-        consts::bitcast(infinity_bits, float_ty)
-    } else {
-        llvm::LLVMConstUIToFP(llval, float_ty.to_ref())
-    }
+    C_struct(cx, &llvals, true)
 }
 
-impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
-    pub fn trans_constant(&mut self,
-                          bx: &Builder<'a, 'tcx>,
-                          constant: &mir::Constant<'tcx>)
-                          -> Const<'tcx>
-    {
-        debug!("trans_constant({:?})", constant);
-        let ty = self.monomorphize(&constant.ty);
-        let result = match constant.literal.clone() {
-            mir::Literal::Promoted { index } => {
-                let mir = &self.mir.promoted[index];
-                MirConstContext::new(bx.cx, mir, self.param_substs, IndexVec::new()).trans()
-            }
-            mir::Literal::Value { value } => {
-                if let ConstVal::Unevaluated(def_id, substs) = value.val {
-                    let substs = self.monomorphize(&substs);
-                    MirConstContext::trans_def(bx.cx, def_id, substs, IndexVec::new())
-                } else {
-                    Ok(Const::from_constval(bx.cx, &value.val, ty))
-                }
-            }
-        };
-
-        let result = result.unwrap_or_else(|_| {
-            // We've errored, so we don't have to produce working code.
-            let llty = bx.cx.layout_of(ty).llvm_type(bx.cx);
-            Const::new(C_undef(llty), ty)
-        });
-
-        debug!("trans_constant({:?}) = {:?}", constant, result);
-        result
-    }
-}
-
-
 pub fn trans_static_initializer<'a, 'tcx>(
     cx: &CodegenCx<'a, 'tcx>,
     def_id: DefId)
     -> Result<ValueRef, ConstEvalErr<'tcx>>
 {
-    MirConstContext::trans_def(cx, def_id, Substs::empty(), IndexVec::new())
-        .map(|c| c.llval)
-}
-
-/// Construct a constant value, suitable for initializing a
-/// GlobalVariable, given a case and constant values for its fields.
-/// Note that this may have a different LLVM type (and different
-/// alignment!) from the representation's `type_of`, so it needs a
-/// pointer cast before use.
-///
-/// The LLVM type system does not directly support unions, and only
-/// pointers can be bitcast, so a constant (and, by extension, the
-/// GlobalVariable initialized by it) will have a type that can vary
-/// depending on which case of an enum it is.
-///
-/// To understand the alignment situation, consider `enum E { V64(u64),
-/// V32(u32, u32) }` on Windows.  The type has 8-byte alignment to
-/// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
-/// i32, i32}`, which is 4-byte aligned.
-///
-/// Currently the returned value has the same size as the type, but
-/// this could be changed in the future to avoid allocating unnecessary
-/// space after values of shorter-than-maximum cases.
-fn trans_const_adt<'a, 'tcx>(
-    cx: &CodegenCx<'a, 'tcx>,
-    t: Ty<'tcx>,
-    kind: &mir::AggregateKind,
-    vals: &[Const<'tcx>]
-) -> Const<'tcx> {
-    let l = cx.layout_of(t);
-    let variant_index = match *kind {
-        mir::AggregateKind::Adt(_, index, _, _) => index,
-        _ => 0,
+    let instance = ty::Instance::mono(cx.tcx, def_id);
+    let cid = GlobalId {
+        instance,
+        promoted: None
     };
+    let param_env = ty::ParamEnv::empty(traits::Reveal::All);
+    cx.tcx.const_eval(param_env.and(cid))?;
 
-    if let layout::Abi::Uninhabited = l.abi {
-        return Const::new(C_undef(l.llvm_type(cx)), t);
-    }
+    let alloc_id = cx
+        .tcx
+        .interpret_interner
+        .get_cached(def_id)
+        .expect("global not cached");
 
-    match l.variants {
-        layout::Variants::Single { index } => {
-            assert_eq!(variant_index, index);
-            if let layout::FieldPlacement::Union(_) = l.fields {
-                assert_eq!(variant_index, 0);
-                assert_eq!(vals.len(), 1);
-                let (field_size, field_align) = cx.size_and_align_of(vals[0].ty);
-                let contents = [
-                    vals[0].llval,
-                    padding(cx, l.size - field_size)
-                ];
+    let alloc = cx
+        .tcx
+        .interpret_interner
+        .get_alloc(alloc_id)
+        .expect("miri allocation never successfully created");
+    Ok(global_initializer(cx, alloc))
+}
 
-                let packed = l.align.abi() < field_align.abi();
-                Const::new(C_struct(cx, &contents, packed), t)
-            } else {
-                if let layout::Abi::Vector { .. } = l.abi {
-                    if let layout::FieldPlacement::Array { .. } = l.fields {
-                        return Const::new(C_vector(&vals.iter().map(|x| x.llval)
-                            .collect::<Vec<_>>()), t);
-                    }
-                }
-                build_const_struct(cx, l, vals, None)
-            }
-        }
-        layout::Variants::Tagged { .. } => {
-            let discr = match *kind {
-                mir::AggregateKind::Adt(adt_def, _, _, _) => {
-                    adt_def.discriminant_for_variant(cx.tcx, variant_index)
-                           .to_u128_unchecked() as u64
-                },
-                _ => 0,
-            };
-            let discr_field = l.field(cx, 0);
-            let discr = C_int(discr_field.llvm_type(cx), discr as i64);
-            if let layout::Abi::Scalar(_) = l.abi {
-                Const::new(discr, t)
-            } else {
-                let discr = Const::new(discr, discr_field.ty);
-                build_const_struct(cx, l.for_variant(cx, variant_index), vals, Some(discr))
-            }
-        }
-        layout::Variants::NicheFilling {
-            dataful_variant,
-            ref niche_variants,
-            niche_start,
-            ..
-        } => {
-            if variant_index == dataful_variant {
-                build_const_struct(cx, l.for_variant(cx, dataful_variant), vals, None)
-            } else {
-                let niche = l.field(cx, 0);
-                let niche_llty = niche.llvm_type(cx);
-                let niche_value = ((variant_index - niche_variants.start) as u128)
-                    .wrapping_add(niche_start);
-                // FIXME(eddyb) Check the actual primitive type here.
-                let niche_llval = if niche_value == 0 {
-                    // HACK(eddyb) Using `C_null` as it works on all types.
-                    C_null(niche_llty)
-                } else {
-                    C_uint_big(niche_llty, niche_value)
+impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
+    fn const_to_miri_value(
+        &mut self,
+        bx: &Builder<'a, 'tcx>,
+        constant: &'tcx ty::Const<'tcx>,
+    ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+        match constant.val {
+            ConstVal::Unevaluated(def_id, ref substs) => {
+                let tcx = bx.tcx();
+                let param_env = ty::ParamEnv::empty(traits::Reveal::All);
+                let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap();
+                let cid = GlobalId {
+                    instance,
+                    promoted: None,
                 };
-                build_const_struct(cx, l, &[Const::new(niche_llval, niche.ty)], None)
-            }
+                let c = tcx.const_eval(param_env.and(cid))?;
+                self.const_to_miri_value(bx, c)
+            },
+            ConstVal::Value(miri_val) => Ok(miri_val),
         }
     }
-}
-
-/// Building structs is a little complicated, because we might need to
-/// insert padding if a field's value is less aligned than its type.
-///
-/// Continuing the example from `trans_const_adt`, a value of type `(u32,
-/// E)` should have the `E` at offset 8, but if that field's
-/// initializer is 4-byte aligned then simply translating the tuple as
-/// a two-element struct will locate it at offset 4, and accesses to it
-/// will read the wrong memory.
-fn build_const_struct<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
-                                layout: layout::TyLayout<'tcx>,
-                                vals: &[Const<'tcx>],
-                                discr: Option<Const<'tcx>>)
-                                -> Const<'tcx> {
-    assert_eq!(vals.len(), layout.fields.count());
 
-    match layout.abi {
-        layout::Abi::Scalar(_) |
-        layout::Abi::ScalarPair(..) |
-        layout::Abi::Vector { .. } if discr.is_none() => {
-            let mut non_zst_fields = vals.iter().enumerate().map(|(i, f)| {
-                (f, layout.fields.offset(i))
-            }).filter(|&(f, _)| !cx.layout_of(f.ty).is_zst());
-            match (non_zst_fields.next(), non_zst_fields.next()) {
-                (Some((x, offset)), None) if offset.bytes() == 0 => {
-                    return Const::new(x.llval, layout.ty);
-                }
-                (Some((a, a_offset)), Some((b, _))) if a_offset.bytes() == 0 => {
-                    return Const::new(C_struct(cx, &[a.llval, b.llval], false), layout.ty);
-                }
-                (Some((a, _)), Some((b, b_offset))) if b_offset.bytes() == 0 => {
-                    return Const::new(C_struct(cx, &[b.llval, a.llval], false), layout.ty);
-                }
-                _ => {}
+    pub fn mir_constant_to_miri_value(
+        &mut self,
+        bx: &Builder<'a, 'tcx>,
+        constant: &mir::Constant<'tcx>,
+    ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+        match constant.literal {
+            mir::Literal::Promoted { index } => {
+                let param_env = ty::ParamEnv::empty(traits::Reveal::All);
+                let cid = mir::interpret::GlobalId {
+                    instance: self.instance,
+                    promoted: Some(index),
+                };
+                bx.tcx().const_eval(param_env.and(cid))
             }
-        }
-        _ => {}
-    }
-
-    // offset of current value
-    let mut packed = false;
-    let mut offset = Size::from_bytes(0);
-    let mut cfields = Vec::new();
-    cfields.reserve(discr.is_some() as usize + 1 + layout.fields.count() * 2);
-
-    if let Some(discr) = discr {
-        let (field_size, field_align) = cx.size_and_align_of(discr.ty);
-        packed |= layout.align.abi() < field_align.abi();
-        cfields.push(discr.llval);
-        offset = field_size;
-    }
-
-    let parts = layout.fields.index_by_increasing_offset().map(|i| {
-        (vals[i], layout.fields.offset(i))
-    });
-    for (val, target_offset) in parts {
-        let (field_size, field_align) = cx.size_and_align_of(val.ty);
-        packed |= layout.align.abi() < field_align.abi();
-        cfields.push(padding(cx, target_offset - offset));
-        cfields.push(val.llval);
-        offset = target_offset + field_size;
+            mir::Literal::Value { value } => {
+                Ok(self.monomorphize(&value))
+            }
+        }.and_then(|c| self.const_to_miri_value(bx, c))
+    }
+
+    /// process constant containing SIMD shuffle indices
+    pub fn simd_shuffle_indices(
+        &mut self,
+        bx: &Builder<'a, 'tcx>,
+        constant: &mir::Constant<'tcx>,
+    ) -> (ValueRef, Ty<'tcx>) {
+        self.mir_constant_to_miri_value(bx, constant)
+            .and_then(|c| {
+                let field_ty = constant.ty.builtin_index().unwrap();
+                let fields = match constant.ty.sty {
+                    ty::TyArray(_, n) => n.val.unwrap_u64(),
+                    ref other => bug!("invalid simd shuffle type: {}", other),
+                };
+                let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
+                    let field = const_val_field(
+                        bx.tcx(),
+                        ty::ParamEnv::empty(traits::Reveal::All),
+                        self.instance,
+                        None,
+                        mir::Field::new(field as usize),
+                        c,
+                        constant.ty,
+                    )?;
+                    match field.val {
+                        ConstVal::Value(MiriValue::ByVal(prim)) => {
+                            let layout = bx.cx.layout_of(field_ty);
+                            let scalar = match layout.abi {
+                                layout::Abi::Scalar(ref x) => x,
+                                _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
+                            };
+                            Ok(primval_to_llvm(
+                                bx.cx, prim, scalar,
+                                layout.immediate_llvm_type(bx.cx),
+                            ))
+                        },
+                        other => bug!("simd shuffle field {:?}, {}", other, constant.ty),
+                    }
+                }).collect();
+                let llval = C_struct(bx.cx, &values?, false);
+                Ok((llval, constant.ty))
+            })
+            .unwrap_or_else(|e| {
+                e.report(bx.tcx(), constant.span, "shuffle_indices");
+                // We've errored, so we don't have to produce working code.
+                let ty = self.monomorphize(&constant.ty);
+                let llty = bx.cx.layout_of(ty).llvm_type(bx.cx);
+                (C_undef(llty), ty)
+            })
     }
-
-    // Pad to the size of the whole type, not e.g. the variant.
-    cfields.push(padding(cx, cx.size_of(layout.ty) - offset));
-
-    Const::new(C_struct(cx, &cfields, packed), layout.ty)
-}
-
-fn padding(cx: &CodegenCx, size: Size) -> ValueRef {
-    C_undef(Type::array(&Type::i8(cx), size.bytes()))
 }
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index 99e3a59e2c4f4..a1044ac87e4c5 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -44,6 +44,8 @@ use self::operand::{OperandRef, OperandValue};
 
 /// Master context for translating MIR.
 pub struct FunctionCx<'a, 'tcx:'a> {
+    instance: Instance<'tcx>,
+
     mir: &'a mir::Mir<'tcx>,
 
     debug_context: debuginfo::FunctionDebugContext,
@@ -227,6 +229,7 @@ pub fn trans_mir<'a, 'tcx: 'a>(
     let (landing_pads, funclets) = create_funclets(mir, &bx, &cleanup_kinds, &block_bxs);
 
     let mut fx = FunctionCx {
+        instance,
         mir,
         llfn,
         fn_ty,
diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs
index e1b906646aa43..75df349de41ee 100644
--- a/src/librustc_trans/mir/operand.rs
+++ b/src/librustc_trans/mir/operand.rs
@@ -9,12 +9,15 @@
 // except according to those terms.
 
 use llvm::ValueRef;
-use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
+use rustc::middle::const_val::ConstEvalErr;
 use rustc::mir;
+use rustc::mir::interpret::Value as MiriValue;
+use rustc::ty;
+use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
 use rustc_data_structures::indexed_vec::Idx;
 
 use base;
-use common::{self, CodegenCx, C_undef, C_usize};
+use common::{self, CodegenCx, C_null, C_undef, C_usize};
 use builder::Builder;
 use value::Value;
 use type_of::LayoutLlvmExt;
@@ -24,6 +27,7 @@ use std::fmt;
 use std::ptr;
 
 use super::{FunctionCx, LocalRef};
+use super::constant::{primval_to_llvm};
 use super::place::PlaceRef;
 
 /// The representation of a Rust value. The enum variant is in fact
@@ -89,6 +93,70 @@ impl<'a, 'tcx> OperandRef<'tcx> {
         }
     }
 
+    pub fn from_const(bx: &Builder<'a, 'tcx>,
+                      miri_val: MiriValue,
+                      ty: ty::Ty<'tcx>)
+                      -> Result<OperandRef<'tcx>, ConstEvalErr<'tcx>> {
+        let layout = bx.cx.layout_of(ty);
+
+        if layout.is_zst() {
+            return Ok(OperandRef::new_zst(bx.cx, layout));
+        }
+
+        let val = match miri_val {
+            MiriValue::ByVal(x) => {
+                let scalar = match layout.abi {
+                    layout::Abi::Scalar(ref x) => x,
+                    _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
+                };
+                let llval = primval_to_llvm(
+                    bx.cx,
+                    x,
+                    scalar,
+                    layout.immediate_llvm_type(bx.cx),
+                );
+                OperandValue::Immediate(llval)
+            },
+            MiriValue::ByValPair(a, b) => {
+                let (a_scalar, b_scalar) = match layout.abi {
+                    layout::Abi::ScalarPair(ref a, ref b) => (a, b),
+                    _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout)
+                };
+                let a_llval = primval_to_llvm(
+                    bx.cx,
+                    a,
+                    a_scalar,
+                    layout.scalar_pair_element_llvm_type(bx.cx, 0),
+                );
+                let b_llval = primval_to_llvm(
+                    bx.cx,
+                    b,
+                    b_scalar,
+                    layout.scalar_pair_element_llvm_type(bx.cx, 1),
+                );
+                OperandValue::Pair(a_llval, b_llval)
+            },
+            MiriValue::ByRef(ptr, align) => {
+                let scalar = layout::Scalar {
+                    value: layout::Primitive::Pointer,
+                    valid_range: 0..=!0
+                };
+                let ptr = primval_to_llvm(
+                    bx.cx,
+                    ptr.into_inner_primval(),
+                    &scalar,
+                    layout.llvm_type(bx.cx).ptr_to(),
+                );
+                return Ok(PlaceRef::new_sized(ptr, layout, align).load(bx));
+            },
+        };
+
+        Ok(OperandRef {
+            val,
+            layout
+        })
+    }
+
     /// Asserts that this operand refers to a scalar and returns
     /// a reference to its value.
     pub fn immediate(self) -> ValueRef {
@@ -327,14 +395,19 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
             }
 
             mir::Operand::Constant(ref constant) => {
-                let val = self.trans_constant(&bx, constant);
-                let operand = val.to_operand(bx.cx);
-                if let OperandValue::Ref(ptr, align) = operand.val {
-                    // If this is a OperandValue::Ref to an immediate constant, load it.
-                    PlaceRef::new_sized(ptr, operand.layout, align).load(bx)
-                } else {
-                    operand
-                }
+                let ty = self.monomorphize(&constant.ty);
+                self.mir_constant_to_miri_value(bx, constant)
+                    .and_then(|c| OperandRef::from_const(bx, c, ty))
+                    .unwrap_or_else(|err| {
+                        err.report(bx.tcx(), constant.span, "const operand");
+                        // We've errored, so we don't have to produce working code.
+                        let layout = bx.cx.layout_of(ty);
+                        PlaceRef::new_sized(
+                            C_null(layout.llvm_type(bx.cx).ptr_to()),
+                            layout,
+                            layout.align,
+                        ).load(bx)
+                    })
             }
         }
     }
diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs
index 99770476e12f9..b340d91b02708 100644
--- a/src/librustc_trans/mir/place.rs
+++ b/src/librustc_trans/mir/place.rs
@@ -328,7 +328,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
                 let ptr = self.project_field(bx, 0);
                 let to = self.layout.ty.ty_adt_def().unwrap()
                     .discriminant_for_variant(bx.tcx(), variant_index)
-                    .to_u128_unchecked() as u64;
+                    .val as u64;
                 bx.store(C_int(ptr.layout.llvm_type(bx.cx), to as i64),
                     ptr.llval, ptr.align);
             }
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 34ac44cec025a..fa0514952d213 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -30,7 +30,6 @@ use type_of::LayoutLlvmExt;
 use value::Value;
 
 use super::{FunctionCx, LocalRef};
-use super::constant::const_scalar_checked_binop;
 use super::operand::{OperandRef, OperandValue};
 use super::place::PlaceRef;
 
@@ -122,7 +121,6 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                     }
                 }
 
-                let count = count.as_u64();
                 let count = C_usize(bx.cx, count);
                 let end = dest.project_index(&bx, count).llval;
 
@@ -497,7 +495,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
         if let mir::Place::Local(index) = *place {
             if let LocalRef::Operand(Some(op)) = self.locals[index] {
                 if let ty::TyArray(_, n) = op.layout.ty.sty {
-                    let n = n.val.to_const_int().unwrap().to_u64().unwrap();
+                    let n = n.val.unwrap_u64();
                     return common::C_usize(bx.cx, n);
                 }
             }
@@ -645,14 +643,6 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
             return OperandValue::Pair(val, C_bool(bx.cx, false));
         }
 
-        // First try performing the operation on constants, which
-        // will only succeed if both operands are constant.
-        // This is necessary to determine when an overflow Assert
-        // will always panic at runtime, and produce a warning.
-        if let Some((val, of)) = const_scalar_checked_binop(bx.tcx(), op, lhs, rhs, input_ty) {
-            return OperandValue::Pair(val, C_bool(bx.cx, of));
-        }
-
         let (val, of) = match op {
             // These are checked using intrinsics
             mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul => {
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 91c1097fc7f8a..06d94e8d15569 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -58,12 +58,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
                 };
                 let attrs = tcx.get_attrs(def_id);
 
-                match consts::trans_static(&cx, def_id, is_mutable, &attrs) {
-                    Ok(_) => { /* Cool, everything's alright. */ },
-                    Err(err) => {
-                        err.report(tcx, tcx.def_span(def_id), "static");
-                    }
-                };
+                consts::trans_static(&cx, def_id, is_mutable, &attrs);
             }
             MonoItem::GlobalAsm(node_id) => {
                 let item = cx.tcx.hir.expect_item(node_id);
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index a261c12bcdd94..eb02c05fd3957 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -413,7 +413,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let expected_ty = self.structurally_resolved_type(pat.span, expected);
                 let (inner_ty, slice_ty) = match expected_ty.sty {
                     ty::TyArray(inner_ty, size) => {
-                        let size = size.val.to_const_int().unwrap().to_u64().unwrap();
+                        let size = size.val.unwrap_u64();
                         let min_len = before.len() as u64 + after.len() as u64;
                         if slice.is_none() {
                             if min_len != size {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0f59973eab251..19085ff039ec5 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -93,13 +93,14 @@ use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
 use rustc::infer::anon_types::AnonTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
+use rustc::mir::interpret::{GlobalId};
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
 use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
 use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::maps::Providers;
-use rustc::ty::util::{Representability, IntTypeExt};
+use rustc::ty::util::{Representability, IntTypeExt, Discr};
 use errors::{DiagnosticBuilder, DiagnosticId};
 
 use require_c_abi_if_variadic;
@@ -132,7 +133,6 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::map::Node;
 use rustc::hir::{self, PatKind};
 use rustc::middle::lang_items;
-use rustc_const_math::ConstInt;
 
 mod autoderef;
 pub mod dropck;
@@ -1631,10 +1631,10 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
     }
 
-    let mut disr_vals: Vec<ConstInt> = Vec::new();
+    let mut disr_vals: Vec<Discr<'tcx>> = Vec::new();
     for (discr, v) in def.discriminants(tcx).zip(vs) {
         // Check for duplicate discriminant values
-        if let Some(i) = disr_vals.iter().position(|&x| x == discr) {
+        if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
             let variant_i_node_id = tcx.hir.as_local_node_id(def.variants[i].did).unwrap();
             let variant_i = tcx.hir.expect_variant(variant_i_node_id);
             let i_span = match variant_i.node.disr_expr {
@@ -3999,10 +3999,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let count_def_id = tcx.hir.body_owner_def_id(count);
             let param_env = ty::ParamEnv::empty(traits::Reveal::UserFacing);
             let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
-            let count = tcx.const_eval(param_env.and((count_def_id, substs)));
+            let instance = ty::Instance::resolve(
+                tcx.global_tcx(),
+                param_env,
+                count_def_id,
+                substs,
+            ).unwrap();
+            let global_id = GlobalId {
+                instance,
+                promoted: None
+            };
+            let count = tcx.const_eval(param_env.and(global_id));
 
             if let Err(ref err) = count {
-               err.report(tcx, tcx.def_span(count_def_id), "constant expression");
+                err.report(tcx, tcx.def_span(count_def_id), "constant expression");
             }
 
             let uty = match expected {
@@ -4029,9 +4039,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             };
 
             if let Ok(count) = count {
-                let zero_or_one = count.val.to_const_int().and_then(|count| {
-                    count.to_u64().map(|count| count <= 1)
-                }).unwrap_or(false);
+                let zero_or_one = count.val.to_raw_bits().map_or(false, |count| count <= 1);
                 if !zero_or_one {
                     // For [foo, ..n] where n > 1, `foo` must have
                     // Copy type:
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 12791107ebb41..47a229cbd3b5b 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -447,10 +447,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 hir::BiBitOr => ("bitor", lang.bitor_trait()),
                 hir::BiShl => ("shl", lang.shl_trait()),
                 hir::BiShr => ("shr", lang.shr_trait()),
-                hir::BiLt => ("lt", lang.ord_trait()),
-                hir::BiLe => ("le", lang.ord_trait()),
-                hir::BiGe => ("ge", lang.ord_trait()),
-                hir::BiGt => ("gt", lang.ord_trait()),
+                hir::BiLt => ("lt", lang.partial_ord_trait()),
+                hir::BiLe => ("le", lang.partial_ord_trait()),
+                hir::BiGe => ("ge", lang.partial_ord_trait()),
+                hir::BiGt => ("gt", lang.partial_ord_trait()),
                 hir::BiEq => ("eq", lang.eq_trait()),
                 hir::BiNe => ("ne", lang.eq_trait()),
                 hir::BiAnd | hir::BiOr => {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 1a7d8bb56780e..858d9fb5b7492 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -28,19 +28,15 @@ use astconv::{AstConv, Bounds};
 use lint;
 use constrained_type_params as ctp;
 use middle::lang_items::SizedTraitLangItem;
-use middle::const_val::ConstVal;
 use middle::resolve_lifetime as rl;
 use rustc::mir::mono::Linkage;
-use rustc::traits::Reveal;
 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::util::nodemap::FxHashSet;
-use util::nodemap::FxHashMap;
-
-use rustc_const_math::ConstInt;
+use rustc::util::nodemap::{FxHashSet, FxHashMap};
+use rustc::ty::util::Discr;
 
 use syntax::{abi, ast};
 use syntax::ast::MetaItemKind;
@@ -512,30 +508,17 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         def_id: DefId,
                                         variants: &[hir::Variant]) {
-    let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
     let def = tcx.adt_def(def_id);
     let repr_type = def.repr.discr_type();
     let initial = repr_type.initial_discriminant(tcx);
-    let mut prev_discr = None::<ConstInt>;
+    let mut prev_discr = None::<Discr<'tcx>>;
 
     // fill the discriminant values and field types
     for variant in variants {
-        let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr());
+        let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
         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::identity_for_item(tcx, expr_did);
-            let result = tcx.at(variant.span).const_eval(param_env.and((expr_did, substs)));
-
-            // 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(&ty::Const { val: ConstVal::Integral(x), .. }) => Some(x),
-                _ => None
-            }
+            def.eval_explicit_discr(tcx, expr_did)
         } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
             Some(discr)
         } else {
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 96b2ec745f132..bd2267a46010b 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -1020,41 +1020,6 @@ Here `X` will have already been specified the discriminant 0 by the time `Y` is
 encountered, so a conflict occurs.
 "##,
 
-E0082: r##"
-#### Note: this error code is no longer emitted by the compiler.
-
-When you specify enum discriminants with `=`, the compiler expects `isize`
-values by default. Or you can add the `repr` attibute to the enum declaration
-for an explicit choice of the discriminant type. In either cases, the
-discriminant values must fall within a valid range for the expected type;
-otherwise this error is raised. For example:
-
-```compile_fail
-# #![deny(overflowing_literals)]
-#[repr(u8)]
-enum Thing {
-    A = 1024,
-    B = 5,
-}
-```
-
-Here, 1024 lies outside the valid range for `u8`, so the discriminant for `A` is
-invalid. Here is another, more subtle example which depends on target word size:
-
-```compile_fail,E0080
-# #[repr(i32)]
-enum DependsOnPointerSize {
-    A = 1 << 32,
-}
-```
-
-Here, `1 << 32` is interpreted as an `isize` value. So it is invalid for 32 bit
-target (`target_pointer_width = "32"`) but valid for 64 bit target.
-
-You may want to change representation types to fix this, or else change invalid
-discriminant values so that they fit within the existing type.
-"##,
-
 E0084: r##"
 An unsupported representation was attempted on a zero-variant enum.
 
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index d9bd96b0d769f..40385cabf5661 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -86,6 +86,7 @@ This API is completely unstable and subject to change.
 #![feature(refcell_replace_swap)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_patterns)]
+#![feature(i128_type)]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index d0230a69374d4..5d4addce2c439 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -34,6 +34,7 @@ use rustc::middle::privacy::AccessLevels;
 use rustc::middle::resolve_lifetime as rl;
 use rustc::ty::fold::TypeFolder;
 use rustc::middle::lang_items;
+use rustc::mir::interpret::GlobalId;
 use rustc::hir::{self, HirVec};
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -51,7 +52,6 @@ use std::collections::hash_map::Entry;
 use std::collections::VecDeque;
 use std::fmt;
 
-use rustc_const_math::ConstInt;
 use std::default::Default;
 use std::{mem, slice, vec};
 use std::iter::{FromIterator, once};
@@ -2501,23 +2501,17 @@ impl Clean<Type> for hir::Ty {
                 let def_id = cx.tcx.hir.body_owner_def_id(n);
                 let param_env = cx.tcx.param_env(def_id);
                 let substs = Substs::identity_for_item(cx.tcx, def_id);
-                let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap_or_else(|_| {
+                let cid = GlobalId {
+                    instance: ty::Instance::new(def_id, substs),
+                    promoted: None
+                };
+                let n = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| {
                     cx.tcx.mk_const(ty::Const {
                         val: ConstVal::Unevaluated(def_id, substs),
                         ty: cx.tcx.types.usize
                     })
                 });
-                let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
-                    n.to_string()
-                } else if let ConstVal::Unevaluated(def_id, _) = n.val {
-                    if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) {
-                        print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id))
-                    } else {
-                        inline::print_inlined_const(cx, def_id)
-                    }
-                } else {
-                    format!("{:?}", n)
-                };
+                let n = print_const(cx, n);
                 Array(box ty.clean(cx), n)
             },
             TyTup(ref tys) => Tuple(tys.clean(cx)),
@@ -2636,21 +2630,15 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 let mut n = cx.tcx.lift(&n).unwrap();
                 if let ConstVal::Unevaluated(def_id, substs) = n.val {
                     let param_env = cx.tcx.param_env(def_id);
-                    if let Ok(new_n) = cx.tcx.const_eval(param_env.and((def_id, substs))) {
+                    let cid = GlobalId {
+                        instance: ty::Instance::new(def_id, substs),
+                        promoted: None
+                    };
+                    if let Ok(new_n) = cx.tcx.const_eval(param_env.and(cid)) {
                         n = new_n;
                     }
                 };
-                let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
-                    n.to_string()
-                } else if let ConstVal::Unevaluated(def_id, _) = n.val {
-                    if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) {
-                        print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id))
-                    } else {
-                        inline::print_inlined_const(cx, def_id)
-                    }
-                } else {
-                    format!("{:?}", n)
-                };
+                let n = print_const(cx, n);
                 Array(box ty.clean(cx), n)
             }
             ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
@@ -3634,6 +3622,28 @@ fn name_from_pat(p: &hir::Pat) -> String {
     }
 }
 
+fn print_const(cx: &DocContext, n: &ty::Const) -> String {
+    match n.val {
+        ConstVal::Unevaluated(def_id, _) => {
+            if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) {
+                print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id))
+            } else {
+                inline::print_inlined_const(cx, def_id)
+            }
+        },
+        ConstVal::Value(val) => {
+            let mut s = String::new();
+            ::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap();
+            // array lengths are obviously usize
+            if s.ends_with("usize") {
+                let n = s.len() - "usize".len();
+                s.truncate(n);
+            }
+            s
+        },
+    }
+}
+
 fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String {
     cx.tcx.hir.node_to_pretty_string(body.node_id)
 }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 45d82bc7af38e..1a790bf78bd86 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -217,9 +217,6 @@ declare_features! (
     // Allows the definition of `const fn` functions.
     (active, const_fn, "1.2.0", Some(24111)),
 
-    // Allows indexing into constant arrays.
-    (active, const_indexing, "1.4.0", Some(29947)),
-
     // Allows using #[prelude_import] on glob `use` items.
     //
     // rustc internal
@@ -490,6 +487,8 @@ declare_features! (
     (accepted, augmented_assignments, "1.8.0", Some(28235)),
     // allow empty structs and enum variants with braces
     (accepted, braced_empty_structs, "1.8.0", Some(29720)),
+    // Allows indexing into constant arrays.
+    (accepted, const_indexing, "1.24.0", Some(29947)),
     (accepted, default_type_params, "1.0.0", None),
     (accepted, globs, "1.0.0", None),
     (accepted, if_let, "1.0.0", None),
diff --git a/src/libsyntax_pos/span_encoding.rs b/src/libsyntax_pos/span_encoding.rs
index b23e40ce7a932..bf9a832519ad9 100644
--- a/src/libsyntax_pos/span_encoding.rs
+++ b/src/libsyntax_pos/span_encoding.rs
@@ -19,16 +19,37 @@ use hygiene::SyntaxContext;
 
 use rustc_data_structures::fx::FxHashMap;
 use std::cell::RefCell;
+use std::hash::{Hash, Hasher};
 
 /// A compressed span.
 /// Contains either fields of `SpanData` inline if they are small, or index into span interner.
 /// The primary goal of `Span` is to be as small as possible and fit into other structures
 /// (that's why it uses `packed` as well). Decoding speed is the second priority.
 /// See `SpanData` for the info on span fields in decoded representation.
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 #[repr(packed)]
 pub struct Span(u32);
 
+impl Copy for Span {}
+impl Clone for Span {
+    fn clone(&self) -> Span {
+        *self
+    }
+}
+impl PartialEq for Span {
+    fn eq(&self, other: &Span) -> bool {
+        let a = self.0;
+        let b = other.0;
+        a == b
+    }
+}
+impl Eq for Span {}
+impl Hash for Span {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        let a = self.0;
+        a.hash(state)
+    }
+}
+
 /// Dummy span, both position and length are zero, syntax context is zero as well.
 /// This span is kept inline and encoded with format 0.
 pub const DUMMY_SP: Span = Span(0);
diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs
index a75b8f3992d07..007fb7f459662 100644
--- a/src/test/codegen/consts.rs
+++ b/src/test/codegen/consts.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // compile-flags: -C no-prepopulate-passes
+// ignore-tidy-linelength
 
 #![crate_type = "lib"]
 
@@ -19,12 +20,11 @@
 // CHECK: @STATIC = {{.*}}, align 4
 
 // This checks the constants from inline_enum_const
-// CHECK: @ref.{{[0-9]+}} = {{.*}}, align 2
+// CHECK: @byte_str.{{[0-9]+}} = {{.*}}, align 2
 
 // This checks the constants from {low,high}_align_const, they share the same
 // constant, but the alignment differs, so the higher one should be used
-// CHECK: [[LOW_HIGH:@ref.[0-9]+]] = {{.*}}, align 4
-// CHECK: [[LOW_HIGH_REF:@const.[0-9]+]] = {{.*}} [[LOW_HIGH]]
+// CHECK: [[LOW_HIGH:@byte_str.[0-9]+]] = {{.*}}, align 4
 
 #[derive(Copy, Clone)]
 
@@ -54,7 +54,7 @@ pub fn inline_enum_const() -> E<i8, i16> {
 #[no_mangle]
 pub fn low_align_const() -> E<i16, [i16; 3]> {
 // Check that low_align_const and high_align_const use the same constant
-// CHECK: load {{.*}} bitcast ({ i16, [0 x i8], i16, [4 x i8] }** [[LOW_HIGH_REF]]
+// CHECK: i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0),
     *&E::A(0)
 }
 
@@ -62,6 +62,6 @@ pub fn low_align_const() -> E<i16, [i16; 3]> {
 #[no_mangle]
 pub fn high_align_const() -> E<i16, i32> {
 // Check that low_align_const and high_align_const use the same constant
-// CHECK: load {{.*}} bitcast ({ i16, [0 x i8], i16, [4 x i8] }** [[LOW_HIGH_REF]]
+// CHECK: i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0),
     *&E::A(0)
 }
diff --git a/src/test/codegen/link_section.rs b/src/test/codegen/link_section.rs
index 1879002e7f3d7..9c56a316b341c 100644
--- a/src/test/codegen/link_section.rs
+++ b/src/test/codegen/link_section.rs
@@ -12,7 +12,7 @@
 
 #![crate_type = "lib"]
 
-// CHECK: @VAR1 = constant i32 1, section ".test_one"
+// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one"
 #[no_mangle]
 #[link_section = ".test_one"]
 pub static VAR1: u32 = 1;
diff --git a/src/test/codegen/remap_path_prefix/main.rs b/src/test/codegen/remap_path_prefix/main.rs
index 2f46b6c5d48da..4fb8c37558d48 100644
--- a/src/test/codegen/remap_path_prefix/main.rs
+++ b/src/test/codegen/remap_path_prefix/main.rs
@@ -22,7 +22,7 @@ mod aux_mod;
 include!("aux_mod.rs");
 
 // Here we check that the expansion of the file!() macro is mapped.
-// CHECK: internal constant [34 x i8] c"/the/src/remap_path_prefix/main.rs"
+// CHECK: @byte_str.1 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>, align 1
 pub static FILE_PATH: &'static str = file!();
 
 fn main() {
diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs
index 18476494300b2..02264228a6bf6 100644
--- a/src/test/compile-fail/const-call.rs
+++ b/src/test/compile-fail/const-call.rs
@@ -15,4 +15,5 @@ fn f(x: usize) -> usize {
 fn main() {
     let _ = [0; f(2)];
     //~^ ERROR calls in constants are limited to constant functions
+    //~| E0080
 }
diff --git a/src/test/compile-fail/const-err-early.rs b/src/test/compile-fail/const-err-early.rs
index 42fb40394fb29..3de0f1ff61e1c 100644
--- a/src/test/compile-fail/const-err-early.rs
+++ b/src/test/compile-fail/const-err-early.rs
@@ -8,17 +8,25 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(const_indexing)]
 #![deny(const_err)]
 
-pub const A: i8 = -std::i8::MIN; //~ ERROR attempt to negate with overflow
-pub const B: u8 = 200u8 + 200u8; //~ ERROR attempt to add with overflow
-pub const C: u8 = 200u8 * 4; //~ ERROR attempt to multiply with overflow
-pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR attempt to subtract with overflow
+pub const A: i8 = -std::i8::MIN; //~ ERROR E0080
+//~^ ERROR attempt to negate with overflow
+//~| ERROR constant evaluation error
+pub const B: u8 = 200u8 + 200u8; //~ ERROR E0080
+//~^ ERROR attempt to add with overflow
+pub const C: u8 = 200u8 * 4; //~ ERROR E0080
+//~^ ERROR attempt to multiply with overflow
+pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR E0080
+//~^ ERROR attempt to subtract with overflow
 pub const E: u8 = [5u8][1];
-//~^ ERROR index out of bounds: the len is 1 but the index is 1
+//~^ ERROR E0080
 
 fn main() {
+    let _a = A;
+    let _b = B;
+    let _c = C;
+    let _d = D;
+    let _e = E;
     let _e = [6u8][1];
-    //~^ ERROR index out of bounds: the len is 1 but the index is 1
 }
diff --git a/src/test/compile-fail/const-err-multi.rs b/src/test/compile-fail/const-err-multi.rs
index d4f9c0fe56dae..d2355f57f1729 100644
--- a/src/test/compile-fail/const-err-multi.rs
+++ b/src/test/compile-fail/const-err-multi.rs
@@ -10,10 +10,17 @@
 
 #![deny(const_err)]
 
-pub const A: i8 = -std::i8::MIN; //~ ERROR attempt to negate with overflow
+pub const A: i8 = -std::i8::MIN;
+//~^ ERROR E0080
+//~| ERROR attempt to negate with overflow
+//~| ERROR constant evaluation error
 pub const B: i8 = A;
+//~^ ERROR E0080
 pub const C: u8 = A as u8;
+//~^ ERROR E0080
 pub const D: i8 = 50 - A;
+//~^ ERROR E0080
 
 fn main() {
+    let _ = (A, B, C, D);
 }
diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs
index e65194ab56f98..8bd759b6d3735 100644
--- a/src/test/compile-fail/const-err.rs
+++ b/src/test/compile-fail/const-err.rs
@@ -26,26 +26,5 @@ const FOO: u8 = [5u8][1];
 //~| index out of bounds: the len is 1 but the index is 1
 
 fn main() {
-    let a = -std::i8::MIN;
-    //~^ WARN this expression will panic at run-time
-    //~| attempt to negate with overflow
-    let b = 200u8 + 200u8 + 200u8;
-    //~^ WARN this expression will panic at run-time
-    //~^^ WARN this expression will panic at run-time
-    //~| attempt to add with overflow
-    let c = 200u8 * 4;
-    //~^ WARN this expression will panic at run-time
-    //~| attempt to multiply with overflow
-    let d = 42u8 - (42u8 + 1);
-    //~^ WARN this expression will panic at run-time
-    //~| attempt to subtract with overflow
-    let _e = [5u8][1];
-    //~^ WARN this expression will panic at run-time
-    //~| index out of bounds: the len is 1 but the index is 1
-    black_box(a);
-    black_box(b);
-    black_box(c);
-    black_box(d);
-
     black_box((FOO, FOO));
 }
diff --git a/src/test/compile-fail/const-err2.rs b/src/test/compile-fail/const-err2.rs
index 9889ca1392ac1..46b73371e56cf 100644
--- a/src/test/compile-fail/const-err2.rs
+++ b/src/test/compile-fail/const-err2.rs
@@ -8,6 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// needed because negating int::MIN will behave differently between
+// optimized compilation and unoptimized compilation and thus would
+// lead to different lints being emitted
+// compile-flags: -O
+
 #![feature(rustc_attrs)]
 #![allow(exceeding_bitshifts)]
 #![deny(const_err)]
@@ -18,13 +23,13 @@ fn black_box<T>(_: T) {
 
 fn main() {
     let a = -std::i8::MIN;
-    //~^ ERROR attempt to negate with overflow
+    //~^ ERROR const_err
     let b = 200u8 + 200u8 + 200u8;
-    //~^ ERROR attempt to add with overflow
+    //~^ ERROR const_err
     let c = 200u8 * 4;
-    //~^ ERROR attempt to multiply with overflow
+    //~^ ERROR const_err
     let d = 42u8 - (42u8 + 1);
-    //~^ ERROR attempt to subtract with overflow
+    //~^ ERROR const_err
     let _e = [5u8][1];
     black_box(a);
     black_box(b);
diff --git a/src/test/compile-fail/const-err3.rs b/src/test/compile-fail/const-err3.rs
new file mode 100644
index 0000000000000..9656af6002442
--- /dev/null
+++ b/src/test/compile-fail/const-err3.rs
@@ -0,0 +1,29 @@
+// Copyright 2012 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.
+
+#![feature(rustc_attrs)]
+#![deny(const_err)]
+
+fn black_box<T>(_: T) {
+    unimplemented!()
+}
+
+fn main() {
+    let b = 200u8 + 200u8 + 200u8;
+    //~^ ERROR const_err
+    let c = 200u8 * 4;
+    //~^ ERROR const_err
+    let d = 42u8 - (42u8 + 1);
+    //~^ ERROR const_err
+    let _e = [5u8][1];
+    black_box(b);
+    black_box(c);
+    black_box(d);
+}
diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs
deleted file mode 100644
index 058a8d0a1bd4f..0000000000000
--- a/src/test/compile-fail/const-eval-overflow.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 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.
-
-#![allow(unused_imports)]
-
-// Note: the relevant lint pass here runs before some of the constant
-// evaluation below (e.g. that performed by trans and llvm), so if you
-// change this warn to a deny, then the compiler will exit before
-// those errors are detected.
-
-#![warn(const_err)]
-
-use std::fmt;
-use std::{i8, i16, i32, i64, isize};
-use std::{u8, u16, u32, u64, usize};
-
-const VALS_I8: (i8, i8, i8, i8) =
-    (-i8::MIN,
-     //~^ ERROR constant evaluation error
-     //~| attempt to negate with overflow
-     i8::MIN - 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to subtract with overflow
-     i8::MAX + 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to add with overflow
-     i8::MIN * 2,
-     //~^ ERROR constant evaluation error
-     //~| attempt to multiply with overflow
-     );
-
-const VALS_I16: (i16, i16, i16, i16) =
-    (-i16::MIN,
-     //~^ ERROR constant evaluation error
-     //~| attempt to negate with overflow
-     i16::MIN - 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to subtract with overflow
-     i16::MAX + 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to add with overflow
-     i16::MIN * 2,
-     //~^ ERROR constant evaluation error
-     //~| attempt to multiply with overflow
-     );
-
-const VALS_I32: (i32, i32, i32, i32) =
-    (-i32::MIN,
-     //~^ ERROR constant evaluation error
-     //~| attempt to negate with overflow
-     i32::MIN - 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to subtract with overflow
-     i32::MAX + 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to add with overflow
-     i32::MIN * 2,
-     //~^ ERROR constant evaluation error
-     //~| attempt to multiply with overflow
-     );
-
-const VALS_I64: (i64, i64, i64, i64) =
-    (-i64::MIN,
-     //~^ ERROR constant evaluation error
-     //~| attempt to negate with overflow
-     i64::MIN - 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to subtract with overflow
-     i64::MAX + 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to add with overflow
-     i64::MAX * 2,
-     //~^ ERROR constant evaluation error
-     //~| attempt to multiply with overflow
-     );
-
-const VALS_U8: (u8, u8, u8, u8) =
-    ( //~ WARN constant evaluation error: attempt to subtract with overflow
-     -(u8::MIN as i8) as u8,
-     u8::MIN - 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to subtract with overflow
-     u8::MAX + 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to add with overflow
-     u8::MAX * 2,
-     //~^ ERROR constant evaluation error
-     //~| attempt to multiply with overflow
-     );
-
-const VALS_U16: (u16, u16, u16, u16) =
-    ( //~ WARN constant evaluation error: attempt to subtract with overflow
-     -(u16::MIN as i16) as u16,
-     u16::MIN - 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to subtract with overflow
-     u16::MAX + 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to add with overflow
-     u16::MAX * 2,
-     //~^ ERROR constant evaluation error
-     //~| attempt to multiply with overflow
-     );
-
-const VALS_U32: (u32, u32, u32, u32) =
-    ( //~ WARN constant evaluation error: attempt to subtract with overflow
-     -(u32::MIN as i32) as u32,
-     u32::MIN - 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to subtract with overflow
-     u32::MAX + 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to add with overflow
-     u32::MAX * 2,
-     //~^ ERROR constant evaluation error
-     //~| attempt to multiply with overflow
-     );
-
-const VALS_U64: (u64, u64, u64, u64) =
-    ( //~ WARN constant evaluation error: attempt to subtract with overflow
-     -(u64::MIN as i64) as u64,
-     u64::MIN - 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to subtract with overflow
-     u64::MAX + 1,
-     //~^ ERROR constant evaluation error
-     //~| attempt to add with overflow
-     u64::MAX * 2,
-     //~^ ERROR constant evaluation error
-     //~| attempt to multiply with overflow
-     );
-
-fn main() {
-    foo(VALS_I8);
-    foo(VALS_I16);
-    foo(VALS_I32);
-    foo(VALS_I64);
-
-    foo(VALS_U8);
-    foo(VALS_U16);
-    foo(VALS_U32);
-    foo(VALS_U64);
-}
-
-fn foo<T:fmt::Debug>(x: T) {
-    println!("{:?}", x);
-}
diff --git a/src/test/compile-fail/const-eval-overflow2.rs b/src/test/compile-fail/const-eval-overflow2.rs
new file mode 100644
index 0000000000000..a0d8f9672c05e
--- /dev/null
+++ b/src/test/compile-fail/const-eval-overflow2.rs
@@ -0,0 +1,91 @@
+// Copyright 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.
+
+#![allow(unused_imports)]
+
+// Note: the relevant lint pass here runs before some of the constant
+// evaluation below (e.g. that performed by trans and llvm), so if you
+// change this warn to a deny, then the compiler will exit before
+// those errors are detected.
+
+#![deny(const_err)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const VALS_I8: (i8,) =
+    (
+     i8::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to subtract with overflow
+     );
+
+const VALS_I16: (i16,) =
+    (
+     i16::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to subtract with overflow
+     );
+
+const VALS_I32: (i32,) =
+    (
+     i32::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to subtract with overflow
+     );
+
+const VALS_I64: (i64,) =
+    (
+     i64::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to subtract with overflow
+     );
+
+const VALS_U8: (u8,) =
+    (
+     u8::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to subtract with overflow
+     );
+
+const VALS_U16: (u16,) = (
+     u16::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to subtract with overflow
+     );
+
+const VALS_U32: (u32,) = (
+     u32::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to subtract with overflow
+     );
+
+const VALS_U64: (u64,) =
+    (
+     u64::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to subtract with overflow
+     );
+
+fn main() {
+    foo(VALS_I8);
+    foo(VALS_I16);
+    foo(VALS_I32);
+    foo(VALS_I64);
+
+    foo(VALS_U8);
+    foo(VALS_U16);
+    foo(VALS_U32);
+    foo(VALS_U64);
+}
+
+fn foo<T>(_: T) {
+}
diff --git a/src/test/compile-fail/const-eval-overflow2b.rs b/src/test/compile-fail/const-eval-overflow2b.rs
new file mode 100644
index 0000000000000..08128f90e532f
--- /dev/null
+++ b/src/test/compile-fail/const-eval-overflow2b.rs
@@ -0,0 +1,91 @@
+// Copyright 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.
+
+#![allow(unused_imports)]
+
+// Note: the relevant lint pass here runs before some of the constant
+// evaluation below (e.g. that performed by trans and llvm), so if you
+// change this warn to a deny, then the compiler will exit before
+// those errors are detected.
+
+#![deny(const_err)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const VALS_I8: (i8,) =
+    (
+     i8::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to add with overflow
+     );
+
+const VALS_I16: (i16,) =
+    (
+     i16::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to add with overflow
+     );
+
+const VALS_I32: (i32,) =
+    (
+     i32::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to add with overflow
+     );
+
+const VALS_I64: (i64,) =
+    (
+     i64::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to add with overflow
+     );
+
+const VALS_U8: (u8,) =
+    (
+     u8::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to add with overflow
+     );
+
+const VALS_U16: (u16,) = (
+     u16::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to add with overflow
+     );
+
+const VALS_U32: (u32,) = (
+     u32::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to add with overflow
+     );
+
+const VALS_U64: (u64,) =
+    (
+     u64::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to add with overflow
+     );
+
+fn main() {
+    foo(VALS_I8);
+    foo(VALS_I16);
+    foo(VALS_I32);
+    foo(VALS_I64);
+
+    foo(VALS_U8);
+    foo(VALS_U16);
+    foo(VALS_U32);
+    foo(VALS_U64);
+}
+
+fn foo<T>(_: T) {
+}
diff --git a/src/test/compile-fail/const-eval-overflow2c.rs b/src/test/compile-fail/const-eval-overflow2c.rs
new file mode 100644
index 0000000000000..31a1638cade17
--- /dev/null
+++ b/src/test/compile-fail/const-eval-overflow2c.rs
@@ -0,0 +1,91 @@
+// Copyright 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.
+
+#![allow(unused_imports)]
+
+// Note: the relevant lint pass here runs before some of the constant
+// evaluation below (e.g. that performed by trans and llvm), so if you
+// change this warn to a deny, then the compiler will exit before
+// those errors are detected.
+
+#![deny(const_err)]
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const VALS_I8: (i8,) =
+    (
+     i8::MIN * 2,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to multiply with overflow
+     );
+
+const VALS_I16: (i16,) =
+    (
+     i16::MIN * 2,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to multiply with overflow
+     );
+
+const VALS_I32: (i32,) =
+    (
+     i32::MIN * 2,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to multiply with overflow
+     );
+
+const VALS_I64: (i64,) =
+    (
+     i64::MIN * 2,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to multiply with overflow
+     );
+
+const VALS_U8: (u8,) =
+    (
+     u8::MAX * 2,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to multiply with overflow
+     );
+
+const VALS_U16: (u16,) = (
+     u16::MAX * 2,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to multiply with overflow
+     );
+
+const VALS_U32: (u32,) = (
+     u32::MAX * 2,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to multiply with overflow
+     );
+
+const VALS_U64: (u64,) =
+    (
+     u64::MAX * 2,
+     //~^ ERROR constant evaluation error
+     //~| ERROR attempt to multiply with overflow
+     );
+
+fn main() {
+    foo(VALS_I8);
+    foo(VALS_I16);
+    foo(VALS_I32);
+    foo(VALS_I64);
+
+    foo(VALS_U8);
+    foo(VALS_U16);
+    foo(VALS_U32);
+    foo(VALS_U64);
+}
+
+fn foo<T>(_: T) {
+}
diff --git a/src/test/compile-fail/const-integer-bool-ops.rs b/src/test/compile-fail/const-integer-bool-ops.rs
index 29bc665a22e7b..3065122af6a94 100644
--- a/src/test/compile-fail/const-integer-bool-ops.rs
+++ b/src/test/compile-fail/const-integer-bool-ops.rs
@@ -16,6 +16,7 @@ const X: usize = 42 && 39;
 //~| ERROR mismatched types
 //~| expected usize, found bool
 const ARR: [i32; X] = [99; 34];
+//~^ ERROR constant evaluation error
 
 const X1: usize = 42 || 39;
 //~^ ERROR mismatched types
@@ -25,6 +26,7 @@ const X1: usize = 42 || 39;
 //~| ERROR mismatched types
 //~| expected usize, found bool
 const ARR1: [i32; X1] = [99; 47];
+//~^ ERROR constant evaluation error
 
 const X2: usize = -42 || -39;
 //~^ ERROR mismatched types
@@ -34,6 +36,7 @@ const X2: usize = -42 || -39;
 //~| ERROR mismatched types
 //~| expected usize, found bool
 const ARR2: [i32; X2] = [99; 18446744073709551607];
+//~^ ERROR constant evaluation error
 
 const X3: usize = -42 && -39;
 //~^ ERROR mismatched types
@@ -43,36 +46,43 @@ const X3: usize = -42 && -39;
 //~| ERROR mismatched types
 //~| expected usize, found bool
 const ARR3: [i32; X3] = [99; 6];
+//~^ ERROR constant evaluation error
 
 const Y: usize = 42.0 == 42.0;
 //~^ ERROR mismatched types
 //~| expected usize, found bool
 const ARRR: [i32; Y] = [99; 1];
+//~^ ERROR constant evaluation error
 
 const Y1: usize = 42.0 >= 42.0;
 //~^ ERROR mismatched types
 //~| expected usize, found bool
 const ARRR1: [i32; Y1] = [99; 1];
+//~^ ERROR constant evaluation error
 
 const Y2: usize = 42.0 <= 42.0;
 //~^ ERROR mismatched types
 //~| expected usize, found bool
 const ARRR2: [i32; Y2] = [99; 1];
+//~^ ERROR constant evaluation error
 
 const Y3: usize = 42.0 > 42.0;
 //~^ ERROR mismatched types
 //~| expected usize, found bool
 const ARRR3: [i32; Y3] = [99; 0];
+//~^ ERROR constant evaluation error
 
 const Y4: usize = 42.0 < 42.0;
 //~^ ERROR mismatched types
 //~| expected usize, found bool
 const ARRR4: [i32; Y4] = [99; 0];
+//~^ ERROR constant evaluation error
 
 const Y5: usize = 42.0 != 42.0;
 //~^ ERROR mismatched types
 //~| expected usize, found bool
 const ARRR5: [i32; Y5] = [99; 0];
+//~^ ERROR constant evaluation error
 
 fn main() {
     let _ = ARR;
diff --git a/src/test/compile-fail/const-len-underflow-subspans.rs b/src/test/compile-fail/const-len-underflow-subspans.rs
index 7f2229b5a6534..85cc893aa133c 100644
--- a/src/test/compile-fail/const-len-underflow-subspans.rs
+++ b/src/test/compile-fail/const-len-underflow-subspans.rs
@@ -16,6 +16,6 @@ const TWO: usize = 2;
 
 fn main() {
     let a: [i8; ONE - TWO] = unimplemented!();
-    //~^ ERROR constant evaluation error [E0080]
+    //~^ ERROR constant evaluation error
     //~| attempt to subtract with overflow
 }
diff --git a/src/test/compile-fail/const-slice-oob.rs b/src/test/compile-fail/const-slice-oob.rs
index b1b4bfe2d1c39..179ea9e853f3a 100644
--- a/src/test/compile-fail/const-slice-oob.rs
+++ b/src/test/compile-fail/const-slice-oob.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#[deny(const_err)]
+
 const FOO: &'static[u32] = &[1, 2, 3];
 const BAR: u32 = FOO[5];
 //~^ ERROR constant evaluation error [E0080]
diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs
index b42c440f87d74..7596881ef9b9a 100644
--- a/src/test/compile-fail/const-tup-index-span.rs
+++ b/src/test/compile-fail/const-tup-index-span.rs
@@ -14,6 +14,7 @@ const TUP: (usize,) = 5usize << 64;
 //~^ ERROR mismatched types
 //~| expected tuple, found usize
 const ARR: [i32; TUP.0] = [];
+//~^ ERROR constant evaluation error
 
 fn main() {
 }
diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs
index 86cc2c144ac07..49f76c532df54 100644
--- a/src/test/compile-fail/eval-enum.rs
+++ b/src/test/compile-fail/eval-enum.rs
@@ -8,12 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-enum test {
-    div_zero = 1/0, //~ ERROR E0080
-                    //~| attempt to divide by zero
-    rem_zero = 1%0,
-    //~^ ERROR E0080
-    //~| attempt to calculate the remainder with a divisor of zero
+enum Test {
+    DivZero = 1/0,
+    //~^ attempt to divide by zero
+    //~| ERROR constant evaluation error
+    //~| WARN constant evaluation error
+    RemZero = 1%0,
+    //~^ attempt to calculate the remainder with a divisor of zero
+    //~| ERROR constant evaluation error
+    //~| WARN constant evaluation error
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/float-int-invalid-const-cast.rs b/src/test/compile-fail/float-int-invalid-const-cast.rs
deleted file mode 100644
index 1f07422e21be4..0000000000000
--- a/src/test/compile-fail/float-int-invalid-const-cast.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(i128_type)]
-#![allow(const_err)] // this test is only about hard errors
-
-use std::{f32, f64};
-
-// Forces evaluation of constants, triggering hard error
-fn force<T>(_: T) {}
-
-fn main() {
-    { const X: u16 = -1. as u16; force(X); } //~ ERROR constant evaluation error
-    { const X: u128 = -100. as u128; force(X); } //~ ERROR constant evaluation error
-
-    { const X: i8 = f32::NAN as i8; force(X); } //~ ERROR constant evaluation error
-    { const X: i32 = f32::NAN as i32; force(X); } //~ ERROR constant evaluation error
-    { const X: u64 = f32::NAN as u64; force(X); } //~ ERROR constant evaluation error
-    { const X: u128 = f32::NAN as u128; force(X); } //~ ERROR constant evaluation error
-
-    { const X: i8 = f32::INFINITY as i8; force(X); } //~ ERROR constant evaluation error
-    { const X: u32 = f32::INFINITY as u32; force(X); } //~ ERROR constant evaluation error
-    { const X: i128 = f32::INFINITY as i128; force(X); } //~ ERROR constant evaluation error
-    { const X: u128 = f32::INFINITY as u128; force(X); } //~ ERROR constant evaluation error
-
-    { const X: u8 = f32::NEG_INFINITY as u8; force(X); } //~ ERROR constant evaluation error
-    { const X: u16 = f32::NEG_INFINITY as u16; force(X); } //~ ERROR constant evaluation error
-    { const X: i64 = f32::NEG_INFINITY as i64; force(X); } //~ ERROR constant evaluation error
-    { const X: i128 = f32::NEG_INFINITY as i128; force(X); } //~ ERROR constant evaluation error
-
-    { const X: i8 = f64::NAN as i8; force(X); } //~ ERROR constant evaluation error
-    { const X: i32 = f64::NAN as i32; force(X); } //~ ERROR constant evaluation error
-    { const X: u64 = f64::NAN as u64; force(X); } //~ ERROR constant evaluation error
-    { const X: u128 = f64::NAN as u128; force(X); } //~ ERROR constant evaluation error
-
-    { const X: i8 = f64::INFINITY as i8; force(X); } //~ ERROR constant evaluation error
-    { const X: u32 = f64::INFINITY as u32; force(X); } //~ ERROR constant evaluation error
-    { const X: i128 = f64::INFINITY as i128; force(X); } //~ ERROR constant evaluation error
-    { const X: u128 = f64::INFINITY as u128; force(X); } //~ ERROR constant evaluation error
-
-    { const X: u8 = f64::NEG_INFINITY as u8; force(X); } //~ ERROR constant evaluation error
-    { const X: u16 = f64::NEG_INFINITY as u16; force(X); } //~ ERROR constant evaluation error
-    { const X: i64 = f64::NEG_INFINITY as i64; force(X); } //~ ERROR constant evaluation error
-    { const X: i128 = f64::NEG_INFINITY as i128; force(X); } //~ ERROR constant evaluation error
-
-    { const X: u8 = 256. as u8; force(X); } //~ ERROR constant evaluation error
-    { const X: i8 = -129. as i8; force(X); } //~ ERROR constant evaluation error
-    { const X: i8 = 128. as i8; force(X); } //~ ERROR constant evaluation error
-    { const X: i32 = 2147483648. as i32; force(X); } //~ ERROR constant evaluation error
-    { const X: i32 = -2147483904. as i32; force(X); } //~ ERROR constant evaluation error
-    { const X: u32 = 4294967296. as u32; force(X); } //~ ERROR constant evaluation error
-    { const X: u128 = 1e40 as u128; force(X); } //~ ERROR constant evaluation error
-    { const X: i128 = 1e40 as i128; force(X); } //~ ERROR constant evaluation error
-}
diff --git a/src/test/compile-fail/huge-array.rs b/src/test/compile-fail/huge-array.rs
index 029e9651cb3cd..7de84802e1d05 100644
--- a/src/test/compile-fail/huge-array.rs
+++ b/src/test/compile-fail/huge-array.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern:; 1518599999
+// error-pattern:; 1518600000
 
 fn generic<T: Copy>(t: T) {
     let s: [T; 1518600000] = [t; 1518600000];
diff --git a/src/test/compile-fail/issue-27895.rs b/src/test/compile-fail/issue-27895.rs
index ca8d5a1f70473..be76796c5c465 100644
--- a/src/test/compile-fail/issue-27895.rs
+++ b/src/test/compile-fail/issue-27895.rs
@@ -14,8 +14,7 @@ fn main() {
 
     match i {
         0...index => println!("winner"),
-        //~^ ERROR constant evaluation error
-        //~| non-constant path in constant expression
+        //~^ ERROR runtime values cannot be referenced in patterns
         _ => println!("hello"),
     }
 }
diff --git a/src/test/compile-fail/issue-31109.rs b/src/test/compile-fail/issue-31109.rs
index e3548d740717f..74121e3a420f9 100644
--- a/src/test/compile-fail/issue-31109.rs
+++ b/src/test/compile-fail/issue-31109.rs
@@ -12,6 +12,5 @@ fn main() {
     // FIXME(#31407) this error should go away, but in the meantime we test that it
     // is accompanied by a somewhat useful error message.
     let _: f64 = 1234567890123456789012345678901234567890e-340;
-    //~^ ERROR constant evaluation error
-    //~| unimplemented constant expression: could not evaluate float literal
+    //~^ ERROR could not evaluate float literal (see issue #31407)
 }
diff --git a/src/test/compile-fail/issue-39559-2.rs b/src/test/compile-fail/issue-39559-2.rs
index aa0750230649d..f01fd1fd8f144 100644
--- a/src/test/compile-fail/issue-39559-2.rs
+++ b/src/test/compile-fail/issue-39559-2.rs
@@ -22,7 +22,9 @@ impl Dim for Dim3 {
 
 fn main() {
     let array: [usize; Dim3::dim()]
-    //~^ ERROR calls in constants are limited to constant functions
+    //~^ ERROR E0015
+    //~| ERROR E0080
         = [0; Dim3::dim()];
-        //~^ ERROR calls in constants are limited to constant functions
+        //~^ ERROR E0015
+        //~| ERROR E0080
 }
diff --git a/src/test/compile-fail/issue-41255.rs b/src/test/compile-fail/issue-41255.rs
index 191b867e7a8b5..ac85e43cf4f05 100644
--- a/src/test/compile-fail/issue-41255.rs
+++ b/src/test/compile-fail/issue-41255.rs
@@ -18,33 +18,33 @@
 fn main() {
     let x = 42.0;
     match x {
-        5.0 => {}, //~ ERROR floating-point literals cannot be used
+        5.0 => {}, //~ ERROR floating-point types cannot be used in patterns
                    //~| WARNING hard error
-        5.0f32 => {}, //~ ERROR floating-point literals cannot be used
+        5.0f32 => {}, //~ ERROR floating-point types cannot be used in patterns
                       //~| WARNING hard error
-        -5.0 => {}, //~ ERROR floating-point literals cannot be used
+        -5.0 => {}, //~ ERROR floating-point types cannot be used in patterns
                     //~| WARNING hard error
-        1.0 .. 33.0 => {}, //~ ERROR floating-point literals cannot be used
+        1.0 .. 33.0 => {}, //~ ERROR floating-point types cannot be used in patterns
                            //~| WARNING hard error
-                           //~| ERROR floating-point literals cannot be used
+                           //~| ERROR floating-point types cannot be used in patterns
                            //~| WARNING hard error
-        39.0 ... 70.0 => {}, //~ ERROR floating-point literals cannot be used
+        39.0 ... 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns
                              //~| WARNING hard error
-                             //~| ERROR floating-point literals cannot be used
+                             //~| ERROR floating-point types cannot be used in patterns
                              //~| WARNING hard error
         _ => {},
     };
     let y = 5.0;
     // Same for tuples
     match (x, 5) {
-        (3.14, 1) => {}, //~ ERROR floating-point literals cannot be used
+        (3.14, 1) => {}, //~ ERROR floating-point types cannot be used
                          //~| WARNING hard error
         _ => {},
     }
     // Or structs
     struct Foo { x: f32 };
     match (Foo { x }) {
-        Foo { x: 2.0 } => {}, //~ ERROR floating-point literals cannot be used
+        Foo { x: 2.0 } => {}, //~ ERROR floating-point types cannot be used
                               //~| WARNING hard error
         _ => {},
     }
diff --git a/src/test/compile-fail/issue-43105.rs b/src/test/compile-fail/issue-43105.rs
index fb419d751b4e8..c0af3b4b9e695 100644
--- a/src/test/compile-fail/issue-43105.rs
+++ b/src/test/compile-fail/issue-43105.rs
@@ -12,6 +12,7 @@ fn xyz() -> u8 { 42 }
 
 const NUM: u8 = xyz();
 //~^ ERROR calls in constants are limited to constant functions, struct and enum constructors
+//~| ERROR constant evaluation error
 
 fn main() {
     match 1 {
diff --git a/src/test/compile-fail/issue-44578.rs b/src/test/compile-fail/issue-44578.rs
index a6ae21c3b5497..18cfb35113dc6 100644
--- a/src/test/compile-fail/issue-44578.rs
+++ b/src/test/compile-fail/issue-44578.rs
@@ -18,7 +18,7 @@ enum Bar<A, B> {
 }
 
 impl<A: Foo, B: Foo> Foo for Bar<A, B> {
-    const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; //~ ERROR constant evaluation
+    const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize];
 }
 
 impl Foo for u8 {
@@ -30,5 +30,5 @@ impl Foo for u16 {
 }
 
 fn main() {
-    println!("{}", <Bar<u16, u8> as Foo>::AMT);
+    println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ E0080
 }
diff --git a/src/test/compile-fail/issue-6804.rs b/src/test/compile-fail/issue-6804.rs
index 2a97945f26648..9191dfa155c65 100644
--- a/src/test/compile-fail/issue-6804.rs
+++ b/src/test/compile-fail/issue-6804.rs
@@ -12,18 +12,21 @@
 
 #![feature(slice_patterns)]
 #![allow(unused)]
+#![deny(illegal_floating_point_literal_pattern)]
 
 use std::f64::NAN;
 
 fn main() {
     let x = NAN;
     match x {
-        NAN => {}, //~ ERROR floating point constants cannot be used
+        NAN => {}, //~ ERROR floating-point types cannot be used
+        //~^ WARN this was previously accepted by the compiler but is being phased out
         _ => {},
     };
 
     match [x, 1.0] {
-        [NAN, _] => {}, //~ ERROR floating point constants cannot be used
+        [NAN, _] => {}, //~ ERROR floating-point types cannot be used
+        //~^ WARN this was previously accepted by the compiler but is being phased out
         _ => {},
     };
 }
diff --git a/src/test/compile-fail/issue-8460-const.rs b/src/test/compile-fail/issue-8460-const.rs
index d8ab48d1ec3e6..1d59e75a0f0f0 100644
--- a/src/test/compile-fail/issue-8460-const.rs
+++ b/src/test/compile-fail/issue-8460-const.rs
@@ -16,42 +16,62 @@ use std::thread;
 fn main() {
     assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
     //~^ ERROR attempt to divide with overflow
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
     //~^ ERROR attempt to divide with overflow
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
     //~^ ERROR attempt to divide with overflow
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
     //~^ ERROR attempt to divide with overflow
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
     //~^ ERROR attempt to divide with overflow
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
+    //~| ERROR constant evaluation error
     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
+    //~| ERROR constant evaluation error
 }
diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs
index 3e51550d1fa07..5ebfcc4926baa 100644
--- a/src/test/compile-fail/lint-exceeding-bitshifts.rs
+++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs
@@ -8,67 +8,50 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![deny(exceeding_bitshifts)]
+#![deny(exceeding_bitshifts, const_err)]
 #![allow(unused_variables)]
 #![allow(dead_code)]
-#![feature(const_indexing)]
 
 fn main() {
       let n = 1u8 << 7;
-      let n = 1u8 << 8;   //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1u8 << 8;   //~ ERROR: attempt to shift left with overflow
       let n = 1u16 << 15;
-      let n = 1u16 << 16; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1u16 << 16; //~ ERROR: attempt to shift left with overflow
       let n = 1u32 << 31;
-      let n = 1u32 << 32; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1u32 << 32; //~ ERROR: attempt to shift left with overflow
       let n = 1u64 << 63;
-      let n = 1u64 << 64; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1u64 << 64; //~ ERROR: attempt to shift left with overflow
       let n = 1i8 << 7;
-      let n = 1i8 << 8;   //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1i8 << 8;   //~ ERROR: attempt to shift left with overflow
       let n = 1i16 << 15;
-      let n = 1i16 << 16; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1i16 << 16; //~ ERROR: attempt to shift left with overflow
       let n = 1i32 << 31;
-      let n = 1i32 << 32; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1i32 << 32; //~ ERROR: attempt to shift left with overflow
       let n = 1i64 << 63;
-      let n = 1i64 << 64; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1i64 << 64; //~ ERROR: attempt to shift left with overflow
 
       let n = 1u8 >> 7;
-      let n = 1u8 >> 8;   //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1u8 >> 8;   //~ ERROR: attempt to shift right with overflow
       let n = 1u16 >> 15;
-      let n = 1u16 >> 16; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1u16 >> 16; //~ ERROR: attempt to shift right with overflow
       let n = 1u32 >> 31;
-      let n = 1u32 >> 32; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1u32 >> 32; //~ ERROR: attempt to shift right with overflow
       let n = 1u64 >> 63;
-      let n = 1u64 >> 64; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1u64 >> 64; //~ ERROR: attempt to shift right with overflow
       let n = 1i8 >> 7;
-      let n = 1i8 >> 8;   //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1i8 >> 8;   //~ ERROR: attempt to shift right with overflow
       let n = 1i16 >> 15;
-      let n = 1i16 >> 16; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1i16 >> 16; //~ ERROR: attempt to shift right with overflow
       let n = 1i32 >> 31;
-      let n = 1i32 >> 32; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1i32 >> 32; //~ ERROR: attempt to shift right with overflow
       let n = 1i64 >> 63;
-      let n = 1i64 >> 64; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = 1i64 >> 64; //~ ERROR: attempt to shift right with overflow
 
       let n = 1u8;
       let n = n << 7;
-      let n = n << 8; //~ ERROR: bitshift exceeds the type's number of bits
-
-      let n = 1u8 << -8; //~ ERROR: bitshift exceeds the type's number of bits
-      //~^ WARN: attempt to shift by a negative amount
-
-      let n = 1u8 << (4+3);
-      let n = 1u8 << (4+4); //~ ERROR: bitshift exceeds the type's number of bits
-
-      #[cfg(target_pointer_width = "32")]
-      const BITS: usize = 32;
-      #[cfg(target_pointer_width = "64")]
-      const BITS: usize = 64;
-
-      let n = 1_isize << BITS; //~ ERROR: bitshift exceeds the type's number of bits
-      let n = 1_usize << BITS; //~ ERROR: bitshift exceeds the type's number of bits
+      let n = n << 8; //~ ERROR: attempt to shift left with overflow
 
+      let n = 1u8 << -8; //~ ERROR: attempt to shift left with overflow
 
       let n = 1i8<<(1isize+-1);
-
-      let n = 1i64 >> [63][0];
-      let n = 1i64 >> [64][0]; //~ ERROR: bitshift exceeds the type's number of bits
 }
diff --git a/src/test/compile-fail/lint-exceeding-bitshifts2.rs b/src/test/compile-fail/lint-exceeding-bitshifts2.rs
new file mode 100644
index 0000000000000..3ba300eb7c4ab
--- /dev/null
+++ b/src/test/compile-fail/lint-exceeding-bitshifts2.rs
@@ -0,0 +1,27 @@
+// Copyright 2014 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.
+
+#![deny(exceeding_bitshifts, const_err)]
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+fn main() {
+      let n = 1u8 << (4+3);
+      let n = 1u8 << (4+4); //~ ERROR: attempt to shift left with overflow
+      let n = 1i64 >> [63][0];
+      let n = 1i64 >> [64][0]; // should be linting, needs to wait for const propagation
+
+      #[cfg(target_pointer_width = "32")]
+      const BITS: usize = 32;
+      #[cfg(target_pointer_width = "64")]
+      const BITS: usize = 64;
+      let n = 1_isize << BITS; //~ ERROR: attempt to shift left with overflow
+      let n = 1_usize << BITS; //~ ERROR: attempt to shift left with overflow
+}
diff --git a/src/test/compile-fail/lint-type-overflow2.rs b/src/test/compile-fail/lint-type-overflow2.rs
index 5593499758346..f7cf8a68d5684 100644
--- a/src/test/compile-fail/lint-type-overflow2.rs
+++ b/src/test/compile-fail/lint-type-overflow2.rs
@@ -17,7 +17,6 @@
 #[rustc_error]
 fn main() { //~ ERROR: compilation successful
     let x2: i8 = --128; //~ warn: literal out of range for i8
-    //~^ warn: attempt to negate with overflow
 
     let x = -3.40282357e+38_f32; //~ warn: literal out of range for f32
     let x =  3.40282357e+38_f32; //~ warn: literal out of range for f32
diff --git a/src/test/compile-fail/non-constant-in-const-path.rs b/src/test/compile-fail/non-constant-in-const-path.rs
index 737f80372debf..fe88ab4e11798 100644
--- a/src/test/compile-fail/non-constant-in-const-path.rs
+++ b/src/test/compile-fail/non-constant-in-const-path.rs
@@ -12,7 +12,6 @@ fn main() {
     let x = 0;
     match 1 {
         0 ... x => {}
-        //~^ ERROR constant evaluation error
-        //~| non-constant path in constant expression
+        //~^ ERROR runtime values cannot be referenced in patterns
     };
 }
diff --git a/src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs b/src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs
index 679be9ce219fe..ca9af78dd9936 100644
--- a/src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs
+++ b/src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs
@@ -28,7 +28,8 @@ fn main() {
     let x = 0.0;
     match x {
         f32::INFINITY => { }
-        //~^ ERROR floating point constants cannot be used in patterns
+        //~^ WARNING floating-point types cannot be used in patterns
+        //~| WARNING will become a hard error in a future release
         _ => { }
     }
 }
diff --git a/src/test/compile-fail/thread-local-in-ctfe.rs b/src/test/compile-fail/thread-local-in-ctfe.rs
index 720e15991c059..dc220bd1cc94f 100644
--- a/src/test/compile-fail/thread-local-in-ctfe.rs
+++ b/src/test/compile-fail/thread-local-in-ctfe.rs
@@ -16,7 +16,6 @@ static A: u32 = 1;
 static B: u32 = A;
 //~^ ERROR thread-local statics cannot be accessed at compile-time
 //~| ERROR cannot refer to other statics by value
-//~| WARN non-constant path in constant expression
 
 static C: &u32 = &A;
 //~^ ERROR thread-local statics cannot be accessed at compile-time
@@ -24,7 +23,6 @@ static C: &u32 = &A;
 const D: u32 = A;
 //~^ ERROR thread-local statics cannot be accessed at compile-time
 //~| ERROR cannot refer to statics by value
-//~| WARN non-constant path in constant expression
 
 const E: &u32 = &A;
 //~^ ERROR thread-local statics cannot be accessed at compile-time
diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs
index d6084d5a6da92..3fb5621c8ae3b 100644
--- a/src/test/mir-opt/end_region_2.rs
+++ b/src/test/mir-opt/end_region_2.rs
@@ -49,7 +49,7 @@ fn main() {
 //         _3 = &'23_1rs _2;
 //         StorageLive(_5);
 //         _5 = _2;
-//         switchInt(move _5) -> [0u8: bb5, otherwise: bb4];
+//         switchInt(move _5) -> [false: bb5, otherwise: bb4];
 //     }
 //     bb3: {
 //         ...
diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs
index 46548f1cce978..070bde8e3c3e6 100644
--- a/src/test/mir-opt/end_region_3.rs
+++ b/src/test/mir-opt/end_region_3.rs
@@ -51,7 +51,7 @@ fn main() {
 //         _3 = &'26_1rs _1;
 //         StorageLive(_5);
 //         _5 = _1;
-//         switchInt(move _5) -> [0u8: bb5, otherwise: bb4];
+//         switchInt(move _5) -> [false: bb5, otherwise: bb4];
 //     }
 //     bb3: {
 //         ...
diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs
index 0f1d714cc6fd2..6d9a27eeeb456 100644
--- a/src/test/mir-opt/end_region_9.rs
+++ b/src/test/mir-opt/end_region_9.rs
@@ -72,7 +72,7 @@ fn main() {
 //    bb4: {
 //        StorageLive(_7);
 //        _7 = _1;
-//        switchInt(move _7) -> [0u8: bb6, otherwise: bb5];
+//        switchInt(move _7) -> [false: bb6, otherwise: bb5];
 //    }
 //    bb5: {
 //        _0 = ();
diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs
index 2a82e2675b67d..83425a72f4598 100644
--- a/src/test/mir-opt/end_region_cyclic.rs
+++ b/src/test/mir-opt/end_region_cyclic.rs
@@ -103,7 +103,7 @@ fn query() -> bool { true }
 //         _11 = const query() -> [return: bb6, unwind: bb3];
 //     }
 //     bb6: {
-//         switchInt(move _11) -> [0u8: bb8, otherwise: bb7];
+//         switchInt(move _11) -> [false: bb8, otherwise: bb7];
 //     }
 //     bb7: {
 //         _0 = ();
diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs
index 3151c0643079c..a9eea26f46643 100644
--- a/src/test/mir-opt/issue-38669.rs
+++ b/src/test/mir-opt/issue-38669.rs
@@ -36,7 +36,7 @@ fn main() {
 //     bb3: {
 //         StorageLive(_4);
 //         _4 = _1;
-//         switchInt(move _4) -> [0u8: bb5, otherwise: bb4];
+//         switchInt(move _4) -> [false: bb5, otherwise: bb4];
 //     }
 //     bb4: {
 //         _0 = ();
diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs
index ba1b54d59f69a..53f178619975e 100644
--- a/src/test/mir-opt/match_false_edges.rs
+++ b/src/test/mir-opt/match_false_edges.rs
@@ -93,7 +93,7 @@ fn main() {
 //      _7 = const guard() -> [return: bb10, unwind: bb1];
 //  }
 //  bb10: { // end of guard
-//      switchInt(move _7) -> [0u8: bb11, otherwise: bb2];
+//      switchInt(move _7) -> [false: bb11, otherwise: bb2];
 //  }
 //  bb11: { // to pre_binding2
 //      falseEdges -> [real: bb5, imaginary: bb5];
@@ -157,7 +157,7 @@ fn main() {
 //      _7 = const guard() -> [return: bb10, unwind: bb1];
 //  }
 //  bb10: { // end of guard
-//      switchInt(move _7) -> [0u8: bb11, otherwise: bb2];
+//      switchInt(move _7) -> [false: bb11, otherwise: bb2];
 //  }
 //  bb11: { // to pre_binding2
 //      falseEdges -> [real: bb6, imaginary: bb5];
@@ -219,7 +219,7 @@ fn main() {
 //     _9 = const guard() -> [return: bb10, unwind: bb1];
 // }
 // bb10: { //end of guard
-//    switchInt(move _9) -> [0u8: bb11, otherwise: bb2];
+//    switchInt(move _9) -> [false: bb11, otherwise: bb2];
 // }
 // bb11: { // to pre_binding2
 //     falseEdges -> [real: bb5, imaginary: bb5];
@@ -240,7 +240,7 @@ fn main() {
 // }
 // bb14: { // end of guard2
 //     StorageDead(_12);
-//     switchInt(move _11) -> [0u8: bb15, otherwise: bb3];
+//     switchInt(move _11) -> [false: bb15, otherwise: bb3];
 // }
 // bb15: { // to pre_binding4
 //     falseEdges -> [real: bb7, imaginary: bb7];
diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs
index e9834305550c3..19d733d4f6b6a 100644
--- a/src/test/mir-opt/nll/region-liveness-basic.rs
+++ b/src/test/mir-opt/nll/region-liveness-basic.rs
@@ -41,7 +41,7 @@ fn main() {
 //            | Live variables on entry to bb2[0]: [_1, _3]
 //        _2 = &'_#2r _1[_3];
 //            | Live variables on entry to bb2[1]: [_2]
-//        switchInt(const true) -> [0u8: bb4, otherwise: bb3];
+//        switchInt(const true) -> [false: bb4, otherwise: bb3];
 //    }
 // END rustc.main.nll.0.mir
 // START rustc.main.nll.0.mir
diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs
index 35786643648eb..52d5892e6560b 100644
--- a/src/test/mir-opt/simplify_if.rs
+++ b/src/test/mir-opt/simplify_if.rs
@@ -17,7 +17,7 @@ fn main() {
 // END RUST SOURCE
 // START rustc.main.SimplifyBranches-initial.before.mir
 // bb0: {
-//     switchInt(const false) -> [0u8: bb3, otherwise: bb2];
+//     switchInt(const false) -> [false: bb3, otherwise: bb2];
 // }
 // END rustc.main.SimplifyBranches-initial.before.mir
 // START rustc.main.SimplifyBranches-initial.after.mir
diff --git a/src/test/compile-fail/const-index-feature-gate.rs b/src/test/run-pass/const-index-feature-gate.rs
similarity index 83%
rename from src/test/compile-fail/const-index-feature-gate.rs
rename to src/test/run-pass/const-index-feature-gate.rs
index 4f92770df289c..2e60634d15eed 100644
--- a/src/test/compile-fail/const-index-feature-gate.rs
+++ b/src/test/run-pass/const-index-feature-gate.rs
@@ -9,8 +9,7 @@
 // except according to those terms.
 
 const ARR: [usize; 1] = [2];
-const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR E0080
-                                    //~| unstable
+const ARR2: [i32; ARR[0]] = [5, 6];
 
 fn main() {
 }
diff --git a/src/test/run-pass/const-negation.rs b/src/test/run-pass/const-negation.rs
index 012fe0d95ec49..5c633eb6112ff 100644
--- a/src/test/run-pass/const-negation.rs
+++ b/src/test/run-pass/const-negation.rs
@@ -17,11 +17,13 @@ fn main() {
     const I: isize = -9223372036854775808isize;
     assert_eq!(::std::i32::MIN as u64, 0xffffffff80000000);
     assert_eq!(-2147483648isize as u64, 0xffffffff80000000);
+    assert_eq!(-2147483648i32 as u64, 0xffffffff80000000);
     assert_eq!(::std::i64::MIN as u64, 0x8000000000000000);
     #[cfg(target_pointer_width = "64")]
     assert_eq!(-9223372036854775808isize as u64, 0x8000000000000000);
     #[cfg(target_pointer_width = "32")]
     assert_eq!(-9223372036854775808isize as u64, 0);
+    assert_eq!(-9223372036854775808i32 as u64, 0);
     const J: usize = ::std::i32::MAX as usize;
     const K: usize = -1i32 as u32 as usize;
     const L: usize = ::std::i32::MIN as usize;
diff --git a/src/test/run-pass/ctfe/chained-constants-stackoverflow.rs b/src/test/run-pass/ctfe/chained-constants-stackoverflow.rs
new file mode 100644
index 0000000000000..813dd5fbb9941
--- /dev/null
+++ b/src/test/run-pass/ctfe/chained-constants-stackoverflow.rs
@@ -0,0 +1,364 @@
+// Copyright 2018 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.
+
+// https://github.com/rust-lang/rust/issues/34997
+
+pub const CST_1: u32 = 0;
+pub const CST_2: u32 = CST_1+1;
+pub const CST_3: u32 = CST_2+1;
+pub const CST_4: u32 = CST_3+1;
+pub const CST_5: u32 = CST_4+1;
+pub const CST_6: u32 = CST_5+1;
+pub const CST_7: u32 = CST_6+1;
+pub const CST_8: u32 = CST_7+1;
+pub const CST_9: u32 = CST_8+1;
+pub const CST_10: u32 = CST_9+1;
+pub const CST_11: u32 = CST_10+1;
+pub const CST_12: u32 = CST_11+1;
+pub const CST_13: u32 = CST_12+1;
+pub const CST_14: u32 = CST_13+1;
+pub const CST_15: u32 = CST_14+1;
+pub const CST_16: u32 = CST_15+1;
+pub const CST_17: u32 = CST_16+1;
+pub const CST_18: u32 = CST_17+1;
+pub const CST_19: u32 = CST_18+1;
+pub const CST_20: u32 = CST_19+1;
+pub const CST_21: u32 = CST_20+1;
+pub const CST_22: u32 = CST_21+1;
+pub const CST_23: u32 = CST_22+1;
+pub const CST_24: u32 = CST_23+1;
+pub const CST_25: u32 = CST_24+1;
+pub const CST_26: u32 = CST_25+1;
+pub const CST_27: u32 = CST_26+1;
+pub const CST_28: u32 = CST_27+1;
+pub const CST_29: u32 = CST_28+1;
+pub const CST_30: u32 = CST_29+1;
+pub const CST_31: u32 = CST_30+1;
+pub const CST_32: u32 = CST_31+1;
+pub const CST_33: u32 = CST_32+1;
+pub const CST_34: u32 = CST_33+1;
+pub const CST_35: u32 = CST_34+1;
+pub const CST_36: u32 = CST_35+1;
+pub const CST_37: u32 = CST_36+1;
+pub const CST_38: u32 = CST_37+1;
+pub const CST_39: u32 = CST_38+1;
+pub const CST_40: u32 = CST_39+1;
+pub const CST_41: u32 = CST_40+1;
+pub const CST_42: u32 = CST_41+1;
+pub const CST_43: u32 = CST_42+1;
+pub const CST_44: u32 = CST_43+1;
+pub const CST_45: u32 = CST_44+1;
+pub const CST_46: u32 = CST_45+1;
+pub const CST_47: u32 = CST_46+1;
+pub const CST_48: u32 = CST_47+1;
+pub const CST_49: u32 = CST_48+1;
+pub const CST_50: u32 = CST_49+1;
+pub const CST_51: u32 = CST_50+1;
+pub const CST_52: u32 = CST_51+1;
+pub const CST_53: u32 = CST_52+1;
+pub const CST_54: u32 = CST_53+1;
+pub const CST_55: u32 = CST_54+1;
+pub const CST_56: u32 = CST_55+1;
+pub const CST_57: u32 = CST_56+1;
+pub const CST_58: u32 = CST_57+1;
+pub const CST_59: u32 = CST_58+1;
+pub const CST_60: u32 = CST_59+1;
+pub const CST_61: u32 = CST_60+1;
+pub const CST_62: u32 = CST_61+1;
+pub const CST_63: u32 = CST_62+1;
+pub const CST_64: u32 = CST_63+1;
+pub const CST_65: u32 = CST_64+1;
+pub const CST_66: u32 = CST_65+1;
+pub const CST_67: u32 = CST_66+1;
+pub const CST_68: u32 = CST_67+1;
+pub const CST_69: u32 = CST_68+1;
+pub const CST_70: u32 = CST_69+1;
+pub const CST_71: u32 = CST_70+1;
+pub const CST_72: u32 = CST_71+1;
+pub const CST_73: u32 = CST_72+1;
+pub const CST_74: u32 = CST_73+1;
+pub const CST_75: u32 = CST_74+1;
+pub const CST_76: u32 = CST_75+1;
+pub const CST_77: u32 = CST_76+1;
+pub const CST_78: u32 = CST_77+1;
+pub const CST_79: u32 = CST_78+1;
+pub const CST_80: u32 = CST_79+1;
+pub const CST_81: u32 = CST_80+1;
+pub const CST_82: u32 = CST_81+1;
+pub const CST_83: u32 = CST_82+1;
+pub const CST_84: u32 = CST_83+1;
+pub const CST_85: u32 = CST_84+1;
+pub const CST_86: u32 = CST_85+1;
+pub const CST_87: u32 = CST_86+1;
+pub const CST_88: u32 = CST_87+1;
+pub const CST_89: u32 = CST_88+1;
+pub const CST_90: u32 = CST_89+1;
+pub const CST_91: u32 = CST_90+1;
+pub const CST_92: u32 = CST_91+1;
+pub const CST_93: u32 = CST_92+1;
+pub const CST_94: u32 = CST_93+1;
+pub const CST_95: u32 = CST_94+1;
+pub const CST_96: u32 = CST_95+1;
+pub const CST_97: u32 = CST_96+1;
+pub const CST_98: u32 = CST_97+1;
+pub const CST_99: u32 = CST_98+1;
+pub const CST_100: u32 = CST_99+1;
+pub const CST_101: u32 = CST_100+1;
+pub const CST_102: u32 = CST_101+1;
+pub const CST_103: u32 = CST_102+1;
+pub const CST_104: u32 = CST_103+1;
+pub const CST_105: u32 = CST_104+1;
+pub const CST_106: u32 = CST_105+1;
+pub const CST_107: u32 = CST_106+1;
+pub const CST_108: u32 = CST_107+1;
+pub const CST_109: u32 = CST_108+1;
+pub const CST_110: u32 = CST_109+1;
+pub const CST_111: u32 = CST_110+1;
+pub const CST_112: u32 = CST_111+1;
+pub const CST_113: u32 = CST_112+1;
+pub const CST_114: u32 = CST_113+1;
+pub const CST_115: u32 = CST_114+1;
+pub const CST_116: u32 = CST_115+1;
+pub const CST_117: u32 = CST_116+1;
+pub const CST_118: u32 = CST_117+1;
+pub const CST_119: u32 = CST_118+1;
+pub const CST_120: u32 = CST_119+1;
+pub const CST_121: u32 = CST_120+1;
+pub const CST_122: u32 = CST_121+1;
+pub const CST_123: u32 = CST_122+1;
+pub const CST_124: u32 = CST_123+1;
+pub const CST_125: u32 = CST_124+1;
+pub const CST_126: u32 = CST_125+1;
+pub const CST_127: u32 = CST_126+1;
+pub const CST_128: u32 = CST_127+1;
+pub const CST_129: u32 = CST_128+1;
+pub const CST_130: u32 = CST_129+1;
+pub const CST_131: u32 = CST_130+1;
+pub const CST_132: u32 = CST_131+1;
+pub const CST_133: u32 = CST_132+1;
+pub const CST_134: u32 = CST_133+1;
+pub const CST_135: u32 = CST_134+1;
+pub const CST_136: u32 = CST_135+1;
+pub const CST_137: u32 = CST_136+1;
+pub const CST_138: u32 = CST_137+1;
+pub const CST_139: u32 = CST_138+1;
+pub const CST_140: u32 = CST_139+1;
+pub const CST_141: u32 = CST_140+1;
+pub const CST_142: u32 = CST_141+1;
+pub const CST_143: u32 = CST_142+1;
+pub const CST_144: u32 = CST_143+1;
+pub const CST_145: u32 = CST_144+1;
+pub const CST_146: u32 = CST_145+1;
+pub const CST_147: u32 = CST_146+1;
+pub const CST_148: u32 = CST_147+1;
+pub const CST_149: u32 = CST_148+1;
+pub const CST_150: u32 = CST_149+1;
+pub const CST_151: u32 = CST_150+1;
+pub const CST_152: u32 = CST_151+1;
+pub const CST_153: u32 = CST_152+1;
+pub const CST_154: u32 = CST_153+1;
+pub const CST_155: u32 = CST_154+1;
+pub const CST_156: u32 = CST_155+1;
+pub const CST_157: u32 = CST_156+1;
+pub const CST_158: u32 = CST_157+1;
+pub const CST_159: u32 = CST_158+1;
+pub const CST_160: u32 = CST_159+1;
+pub const CST_161: u32 = CST_160+1;
+pub const CST_162: u32 = CST_161+1;
+pub const CST_163: u32 = CST_162+1;
+pub const CST_164: u32 = CST_163+1;
+pub const CST_165: u32 = CST_164+1;
+pub const CST_166: u32 = CST_165+1;
+pub const CST_167: u32 = CST_166+1;
+pub const CST_168: u32 = CST_167+1;
+pub const CST_169: u32 = CST_168+1;
+pub const CST_170: u32 = CST_169+1;
+pub const CST_171: u32 = CST_170+1;
+pub const CST_172: u32 = CST_171+1;
+pub const CST_173: u32 = CST_172+1;
+pub const CST_174: u32 = CST_173+1;
+pub const CST_175: u32 = CST_174+1;
+pub const CST_176: u32 = CST_175+1;
+pub const CST_177: u32 = CST_176+1;
+pub const CST_178: u32 = CST_177+1;
+pub const CST_179: u32 = CST_178+1;
+pub const CST_180: u32 = CST_179+1;
+pub const CST_181: u32 = CST_180+1;
+pub const CST_182: u32 = CST_181+1;
+pub const CST_183: u32 = CST_182+1;
+pub const CST_184: u32 = CST_183+1;
+pub const CST_185: u32 = CST_184+1;
+pub const CST_186: u32 = CST_185+1;
+pub const CST_187: u32 = CST_186+1;
+pub const CST_188: u32 = CST_187+1;
+pub const CST_189: u32 = CST_188+1;
+pub const CST_190: u32 = CST_189+1;
+pub const CST_191: u32 = CST_190+1;
+pub const CST_192: u32 = CST_191+1;
+pub const CST_193: u32 = CST_192+1;
+pub const CST_194: u32 = CST_193+1;
+pub const CST_195: u32 = CST_194+1;
+pub const CST_196: u32 = CST_195+1;
+pub const CST_197: u32 = CST_196+1;
+pub const CST_198: u32 = CST_197+1;
+pub const CST_199: u32 = CST_198+1;
+pub const CST_200: u32 = CST_199+1;
+pub const CST_201: u32 = CST_200+1;
+pub const CST_202: u32 = CST_201+1;
+pub const CST_203: u32 = CST_202+1;
+pub const CST_204: u32 = CST_203+1;
+pub const CST_205: u32 = CST_204+1;
+pub const CST_206: u32 = CST_205+1;
+pub const CST_207: u32 = CST_206+1;
+pub const CST_208: u32 = CST_207+1;
+pub const CST_209: u32 = CST_208+1;
+pub const CST_210: u32 = CST_209+1;
+pub const CST_211: u32 = CST_210+1;
+pub const CST_212: u32 = CST_211+1;
+pub const CST_213: u32 = CST_212+1;
+pub const CST_214: u32 = CST_213+1;
+pub const CST_215: u32 = CST_214+1;
+pub const CST_216: u32 = CST_215+1;
+pub const CST_217: u32 = CST_216+1;
+pub const CST_218: u32 = CST_217+1;
+pub const CST_219: u32 = CST_218+1;
+pub const CST_220: u32 = CST_219+1;
+pub const CST_221: u32 = CST_220+1;
+pub const CST_222: u32 = CST_221+1;
+pub const CST_223: u32 = CST_222+1;
+pub const CST_224: u32 = CST_223+1;
+pub const CST_225: u32 = CST_224+1;
+pub const CST_226: u32 = CST_225+1;
+pub const CST_227: u32 = CST_226+1;
+pub const CST_228: u32 = CST_227+1;
+pub const CST_229: u32 = CST_228+1;
+pub const CST_230: u32 = CST_229+1;
+pub const CST_231: u32 = CST_230+1;
+pub const CST_232: u32 = CST_231+1;
+pub const CST_233: u32 = CST_232+1;
+pub const CST_234: u32 = CST_233+1;
+pub const CST_235: u32 = CST_234+1;
+pub const CST_236: u32 = CST_235+1;
+pub const CST_237: u32 = CST_236+1;
+pub const CST_238: u32 = CST_237+1;
+pub const CST_239: u32 = CST_238+1;
+pub const CST_240: u32 = CST_239+1;
+pub const CST_241: u32 = CST_240+1;
+pub const CST_242: u32 = CST_241+1;
+pub const CST_243: u32 = CST_242+1;
+pub const CST_244: u32 = CST_243+1;
+pub const CST_245: u32 = CST_244+1;
+pub const CST_246: u32 = CST_245+1;
+pub const CST_247: u32 = CST_246+1;
+pub const CST_248: u32 = CST_247+1;
+pub const CST_249: u32 = CST_248+1;
+pub const CST_250: u32 = CST_249+1;
+pub const CST_251: u32 = CST_250+1;
+pub const CST_252: u32 = CST_251+1;
+pub const CST_253: u32 = CST_252+1;
+pub const CST_254: u32 = CST_253+1;
+pub const CST_255: u32 = CST_254+1;
+pub const CST_256: u32 = CST_255+1;
+pub const CST_257: u32 = CST_256+1;
+pub const CST_258: u32 = CST_257+1;
+pub const CST_259: u32 = CST_258+1;
+pub const CST_260: u32 = CST_259+1;
+pub const CST_261: u32 = CST_260+1;
+pub const CST_262: u32 = CST_261+1;
+pub const CST_263: u32 = CST_262+1;
+pub const CST_264: u32 = CST_263+1;
+pub const CST_265: u32 = CST_264+1;
+pub const CST_266: u32 = CST_265+1;
+pub const CST_267: u32 = CST_266+1;
+pub const CST_268: u32 = CST_267+1;
+pub const CST_269: u32 = CST_268+1;
+pub const CST_270: u32 = CST_269+1;
+pub const CST_271: u32 = CST_270+1;
+pub const CST_272: u32 = CST_271+1;
+pub const CST_273: u32 = CST_272+1;
+pub const CST_274: u32 = CST_273+1;
+pub const CST_275: u32 = CST_274+1;
+pub const CST_276: u32 = CST_275+1;
+pub const CST_277: u32 = CST_276+1;
+pub const CST_278: u32 = CST_277+1;
+pub const CST_279: u32 = CST_278+1;
+pub const CST_280: u32 = CST_279+1;
+pub const CST_281: u32 = CST_280+1;
+pub const CST_282: u32 = CST_281+1;
+pub const CST_283: u32 = CST_282+1;
+pub const CST_284: u32 = CST_283+1;
+pub const CST_285: u32 = CST_284+1;
+pub const CST_286: u32 = CST_285+1;
+pub const CST_287: u32 = CST_286+1;
+pub const CST_288: u32 = CST_287+1;
+pub const CST_289: u32 = CST_288+1;
+pub const CST_290: u32 = CST_289+1;
+pub const CST_291: u32 = CST_290+1;
+pub const CST_292: u32 = CST_291+1;
+pub const CST_293: u32 = CST_292+1;
+pub const CST_294: u32 = CST_293+1;
+pub const CST_295: u32 = CST_294+1;
+pub const CST_296: u32 = CST_295+1;
+pub const CST_297: u32 = CST_296+1;
+pub const CST_298: u32 = CST_297+1;
+pub const CST_299: u32 = CST_298+1;
+pub const CST_300: u32 = CST_299+1;
+pub const CST_301: u32 = CST_300+1;
+pub const CST_302: u32 = CST_301+1;
+pub const CST_303: u32 = CST_302+1;
+pub const CST_304: u32 = CST_303+1;
+pub const CST_305: u32 = CST_304+1;
+pub const CST_306: u32 = CST_305+1;
+pub const CST_307: u32 = CST_306+1;
+pub const CST_308: u32 = CST_307+1;
+pub const CST_309: u32 = CST_308+1;
+pub const CST_310: u32 = CST_309+1;
+pub const CST_311: u32 = CST_310+1;
+pub const CST_312: u32 = CST_311+1;
+pub const CST_313: u32 = CST_312+1;
+pub const CST_314: u32 = CST_313+1;
+pub const CST_315: u32 = CST_314+1;
+pub const CST_316: u32 = CST_315+1;
+pub const CST_317: u32 = CST_316+1;
+pub const CST_318: u32 = CST_317+1;
+pub const CST_319: u32 = CST_318+1;
+pub const CST_320: u32 = CST_319+1;
+pub const CST_321: u32 = CST_320+1;
+pub const CST_322: u32 = CST_321+1;
+pub const CST_323: u32 = CST_322+1;
+pub const CST_324: u32 = CST_323+1;
+pub const CST_325: u32 = CST_324+1;
+pub const CST_326: u32 = CST_325+1;
+pub const CST_327: u32 = CST_326+1;
+pub const CST_328: u32 = CST_327+1;
+pub const CST_329: u32 = CST_328+1;
+pub const CST_330: u32 = CST_329+1;
+pub const CST_331: u32 = CST_330+1;
+pub const CST_332: u32 = CST_331+1;
+pub const CST_333: u32 = CST_332+1;
+pub const CST_334: u32 = CST_333+1;
+pub const CST_335: u32 = CST_334+1;
+pub const CST_336: u32 = CST_335+1;
+pub const CST_337: u32 = CST_336+1;
+pub const CST_338: u32 = CST_337+1;
+pub const CST_339: u32 = CST_338+1;
+pub const CST_340: u32 = CST_339+1;
+pub const CST_341: u32 = CST_340+1;
+pub const CST_342: u32 = CST_341+1;
+pub const CST_343: u32 = CST_342+1;
+pub const CST_344: u32 = CST_343+1;
+pub const CST_345: u32 = CST_344+1;
+pub const CST_346: u32 = CST_345+1;
+pub const CST_347: u32 = CST_346+1;
+pub const CST_348: u32 = CST_347+1;
+pub const CST_349: u32 = CST_348+1;
+pub const CST_350: u32 = CST_349+1;
+
+fn main() {}
diff --git a/src/test/run-pass/ctfe/deref_in_pattern.rs b/src/test/run-pass/ctfe/deref_in_pattern.rs
new file mode 100644
index 0000000000000..4ccfa0338f393
--- /dev/null
+++ b/src/test/run-pass/ctfe/deref_in_pattern.rs
@@ -0,0 +1,20 @@
+// Copyright 2018 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.
+
+// https://github.com/rust-lang/rust/issues/25574
+
+const A: [u8; 4] = *b"fooo";
+
+fn main() {
+    match *b"xxxx" {
+        A => {},
+        _ => {}
+    }
+}
diff --git a/src/test/run-pass/ctfe/ice-48279.rs b/src/test/run-pass/ctfe/ice-48279.rs
new file mode 100644
index 0000000000000..c435e5fdaab4a
--- /dev/null
+++ b/src/test/run-pass/ctfe/ice-48279.rs
@@ -0,0 +1,34 @@
+// Copyright 2018 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.
+
+// https://github.com/rust-lang/rust/issues/48279
+
+#![feature(const_fn)]
+
+#[derive(PartialEq, Eq)]
+pub struct NonZeroU32 {
+    value: u32
+}
+
+impl NonZeroU32 {
+    const unsafe fn new_unchecked(value: u32) -> Self {
+        NonZeroU32 { value }
+    }
+}
+
+//pub const FOO_ATOM: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(7) };
+pub const FOO_ATOM: NonZeroU32 = unsafe { NonZeroU32 { value: 7 } };
+
+fn main() {
+    match None {
+        Some(FOO_ATOM) => {}
+        _ => {}
+    }
+}
diff --git a/src/test/run-pass/ctfe/issue-broken-mir.rs b/src/test/run-pass/ctfe/issue-broken-mir.rs
new file mode 100644
index 0000000000000..6ed0c7c0d5dc4
--- /dev/null
+++ b/src/test/run-pass/ctfe/issue-broken-mir.rs
@@ -0,0 +1,18 @@
+// Copyright 2018 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.
+
+// https://github.com/rust-lang/rust/issues/27918
+
+fn main() {
+    match b"    " {
+        b"1234" => {},
+        _ => {},
+    }
+}
diff --git a/src/test/run-pass/ctfe/match-const-fn-structs.rs b/src/test/run-pass/ctfe/match-const-fn-structs.rs
new file mode 100644
index 0000000000000..0bb253d1a6455
--- /dev/null
+++ b/src/test/run-pass/ctfe/match-const-fn-structs.rs
@@ -0,0 +1,31 @@
+// Copyright 2018 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.
+
+// https://github.com/rust-lang/rust/issues/46114
+
+#![feature(const_fn)]
+
+#[derive(Eq, PartialEq)]
+struct A { value: u32 }
+
+const fn new(value: u32) -> A {
+    A { value }
+}
+
+const A_1: A = new(1);
+const A_2: A = new(2);
+
+fn main() {
+    let a_str = match new(42) {
+        A_1 => "A 1",
+        A_2 => "A 2",
+        _ => "Unknown A",
+    };
+}
diff --git a/src/test/run-pass/ctfe/mozjs-error.rs b/src/test/run-pass/ctfe/mozjs-error.rs
new file mode 100644
index 0000000000000..9c8a4b5ae6a2d
--- /dev/null
+++ b/src/test/run-pass/ctfe/mozjs-error.rs
@@ -0,0 +1,37 @@
+// Copyright 2018 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.
+
+struct CustomAutoRooterVFTable {
+    trace: unsafe extern "C" fn(this: *mut i32, trc: *mut u32),
+}
+
+unsafe trait CustomAutoTraceable: Sized {
+    const vftable: CustomAutoRooterVFTable = CustomAutoRooterVFTable {
+        trace: Self::trace,
+    };
+
+    unsafe extern "C" fn trace(this: *mut i32, trc: *mut u32) {
+        let this = this as *const Self;
+        let this = this.as_ref().unwrap();
+        Self::do_trace(this, trc);
+    }
+
+    fn do_trace(&self, trc: *mut u32);
+}
+
+unsafe impl CustomAutoTraceable for () {
+    fn do_trace(&self, _: *mut u32) {
+        // nop
+    }
+}
+
+fn main() {
+    let _ = <()>::vftable;
+}
diff --git a/src/test/run-pass/ctfe/non-scalar-cast.rs b/src/test/run-pass/ctfe/non-scalar-cast.rs
new file mode 100644
index 0000000000000..ff4474f47c9f3
--- /dev/null
+++ b/src/test/run-pass/ctfe/non-scalar-cast.rs
@@ -0,0 +1,17 @@
+// Copyright 2018 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.
+
+// https://github.com/rust-lang/rust/issues/37448
+
+fn main() {
+    struct A;
+    const FOO: &A = &(A as A);
+    let _x = FOO;
+}
diff --git a/src/test/run-pass/ctfe/promotion.rs b/src/test/run-pass/ctfe/promotion.rs
new file mode 100644
index 0000000000000..2d228408254aa
--- /dev/null
+++ b/src/test/run-pass/ctfe/promotion.rs
@@ -0,0 +1,17 @@
+// Copyright 2018 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.
+
+fn foo(_: &'static [&'static str]) {}
+fn bar(_: &'static [&'static str; 3]) {}
+
+fn main() {
+    foo(&["a", "b", "c"]);
+    bar(&["d", "e", "f"]);
+}
diff --git a/src/test/run-pass/ctfe/references.rs b/src/test/run-pass/ctfe/references.rs
new file mode 100644
index 0000000000000..ad7dbeb79c721
--- /dev/null
+++ b/src/test/run-pass/ctfe/references.rs
@@ -0,0 +1,34 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const FOO: &[u8] = b"foo";
+const BAR: &[u8] = &[1, 2, 3];
+
+const BOO: &i32 = &42;
+
+fn main() {
+    match &[1u8, 2, 3] as &[u8] {
+        FOO => panic!("a"),
+        BAR => println!("b"),
+        _ => panic!("c"),
+    }
+
+    match b"foo" as &[u8] {
+        FOO => println!("a"),
+        BAR => panic!("b"),
+        _ => panic!("c"),
+    }
+
+    match &43 {
+        &42 => panic!(),
+        BOO => panic!(),
+        _ => println!("d"),
+    }
+}
diff --git a/src/test/run-pass/ctfe/repeat_match.rs b/src/test/run-pass/ctfe/repeat_match.rs
new file mode 100644
index 0000000000000..dedf5defebb7c
--- /dev/null
+++ b/src/test/run-pass/ctfe/repeat_match.rs
@@ -0,0 +1,20 @@
+// Copyright 2018 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.
+
+// https://github.com/rust-lang/rust/issues/45044
+
+const X: [u8; 1] = [0; 1];
+
+fn main() {
+    match &X {
+        &X => println!("a"),
+        _ => println!("b"),
+    };
+}
diff --git a/src/test/run-pass/ctfe/return-in-const-fn.rs b/src/test/run-pass/ctfe/return-in-const-fn.rs
new file mode 100644
index 0000000000000..d57d3bcb49aa8
--- /dev/null
+++ b/src/test/run-pass/ctfe/return-in-const-fn.rs
@@ -0,0 +1,19 @@
+// Copyright 2018 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.
+
+// https://github.com/rust-lang/rust/issues/43754
+
+#![feature(const_fn)]
+const fn foo(x: usize) -> usize {
+    return x;
+}
+fn main() {
+    [0; foo(2)];
+}
diff --git a/src/test/run-pass/ctfe/tuple-struct-constructors.rs b/src/test/run-pass/ctfe/tuple-struct-constructors.rs
new file mode 100644
index 0000000000000..ecc5d37663679
--- /dev/null
+++ b/src/test/run-pass/ctfe/tuple-struct-constructors.rs
@@ -0,0 +1,20 @@
+// Copyright 2018 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.
+
+// https://github.com/rust-lang/rust/issues/41898
+
+#![feature(nonzero, const_fn)]
+extern crate core;
+use core::nonzero::NonZero;
+
+fn main() {
+    const FOO: NonZero<u64> = unsafe { NonZero::new_unchecked(2) };
+    if let FOO = FOO {}
+}
diff --git a/src/test/run-pass/ctfe/union-ice.rs b/src/test/run-pass/ctfe/union-ice.rs
new file mode 100644
index 0000000000000..f83f49f298b90
--- /dev/null
+++ b/src/test/run-pass/ctfe/union-ice.rs
@@ -0,0 +1,45 @@
+// Copyright 2018 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.
+
+#![feature(const_fn)]
+
+type Field1 = i32;
+type Field2 = f32;
+type Field3 = i64;
+
+union DummyUnion {
+    field1: Field1,
+    field2: Field2,
+    field3: Field3,
+}
+
+const FLOAT1_AS_I32: i32 = 1065353216;
+const UNION: DummyUnion = DummyUnion { field1: FLOAT1_AS_I32 };
+
+const fn read_field1() -> Field1 {
+    const FIELD1: Field1 = unsafe { UNION.field1 };
+    FIELD1
+}
+
+const fn read_field2() -> Field2 {
+    const FIELD2: Field2 = unsafe { UNION.field2 };
+    FIELD2
+}
+
+const fn read_field3() -> Field3 {
+    const FIELD3: Field3 = unsafe { UNION.field3 };
+    FIELD3
+}
+
+fn main() {
+    assert_eq!(read_field1(), FLOAT1_AS_I32);
+    assert_eq!(read_field2(), 1.0);
+    assert_eq!(read_field3(), unsafe { UNION.field3 });
+}
diff --git a/src/test/run-pass/float-int-invalid-const-cast.rs b/src/test/run-pass/float-int-invalid-const-cast.rs
new file mode 100644
index 0000000000000..80ab12482cbb7
--- /dev/null
+++ b/src/test/run-pass/float-int-invalid-const-cast.rs
@@ -0,0 +1,61 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(i128_type)]
+#![deny(const_err)]
+
+use std::{f32, f64};
+
+// Forces evaluation of constants, triggering hard error
+fn force<T>(_: T) {}
+
+fn main() {
+    { const X: u16 = -1. as u16; force(X); }
+    { const X: u128 = -100. as u128; force(X); }
+
+    { const X: i8 = f32::NAN as i8; force(X); }
+    { const X: i32 = f32::NAN as i32; force(X); }
+    { const X: u64 = f32::NAN as u64; force(X); }
+    { const X: u128 = f32::NAN as u128; force(X); }
+
+    { const X: i8 = f32::INFINITY as i8; force(X); }
+    { const X: u32 = f32::INFINITY as u32; force(X); }
+    { const X: i128 = f32::INFINITY as i128; force(X); }
+    { const X: u128 = f32::INFINITY as u128; force(X); }
+
+    { const X: u8 = f32::NEG_INFINITY as u8; force(X); }
+    { const X: u16 = f32::NEG_INFINITY as u16; force(X); }
+    { const X: i64 = f32::NEG_INFINITY as i64; force(X); }
+    { const X: i128 = f32::NEG_INFINITY as i128; force(X); }
+
+    { const X: i8 = f64::NAN as i8; force(X); }
+    { const X: i32 = f64::NAN as i32; force(X); }
+    { const X: u64 = f64::NAN as u64; force(X); }
+    { const X: u128 = f64::NAN as u128; force(X); }
+
+    { const X: i8 = f64::INFINITY as i8; force(X); }
+    { const X: u32 = f64::INFINITY as u32; force(X); }
+    { const X: i128 = f64::INFINITY as i128; force(X); }
+    { const X: u128 = f64::INFINITY as u128; force(X); }
+
+    { const X: u8 = f64::NEG_INFINITY as u8; force(X); }
+    { const X: u16 = f64::NEG_INFINITY as u16; force(X); }
+    { const X: i64 = f64::NEG_INFINITY as i64; force(X); }
+    { const X: i128 = f64::NEG_INFINITY as i128; force(X); }
+
+    { const X: u8 = 256. as u8; force(X); }
+    { const X: i8 = -129. as i8; force(X); }
+    { const X: i8 = 128. as i8; force(X); }
+    { const X: i32 = 2147483648. as i32; force(X); }
+    { const X: i32 = -2147483904. as i32; force(X); }
+    { const X: u32 = 4294967296. as u32; force(X); }
+    { const X: u128 = 1e40 as u128; force(X); }
+    { const X: i128 = 1e40 as i128; force(X); }
+}
diff --git a/src/test/ui/const-eval-overflow-2.rs b/src/test/ui/const-eval-overflow-2.rs
index 6b7f631ff4c8d..885edb55ed86c 100644
--- a/src/test/ui/const-eval-overflow-2.rs
+++ b/src/test/ui/const-eval-overflow-2.rs
@@ -19,8 +19,7 @@ use std::{u8, u16, u32, u64, usize};
 
 const NEG_128: i8 = -128;
 const NEG_NEG_128: i8 = -NEG_128;
-//~^ ERROR constant evaluation error
-//~| attempt to negate with overflow
+//~^ ERROR E0080
 
 fn main() {
     match -128i8 {
diff --git a/src/test/ui/const-eval-overflow-2.stderr b/src/test/ui/const-eval-overflow-2.stderr
index 05a286d4e7eb3..f376de7cc4c17 100644
--- a/src/test/ui/const-eval-overflow-2.stderr
+++ b/src/test/ui/const-eval-overflow-2.stderr
@@ -5,7 +5,7 @@ LL | const NEG_NEG_128: i8 = -NEG_128;
    |                         ^^^^^^^^ attempt to negate with overflow
    |
 note: for pattern here
-  --> $DIR/const-eval-overflow-2.rs:27:9
+  --> $DIR/const-eval-overflow-2.rs:26:9
    |
 LL |         NEG_NEG_128 => println!("A"),
    |         ^^^^^^^^^^^
diff --git a/src/test/ui/const-eval-overflow-4.rs b/src/test/ui/const-eval-overflow-4.rs
index 4423fdec33a85..24e178152eef0 100644
--- a/src/test/ui/const-eval-overflow-4.rs
+++ b/src/test/ui/const-eval-overflow-4.rs
@@ -21,8 +21,8 @@ use std::{u8, u16, u32, u64, usize};
 
 const A_I8_T
     : [u32; (i8::MAX as i8 + 1i8) as usize]
-    //~^ ERROR constant evaluation error
-    //~| WARNING constant evaluation error
+    //~^ ERROR E0080
+    //~| WARN attempt to add with overflow
     = [0; (i8::MAX as usize) + 1];
 
 fn main() {
diff --git a/src/test/ui/const-eval-overflow-4.stderr b/src/test/ui/const-eval-overflow-4.stderr
index b907a47afb963..14753038fef04 100644
--- a/src/test/ui/const-eval-overflow-4.stderr
+++ b/src/test/ui/const-eval-overflow-4.stderr
@@ -1,8 +1,8 @@
-warning: constant evaluation error: attempt to add with overflow
+warning: attempt to add with overflow
   --> $DIR/const-eval-overflow-4.rs:23:13
    |
 LL |     : [u32; (i8::MAX as i8 + 1i8) as usize]
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^^
    |
    = note: #[warn(const_err)] on by default
 
diff --git a/src/test/ui/const-eval/conditional_array_execution.rs b/src/test/ui/const-eval/conditional_array_execution.rs
new file mode 100644
index 0000000000000..324bcf60e8ff6
--- /dev/null
+++ b/src/test/ui/const-eval/conditional_array_execution.rs
@@ -0,0 +1,18 @@
+// Copyright 2018 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.
+
+const X: u32 = 5;
+const Y: u32 = 6;
+const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
+//~^ WARN attempt to subtract with overflow
+
+fn main() {
+    println!("{}", FOO); //~ E0080
+}
diff --git a/src/test/ui/const-eval/conditional_array_execution.stderr b/src/test/ui/const-eval/conditional_array_execution.stderr
new file mode 100644
index 0000000000000..4cf12e222831c
--- /dev/null
+++ b/src/test/ui/const-eval/conditional_array_execution.stderr
@@ -0,0 +1,17 @@
+warning: attempt to subtract with overflow
+  --> $DIR/conditional_array_execution.rs:13:19
+   |
+LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
+   |                   ^^^^^
+   |
+   = note: #[warn(const_err)] on by default
+
+error[E0080]: constant evaluation error
+  --> $DIR/conditional_array_execution.rs:17:20
+   |
+LL |     println!("{}", FOO); //~ E0080
+   |                    ^^^ referenced constant has errors
+
+error: aborting due to previous error
+
+If you want more information on this error, try using "rustc --explain E0080"
diff --git a/src/test/ui/const-eval/const_transmute.rs b/src/test/ui/const-eval/const_transmute.rs
new file mode 100644
index 0000000000000..a64a1d212abf3
--- /dev/null
+++ b/src/test/ui/const-eval/const_transmute.rs
@@ -0,0 +1,62 @@
+// Copyright 2018 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.
+
+// must-compile-successfully
+// run-pass
+
+union Transmute<T: Copy, U: Copy> {
+    t: T,
+    u: U,
+}
+
+trait Bar {
+    fn bar(&self) -> u32;
+}
+
+struct Foo {
+    foo: u32,
+    bar: bool,
+}
+
+impl Bar for Foo {
+    fn bar(&self) -> u32 {
+        self.foo
+    }
+}
+
+impl Drop for Foo {
+    fn drop(&mut self) {
+        assert!(!self.bar);
+        self.bar = true;
+        println!("dropping Foo");
+    }
+}
+
+#[derive(Copy, Clone)]
+struct Fat<'a>(&'a Foo, &'static VTable);
+
+struct VTable {
+    drop: Option<for<'a> fn(&'a mut Foo)>,
+    size: usize,
+    align: usize,
+    bar: for<'a> fn(&'a Foo) -> u32,
+}
+
+const FOO: &Bar = &Foo { foo: 128, bar: false };
+const G: Fat = unsafe { Transmute { t: FOO }.u };
+const F: Option<for<'a> fn(&'a mut Foo)> = G.1.drop;
+const H: for<'a> fn(&'a Foo) -> u32 = G.1.bar;
+
+fn main() {
+    let mut foo = Foo { foo: 99, bar: false };
+    (F.unwrap())(&mut foo);
+    std::mem::forget(foo); // already ran the drop impl
+    assert_eq!(H(&Foo { foo: 42, bar: false }), 42);
+}
diff --git a/src/test/ui/const-eval/const_transmute.stderr b/src/test/ui/const-eval/const_transmute.stderr
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/src/test/ui/const-eval/index_out_of_bound.rs b/src/test/ui/const-eval/index_out_of_bound.rs
new file mode 100644
index 0000000000000..e7ffbe81b9ae7
--- /dev/null
+++ b/src/test/ui/const-eval/index_out_of_bound.rs
@@ -0,0 +1,14 @@
+// Copyright 2018 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.
+
+static FOO: i32 = [][0];
+//~^ ERROR E0080
+
+fn main() {}
diff --git a/src/test/ui/const-eval/index_out_of_bound.stderr b/src/test/ui/const-eval/index_out_of_bound.stderr
new file mode 100644
index 0000000000000..7651fb257e3ce
--- /dev/null
+++ b/src/test/ui/const-eval/index_out_of_bound.stderr
@@ -0,0 +1,9 @@
+error[E0080]: constant evaluation error
+  --> $DIR/index_out_of_bound.rs:11:19
+   |
+LL | static FOO: i32 = [][0];
+   |                   ^^^^^ index out of bounds: the len is 0 but the index is 0 at $DIR/index_out_of_bound.rs:11:19: 11:24
+
+error: aborting due to previous error
+
+If you want more information on this error, try using "rustc --explain E0080"
diff --git a/src/test/ui/const-eval/issue-43197.rs b/src/test/ui/const-eval/issue-43197.rs
index 85ab2a0052164..d5c4796d0b497 100644
--- a/src/test/ui/const-eval/issue-43197.rs
+++ b/src/test/ui/const-eval/issue-43197.rs
@@ -15,9 +15,11 @@ const fn foo(x: u32) -> u32 {
 }
 
 fn main() {
-    const X: u32 = 0-1; //~ ERROR constant evaluation error
-    //~^ WARN constant evaluation error
-    const Y: u32 = foo(0-1); //~ ERROR constant evaluation error
-    //~^ WARN constant evaluation error
+    const X: u32 = 0-1;
+    //~^ WARN attempt to subtract with overflow
+    const Y: u32 = foo(0-1);
+    //~^ WARN attempt to subtract with overflow
     println!("{} {}", X, Y);
+    //~^ ERROR constant evaluation error
+    //~| ERROR constant evaluation error
 }
diff --git a/src/test/ui/const-eval/issue-43197.stderr b/src/test/ui/const-eval/issue-43197.stderr
index c523b749d376f..3f10826874754 100644
--- a/src/test/ui/const-eval/issue-43197.stderr
+++ b/src/test/ui/const-eval/issue-43197.stderr
@@ -1,28 +1,28 @@
-warning: constant evaluation error: attempt to subtract with overflow
+warning: attempt to subtract with overflow
   --> $DIR/issue-43197.rs:18:20
    |
-LL |     const X: u32 = 0-1; //~ ERROR constant evaluation error
+LL |     const X: u32 = 0-1;
    |                    ^^^
    |
    = note: #[warn(const_err)] on by default
 
-warning: constant evaluation error: attempt to subtract with overflow
-  --> $DIR/issue-43197.rs:20:20
+error[E0080]: constant evaluation error
+  --> $DIR/issue-43197.rs:22:23
    |
-LL |     const Y: u32 = foo(0-1); //~ ERROR constant evaluation error
-   |                    ^^^^^^^^
+LL |     println!("{} {}", X, Y);
+   |                       ^ referenced constant has errors
 
-error[E0080]: constant evaluation error
-  --> $DIR/issue-43197.rs:18:20
+warning: attempt to subtract with overflow
+  --> $DIR/issue-43197.rs:20:24
    |
-LL |     const X: u32 = 0-1; //~ ERROR constant evaluation error
-   |                    ^^^ attempt to subtract with overflow
+LL |     const Y: u32 = foo(0-1);
+   |                        ^^^
 
 error[E0080]: constant evaluation error
-  --> $DIR/issue-43197.rs:20:24
+  --> $DIR/issue-43197.rs:22:26
    |
-LL |     const Y: u32 = foo(0-1); //~ ERROR constant evaluation error
-   |                        ^^^ attempt to subtract with overflow
+LL |     println!("{} {}", X, Y);
+   |                          ^ referenced constant has errors
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-eval/issue-47971.rs b/src/test/ui/const-eval/issue-47971.rs
new file mode 100644
index 0000000000000..4a2f0a7f38cda
--- /dev/null
+++ b/src/test/ui/const-eval/issue-47971.rs
@@ -0,0 +1,21 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// must-compile-successfully
+
+#![feature(const_fn)]
+
+struct S(pub &'static u32, pub u32);
+
+const fn g(ss: &S) -> &u32 { &ss.1 }
+
+static T: S = S(g(&T), 0);
+
+fn main () { }
diff --git a/src/test/ui/const-eval/no_lint_for_statically_known_error.rs b/src/test/ui/const-eval/no_lint_for_statically_known_error.rs
new file mode 100644
index 0000000000000..968a7de469107
--- /dev/null
+++ b/src/test/ui/const-eval/no_lint_for_statically_known_error.rs
@@ -0,0 +1,28 @@
+// Copyright 2018 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.
+
+// must-compile-successfully
+
+// if `X` were used instead of `x`, `X - 10` would result in a lint.
+// This file should never produce a lint, no matter how the const
+// propagator is improved.
+
+#![deny(warnings)]
+
+const X: u32 = 5;
+
+fn main() {
+    let x = X;
+    if x > 10 {
+        println!("{}", x - 10);
+    } else {
+        println!("{}", 10 - x);
+    }
+}
diff --git a/src/test/ui/const-eval/pub_const_err.rs b/src/test/ui/const-eval/pub_const_err.rs
new file mode 100644
index 0000000000000..bdb9f5b19a885
--- /dev/null
+++ b/src/test/ui/const-eval/pub_const_err.rs
@@ -0,0 +1,16 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(const_err)]
+
+#![crate_type = "lib"]
+
+pub const Z: u32 = 0 - 1;
+//~^ ERROR attempt to subtract with overflow
diff --git a/src/test/ui/const-eval/pub_const_err.stderr b/src/test/ui/const-eval/pub_const_err.stderr
new file mode 100644
index 0000000000000..b77ec38ca1679
--- /dev/null
+++ b/src/test/ui/const-eval/pub_const_err.stderr
@@ -0,0 +1,14 @@
+error: attempt to subtract with overflow
+  --> $DIR/pub_const_err.rs:15:20
+   |
+LL | pub const Z: u32 = 0 - 1;
+   |                    ^^^^^
+   |
+note: lint level defined here
+  --> $DIR/pub_const_err.rs:11:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-expr-addr-operator.rs b/src/test/ui/const-expr-addr-operator.rs
index 24d4457f01d70..bfd6a4090649b 100644
--- a/src/test/ui/const-expr-addr-operator.rs
+++ b/src/test/ui/const-expr-addr-operator.rs
@@ -9,10 +9,11 @@
 // except according to those terms.
 
 // Encountered while testing #44614.
+// must-compile-successfully
 
 pub fn main() {
     // Constant of generic type (int)
-    const X: &'static u32 = &22; //~ ERROR constant evaluation error
+    const X: &'static u32 = &22;
     assert_eq!(0, match &22 {
         X => 0,
         _ => 1,
diff --git a/src/test/ui/const-expr-addr-operator.stderr b/src/test/ui/const-expr-addr-operator.stderr
index bd86f270f319c..e69de29bb2d1d 100644
--- a/src/test/ui/const-expr-addr-operator.stderr
+++ b/src/test/ui/const-expr-addr-operator.stderr
@@ -1,15 +0,0 @@
-error[E0080]: constant evaluation error
-  --> $DIR/const-expr-addr-operator.rs:15:29
-   |
-LL |     const X: &'static u32 = &22; //~ ERROR constant evaluation error
-   |                             ^^^ unimplemented constant expression: address operator
-   |
-note: for pattern here
-  --> $DIR/const-expr-addr-operator.rs:17:9
-   |
-LL |         X => 0,
-   |         ^
-
-error: aborting due to previous error
-
-If you want more information on this error, try using "rustc --explain E0080"
diff --git a/src/test/ui/const-fn-error.rs b/src/test/ui/const-fn-error.rs
index ac1c2fe5432de..9e09f66776c9b 100644
--- a/src/test/ui/const-fn-error.rs
+++ b/src/test/ui/const-fn-error.rs
@@ -13,17 +13,18 @@
 const X : usize = 2;
 
 const fn f(x: usize) -> usize {
-    let mut sum = 0; //~ ERROR blocks in constant functions are limited
-    for i in 0..x { //~ ERROR calls in constant functions
-    //~| ERROR constant function contains unimplemented
+    let mut sum = 0;
+    //~^ ERROR E0016
+    for i in 0..x {
+        //~^ ERROR E0015
+        //~| ERROR E0019
+        //~| ERROR E0080
         sum += i;
     }
-    sum //~ ERROR E0080
-        //~| non-constant path in constant
+    sum
 }
 
 #[allow(unused_variables)]
 fn main() {
     let a : [i32; f(X)];
-    //~^ WARNING constant evaluation error: non-constant path
 }
diff --git a/src/test/ui/const-fn-error.stderr b/src/test/ui/const-fn-error.stderr
index e738a5e4ff308..d57efce0dffc0 100644
--- a/src/test/ui/const-fn-error.stderr
+++ b/src/test/ui/const-fn-error.stderr
@@ -1,37 +1,32 @@
-warning: constant evaluation error: non-constant path in constant expression
-  --> $DIR/const-fn-error.rs:27:19
-   |
-LL |     let a : [i32; f(X)];
-   |                   ^^^^
-   |
-   = note: #[warn(const_err)] on by default
-
 error[E0016]: blocks in constant functions are limited to items and tail expressions
   --> $DIR/const-fn-error.rs:16:19
    |
-LL |     let mut sum = 0; //~ ERROR blocks in constant functions are limited
+LL |     let mut sum = 0;
    |                   ^
 
 error[E0015]: calls in constant functions are limited to constant functions, struct and enum constructors
-  --> $DIR/const-fn-error.rs:17:14
+  --> $DIR/const-fn-error.rs:18:14
    |
-LL |     for i in 0..x { //~ ERROR calls in constant functions
+LL |     for i in 0..x {
    |              ^^^^
 
 error[E0019]: constant function contains unimplemented expression type
-  --> $DIR/const-fn-error.rs:17:14
+  --> $DIR/const-fn-error.rs:18:14
    |
-LL |     for i in 0..x { //~ ERROR calls in constant functions
+LL |     for i in 0..x {
    |              ^^^^
 
 error[E0080]: constant evaluation error
-  --> $DIR/const-fn-error.rs:21:5
+  --> $DIR/const-fn-error.rs:18:14
    |
-LL |     sum //~ ERROR E0080
-   |     ^^^ non-constant path in constant expression
+LL |     for i in 0..x {
+   |              ^^^^ calling non-const fn `<I as std::iter::IntoIterator><std::ops::Range<usize>>::into_iter`
+...
+LL |     let a : [i32; f(X)];
+   |                   ---- inside call to `f`
    |
 note: for constant expression here
-  --> $DIR/const-fn-error.rs:27:13
+  --> $DIR/const-fn-error.rs:29:13
    |
 LL |     let a : [i32; f(X)];
    |             ^^^^^^^^^^^
diff --git a/src/test/ui/const-len-underflow-separate-spans.rs b/src/test/ui/const-len-underflow-separate-spans.rs
index 823cc988947cb..ee07dabab1fc8 100644
--- a/src/test/ui/const-len-underflow-separate-spans.rs
+++ b/src/test/ui/const-len-underflow-separate-spans.rs
@@ -15,9 +15,10 @@
 const ONE: usize = 1;
 const TWO: usize = 2;
 const LEN: usize = ONE - TWO;
-//~^ ERROR constant evaluation error [E0080]
+//~^ ERROR E0080
 //~| WARN attempt to subtract with overflow
 
 fn main() {
     let a: [i8; LEN] = unimplemented!();
+//~^ ERROR E0080
 }
diff --git a/src/test/ui/const-len-underflow-separate-spans.stderr b/src/test/ui/const-len-underflow-separate-spans.stderr
index 6391433ebaf1e..98f4ac9e83fb8 100644
--- a/src/test/ui/const-len-underflow-separate-spans.stderr
+++ b/src/test/ui/const-len-underflow-separate-spans.stderr
@@ -1,4 +1,4 @@
-warning: constant evaluation error: attempt to subtract with overflow
+warning: attempt to subtract with overflow
   --> $DIR/const-len-underflow-separate-spans.rs:17:20
    |
 LL | const LEN: usize = ONE - TWO;
@@ -11,13 +11,13 @@ error[E0080]: constant evaluation error
    |
 LL | const LEN: usize = ONE - TWO;
    |                    ^^^^^^^^^ attempt to subtract with overflow
-   |
-note: for constant expression here
-  --> $DIR/const-len-underflow-separate-spans.rs:22:12
+
+error[E0080]: constant evaluation error
+  --> $DIR/const-len-underflow-separate-spans.rs:22:17
    |
 LL |     let a: [i8; LEN] = unimplemented!();
-   |            ^^^^^^^^^
+   |                 ^^^ referenced constant has errors
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 If you want more information on this error, try using "rustc --explain E0080"
diff --git a/src/test/ui/const-pattern-not-const-evaluable.rs b/src/test/ui/const-pattern-not-const-evaluable.rs
index 263c0bdc64c6f..09b24d1ffa208 100644
--- a/src/test/ui/const-pattern-not-const-evaluable.rs
+++ b/src/test/ui/const-pattern-not-const-evaluable.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// must-compile-successfully
+
 #![feature(const_fn)]
 
 #[derive(PartialEq, Eq)]
@@ -20,8 +22,6 @@ use Cake::*;
 struct Pair<A, B>(A, B);
 
 const BOO: Pair<Cake, Cake> = Pair(Marmor, BlackForest);
-//~^ ERROR: constant evaluation error [E0080]
-//~| unimplemented constant expression: tuple struct constructors
 const FOO: Cake = BOO.1;
 
 const fn foo() -> Cake {
diff --git a/src/test/ui/const-pattern-not-const-evaluable.stderr b/src/test/ui/const-pattern-not-const-evaluable.stderr
index 74677c7f117a8..e69de29bb2d1d 100644
--- a/src/test/ui/const-pattern-not-const-evaluable.stderr
+++ b/src/test/ui/const-pattern-not-const-evaluable.stderr
@@ -1,15 +0,0 @@
-error[E0080]: constant evaluation error
-  --> $DIR/const-pattern-not-const-evaluable.rs:22:31
-   |
-LL | const BOO: Pair<Cake, Cake> = Pair(Marmor, BlackForest);
-   |                               ^^^^ unimplemented constant expression: tuple struct constructors
-   |
-note: for pattern here
-  --> $DIR/const-pattern-not-const-evaluable.rs:37:9
-   |
-LL |         FOO => println!("hi"),
-   |         ^^^
-
-error: aborting due to previous error
-
-If you want more information on this error, try using "rustc --explain E0080"
diff --git a/src/test/ui/discrim-overflow-2.stderr b/src/test/ui/discrim-overflow-2.stderr
index 1facda94cd6e6..6162766b58705 100644
--- a/src/test/ui/discrim-overflow-2.stderr
+++ b/src/test/ui/discrim-overflow-2.stderr
@@ -2,65 +2,65 @@ error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow-2.rs:27:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 127i8
+   |         ^^^^ overflowed on value after 127
    |
-   = note: explicitly set `OhNo = -128i8` if that is desired outcome
+   = note: explicitly set `OhNo = -128` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow-2.rs:36:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 255u8
+   |         ^^^^ overflowed on value after 255
    |
-   = note: explicitly set `OhNo = 0u8` if that is desired outcome
+   = note: explicitly set `OhNo = 0` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow-2.rs:45:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 32767i16
+   |         ^^^^ overflowed on value after 32767
    |
-   = note: explicitly set `OhNo = -32768i16` if that is desired outcome
+   = note: explicitly set `OhNo = -32768` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow-2.rs:54:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 65535u16
+   |         ^^^^ overflowed on value after 65535
    |
-   = note: explicitly set `OhNo = 0u16` if that is desired outcome
+   = note: explicitly set `OhNo = 0` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow-2.rs:63:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 2147483647i32
+   |         ^^^^ overflowed on value after 2147483647
    |
-   = note: explicitly set `OhNo = -2147483648i32` if that is desired outcome
+   = note: explicitly set `OhNo = -2147483648` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow-2.rs:72:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 4294967295u32
+   |         ^^^^ overflowed on value after 4294967295
    |
-   = note: explicitly set `OhNo = 0u32` if that is desired outcome
+   = note: explicitly set `OhNo = 0` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow-2.rs:81:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 9223372036854775807i64
+   |         ^^^^ overflowed on value after 9223372036854775807
    |
-   = note: explicitly set `OhNo = -9223372036854775808i64` if that is desired outcome
+   = note: explicitly set `OhNo = -9223372036854775808` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow-2.rs:90:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 18446744073709551615u64
+   |         ^^^^ overflowed on value after 18446744073709551615
    |
-   = note: explicitly set `OhNo = 0u64` if that is desired outcome
+   = note: explicitly set `OhNo = 0` if that is desired outcome
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/discrim-overflow.rs b/src/test/ui/discrim-overflow.rs
index 0b31d9f97f174..16b417c61a517 100644
--- a/src/test/ui/discrim-overflow.rs
+++ b/src/test/ui/discrim-overflow.rs
@@ -56,7 +56,7 @@ fn f_u16() {
         Ok = u16::MAX - 1,
         Ok2,
         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-              //~| overflowed on value after 65535u16
+              //~| overflowed on value after 65535
     }
 
     let x = A::Ok;
@@ -68,7 +68,7 @@ fn f_i32() {
         Ok = i32::MAX - 1,
         Ok2,
         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-              //~| overflowed on value after 2147483647i32
+              //~| overflowed on value after 2147483647
     }
 
     let x = A::Ok;
@@ -80,7 +80,7 @@ fn f_u32() {
         Ok = u32::MAX - 1,
         Ok2,
         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-              //~| overflowed on value after 4294967295u32
+              //~| overflowed on value after 4294967295
     }
 
     let x = A::Ok;
@@ -92,7 +92,7 @@ fn f_i64() {
         Ok = i64::MAX - 1,
         Ok2,
         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-              //~| overflowed on value after 9223372036854775807i64
+              //~| overflowed on value after 9223372036854775807
     }
 
     let x = A::Ok;
@@ -104,7 +104,7 @@ fn f_u64() {
         Ok = u64::MAX - 1,
         Ok2,
         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-              //~| overflowed on value after 18446744073709551615u64
+              //~| overflowed on value after 18446744073709551615
     }
 
     let x = A::Ok;
diff --git a/src/test/ui/discrim-overflow.stderr b/src/test/ui/discrim-overflow.stderr
index 43c032b12a6c4..a713aea1b21ef 100644
--- a/src/test/ui/discrim-overflow.stderr
+++ b/src/test/ui/discrim-overflow.stderr
@@ -2,65 +2,65 @@ error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow.rs:25:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 127i8
+   |         ^^^^ overflowed on value after 127
    |
-   = note: explicitly set `OhNo = -128i8` if that is desired outcome
+   = note: explicitly set `OhNo = -128` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow.rs:36:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 255u8
+   |         ^^^^ overflowed on value after 255
    |
-   = note: explicitly set `OhNo = 0u8` if that is desired outcome
+   = note: explicitly set `OhNo = 0` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow.rs:47:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 32767i16
+   |         ^^^^ overflowed on value after 32767
    |
-   = note: explicitly set `OhNo = -32768i16` if that is desired outcome
+   = note: explicitly set `OhNo = -32768` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow.rs:58:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 65535u16
+   |         ^^^^ overflowed on value after 65535
    |
-   = note: explicitly set `OhNo = 0u16` if that is desired outcome
+   = note: explicitly set `OhNo = 0` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow.rs:70:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 2147483647i32
+   |         ^^^^ overflowed on value after 2147483647
    |
-   = note: explicitly set `OhNo = -2147483648i32` if that is desired outcome
+   = note: explicitly set `OhNo = -2147483648` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow.rs:82:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 4294967295u32
+   |         ^^^^ overflowed on value after 4294967295
    |
-   = note: explicitly set `OhNo = 0u32` if that is desired outcome
+   = note: explicitly set `OhNo = 0` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow.rs:94:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 9223372036854775807i64
+   |         ^^^^ overflowed on value after 9223372036854775807
    |
-   = note: explicitly set `OhNo = -9223372036854775808i64` if that is desired outcome
+   = note: explicitly set `OhNo = -9223372036854775808` if that is desired outcome
 
 error[E0370]: enum discriminant overflowed
   --> $DIR/discrim-overflow.rs:106:9
    |
 LL |         OhNo, //~ ERROR enum discriminant overflowed [E0370]
-   |         ^^^^ overflowed on value after 18446744073709551615u64
+   |         ^^^^ overflowed on value after 18446744073709551615
    |
-   = note: explicitly set `OhNo = 0u64` if that is desired outcome
+   = note: explicitly set `OhNo = 0` if that is desired outcome
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/error-codes/E0080.rs b/src/test/ui/error-codes/E0080.rs
index 2f199c48e46e7..c8e425711284e 100644
--- a/src/test/ui/error-codes/E0080.rs
+++ b/src/test/ui/error-codes/E0080.rs
@@ -10,9 +10,12 @@
 
 enum Enum {
     X = (1 << 500), //~ ERROR E0080
-    //~| WARNING shift left with overflow
+    //~| shift left with overflow
     Y = (1 / 0) //~ ERROR E0080
-    //~| WARNING divide by zero
+    //~| const_err
+    //~| const_err
+    //~| const_err
+    //~| divide by zero
 }
 
 fn main() {
diff --git a/src/test/ui/error-codes/E0080.stderr b/src/test/ui/error-codes/E0080.stderr
index 01cfa0c375bb1..6db53acd6b982 100644
--- a/src/test/ui/error-codes/E0080.stderr
+++ b/src/test/ui/error-codes/E0080.stderr
@@ -1,10 +1,10 @@
-warning: constant evaluation error: attempt to shift left with overflow
+error: attempt to shift left with overflow
   --> $DIR/E0080.rs:12:9
    |
 LL |     X = (1 << 500), //~ ERROR E0080
    |         ^^^^^^^^^^
    |
-   = note: #[warn(const_err)] on by default
+   = note: #[deny(exceeding_bitshifts)] on by default
 
 error[E0080]: constant evaluation error
   --> $DIR/E0080.rs:12:9
@@ -12,11 +12,19 @@ error[E0080]: constant evaluation error
 LL |     X = (1 << 500), //~ ERROR E0080
    |         ^^^^^^^^^^ attempt to shift left with overflow
 
-warning: constant evaluation error: attempt to divide by zero
+warning: attempt to divide by zero
   --> $DIR/E0080.rs:14:9
    |
 LL |     Y = (1 / 0) //~ ERROR E0080
    |         ^^^^^^^
+   |
+   = note: #[warn(const_err)] on by default
+
+warning: constant evaluation error
+  --> $DIR/E0080.rs:14:9
+   |
+LL |     Y = (1 / 0) //~ ERROR E0080
+   |         ^^^^^^^ attempted to do overflowing math
 
 error[E0080]: constant evaluation error
   --> $DIR/E0080.rs:14:9
@@ -24,6 +32,6 @@ error[E0080]: constant evaluation error
 LL |     Y = (1 / 0) //~ ERROR E0080
    |         ^^^^^^^ attempt to divide by zero
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 If you want more information on this error, try using "rustc --explain E0080"
diff --git a/src/test/ui/error-codes/E0081.rs b/src/test/ui/error-codes/E0081.rs
index 3b571667336ac..c0cdad258687d 100644
--- a/src/test/ui/error-codes/E0081.rs
+++ b/src/test/ui/error-codes/E0081.rs
@@ -11,7 +11,7 @@
 enum Enum {
     P = 3,
     X = 3,
-    //~^ ERROR discriminant value `3isize` already exists
+    //~^ ERROR discriminant value `3` already exists
     Y = 5
 }
 
diff --git a/src/test/ui/error-codes/E0081.stderr b/src/test/ui/error-codes/E0081.stderr
index 42d0769bb5701..e1133c1fc587e 100644
--- a/src/test/ui/error-codes/E0081.stderr
+++ b/src/test/ui/error-codes/E0081.stderr
@@ -1,10 +1,10 @@
-error[E0081]: discriminant value `3isize` already exists
+error[E0081]: discriminant value `3` already exists
   --> $DIR/E0081.rs:13:9
    |
 LL |     P = 3,
-   |         - first use of `3isize`
+   |         - first use of `3`
 LL |     X = 3,
-   |         ^ enum already has `3isize`
+   |         ^ enum already has `3`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0370.stderr b/src/test/ui/error-codes/E0370.stderr
index 1c7a18bd6d867..60e077e063e09 100644
--- a/src/test/ui/error-codes/E0370.stderr
+++ b/src/test/ui/error-codes/E0370.stderr
@@ -2,9 +2,9 @@ error[E0370]: enum discriminant overflowed
   --> $DIR/E0370.rs:17:5
    |
 LL |     Y, //~ ERROR E0370
-   |     ^ overflowed on value after 9223372036854775807i64
+   |     ^ overflowed on value after 9223372036854775807
    |
-   = note: explicitly set `Y = -9223372036854775808i64` if that is desired outcome
+   = note: explicitly set `Y = -9223372036854775808` if that is desired outcome
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gate-const-indexing.rs b/src/test/ui/feature-gate-const-indexing.rs
index 0d61878cd8073..eb5f746774cf1 100644
--- a/src/test/ui/feature-gate-const-indexing.rs
+++ b/src/test/ui/feature-gate-const-indexing.rs
@@ -8,10 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// must-compile-successfully
 
 fn main() {
     const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47];
     const IDX: usize = 3;
     const VAL: i32 = ARR[IDX];
-    const BLUB: [i32; (ARR[0] - 41) as usize] = [5]; //~ ERROR constant evaluation error
+    const BLUB: [i32; (ARR[0] - 41) as usize] = [5];
 }
diff --git a/src/test/ui/feature-gate-const-indexing.stderr b/src/test/ui/feature-gate-const-indexing.stderr
index 419400bb0ac0c..e69de29bb2d1d 100644
--- a/src/test/ui/feature-gate-const-indexing.stderr
+++ b/src/test/ui/feature-gate-const-indexing.stderr
@@ -1,9 +0,0 @@
-error[E0080]: constant evaluation error
-  --> $DIR/feature-gate-const-indexing.rs:16:24
-   |
-LL |     const BLUB: [i32; (ARR[0] - 41) as usize] = [5]; //~ ERROR constant evaluation error
-   |                        ^^^^^^ the index operation on const values is unstable
-
-error: aborting due to previous error
-
-If you want more information on this error, try using "rustc --explain E0080"
diff --git a/src/test/ui/infinite-recursion-const-fn.rs b/src/test/ui/infinite-recursion-const-fn.rs
new file mode 100644
index 0000000000000..f98074bc554bb
--- /dev/null
+++ b/src/test/ui/infinite-recursion-const-fn.rs
@@ -0,0 +1,18 @@
+// Copyright 2018 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.
+
+//https://github.com/rust-lang/rust/issues/31364
+
+#![feature(const_fn)]
+const fn a() -> usize { b() } //~ ERROR constant evaluation error
+const fn b() -> usize { a() }
+const ARR: [i32; a()] = [5; 6];
+
+fn main(){}
diff --git a/src/test/ui/infinite-recursion-const-fn.stderr b/src/test/ui/infinite-recursion-const-fn.stderr
new file mode 100644
index 0000000000000..bc062ecce2587
--- /dev/null
+++ b/src/test/ui/infinite-recursion-const-fn.stderr
@@ -0,0 +1,72 @@
+error[E0080]: constant evaluation error
+  --> $DIR/infinite-recursion-const-fn.rs:14:25
+   |
+LL | const fn a() -> usize { b() } //~ ERROR constant evaluation error
+   |                         ^^^
+   |                         |
+   |                         reached the configured maximum number of stack frames
+   |                         inside call to `b`
+LL | const fn b() -> usize { a() }
+   |                         ---
+   |                         |
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+   |                         inside call to `a`
+LL | const ARR: [i32; a()] = [5; 6];
+   |                  --- inside call to `a`
+   |
+note: for constant expression here
+  --> $DIR/infinite-recursion-const-fn.rs:16:1
+   |
+LL | const ARR: [i32; a()] = [5; 6];
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+If you want more information on this error, try using "rustc --explain E0080"
diff --git a/src/test/ui/issue-15524.rs b/src/test/ui/issue-15524.rs
index 85214bd86336c..7e696c97595aa 100644
--- a/src/test/ui/issue-15524.rs
+++ b/src/test/ui/issue-15524.rs
@@ -13,13 +13,13 @@ const N: isize = 1;
 enum Foo {
     A = 1,
     B = 1,
-    //~^ ERROR discriminant value `1isize` already exists
+    //~^ ERROR discriminant value `1` already exists
     C = 0,
     D,
-    //~^ ERROR discriminant value `1isize` already exists
+    //~^ ERROR discriminant value `1` already exists
 
     E = N,
-    //~^ ERROR discriminant value `1isize` already exists
+    //~^ ERROR discriminant value `1` already exists
 
 }
 
diff --git a/src/test/ui/issue-15524.stderr b/src/test/ui/issue-15524.stderr
index 1cb16dfe19a58..e26766eca373d 100644
--- a/src/test/ui/issue-15524.stderr
+++ b/src/test/ui/issue-15524.stderr
@@ -1,28 +1,28 @@
-error[E0081]: discriminant value `1isize` already exists
+error[E0081]: discriminant value `1` already exists
   --> $DIR/issue-15524.rs:15:9
    |
 LL |     A = 1,
-   |         - first use of `1isize`
+   |         - first use of `1`
 LL |     B = 1,
-   |         ^ enum already has `1isize`
+   |         ^ enum already has `1`
 
-error[E0081]: discriminant value `1isize` already exists
+error[E0081]: discriminant value `1` already exists
   --> $DIR/issue-15524.rs:18:5
    |
 LL |     A = 1,
-   |         - first use of `1isize`
+   |         - first use of `1`
 ...
 LL |     D,
-   |     ^ enum already has `1isize`
+   |     ^ enum already has `1`
 
-error[E0081]: discriminant value `1isize` already exists
+error[E0081]: discriminant value `1` already exists
   --> $DIR/issue-15524.rs:21:9
    |
 LL |     A = 1,
-   |         - first use of `1isize`
+   |         - first use of `1`
 ...
 LL |     E = N,
-   |         ^ enum already has `1isize`
+   |         ^ enum already has `1`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/issue-23302-1.stderr b/src/test/ui/issue-23302-1.stderr
index 13a2a23cc527d..087eae43a2994 100644
--- a/src/test/ui/issue-23302-1.stderr
+++ b/src/test/ui/issue-23302-1.stderr
@@ -5,10 +5,15 @@ LL |     A = X::A as isize, //~ ERROR E0391
    |         ^^^^^^^^^^^^^ cyclic reference
    |
 note: the cycle begins when const-evaluating `X::A::{{initializer}}`...
-  --> $DIR/issue-23302-1.rs:14:5
+  --> $DIR/issue-23302-1.rs:14:9
+   |
+LL |     A = X::A as isize, //~ ERROR E0391
+   |         ^^^^^^^^^^^^^
+note: ...which then requires computing layout of `X`...
+  --> $DIR/issue-23302-1.rs:14:9
    |
 LL |     A = X::A as isize, //~ ERROR E0391
-   |     ^^^^^^^^^^^^^^^^^
+   |         ^^^^
    = note: ...which then again requires const-evaluating `X::A::{{initializer}}`, completing the cycle.
 
 error: aborting due to previous error
diff --git a/src/test/ui/issue-23302-2.stderr b/src/test/ui/issue-23302-2.stderr
index f303fa7c6718e..66ba5c3258211 100644
--- a/src/test/ui/issue-23302-2.stderr
+++ b/src/test/ui/issue-23302-2.stderr
@@ -5,10 +5,15 @@ LL |     A = Y::B as isize, //~ ERROR E0391
    |         ^^^^^^^^^^^^^ cyclic reference
    |
 note: the cycle begins when const-evaluating `Y::A::{{initializer}}`...
-  --> $DIR/issue-23302-2.rs:14:5
+  --> $DIR/issue-23302-2.rs:14:9
+   |
+LL |     A = Y::B as isize, //~ ERROR E0391
+   |         ^^^^^^^^^^^^^
+note: ...which then requires computing layout of `Y`...
+  --> $DIR/issue-23302-2.rs:14:9
    |
 LL |     A = Y::B as isize, //~ ERROR E0391
-   |     ^^^^^^^^^^^^^^^^^
+   |         ^^^^
    = note: ...which then again requires const-evaluating `Y::A::{{initializer}}`, completing the cycle.
 
 error: aborting due to previous error
diff --git a/src/test/ui/issue-23302-3.rs b/src/test/ui/issue-23302-3.rs
index 1d750b09025b9..5903acc8b7a6d 100644
--- a/src/test/ui/issue-23302-3.rs
+++ b/src/test/ui/issue-23302-3.rs
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-const A: i32 = B; //~ ERROR E0391
+const A: i32 = B;
 
-const B: i32 = A;
+const B: i32 = A; //~ ERROR cyclic dependency detected
 
 fn main() { }
diff --git a/src/test/ui/issue-23302-3.stderr b/src/test/ui/issue-23302-3.stderr
index ec615809749ae..31168579394d3 100644
--- a/src/test/ui/issue-23302-3.stderr
+++ b/src/test/ui/issue-23302-3.stderr
@@ -1,20 +1,30 @@
 error[E0391]: cyclic dependency detected
-  --> $DIR/issue-23302-3.rs:11:16
+  --> $DIR/issue-23302-3.rs:13:16
    |
-LL | const A: i32 = B; //~ ERROR E0391
+LL | const B: i32 = A; //~ ERROR cyclic dependency detected
    |                ^ cyclic reference
    |
-note: the cycle begins when processing `B`...
-  --> $DIR/issue-23302-3.rs:13:1
+note: the cycle begins when const checking if rvalue is promotable to static `A`...
+  --> $DIR/issue-23302-3.rs:11:1
    |
-LL | const B: i32 = A;
+LL | const A: i32 = B;
    | ^^^^^^^^^^^^^^^^^
-note: ...which then requires processing `A`...
-  --> $DIR/issue-23302-3.rs:13:16
+note: ...which then requires checking which parts of `A` are promotable to static...
+  --> $DIR/issue-23302-3.rs:11:1
+   |
+LL | const A: i32 = B;
+   | ^^^^^^^^^^^^^^^^^
+note: ...which then requires const checking if rvalue is promotable to static `B`...
+  --> $DIR/issue-23302-3.rs:11:16
    |
-LL | const B: i32 = A;
+LL | const A: i32 = B;
    |                ^
-   = note: ...which then again requires processing `B`, completing the cycle.
+note: ...which then requires checking which parts of `B` are promotable to static...
+  --> $DIR/issue-23302-3.rs:13:1
+   |
+LL | const B: i32 = A; //~ ERROR cyclic dependency detected
+   | ^^^^^^^^^^^^^^^^^
+   = note: ...which then again requires const checking if rvalue is promotable to static `A`, completing the cycle.
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issue-36163.stderr b/src/test/ui/issue-36163.stderr
index c511b576a2184..4323eb4858f40 100644
--- a/src/test/ui/issue-36163.stderr
+++ b/src/test/ui/issue-36163.stderr
@@ -5,15 +5,25 @@ LL |     B = A, //~ ERROR E0391
    |         ^ cyclic reference
    |
 note: the cycle begins when const-evaluating `Foo::B::{{initializer}}`...
-  --> $DIR/issue-36163.rs:14:5
+  --> $DIR/issue-36163.rs:14:9
    |
 LL |     B = A, //~ ERROR E0391
-   |     ^^^^^
-note: ...which then requires const-evaluating `A`...
+   |         ^
+note: ...which then requires processing `Foo::B::{{initializer}}`...
   --> $DIR/issue-36163.rs:14:9
    |
 LL |     B = A, //~ ERROR E0391
    |         ^
+note: ...which then requires const-evaluating `A`...
+  --> $DIR/issue-36163.rs:11:1
+   |
+LL | const A: isize = Foo::B as isize;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which then requires computing layout of `Foo`...
+  --> $DIR/issue-36163.rs:11:18
+   |
+LL | const A: isize = Foo::B as isize;
+   |                  ^^^^^^
    = note: ...which then again requires const-evaluating `Foo::B::{{initializer}}`, completing the cycle.
 
 error: aborting due to previous error
diff --git a/src/test/ui/issue-38875/issue_38875.rs b/src/test/ui/issue-38875/issue_38875.rs
index 42e3c05a38c7e..24cd20a84a9fe 100644
--- a/src/test/ui/issue-38875/issue_38875.rs
+++ b/src/test/ui/issue-38875/issue_38875.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // aux-build:issue_38875_b.rs
+// must-compile-successfully
 
 extern crate issue_38875_b;
 
diff --git a/src/test/ui/issue-38875/issue_38875.stderr b/src/test/ui/issue-38875/issue_38875.stderr
index 9a412be6a674e..e69de29bb2d1d 100644
--- a/src/test/ui/issue-38875/issue_38875.stderr
+++ b/src/test/ui/issue-38875/issue_38875.stderr
@@ -1,15 +0,0 @@
-error[E0080]: constant evaluation error
-  --> $DIR/auxiliary/issue_38875_b.rs:11:24
-   |
-LL | pub const FOO: usize = *&0;
-   |                        ^^^ unimplemented constant expression: deref operation
-   |
-note: for constant expression here
-  --> $DIR/issue_38875.rs:16:22
-   |
-LL |     let test_x = [0; issue_38875_b::FOO];
-   |                      ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-If you want more information on this error, try using "rustc --explain E0080"
diff --git a/src/test/ui/union/union-const-eval.rs b/src/test/ui/union/union-const-eval.rs
index a4c969ba20c46..aeafb45e6a552 100644
--- a/src/test/ui/union/union-const-eval.rs
+++ b/src/test/ui/union/union-const-eval.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// must-compile-successfully
+
 union U {
     a: usize,
     b: usize,
@@ -16,9 +18,6 @@ union U {
 const C: U = U { a: 10 };
 
 fn main() {
-    unsafe {
-        let a: [u8; C.a]; // OK
-        let b: [u8; C.b]; //~ ERROR constant evaluation error
-                          //~| WARNING constant evaluation error
-    }
+    let a: [u8; unsafe { C.a }];
+    let b: [u8; unsafe { C.b }];
 }
diff --git a/src/test/ui/union/union-const-eval.stderr b/src/test/ui/union/union-const-eval.stderr
index afd661337c6c4..e69de29bb2d1d 100644
--- a/src/test/ui/union/union-const-eval.stderr
+++ b/src/test/ui/union/union-const-eval.stderr
@@ -1,17 +0,0 @@
-warning: constant evaluation error: nonexistent struct field
-  --> $DIR/union-const-eval.rs:21:21
-   |
-LL |         let b: [u8; C.b]; //~ ERROR constant evaluation error
-   |                     ^^^
-   |
-   = note: #[warn(const_err)] on by default
-
-error[E0080]: constant evaluation error
-  --> $DIR/union-const-eval.rs:21:21
-   |
-LL |         let b: [u8; C.b]; //~ ERROR constant evaluation error
-   |                     ^^^ nonexistent struct field
-
-error: aborting due to previous error
-
-If you want more information on this error, try using "rustc --explain E0080"