about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/const_val.rs13
-rw-r--r--src/librustc/mir/interpret/error.rs4
-rw-r--r--src/librustc/mir/interpret/mod.rs3
-rw-r--r--src/librustc/mir/mod.rs17
-rw-r--r--src/librustc/traits/error_reporting.rs3
-rw-r--r--src/librustc/traits/fulfill.rs9
-rw-r--r--src/librustc/traits/mod.rs2
-rw-r--r--src/librustc/ty/context.rs32
-rw-r--r--src/librustc/ty/maps/mod.rs4
-rw-r--r--src/librustc/ty/mod.rs8
-rw-r--r--src/librustc/ty/util.rs28
-rw-r--r--src/librustc_llvm/ffi.rs10
-rw-r--r--src/librustc_metadata/decoder.rs4
-rw-r--r--src/librustc_metadata/encoder.rs8
-rw-r--r--src/librustc_mir/borrow_check/mod.rs13
-rw-r--r--src/librustc_mir/const_eval/check.rs92
-rw-r--r--src/librustc_mir/const_eval/check_match.rs14
-rw-r--r--src/librustc_mir/const_eval/eval.rs12
-rw-r--r--src/librustc_mir/const_eval/pattern.rs75
-rw-r--r--src/librustc_mir/dataflow/impls/borrows.rs2
-rw-r--r--src/librustc_mir/hair/cx/expr.rs5
-rw-r--r--src/librustc_mir/hair/cx/mod.rs13
-rw-r--r--src/librustc_mir/interpret/cast.rs2
-rw-r--r--src/librustc_mir/interpret/const_eval.rs208
-rw-r--r--src/librustc_mir/interpret/eval_context.rs125
-rw-r--r--src/librustc_mir/interpret/machine.rs28
-rw-r--r--src/librustc_mir/interpret/memory.rs144
-rw-r--r--src/librustc_mir/interpret/mod.rs13
-rw-r--r--src/librustc_mir/interpret/operator.rs22
-rw-r--r--src/librustc_mir/interpret/place.rs55
-rw-r--r--src/librustc_mir/interpret/step.rs241
-rw-r--r--src/librustc_mir/interpret/terminator/drop.rs2
-rw-r--r--src/librustc_mir/interpret/terminator/mod.rs2
-rw-r--r--src/librustc_mir/interpret/traits.rs4
-rw-r--r--src/librustc_mir/monomorphize/collector.rs51
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs2
-rw-r--r--src/librustc_mir/transform/instcombine.rs487
-rw-r--r--src/librustc_trans/consts.rs12
-rw-r--r--src/librustc_trans/mir/block.rs35
-rw-r--r--src/librustc_trans/mir/constant.rs1424
-rw-r--r--src/librustc_trans/mir/mod.rs3
-rw-r--r--src/librustc_trans/mir/operand.rs92
-rw-r--r--src/librustc_trans/trans_item.rs7
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/librustc_typeck/collect.rs2
-rw-r--r--src/librustdoc/clean/mod.rs12
-rw-r--r--src/test/compile-fail/const-call.rs1
-rw-r--r--src/test/compile-fail/const-err-early.rs13
-rw-r--r--src/test/compile-fail/const-err-multi.rs5
-rw-r--r--src/test/compile-fail/const-err.rs21
-rw-r--r--src/test/compile-fail/const-err2.rs6
-rw-r--r--src/test/compile-fail/const-err3.rs28
-rw-r--r--src/test/compile-fail/const-eval-overflow.rs154
-rw-r--r--src/test/compile-fail/const-eval-overflow2.rs91
-rw-r--r--src/test/compile-fail/const-eval-overflow2b.rs91
-rw-r--r--src/test/compile-fail/const-eval-overflow2c.rs91
-rw-r--r--src/test/compile-fail/const-integer-bool-ops.rs10
-rw-r--r--src/test/compile-fail/const-len-underflow-subspans.rs2
-rw-r--r--src/test/compile-fail/const-slice-oob.rs2
-rw-r--r--src/test/compile-fail/const-tup-index-span.rs1
-rw-r--r--src/test/compile-fail/eval-enum.rs15
-rw-r--r--src/test/compile-fail/float-int-invalid-const-cast.rs61
-rw-r--r--src/test/compile-fail/issue-27895.rs3
-rw-r--r--src/test/compile-fail/issue-41255.rs18
-rw-r--r--src/test/compile-fail/issue-44578.rs4
-rw-r--r--src/test/compile-fail/issue-6804.rs7
-rw-r--r--src/test/compile-fail/issue-8460-const.rs20
-rw-r--r--src/test/compile-fail/lint-exceeding-bitshifts.rs18
-rw-r--r--src/test/compile-fail/lint-exceeding-bitshifts2.rs27
-rw-r--r--src/test/compile-fail/lint-type-overflow2.rs1
-rw-r--r--src/test/compile-fail/non-constant-in-const-path.rs3
-rw-r--r--src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs2
-rw-r--r--src/test/run-pass/const-index-feature-gate.rs (renamed from src/test/compile-fail/const-index-feature-gate.rs)3
-rw-r--r--src/test/run-pass/float-int-invalid-const-cast.rs61
-rw-r--r--src/test/ui/const-eval/issue-43197.rs2
-rw-r--r--src/test/ui/const-len-underflow-separate-spans.rs1
-rw-r--r--src/test/ui/error-codes/E0030.rs2
-rw-r--r--src/test/ui/error-codes/E0080.rs5
78 files changed, 1932 insertions, 2183 deletions
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index dd99305809c..35c51c0c206 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -15,9 +15,9 @@ 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;
 use syntax_pos::Span;
 
@@ -169,6 +169,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
 
             TypeckError => simple!("type-checking failed"),
             CheckMatchError => simple!("match-checking failed"),
+            // FIXME: report a full backtrace
             Miri(ref err) => simple!("miri failed: {}", err),
         }
     }
@@ -186,7 +187,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
             err = i_err;
         }
 
-        let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
+        let mut diag = struct_error(tcx, err.span, "constant evaluation error");
         err.note(tcx, primary_span, primary_kind, &mut diag);
         diag
     }
@@ -221,3 +222,11 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
         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/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 6386de5952f..977e617968a 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -286,8 +286,8 @@ 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) =>
diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs
index 8b4f56e1dba..394b3d96a4f 100644
--- a/src/librustc/mir/interpret/mod.rs
+++ b/src/librustc/mir/interpret/mod.rs
@@ -169,6 +169,8 @@ pub struct Allocation {
     pub undef_mask: UndefMask,
     /// The alignment of the allocation to detect unaligned reads.
     pub align: Align,
+    /// Whether the allocation should be put into mutable memory when translating via llvm
+    pub mutable: bool,
 }
 
 impl Allocation {
@@ -180,6 +182,7 @@ impl Allocation {
             relocations: BTreeMap::new(),
             undef_mask,
             align: Align::from_bytes(1, 1).unwrap(),
+            mutable: false,
         }
     }
 }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index d8994351418..9e9ba516203 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1898,13 +1898,16 @@ fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Result {
                 let alloc = tcx
                     .interpret_interner
                     .borrow()
-                    .get_alloc(ptr.alloc_id)
-                    .expect("miri alloc not found");
-                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)
+                    .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),
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index ce23cb23496..2e554aff13e 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 2eeef70a14e..5c082b0610f 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -9,8 +9,6 @@
 // except according to those terms.
 
 use infer::{RegionObligation, InferCtxt};
-use middle::const_val::ConstEvalErr;
-use middle::const_val::ErrKind::TypeckError;
 use mir::interpret::GlobalId;
 use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
 use ty::error::ExpectedFound;
@@ -18,6 +16,7 @@ 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;
@@ -532,12 +531,12 @@ fn process_predicate<'a, 'gcx, 'tcx>(
                                 match selcx.tcx().at(obligation.cause.span)
                                                  .const_eval(param_env.and(cid)) {
                                     Ok(_) => Ok(Some(vec![])),
-                                    Err(e) => Err(CodeSelectionError(ConstEvalFailure(e)))
+                                    Err(err) => Err(CodeSelectionError(ConstEvalFailure(err)))
                                 }
                             } else {
                                 Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr {
-                                    span: selcx.tcx().def_span(def_id),
-                                    kind: TypeckError,
+                                    span: obligation.cause.span,
+                                    kind: ErrKind::UnimplementedConstVal("could not resolve"),
                                 })))
                             }
                         },
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 8ac69c4b528..e0e85600b90 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/ty/context.rs b/src/librustc/ty/context.rs
index ebd78467c3b..bf75afcfa1a 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -907,16 +907,17 @@ pub struct InterpretInterner<'tcx> {
     alloc_by_id: FxHashMap<interpret::AllocId, &'tcx interpret::Allocation>,
 
     /// Reverse map of `alloc_cache`
-    ///
-    /// Multiple globals may share the same memory
-    global_cache: FxHashMap<interpret::AllocId, Vec<interpret::GlobalId<'tcx>>>,
+    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.
@@ -951,30 +952,27 @@ impl<'tcx> InterpretInterner<'tcx> {
 
     pub fn get_cached(
         &self,
-        global_id: interpret::GlobalId<'tcx>,
+        static_id: DefId,
     ) -> Option<interpret::AllocId> {
-        self.alloc_cache.get(&global_id).cloned()
+        self.alloc_cache.get(&static_id).cloned()
     }
 
     pub fn cache(
         &mut self,
-        global_id: interpret::GlobalId<'tcx>,
+        static_id: DefId,
         alloc_id: interpret::AllocId,
     ) {
-        self.global_cache.entry(alloc_id).or_default().push(global_id);
-        if let Some(old) = self.alloc_cache.insert(global_id, alloc_id) {
-            bug!("tried to cache {:?}, but was already existing as {:#?}", global_id, old);
+        self.global_cache.insert(alloc_id, static_id);
+        if let Some(old) = self.alloc_cache.insert(static_id, alloc_id) {
+            bug!("tried to cache {:?}, but was already existing as {:#?}", static_id, old);
         }
     }
 
-    pub fn get_globals(
+    pub fn get_corresponding_static_def_id(
         &self,
         ptr: interpret::AllocId,
-    ) -> &[interpret::GlobalId<'tcx>] {
-        match self.global_cache.get(&ptr) {
-            Some(v) => v,
-            None => &[],
-        }
+    ) -> Option<DefId> {
+        self.global_cache.get(&ptr).cloned()
     }
 
     pub fn intern_at_reserved(
diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs
index f41bdf61d9b..0ded759fec7 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,6 +26,7 @@ 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};
@@ -212,7 +212,7 @@ 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, GlobalId<'tcx>>)
-        -> const_val::EvalResult<'tcx>,
+        -> EvalResult<'tcx>,
 
     [] fn check_match: CheckMatch(DefId)
         -> Result<(), ErrorReported>,
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 02bf409f33f..f9071cff78f 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1854,11 +1854,11 @@ impl<'a, 'gcx, 'tcx> AdtDef {
                                 b, uint_type, tcx.sess.target.usize_ty).unwrap(),
                         };
                     }
-                    err => {
+                    _ => {
                         if !expr_did.is_local() {
                             span_bug!(tcx.def_span(expr_did),
                                 "variant discriminant evaluation succeeded \
-                                 in its crate but failed locally: {:?}", err);
+                                 in its crate but failed locally");
                         }
                     }
                 }
@@ -1910,11 +1910,11 @@ impl<'a, 'gcx, 'tcx> AdtDef {
                             };
                             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);
+                                     in its crate but failed locally");
                             }
                             if explicit_index == 0 {
                                 break;
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 6ae0d520e54..cdf619a1dfa 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -691,22 +691,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// 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
             }
         }
     }
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index e71bef512cf..0ec5700f5f3 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 d991fb0f67b..14984e8a6d7 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -298,9 +298,7 @@ impl<'a, 'tcx> SpecializedDecoder<interpret::AllocId> for DecodeContext<'a, 'tcx
                 let allocation = self.tcx.unwrap().intern_const_alloc(allocation);
                 interpret_interner().intern_at_reserved(alloc_id, allocation);
 
-                let num = usize::decode(self)?;
-                for _ in 0..num {
-                    let glob = interpret::GlobalId::decode(self)?;
+                if let Some(glob) = Option::<DefId>::decode(self)? {
                     interpret_interner().cache(glob, alloc_id);
                 }
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 04ac32af7cc..71be3f28759 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -210,11 +210,9 @@ impl<'a, 'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'a, 'tcx
             trace!("encoding {:?} with {:#?}", alloc_id, alloc);
             usize::max_value().encode(self)?;
             alloc.encode(self)?;
-            let globals = interpret_interner.get_globals(*alloc_id);
-            globals.len().encode(self)?;
-            for glob in globals {
-                glob.encode(self)?;
-            }
+            interpret_interner
+                .get_corresponding_static_def_id(*alloc_id)
+                .encode(self)?;
         } else if let Some(fn_instance) = interpret_interner.get_fn(*alloc_id) {
             trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
             (usize::max_value() - 1).encode(self)?;
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 1ff0ffaaa68..028fc337967 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/const_eval/check.rs b/src/librustc_mir/const_eval/check.rs
index a9508defdcd..9827dd58cd6 100644
--- a/src/librustc_mir/const_eval/check.rs
+++ b/src/librustc_mir/const_eval/check.rs
@@ -11,47 +11,77 @@
 //! Lints statically known runtime failures
 
 use rustc::mir::*;
+use rustc::hir;
+use rustc::hir::map::Node;
 use rustc::mir::visit::Visitor;
 use rustc::mir::interpret::{Value, PrimVal, GlobalId};
 use rustc::middle::const_val::{ConstVal, ConstEvalErr, ErrKind};
+use rustc::hir::def::Def;
 use rustc::traits;
-use interpret::{eval_body_as_integer, check_body};
-use rustc::ty::{TyCtxt, ParamEnv, self};
+use interpret::eval_body_with_mir;
+use rustc::ty::{TyCtxt, ParamEnv};
 use rustc::ty::Instance;
 use rustc::ty::layout::LayoutOf;
 use rustc::hir::def_id::DefId;
+use rustc::ty::subst::Substs;
+
+fn is_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
+    if let Some(node) = tcx.hir.get_if_local(def_id) {
+        match node {
+            Node::NodeItem(&hir::Item {
+                node: hir::ItemConst(..), ..
+            }) => true,
+            _ => false
+        }
+    } else {
+        match tcx.describe_def(def_id) {
+            Some(Def::Const(_)) => true,
+            _ => false
+        }
+    }
+}
 
 pub fn check<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
-    if tcx.is_closure(def_id) {
-        return;
+    let mir = &tcx.optimized_mir(def_id);
+    let substs = Substs::identity_for_item(tcx, def_id);
+    let instance = Instance::new(def_id, substs);
+    let param_env = tcx.param_env(def_id);
+
+    if is_const(tcx, def_id) {
+        let cid = GlobalId {
+            instance,
+            promoted: None,
+        };
+        eval_body_with_mir(tcx, cid, mir, param_env);
     }
-    let generics = tcx.generics_of(def_id);
+
+    ConstErrVisitor {
+        tcx,
+        mir,
+    }.visit_mir(mir);
+    let outer_def_id = if tcx.is_closure(def_id) {
+        tcx.closure_base_def_id(def_id)
+    } else {
+        def_id
+    };
+    let generics = tcx.generics_of(outer_def_id);
     // FIXME: miri should be able to eval stuff that doesn't need info
     // from the generics
     if generics.parent_types as usize + generics.types.len() > 0 {
         return;
     }
-    let mir = &tcx.optimized_mir(def_id);
-    ConstErrVisitor {
-        tcx,
-        def_id,
-        mir,
-    }.visit_mir(mir);
-    let param_env = ParamEnv::empty(traits::Reveal::All);
-    let instance = Instance::mono(tcx, def_id);
     for i in 0.. mir.promoted.len() {
         use rustc_data_structures::indexed_vec::Idx;
         let cid = GlobalId {
             instance,
             promoted: Some(Promoted::new(i)),
         };
-        check_body(tcx, cid, param_env);
+        eval_body_with_mir(tcx, cid, mir, param_env);
     }
 }
 
 struct ConstErrVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    def_id: DefId,
     mir: &'a Mir<'tcx>,
 }
 
@@ -61,22 +91,13 @@ impl<'a, 'tcx> ConstErrVisitor<'a, 'tcx> {
             Operand::Constant(ref c) => c,
             _ => return None,
         };
-        let param_env = ParamEnv::empty(traits::Reveal::All);
-        let val = match op.literal {
+        match op.literal {
             Literal::Value { value } => match value.val {
-                ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => b,
+                ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => Some(b),
                 _ => return None,
             },
-            Literal::Promoted { index } => {
-                let instance = Instance::mono(self.tcx, self.def_id);
-                let cid = GlobalId {
-                    instance,
-                    promoted: Some(index),
-                };
-                eval_body_as_integer(self.tcx, cid, param_env).unwrap()
-            }
-        };
-        Some(val)
+            _ => None,
+        }
     }
 }
 
@@ -87,13 +108,14 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstErrVisitor<'a, 'tcx> {
                         location: Location) {
         self.super_terminator(block, terminator, location);
         match terminator.kind {
-            TerminatorKind::Assert { cond: Operand::Constant(box Constant {
-                literal: Literal::Value {
-                    value: &ty::Const {
-                        val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))),
-                    .. }
-                }, ..
-            }), expected, ref msg, .. } if (cond == 1) != expected => {
+            TerminatorKind::Assert { ref cond, expected, ref msg, .. } => {
+                let cond = match self.eval_op(cond) {
+                    Some(val) => val,
+                    None => return,
+                };
+                if (cond == 1) == expected {
+                    return;
+                }
                 assert!(cond <= 1);
                 // If we know we always panic, and the error message
                 // is also constant, then we can produce a warning.
diff --git a/src/librustc_mir/const_eval/check_match.rs b/src/librustc_mir/const_eval/check_match.rs
index 3621d80df1d..9fbf5539698 100644
--- a/src/librustc_mir/const_eval/check_match.rs
+++ b/src/librustc_mir/const_eval/check_match.rs
@@ -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_mir/const_eval/eval.rs b/src/librustc_mir/const_eval/eval.rs
index 370b8681ba6..25a9e522367 100644
--- a/src/librustc_mir/const_eval/eval.rs
+++ b/src/librustc_mir/const_eval/eval.rs
@@ -9,8 +9,7 @@
 // except according to those terms.
 
 use rustc::middle::const_val::ConstVal::*;
-use rustc::middle::const_val::ErrKind::*;
-use rustc::middle::const_val::{ConstVal, ErrKind};
+use rustc::middle::const_val::ConstVal;
 
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -39,7 +38,7 @@ pub fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           ty: Ty<'tcx>,
                           neg: bool)
-                          -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
+                          -> Result<ConstVal<'tcx>, ()> {
     use syntax::ast::*;
 
     use rustc::mir::interpret::*;
@@ -126,11 +125,8 @@ pub fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
 }
 
 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)")
-    })
+                     -> Result<ConstFloat, ()> {
+    ConstFloat::from_str(num, fty).map_err(|_| ())
 }
 
 pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option<Ordering> {
diff --git a/src/librustc_mir/const_eval/pattern.rs b/src/librustc_mir/const_eval/pattern.rs
index a70ee2d1d64..4ecf0d6e638 100644
--- a/src/librustc_mir/const_eval/pattern.rs
+++ b/src/librustc_mir/const_eval/pattern.rs
@@ -10,7 +10,7 @@
 
 use interpret::{const_val_field, const_discr};
 
-use rustc::middle::const_val::{ConstEvalErr, ErrKind, ConstVal};
+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};
@@ -28,10 +28,11 @@ 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)]
@@ -279,7 +280,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> {
@@ -650,10 +651,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
             }
 
             _ => {
-                self.errors.push(PatternError::ConstEval(ConstEvalErr {
-                    span,
-                    kind: ErrKind::NonConstPath,
-                }));
+                self.errors.push(PatternError::NonConstPath(span));
                 PatternKind::Wild
             }
         }
@@ -673,24 +671,35 @@ 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);
-                let instance = ty::Instance::resolve(
+                match ty::Instance::resolve(
                     self.tcx,
                     self.param_env,
                     def_id,
                     substs,
-                ).unwrap();
-                let cid = GlobalId {
-                    instance,
-                    promoted: None,
-                };
-                match self.tcx.at(span).const_eval(self.param_env.and(cid)) {
-                    Ok(value) => {
-                        return self.const_to_pat(instance, value, id, span)
+                ) {
+                    Some(instance) => {
+                        let cid = GlobalId {
+                            instance,
+                            promoted: None,
+                        };
+                        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
+                            },
+                        }
                     },
-                    Err(e) => {
-                        self.errors.push(PatternError::ConstEval(e));
+                    None => {
+                        self.errors.push(if is_associated_const {
+                            PatternError::AssociatedConstInPattern(span)
+                        } else {
+                            PatternError::StaticInPattern(span)
+                        });
                         PatternKind::Wild
-                    }
+                    },
                 }
             }
             _ => self.lower_variant_or_leaf(def, span, ty, vec![]),
@@ -716,11 +725,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                         let cv = self.tcx.mk_const(ty::Const { val, ty });
                         *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
                     },
-                    Err(e) => {
-                        self.errors.push(PatternError::ConstEval(ConstEvalErr {
-                            span: lit.span,
-                            kind: e,
-                        }));
+                    Err(()) => {
+                        self.errors.push(PatternError::FloatBug);
                         PatternKind::Wild
                     },
                 }
@@ -733,17 +739,16 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                     _ => span_bug!(expr.span, "not a literal: {:?}", expr),
                 };
                 match super::eval::lit_to_const(&lit.node, self.tcx, ty, true) {
-                    Ok(value) => PatternKind::Constant {
-                        value: self.tcx.mk_const(ty::Const {
-                            ty,
-                            val: value,
-                        }),
+                    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(e) => {
-                        self.errors.push(PatternError::ConstEval(ConstEvalErr {
-                            span: lit.span,
-                            kind: e,
-                        }));
+                    Err(()) => {
+                        self.errors.push(PatternError::FloatBug);
                         PatternKind::Wild
                     },
                 }
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 533bad18c38..a150335a1ae 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/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index dc8bbdc60e0..db44d870acb 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -524,7 +524,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             };
             let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) {
                 Ok(cv) => cv.val.unwrap_usize(cx.tcx),
-                Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
+                Err(e) => {
+                    e.report(cx.tcx, cx.tcx.def_span(def_id), "array length");
+                    ConstUsize::new(0, cx.tcx.sess.target.usize_ty).unwrap()
+                },
             };
 
             ExprKind::Repeat {
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 6fda4703d1c..24bf9445d45 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -16,7 +16,7 @@
 
 use hair::*;
 
-use rustc::middle::const_val::{ConstEvalErr, ConstVal};
+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;
@@ -238,17 +238,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,
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index b476ea56852..7d7e6ec9451 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -7,7 +7,7 @@ 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,
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index 48f123b1f57..2e2246f9ab9 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/interpret/const_eval.rs
@@ -1,6 +1,6 @@
 use rustc::hir;
-use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError};
 use rustc::middle::const_val::{ConstEvalErr, ConstVal};
+use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError};
 use rustc::mir;
 use rustc::ty::{self, TyCtxt, Ty, Instance};
 use rustc::ty::layout::{self, LayoutOf};
@@ -9,17 +9,37 @@ 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, PlaceExtra};
+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;
 
+pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    instance: Instance<'tcx>,
+    mir: &'mir mir::Mir<'tcx>,
+) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>> {
+    debug!("mk_borrowck_eval_cx: {:?}", instance);
+    let param_env = tcx.param_env(instance.def_id());
+    let limits = super::ResourceLimits::default();
+    let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ());
+    // insert a stack frame so any queries have the correct substs
+    ecx.push_stack_frame(
+        instance,
+        mir.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, ());
@@ -35,64 +55,95 @@ 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>,
     cid: GlobalId<'tcx>,
+    mir: &'mir mir::Mir<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> {
-    eval_body_and_ecx(tcx, cid, param_env).0
+) -> 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
+        }
+    }
 }
 
-pub fn check_body<'a, 'tcx>(
+pub fn eval_body<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     cid: GlobalId<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-) {
-    let (res, ecx) = eval_body_and_ecx(tcx, cid, param_env);
-    if let Err(mut err) = res {
-        ecx.report(&mut err);
+) -> 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
+        }
     }
 }
 
-fn eval_body_and_ecx<'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>,
-) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'tcx, CompileTimeEvaluator>) {
+) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
     debug!("eval_body: {:?}, {:?}", cid, param_env);
     let limits = super::ResourceLimits::default();
     let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ());
     let res = (|| {
-        let mut mir = ecx.load_mir(cid.instance.def)?;
+        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];
         }
         let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
-        if ecx.tcx.has_attr(cid.instance.def_id(), "linkage") {
-            return Err(ConstEvalError::NotConst("extern global".to_string()).into());
-        }
-        if tcx.interpret_interner.borrow().get_cached(cid).is_none() {
-            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(cid.instance.def_id()));
-            trace!("const_eval: pushing stack frame for global: {}", name);
-            ecx.push_stack_frame(
-                cid.instance,
-                mir.span,
-                mir,
-                Place::from_ptr(ptr, layout.align),
-                cleanup.clone(),
-            )?;
-
-            while ecx.step()? {}
-        }
-        let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached");
+        let alloc = tcx.interpret_interner.borrow().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.borrow_mut().cache(cid.instance.def_id(), ptr.alloc_id);
+                }
+                let span = tcx.def_span(cid.instance.def_id());
+                let internally_mutable = !layout.ty.is_freeze(tcx, param_env, 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()));
+                trace!("const_eval: pushing stack frame for global: {}", name);
+                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,
@@ -103,18 +154,6 @@ fn eval_body_and_ecx<'a, 'tcx>(
     (res, ecx)
 }
 
-pub fn eval_body_as_integer<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    cid: GlobalId<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-) -> EvalResult<'tcx, u128> {
-    let (value, _, ty) = eval_body(tcx, cid, param_env)?;
-    match value {
-        Value::ByVal(prim) => prim.to_bytes(),
-        _ => err!(TypeNotPrimitive(ty)),
-    }
-}
-
 pub struct CompileTimeEvaluator;
 
 impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
@@ -159,11 +198,11 @@ 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>],
@@ -204,7 +243,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,
@@ -246,7 +285,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>,
@@ -262,12 +301,16 @@ 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 box_alloc<'a>(
-        _ecx: &mut EvalContext<'a, 'tcx, Self>,
+        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         _ty: Ty<'tcx>,
         _dest: Place,
     ) -> EvalResult<'tcx> {
@@ -277,7 +320,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> {
@@ -374,14 +417,34 @@ pub fn const_eval_provider<'a, 'tcx>(
     let def_id = cid.instance.def.def_id();
     let span = tcx.def_span(def_id);
 
+    if tcx.is_foreign_item(def_id) {
+        let id = tcx.interpret_interner.borrow().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.borrow_mut().reserve();
+                tcx.interpret_interner.borrow_mut().cache(def_id, id);
+                id
+            },
+        };
+        let ty = tcx.type_of(def_id);
+        let layout = (tcx, key.param_env).layout_of(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,
+        }))
+    }
+
     if let Some(id) = tcx.hir.as_local_node_id(def_id) {
         let tables = tcx.typeck_tables_of(def_id);
 
         // Do match-check before building MIR
         if tcx.check_match(def_id).is_err() {
             return Err(ConstEvalErr {
-                span,
                 kind: CheckMatchError,
+                span,
             });
         }
 
@@ -392,22 +455,25 @@ pub fn const_eval_provider<'a, 'tcx>(
         // Do not continue into miri if typeck errors occurred; it will fail horribly
         if tables.tainted_by_errors {
             return Err(ConstEvalErr {
+                kind: TypeckError,
                 span,
-                kind: TypeckError
             });
         }
     };
 
-    match ::interpret::eval_body(tcx, cid, key.param_env) {
-        Ok((miri_value, _, miri_ty)) => Ok(tcx.mk_const(ty::Const {
+    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,
-        })),
-        Err(err) => {
-            Err(ConstEvalErr {
-                span,
-                kind: err.into()
-            })
+        })
+    }).map_err(|mut err| {
+        if tcx.is_static(def_id).is_some() {
+            ecx.report(&mut err, true);
         }
-    }
+        ConstEvalErr {
+        kind: err.into(),
+        span,
+        }
+    })
 }
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 63939f7e038..7d2b83e9217 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -3,7 +3,7 @@ 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};
@@ -21,7 +21,7 @@ use super::{Place, PlaceExtra, Memory,
             HasMemory, MemoryKind, operator,
             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,
 
@@ -32,10 +32,10 @@ pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> {
     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,
@@ -47,12 +47,12 @@ pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> {
 }
 
 /// 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>,
@@ -131,6 +131,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 +147,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
     }
 }
 
-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
     }
 }
 
-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 +186,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,7 +196,7 @@ 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>,
         param_env: ty::ParamEnv<'tcx>,
@@ -214,15 +223,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,14 +249,14 @@ 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> {
+    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)?;
-                Ok(self.read_global_as_value(GlobalId {
+                self.read_global_as_value(GlobalId {
                     instance,
                     promoted: None,
-                }, self.layout_of(ty)?))
+                }, ty)
             }
             ConstVal::Value(val) => Ok(val),
         }
@@ -380,14 +389,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();
@@ -819,7 +828,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)?
                     }
                 };
 
@@ -931,9 +940,28 @@ 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
+                .borrow()
+                .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 = match self.tcx.const_eval(self.param_env.and(gid)) {
+            Ok(val) => val,
+            Err(err) => match err.kind {
+                ErrKind::Miri(miri) => return Err(miri),
+                ErrKind::TypeckError => return err!(TypeckError),
+                other => bug!("const eval returned {:?}", other),
+            },
+        };
+        self.const_to_value(&cv.val, ty)
     }
 
     pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> {
@@ -1326,15 +1354,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
     }
 
@@ -1544,7 +1572,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         Ok(())
     }
 
-    pub fn report(&self, e: &mut EvalError) {
+    pub fn report(&self, e: &mut EvalError, as_err: bool) {
+        if let EvalErrorKind::TypeckError = e.kind {
+            return;
+        }
         if let Some(ref mut backtrace) = e.backtrace {
             let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
             backtrace.resolve();
@@ -1582,8 +1613,34 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             } else {
                 block.terminator().source_info.span
             };
-            let mut err = self.tcx.sess.struct_span_err(span, &e.to_string());
+            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");
+            let mut err = if as_err {
+                ::rustc::middle::const_val::struct_error(self.tcx, span, "constant evaluation error")
+            } else {
+                self.tcx.struct_span_lint_node(
+                    ::rustc::lint::builtin::CONST_ERR,
+                    node_id,
+                    span,
+                    "constant evaluation error",
+                )
+            };
+            err.span_label(span, e.to_string());
+            let mut last_span = None;
             for &Frame { instance, span, .. } in self.stack().iter().rev() {
+                // make sure we don't emit frames that are duplicates of the previous
+                if let Some(last) = last_span {
+                    if last == span {
+                        continue;
+                    }
+                } else {
+                    last_span = Some(span);
+                }
                 if self.tcx.def_key(instance.def_id()).disambiguated_data.data ==
                     DefPathData::ClosureExpr
                 {
@@ -1599,7 +1656,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
     }
 }
 
-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())
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index c2989dbaaf1..d5e57d3317c 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -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,30 @@ 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>;
 
     /// 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 +92,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 +105,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 7cc4ba84895..5ee84e0e02c 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -1,6 +1,6 @@
 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::layout::{self, Align, TargetDataLayout};
@@ -19,8 +19,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 +27,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,
 
@@ -56,7 +54,7 @@ pub struct Memory<'a, 'tcx: 'a, M: Machine<'tcx>> {
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
-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 new(tcx: TyCtxt<'a, 'tcx, 'tcx>, max_memory: u64, data: M::MemoryData) -> Self {
         Memory {
             data,
@@ -107,6 +105,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             relocations: BTreeMap::new(),
             undef_mask: UndefMask::new(size),
             align,
+            mutable: false,
         };
         let id = self.tcx.interpret_interner.borrow_mut().reserve();
         M::add_lock(self, id);
@@ -119,7 +118,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 +162,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(()),
@@ -292,7 +286,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) {
@@ -376,7 +370,6 @@ 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) {
@@ -388,15 +381,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
                                 Some(a) => (a, "(immutable)".to_owned()),
                                 None => if let Some(func) = int.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 +434,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 +445,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 +509,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,10 +517,8 @@ 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),
         }
@@ -549,60 +535,27 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             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(());
+        // The machine handled it
+        if M::mark_static_initialized(self, alloc_id, 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);
+        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) => {},
         }
-        // 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())
+        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.mutable = mutability == Mutability::Mutable;
+            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)?;
             }
-            None => return err!(DanglingPointerDeref),
-        };
-        // recurse into inner allocations
-        for &alloc in relocations.values() {
-            self.mark_inner_allocation_initialized(alloc, mutability)?;
         }
-        // put back the relocations
-        self.alloc_map
-            .get_mut(&alloc_id)
-            .expect("checked above")
-            .relocations = relocations;
         Ok(())
     }
 
@@ -829,7 +782,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 +836,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 +897,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 +908,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,14 +921,14 @@ 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> {
+pub 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()),
@@ -985,9 +939,9 @@ fn read_target_int(endianness: layout::Endian, mut source: &[u8]) -> Result<i128
 // 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.
@@ -1051,31 +1005,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 ba894a1728a..f23ba90fd4c 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -18,6 +18,17 @@ 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, const_val_field, const_discr, check_body};
+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::operator::unary_op;
+pub use self::memory::{write_target_uint, write_target_int, read_target_uint, read_target_int};
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index b20540b00ce..bad744194d5 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -8,7 +8,7 @@ use super::{EvalContext, Place, Machine, ValTy};
 
 use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, bytes_to_f32, bytes_to_f64};
 
-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,
@@ -56,6 +56,24 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 }
 
 macro_rules! overflow {
+    (overflowing_div, $l:expr, $r:expr) => ({
+        let (val, overflowed) = if $r == 0 {
+            ($l, true)
+        } else {
+            $l.overflowing_div($r)
+        };
+        let primval = PrimVal::Bytes(val as u128);
+        Ok((primval, overflowed))
+    });
+    (overflowing_rem, $l:expr, $r:expr) => ({
+        let (val, overflowed) = if $r == 0 {
+            ($l, true)
+        } else {
+            $l.overflowing_rem($r)
+        };
+        let primval = PrimVal::Bytes(val as u128);
+        Ok((primval, overflowed))
+    });
     ($op:ident, $l:expr, $r:expr) => ({
         let (val, overflowed) = $l.$op($r);
         let primval = PrimVal::Bytes(val as u128);
@@ -105,7 +123,7 @@ macro_rules! int_shift {
     })
 }
 
-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,
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 4a2b4547cb0..349ac630559 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -1,11 +1,13 @@
 use rustc::mir;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
+use rustc::traits;
 use rustc_data_structures::indexed_vec::Idx;
 
 use rustc::mir::interpret::{GlobalId, Value, PrimVal, EvalResult, Pointer, MemoryPointer};
 use super::{EvalContext, Machine, ValTy};
 use interpret::memory::HasMemory;
+use rustc::middle::const_val::ErrKind;
 
 #[derive(Copy, Clone, Debug)]
 pub enum Place {
@@ -90,7 +92,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(
@@ -106,10 +108,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             // 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 {
+                self.read_global_as_value(GlobalId {
                     instance,
                     promoted: None,
-                }, self.layout_of(self.place_ty(place))?)))
+                }, self.place_ty(place)).map(Some)
             }
             Projection(ref proj) => self.try_read_place_projection(proj),
         }
@@ -199,17 +201,44 @@ 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
+                    .borrow()
+                    .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 param_env = ty::ParamEnv::empty(traits::Reveal::All);
+                    // ensure the static is computed
+                    if let Err(err) = self.tcx.const_eval(param_env.and(cid)) {
+                        match err.kind {
+                            ErrKind::Miri(miri) => return Err(miri),
+                            ErrKind::TypeckError => return err!(TypeckError),
+                            other => bug!("const eval returned {:?}", other),
+                        }
+                    };
+                    let alloc = self
+                        .tcx
+                        .interpret_interner
+                        .borrow()
+                        .get_cached(static_.def_id)
+                        .expect("uncached static");
+                    Place::Ptr {
+                        ptr: MemoryPointer::new(alloc, 0).into(),
+                        align: layout.align,
+                        extra: PlaceExtra::None,
+                    }
                 }
             }
 
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 2b0f9041d51..21e81ff668e 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -2,21 +2,12 @@
 //!
 //! 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> {
+impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> {
         self.steps_remaining = self.steps_remaining.saturating_sub(n);
         if self.steps_remaining > 0 {
@@ -41,52 +32,14 @@ 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);
         }
 
         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)
     }
 
@@ -152,184 +105,4 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         }
         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 c5942712b87..fbc0c499e59 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 c18cf6d9f96..b1b5f77a2e6 100644
--- a/src/librustc_mir/interpret/terminator/mod.rs
+++ b/src/librustc_mir/interpret/terminator/mod.rs
@@ -13,7 +13,7 @@ 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;
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index 22417201f0d..4dc0879c85d 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -6,7 +6,7 @@ use rustc::mir::interpret::{PrimVal, Value, MemoryPointer, EvalResult};
 use super::{EvalContext, eval_context,
             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.
     ///
@@ -54,7 +54,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
         self.memory.mark_static_initalized(
             vtable.alloc_id,
-            Mutability::Mutable,
+            Mutability::Immutable,
         )?;
 
         Ok(vtable)
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 0f512569adf..0a8fd022dd1 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -194,6 +194,7 @@ 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};
@@ -568,14 +569,26 @@ 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);
+        match constant.val {
+            ConstVal::Unevaluated(def_id, substs) => {
+                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);
+            },
+            ConstVal::Value(Value::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => {
+                collect_miri(self.tcx, a.alloc_id, self.output);
+                collect_miri(self.tcx, b.alloc_id, self.output);
+            }
+            ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) |
+            ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) |
+            ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) |
+            ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) =>
+                collect_miri(self.tcx, ptr.alloc_id, self.output),
+            _ => {},
         }
 
         self.super_const(constant);
@@ -1098,6 +1111,28 @@ 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>>,
+) {
+    let interpret_interner = tcx.interpret_interner.borrow();
+    if let Some(alloc) = 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) = 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>,
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 0bef9f0602d..86d08dec2b9 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/instcombine.rs b/src/librustc_mir/transform/instcombine.rs
index 8856d263864..e27e7c72473 100644
--- a/src/librustc_mir/transform/instcombine.rs
+++ b/src/librustc_mir/transform/instcombine.rs
@@ -11,44 +11,52 @@
 //! Performs various peephole optimizations.
 
 use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, ProjectionElem, Rvalue, Local};
-use rustc::mir::visit::{MutVisitor, Visitor};
-use rustc::ty::{TyCtxt, TypeVariants};
+use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock};
+use rustc::mir::{SourceInfo, ARGUMENT_VISIBILITY_SCOPE, TerminatorKind};
+use rustc::mir::visit::{MutVisitor, Visitor, TyContext};
+use rustc::middle::const_val::ConstVal;
+use rustc::ty::{TyCtxt, TypeVariants, self, Instance};
+use rustc::mir::interpret::{Value, PrimVal, GlobalId};
+use interpret::{eval_body_with_mir, eval_body, mk_borrowck_eval_cx, unary_op, ValTy};
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::indexed_vec::Idx;
 use std::mem;
+use std::collections::VecDeque;
 use transform::{MirPass, MirSource};
+use syntax::codemap::{Span, DUMMY_SP};
+use rustc_data_structures::control_flow_graph::ControlFlowGraph;
+use rustc::ty::subst::Substs;
 
 pub struct InstCombine;
 
 impl MirPass for InstCombine {
     fn run_pass<'a, 'tcx>(&self,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          _: MirSource,
+                          source: MirSource,
                           mir: &mut Mir<'tcx>) {
-        // We only run when optimizing MIR (at any level).
-        if tcx.sess.opts.debugging_opts.mir_opt_level == 0 {
-            return
-        }
 
         // First, find optimization opportunities. This is done in a pre-pass to keep the MIR
         // read-only so that we can do global analyses on the MIR in the process (e.g.
         // `Place::ty()`).
         let optimizations = {
-            let mut optimization_finder = OptimizationFinder::new(mir, tcx);
+            let mut optimization_finder = OptimizationFinder::new(mir, tcx, source);
             optimization_finder.visit_mir(mir);
             optimization_finder.optimizations
         };
 
         // Then carry out those optimizations.
-        MutVisitor::visit_mir(&mut InstCombineVisitor { optimizations }, mir);
+        MutVisitor::visit_mir(&mut InstCombineVisitor { optimizations, tcx }, mir);
     }
 }
 
-pub struct InstCombineVisitor<'tcx> {
+type Const<'tcx> = (Value, ty::Ty<'tcx>, Span);
+
+pub struct InstCombineVisitor<'a, 'tcx: 'a> {
     optimizations: OptimizationList<'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
-impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
+impl<'a, 'tcx> MutVisitor<'tcx> for InstCombineVisitor<'a, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
         if self.optimizations.and_stars.remove(&location) {
             debug!("Replacing `&*`: {:?}", rvalue);
@@ -67,28 +75,460 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
             *rvalue = Rvalue::Use(Operand::Constant(box constant));
         }
 
+        if let Some((value, ty, span)) = self.optimizations.const_prop.remove(&location) {
+            let value = self.tcx.mk_const(ty::Const {
+                val: ConstVal::Value(value),
+                ty,
+            });
+            debug!("Replacing `{:?}` with {:?}", rvalue, value);
+            let constant = Constant {
+                ty,
+                literal: Literal::Value { value },
+                span,
+            };
+            *rvalue = Rvalue::Use(Operand::Constant(box constant));
+        }
+
         self.super_rvalue(rvalue, location)
     }
+
+    fn visit_constant(
+        &mut self,
+        constant: &mut Constant<'tcx>,
+        location: Location,
+    ) {
+        self.super_constant(constant, location);
+        if let Some(&(val, ty, _)) = self.optimizations.constants.get(constant) {
+            constant.literal = Literal::Value {
+                value: self.tcx.mk_const(ty::Const {
+                    val: ConstVal::Value(val),
+                    ty,
+                }),
+            };
+        }
+    }
+
+    fn visit_operand(
+        &mut self,
+        operand: &mut Operand<'tcx>,
+        location: Location,
+    ) {
+        self.super_operand(operand, location);
+        let new = match operand {
+            Operand::Move(Place::Local(local)) |
+            Operand::Copy(Place::Local(local)) => {
+                trace!("trying to read {:?}", local);
+                self.optimizations.places.get(&local).cloned()
+            },
+            _ => return,
+        };
+        if let Some((value, ty, span)) = new {
+            let value = self.tcx.mk_const(ty::Const {
+                val: ConstVal::Value(value),
+                ty,
+            });
+            debug!("Replacing `{:?}` with {:?}", operand, value);
+            let constant = Constant {
+                ty,
+                literal: Literal::Value { value },
+                span,
+            };
+            *operand = Operand::Constant(box constant);
+        }
+    }
+
+    fn visit_terminator_kind(
+        &mut self,
+        block: BasicBlock,
+        kind: &mut TerminatorKind<'tcx>,
+        location: Location,
+    ) {
+        match kind {
+            TerminatorKind::SwitchInt { discr: value, .. } |
+            TerminatorKind::Yield { value, .. } |
+            TerminatorKind::Assert { cond: value, .. } => {
+                if let Some((new, ty, span)) = self.optimizations.const_prop.remove(&location) {
+                    let new = self.tcx.mk_const(ty::Const {
+                        val: ConstVal::Value(new),
+                        ty,
+                    });
+                    debug!("Replacing `{:?}` with {:?}", value, new);
+                    let constant = Constant {
+                        ty,
+                        literal: Literal::Value { value: new },
+                        span,
+                    };
+                    *value = Operand::Constant(box constant);
+                }
+            }
+            // FIXME: do this optimization for function calls
+            _ => {},
+        }
+        self.super_terminator_kind(block, kind, location)
+    }
 }
 
 /// Finds optimization opportunities on the MIR.
 struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> {
     mir: &'b Mir<'tcx>,
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    source: MirSource,
     optimizations: OptimizationList<'tcx>,
 }
 
 impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> {
-    fn new(mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> OptimizationFinder<'b, 'a, 'tcx> {
+    fn new(
+        mir: &'b Mir<'tcx>,
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        source: MirSource,
+    ) -> OptimizationFinder<'b, 'a, 'tcx> {
         OptimizationFinder {
             mir,
             tcx,
+            source,
             optimizations: OptimizationList::default(),
         }
     }
+
+    fn eval_constant(&mut self, c: &Constant<'tcx>, span: Span) -> Option<Const<'tcx>> {
+        if let Some(&val) = self.optimizations.constants.get(c) {
+            return Some(val);
+        }
+        match c.literal {
+            Literal::Value { value } => match value.val {
+                ConstVal::Value(v) => Some((v, value.ty, span)),
+                ConstVal::Unevaluated(did, substs) => {
+                    let param_env = self.tcx.param_env(self.source.def_id);
+                    let span = self.tcx.def_span(did);
+                    let instance = Instance::resolve(
+                        self.tcx,
+                        param_env,
+                        did,
+                        substs,
+                    )?;
+                    let cid = GlobalId {
+                        instance,
+                        promoted: None,
+                    };
+                    let (value, _, ty) = eval_body(self.tcx, cid, param_env)?;
+                    let val = (value, ty, span);
+                    trace!("evaluated {:?} to {:?}", c, val);
+                    self.optimizations.constants.insert(c.clone(), val);
+                    Some(val)
+                },
+            },
+            // 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),
+                };
+                let span = self.tcx.def_span(self.source.def_id);
+                let param_env = self.tcx.param_env(self.source.def_id);
+                let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, param_env)?;
+                let val = (value, ty, span);
+                trace!("evaluated {:?} to {:?}", c, val);
+                self.optimizations.constants.insert(c.clone(), val);
+                Some(val)
+            }
+        }
+    }
+
+    fn eval_operand(&mut self, op: &Operand<'tcx>, span: Span) -> Option<Const<'tcx>> {
+        match *op {
+            Operand::Constant(ref c) => self.eval_constant(c, span),
+            Operand::Move(ref place) | Operand::Copy(ref place) => match *place {
+                Place::Local(loc) => self.optimizations.places.get(&loc).cloned(),
+                // FIXME(oli-obk): field and index projections
+                Place::Projection(_) => None,
+                _ => None,
+            },
+        }
+    }
+
+    fn simplify_operand(&mut self, op: &Operand<'tcx>, span: Span) -> Option<Const<'tcx>> {
+        match *op {
+            Operand::Constant(ref c) => match c.literal {
+                Literal::Value { .. } => None,
+                _ => self.eval_operand(op, span),
+            },
+            _ => self.eval_operand(op, span),
+        }
+    }
+
+    fn const_prop(
+        &mut self,
+        rvalue: &Rvalue<'tcx>,
+        place_ty: ty::Ty<'tcx>,
+        span: Span,
+    ) -> Option<Const<'tcx>> {
+        match *rvalue {
+            Rvalue::Use(ref op) => self.simplify_operand(op, span),
+            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).unwrap();
+
+                let val = self.eval_operand(arg, span)?;
+                let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?;
+                let kind = ecx.ty_to_primval_kind(val.1).ok()?;
+                match unary_op(op, prim, kind) {
+                    Ok(val) => Some((Value::ByVal(val), place_ty, span)),
+                    Err(mut err) => {
+                        ecx.report(&mut err, false);
+                        None
+                    },
+                }
+            }
+            Rvalue::CheckedBinaryOp(op, ref left, ref right) |
+            Rvalue::BinaryOp(op, ref left, ref right) => {
+                trace!("rvalue binop {:?} for {:?} and {:?}", op, left, right);
+                let left = self.eval_operand(left, span)?;
+                let right = self.eval_operand(right, span)?;
+                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).unwrap();
+
+                let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?;
+                let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.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::EvalError;
+                                use rustc::mir::interpret::EvalErrorKind;
+                                let mut err = EvalError {
+                                    kind: EvalErrorKind::OverflowingMath,
+                                    backtrace: None,
+                                };
+                                ecx.report(&mut err, false);
+                                return None;
+                            }
+                            Value::ByVal(val)
+                        };
+                        Some((val, place_ty, span))
+                    },
+                    Err(mut err) => {
+                        ecx.report(&mut err, false);
+                        None
+                    },
+                }
+            },
+        }
+    }
+}
+
+fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          param_env: ty::ParamEnv<'tcx>,
+                          ty: ty::Ty<'tcx>) -> Option<u64> {
+    use rustc::ty::layout::LayoutOf;
+    (tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes())
+}
+
+struct ConstPropVisitor {
+    local: Local,
+    can_const_prop: bool,
+    // false at the beginning, once set, there are not allowed to be any more assignments
+    found_assignment: bool,
+}
+
+impl ConstPropVisitor {
+    /// returns true if `local` can be propagated
+    fn check<'tcx>(local: Local, mir: &Mir<'tcx>) -> bool {
+        let mut cpv = ConstPropVisitor {
+            local,
+            can_const_prop: true,
+            found_assignment: false,
+        };
+        cpv.visit_mir(mir);
+        cpv.can_const_prop
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for ConstPropVisitor {
+    fn visit_statement(
+        &mut self,
+        block: BasicBlock,
+        statement: &Statement<'tcx>,
+        location: Location,
+    ) {
+        self.super_statement(block, statement, location);
+        match statement.kind {
+            StatementKind::SetDiscriminant { place: Place::Local(local), .. } |
+            StatementKind::Assign(Place::Local(local), _) => {
+                if local == self.local {
+                    if self.found_assignment {
+                        self.can_const_prop = false;
+                    } else {
+                        self.found_assignment = true
+                    }
+                }
+            },
+            StatementKind::InlineAsm { ref outputs, .. } => {
+                for place in outputs {
+                    if let Place::Local(local) = *place {
+                        if local == self.local {
+                            if self.found_assignment {
+                                self.can_const_prop = false;
+                            } else {
+                                self.found_assignment = true
+                            }
+                            return;
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
+    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+        self.super_rvalue(rvalue, location);
+        if let Rvalue::Ref(_, _, Place::Local(local)) = *rvalue {
+            if local == self.local {
+                self.can_const_prop = false;
+            }
+        }
+    }
 }
 
 impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> {
+    // override to visit basic blocks in execution order
+    fn super_mir(&mut self, mir: &Mir<'tcx>) {
+        let mut seen = FxHashSet::default();
+        seen.insert(mir.start_node());
+        let mut sorted = Vec::new();
+        let mut next = VecDeque::new();
+        sorted.push(mir.start_node());
+        next.push_back(mir.start_node());
+        while let Some(current) = next.pop_front() {
+            for successor in mir.successors(current) {
+                trace!("checking successor of {:?}: {:?}", current, successor);
+                trace!("{:?}, {:?}", sorted, next);
+                if seen.contains(&successor) {
+                    for &pending in &next {
+                        // not a back-edge, just a branch merging back into a single execution
+                        if pending == successor {
+                            // move to the back of the queue
+                            let i = sorted.iter().position(|&b| b == successor).unwrap();
+                            sorted.remove(i);
+                            sorted.push(successor);
+                            break;
+                        }
+                    }
+                } else {
+                    seen.insert(successor);
+                    sorted.push(successor);
+                    next.push_back(successor);
+                }
+            }
+        }
+        trace!("checking basic blocks: {:?}", sorted);
+        for bb in sorted {
+            self.visit_basic_block_data(bb, &mir[bb]);
+        }
+
+        for scope in &mir.visibility_scopes {
+            self.visit_visibility_scope_data(scope);
+        }
+
+        self.visit_ty(&mir.return_ty(), TyContext::ReturnTy(SourceInfo {
+            span: mir.span,
+            scope: ARGUMENT_VISIBILITY_SCOPE,
+        }));
+
+        for local in mir.local_decls.indices() {
+            self.visit_local_decl(local, &mir.local_decls[local]);
+        }
+
+        self.visit_span(&mir.span);
+    }
+
+    fn visit_constant(
+        &mut self,
+        constant: &Constant<'tcx>,
+        location: Location,
+    ) {
+        trace!("visit_constant: {:?}", constant);
+        self.super_constant(constant, location);
+        self.eval_constant(constant, DUMMY_SP);
+    }
+
+    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);
+            let span = self.mir.source_info(location).span;
+            if let Some(value) = self.const_prop(rval, place_ty, span) {
+                self.optimizations.const_prop.insert(location, value);
+                if let Place::Local(local) = *place {
+                    if !self.mir.local_decls[local].is_user_variable
+                        && ConstPropVisitor::check(local, self.mir) {
+                        trace!("storing {:?} to {:?}", value, local);
+                        assert!(self.optimizations.places.insert(local, value).is_none());
+                    }
+                }
+            }
+        }
+        self.super_statement(block, statement, location);
+    }
+
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         if let Rvalue::Ref(_, _, Place::Projection(ref projection)) = *rvalue {
             if let ProjectionElem::Deref = projection.elem {
@@ -111,10 +551,33 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> {
 
         self.super_rvalue(rvalue, location)
     }
+
+    fn visit_terminator_kind(
+        &mut self,
+        _block: BasicBlock,
+        kind: &TerminatorKind<'tcx>,
+        location: Location,
+    ) {
+        let span = self.mir.source_info(location).span;
+        match kind {
+            TerminatorKind::SwitchInt { discr: value, .. } |
+            TerminatorKind::Yield { value, .. } |
+            TerminatorKind::Assert { cond: value, .. } => {
+                if let Some(value) = self.simplify_operand(value, span) {
+                    self.optimizations.const_prop.insert(location, value);
+                }
+            }
+            // FIXME: do this optimization for function calls
+            _ => {},
+        }
+    }
 }
 
 #[derive(Default)]
 struct OptimizationList<'tcx> {
     and_stars: FxHashSet<Location>,
     arrays_lengths: FxHashMap<Location, Constant<'tcx>>,
+    const_prop: FxHashMap<Location, Const<'tcx>>,
+    places: FxHashMap<Local, Const<'tcx>>,
+    constants: FxHashMap<Constant<'tcx>, Const<'tcx>>,
 }
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 0ce3f729305..122b51dbbb7 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/mir/block.rs b/src/librustc_trans/mir/block.rs
index 239300c1ecf..6d2f9c6c97f 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, 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};
@@ -206,10 +204,11 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                     let (otherwise, targets) = targets.split_last().unwrap();
                     let switch = bx.switch(discr.immediate(),
                                             llblock(self, *otherwise), values.len());
+                    let switch_llty = bcx.ccx.layout_of(switch_ty).immediate_llvm_type(bcx.ccx);
                     for (&value, target) in values.iter().zip(targets) {
-                        let val = Const::from_bytes(bx.cx, value, switch_ty);
+                        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)
                     }
                 }
             }
@@ -359,10 +358,10 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
 
                         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
-                                }));
+                                .map(|index| format!(
+                                    "index out of bounds: the len is {} but the index is {}",
+                                    len, index,
+                                )));
 
                         let file_line_col = C_struct(bx.cx, &[filename, line, col], false);
                         let file_line_col = consts::addr_of(bx.cx,
@@ -385,7 +384,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                                                                 "panic_loc");
                         (lang_items::PanicFnLangItem,
                          vec![msg_file_line_col],
-                         Some(ErrKind::Math(err.clone())))
+                         Some(err.description().to_owned()))
                     }
                     mir::AssertMessage::GeneratorResumedAfterReturn |
                     mir::AssertMessage::GeneratorResumedAfterPanic => {
@@ -413,10 +412,11 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
                 // 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);
+                            span, &format!(
+                                "this expression will panic at run-time with {:?}",
+                                err,
+                            ));
                         diag.emit();
                     }
                 }
@@ -530,10 +530,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.remove_me_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 66173cfef92..5050628b024 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -9,966 +9,27 @@
 // except according to those terms.
 
 use llvm::{self, ValueRef};
-use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
-use rustc_const_math::{ConstInt, ConstMathErr, MAX_F32_PLUS_HALF_ULP};
+use rustc_const_math::{ConstInt, ConstMathErr};
+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::interpret::{Value as MiriValue, PrimVal};
-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 rustc_data_structures::indexed_vec::Idx;
+use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue};
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
 use base;
-use abi::{self, Abi};
-use callee;
 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::{CodegenCx};
+use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize};
 use common::const_to_opt_u128;
 use consts;
 use type_of::LayoutLlvmExt;
 use type_::Type;
-use value::Value;
 
-use syntax_pos::Span;
-use syntax::ast;
-use syntax::symbol::Symbol;
-
-use std::fmt;
-use std::ptr;
-
-use super::operand::{OperandRef, OperandValue};
-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_bytes(ccx: &CrateContext<'a, 'tcx>, b: u128, ty: Ty<'tcx>) -> Const<'tcx> {
-        let llval = match ty.sty {
-            ty::TyInt(ast::IntTy::I128) |
-            ty::TyUint(ast::UintTy::U128) => C_uint_big(Type::i128(ccx), b),
-            ty::TyInt(i) => C_int(Type::int_from_ty(ccx, i), b as i128 as i64),
-            ty::TyUint(u) => C_uint(Type::uint_from_ty(ccx, u), b as u64),
-            ty::TyBool => {
-                assert!(b <= 1);
-                C_bool(ccx, b == 1)
-            },
-            ty::TyChar => {
-                assert_eq!(b as u32 as u128, b);
-                let c = b as u32;
-                assert!(::std::char::from_u32(c).is_some());
-                C_uint(Type::char(ccx), c as u64)
-            },
-            ty::TyFloat(fty) => {
-                let llty = ccx.layout_of(ty).llvm_type(ccx);
-                let bits = match fty {
-                    ast::FloatTy::F32 => C_u32(ccx, b as u32),
-                    ast::FloatTy::F64 => C_u64(ccx, b as u64),
-                };
-                consts::bitcast(bits, llty)
-            },
-            ty::TyAdt(adt, _) if adt.is_enum() => {
-                use rustc::ty::util::IntTypeExt;
-                Const::from_bytes(ccx, b, adt.repr.discr_type().to_ty(ccx.tcx())).llval
-            },
-            _ => bug!("from_bytes({}, {})", b, ty),
-        };
-        Const { llval, 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);
-        trace!("from_constval: {:#?}: {}", cv, ty);
-        let val = match *cv {
-            ConstVal::Unevaluated(..) => unimplemented!("const val `{:?}`", cv),
-            ConstVal::Value(MiriValue::ByRef(..)) => unimplemented!("{:#?}:{}", cv, ty),
-            ConstVal::Value(MiriValue::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) => {
-                match ty.sty {
-                    ty::TyRef(_, ref tam) => match tam.ty.sty {
-                        ty::TyStr => {},
-                        _ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty),
-                    },
-                    _ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty),
-                }
-                let alloc = ccx
-                    .tcx()
-                    .interpret_interner
-                    .borrow()
-                    .get_alloc(ptr.alloc_id)
-                    .expect("miri alloc not found");
-                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");
-                C_str_slice(ccx, Symbol::intern(s).as_str())
-            },
-            ConstVal::Value(MiriValue::ByValPair(..)) => unimplemented!(),
-            ConstVal::Value(MiriValue::ByVal(PrimVal::Bytes(b))) =>
-                return Const::from_bytes(ccx, b, ty),
-            ConstVal::Value(MiriValue::ByVal(PrimVal::Undef)) => C_undef(llty),
-            ConstVal::Value(MiriValue::ByVal(PrimVal::Ptr(ptr))) => {
-                let alloc = ccx
-                    .tcx()
-                    .interpret_interner
-                    .borrow()
-                    .get_alloc(ptr.alloc_id)
-                    .expect("miri alloc not found");
-                let data = &alloc.bytes[(ptr.offset as usize)..];
-                consts::addr_of(ccx, C_bytes(ccx, data), ccx.align_of(ty), "byte_str")
-            }
-        };
-
-        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.unwrap_u64())
-            }
-            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 statements 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);
-                    }
-                }
-            }
-
-            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)
-                    };
-                    trace!("trans const fn call {:?}, {:?}, {:#?}", func, fn_ty, args);
-
-                    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)) = tcx.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
-                    } else {
-                        span_bug!(span, "diverging {:?} in constant", terminator.kind);
-                    }
-                }
-                _ => span_bug!(span, "{:?} in constant", terminator.kind)
-            };
-        }
-    }
-
-    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)
-                            }
-                        }
-                    }
-                    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)
-                };
-                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)
-    }
-
-}
+use super::super::callee;
+use super::MirContext;
 
 fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
     match t.sty {
@@ -1074,278 +135,239 @@ pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-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");
-    }
-    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())
-    }
-}
-
-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()
+pub fn primval_to_llvm(ccx: &CrateContext,
+                       cv: PrimVal,
+                       scalar: &Scalar,
+                       llty: Type) -> ValueRef {
+    let bits = if scalar.is_bool() { 1 } else { scalar.value.size(ccx).bits() };
+    match cv {
+        PrimVal::Undef => C_undef(Type::ix(ccx, bits)),
+        PrimVal::Bytes(b) => {
+            let llval = C_uint_big(Type::ix(ccx, bits), b);
+            if scalar.value == layout::Pointer {
+                unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) }
+            } else {
+                consts::bitcast(llval, llty)
             }
-            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())
+        },
+        PrimVal::Ptr(ptr) => {
+            let interpret_interner = ccx.tcx().interpret_interner.borrow();
+            if let Some(fn_instance) = interpret_interner.get_fn(ptr.alloc_id) {
+                callee::get_fn(ccx, fn_instance)
+            } else {
+                let static_ = interpret_interner.get_corresponding_static_def_id(ptr.alloc_id);
+                let base_addr = if let Some(def_id) = static_ {
+                    assert!(ccx.tcx().is_static(def_id).is_some());
+                    consts::get_static(ccx, def_id)
+                } else if let Some(alloc) = interpret_interner.get_alloc(ptr.alloc_id) {
+                    let init = global_initializer(ccx, alloc);
+                    if alloc.mutable {
+                        consts::addr_of_mut(ccx, init, alloc.align, "byte_str")
+                    } else {
+                        consts::addr_of(ccx, init, alloc.align, "byte_str")
+                    }
                 } else {
-                    Ok(Const::from_constval(bx.cx, &value.val, ty))
+                    bug!("missing allocation {:?}", ptr.alloc_id);
+                };
+
+                let llval = unsafe { llvm::LLVMConstInBoundsGEP(
+                    consts::bitcast(base_addr, Type::i8p(ccx)),
+                    &C_usize(ccx, ptr.offset),
+                    1,
+                ) };
+                if scalar.value != layout::Pointer {
+                    unsafe { llvm::LLVMConstPtrToInt(llval, llty.to_ref()) }
+                } else {
+                    consts::bitcast(llval, llty)
                 }
             }
-        };
-
-        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 global_initializer(ccx: &CrateContext, alloc: &Allocation) -> ValueRef {
+    let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
+    let layout = ccx.data_layout();
+    let pointer_size = layout.pointer_size.bytes() as usize;
+
+    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(ccx, &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(
+            ccx,
+            PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
+            &Scalar {
+                value: layout::Primitive::Pointer,
+                valid_range: 0..=!0
+            },
+            Type::i8p(ccx)
+        ));
+        next_offset = offset + pointer_size;
+    }
+    if alloc.bytes.len() >= next_offset {
+        llvals.push(C_bytes(ccx, &alloc.bytes[next_offset ..]));
+    }
+
+    C_struct(ccx, &llvals, true)
+}
 
 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(ccx.tcx(), def_id);
+    let cid = GlobalId {
+        instance,
+        promoted: None
     };
+    let param_env = ty::ParamEnv::empty(traits::Reveal::All);
+    ccx.tcx().const_eval(param_env.and(cid))?;
+
+    let alloc_id = ccx
+        .tcx()
+        .interpret_interner
+        .borrow()
+        .get_cached(def_id)
+        .expect("global not cached");
+
+    let alloc = ccx
+        .tcx()
+        .interpret_interner
+        .borrow()
+        .get_alloc(alloc_id)
+        .expect("miri allocation never successfully created");
+    Ok(global_initializer(ccx, alloc))
+}
 
-    if let layout::Abi::Uninhabited = l.abi {
-        return Const::new(C_undef(l.llvm_type(cx)), t);
-    }
-
-    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 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,
+        bcx: &Builder<'a, 'tcx>,
+        constant: &'tcx ty::Const<'tcx>,
+    ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+        match constant.val {
+            ConstVal::Unevaluated(def_id, ref substs) => {
+                let tcx = bcx.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(bcx, 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,
+        bcx: &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),
+                };
+                bcx.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;
+            mir::Literal::Value { value } => {
+                Ok(self.monomorphize(&value))
+            }
+        }.and_then(|c| self.const_to_miri_value(bcx, c))
     }
 
-    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;
+    // Old version of trans_constant now used just for SIMD shuffle
+    pub fn remove_me_shuffle_indices(&mut self,
+                                      bcx: &Builder<'a, 'tcx>,
+                                      constant: &mir::Constant<'tcx>)
+                                      -> (ValueRef, Ty<'tcx>)
+    {
+        let layout = bcx.ccx.layout_of(constant.ty);
+        self.mir_constant_to_miri_value(bcx, constant)
+            .and_then(|c| {
+                let llval = match c {
+                    MiriValue::ByVal(val) => {
+                        let scalar = match layout.abi {
+                            layout::Abi::Scalar(ref x) => x,
+                            _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
+                        };
+                        primval_to_llvm(bcx.ccx, val, scalar, layout.immediate_llvm_type(bcx.ccx))
+                    },
+                    MiriValue::ByValPair(a_val, b_val) => {
+                        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(
+                            bcx.ccx,
+                            a_val,
+                            a_scalar,
+                            layout.scalar_pair_element_llvm_type(bcx.ccx, 0),
+                        );
+                        let b_llval = primval_to_llvm(
+                            bcx.ccx,
+                            b_val,
+                            b_scalar,
+                            layout.scalar_pair_element_llvm_type(bcx.ccx, 1),
+                        );
+                        C_struct(bcx.ccx, &[a_llval, b_llval], false)
+                    },
+                    MiriValue::ByRef(..) => {
+                        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(
+                                bcx.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 = bcx.ccx.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(
+                                        bcx.ccx, prim, scalar,
+                                        layout.immediate_llvm_type(bcx.ccx),
+                                    ))
+                                },
+                                other => bug!("simd shuffle field {:?}, {}", other, constant.ty),
+                            }
+                        }).collect();
+                        C_struct(bcx.ccx, &values?, false)
+                    },
+                };
+                Ok((llval, constant.ty))
+            })
+            .unwrap_or_else(|e| {
+                e.report(bcx.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 = bcx.ccx.layout_of(ty).llvm_type(bcx.ccx);
+                (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 99e3a59e2c4..a1044ac87e4 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 e1b906646aa..01cf324124c 100644
--- a/src/librustc_trans/mir/operand.rs
+++ b/src/librustc_trans/mir/operand.rs
@@ -9,12 +9,14 @@
 // 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::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 +26,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 +92,70 @@ impl<'a, 'tcx> OperandRef<'tcx> {
         }
     }
 
+    pub fn from_const(bcx: &Builder<'a, 'tcx>,
+                      miri_val: MiriValue,
+                      ty: ty::Ty<'tcx>)
+                      -> Result<OperandRef<'tcx>, ConstEvalErr<'tcx>> {
+        let layout = bcx.ccx.layout_of(ty);
+
+        if layout.is_zst() {
+            return Ok(OperandRef::new_zst(bcx.ccx, 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(
+                    bcx.ccx,
+                    x,
+                    scalar,
+                    layout.immediate_llvm_type(bcx.ccx),
+                );
+                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(
+                    bcx.ccx,
+                    a,
+                    a_scalar,
+                    layout.scalar_pair_element_llvm_type(bcx.ccx, 0),
+                );
+                let b_llval = primval_to_llvm(
+                    bcx.ccx,
+                    b,
+                    b_scalar,
+                    layout.scalar_pair_element_llvm_type(bcx.ccx, 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(
+                    bcx.ccx,
+                    ptr.into_inner_primval(),
+                    &scalar,
+                    layout.llvm_type(bcx.ccx).ptr_to(),
+                );
+                return Ok(PlaceRef::new_sized(ptr, layout, align).load(bcx));
+            },
+        };
+
+        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 +394,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/trans_item.rs b/src/librustc_trans/trans_item.rs
index 91c1097fc7f..06d94e8d155 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/mod.rs b/src/librustc_typeck/check/mod.rs
index 1ad26b4cda5..f5303979f9c 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4013,7 +4013,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             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 {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 0271ad269e1..bb41acc5410 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -535,7 +535,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // 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 {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index d1e6f27069c..b9e4ce661d0 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2500,7 +2500,11 @@ 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
@@ -2633,7 +2637,11 @@ 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;
                     }
                 };
diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs
index 18476494300..02264228a6b 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 42fb40394fb..8c2e6233abf 100644
--- a/src/test/compile-fail/const-err-early.rs
+++ b/src/test/compile-fail/const-err-early.rs
@@ -11,14 +11,15 @@
 #![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 const_err
+pub const B: u8 = 200u8 + 200u8; //~ ERROR E0080
+pub const C: u8 = 200u8 * 4; //~ ERROR E0080
+pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR E0080
 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 _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 d4f9c0fe56d..668f95f2c8d 100644
--- a/src/test/compile-fail/const-err-multi.rs
+++ b/src/test/compile-fail/const-err-multi.rs
@@ -11,9 +11,14 @@
 #![deny(const_err)]
 
 pub const A: i8 = -std::i8::MIN; //~ ERROR attempt to negate with overflow
+//~^ ERROR E0080
+//~| ERROR const_err
 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() {
 }
diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs
index e65194ab56f..8bd759b6d37 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 9889ca1392a..a0648993aac 100644
--- a/src/test/compile-fail/const-err2.rs
+++ b/src/test/compile-fail/const-err2.rs
@@ -18,13 +18,11 @@ fn black_box<T>(_: T) {
 
 fn main() {
     let a = -std::i8::MIN;
-    //~^ ERROR attempt to negate with overflow
+    //~^ ERROR const_err
+    //~| ERROR const_err
     let b = 200u8 + 200u8 + 200u8;
-    //~^ ERROR attempt to add with overflow
     let c = 200u8 * 4;
-    //~^ ERROR attempt to multiply with overflow
     let d = 42u8 - (42u8 + 1);
-    //~^ ERROR attempt to subtract with overflow
     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 00000000000..636537d1df2
--- /dev/null
+++ b/src/test/compile-fail/const-err3.rs
@@ -0,0 +1,28 @@
+// 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
+    //~| ERROR const_err
+    let c = 200u8 * 4;
+    let d = 42u8 - (42u8 + 1);
+    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 058a8d0a1bd..00000000000
--- 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 00000000000..61a653589ff
--- /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
+     //~| attempt to subtract with overflow
+     );
+
+const VALS_I16: (i16,) =
+    (
+     i16::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| attempt to subtract with overflow
+     );
+
+const VALS_I32: (i32,) =
+    (
+     i32::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| attempt to subtract with overflow
+     );
+
+const VALS_I64: (i64,) =
+    (
+     i64::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| attempt to subtract with overflow
+     );
+
+const VALS_U8: (u8,) =
+    (
+     u8::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| attempt to subtract with overflow
+     );
+
+const VALS_U16: (u16,) = (
+     u16::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| attempt to subtract with overflow
+     );
+
+const VALS_U32: (u32,) = (
+     u32::MIN - 1,
+     //~^ ERROR constant evaluation error
+     //~| attempt to subtract with overflow
+     );
+
+const VALS_U64: (u64,) =
+    (
+     u64::MIN - 1,
+     //~^ ERROR constant evaluation 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 00000000000..b2e84486101
--- /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
+     //~| attempt to add with overflow
+     );
+
+const VALS_I16: (i16,) =
+    (
+     i16::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| attempt to add with overflow
+     );
+
+const VALS_I32: (i32,) =
+    (
+     i32::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| attempt to add with overflow
+     );
+
+const VALS_I64: (i64,) =
+    (
+     i64::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| attempt to add with overflow
+     );
+
+const VALS_U8: (u8,) =
+    (
+     u8::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| attempt to add with overflow
+     );
+
+const VALS_U16: (u16,) = (
+     u16::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| attempt to add with overflow
+     );
+
+const VALS_U32: (u32,) = (
+     u32::MAX + 1,
+     //~^ ERROR constant evaluation error
+     //~| attempt to add with overflow
+     );
+
+const VALS_U64: (u64,) =
+    (
+     u64::MAX + 1,
+     //~^ ERROR constant evaluation 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 00000000000..c4a8beaf0f0
--- /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
+     //~| attempt to multiply with overflow
+     );
+
+const VALS_I16: (i16,) =
+    (
+     i16::MIN * 2,
+     //~^ ERROR constant evaluation error
+     //~| attempt to multiply with overflow
+     );
+
+const VALS_I32: (i32,) =
+    (
+     i32::MIN * 2,
+     //~^ ERROR constant evaluation error
+     //~| attempt to multiply with overflow
+     );
+
+const VALS_I64: (i64,) =
+    (
+     i64::MIN * 2,
+     //~^ ERROR constant evaluation error
+     //~| attempt to multiply with overflow
+     );
+
+const VALS_U8: (u8,) =
+    (
+     u8::MAX * 2,
+     //~^ ERROR constant evaluation error
+     //~| attempt to multiply with overflow
+     );
+
+const VALS_U16: (u16,) = (
+     u16::MAX * 2,
+     //~^ ERROR constant evaluation error
+     //~| attempt to multiply with overflow
+     );
+
+const VALS_U32: (u32,) = (
+     u32::MAX * 2,
+     //~^ ERROR constant evaluation error
+     //~| attempt to multiply with overflow
+     );
+
+const VALS_U64: (u64,) =
+    (
+     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>(_: T) {
+}
diff --git a/src/test/compile-fail/const-integer-bool-ops.rs b/src/test/compile-fail/const-integer-bool-ops.rs
index 29bc665a22e..3065122af6a 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 7f2229b5a65..85cc893aa13 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 b1b4bfe2d1c..179ea9e853f 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 b42c440f87d..7596881ef9b 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 86cc2c144ac..49f76c532df 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 1f07422e21b..00000000000
--- 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/issue-27895.rs b/src/test/compile-fail/issue-27895.rs
index ca8d5a1f704..be76796c5c4 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-41255.rs b/src/test/compile-fail/issue-41255.rs
index 823ece2bdca..ac85e43cf4f 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 cannot be used
+        5.0 => {}, //~ ERROR floating-point types cannot be used in patterns
                    //~| WARNING hard error
-        5.0f32 => {}, //~ ERROR floating-point cannot be used
+        5.0f32 => {}, //~ ERROR floating-point types cannot be used in patterns
                       //~| WARNING hard error
-        -5.0 => {}, //~ ERROR floating-point cannot be used
+        -5.0 => {}, //~ ERROR floating-point types cannot be used in patterns
                     //~| WARNING hard error
-        1.0 .. 33.0 => {}, //~ ERROR floating-point cannot be used
+        1.0 .. 33.0 => {}, //~ ERROR floating-point types cannot be used in patterns
                            //~| WARNING hard error
-                           //~| ERROR floating-point cannot be used
+                           //~| ERROR floating-point types cannot be used in patterns
                            //~| WARNING hard error
-        39.0 ... 70.0 => {}, //~ ERROR floating-point cannot be used
+        39.0 ... 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns
                              //~| WARNING hard error
-                             //~| ERROR floating-point 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 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 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-44578.rs b/src/test/compile-fail/issue-44578.rs
index a6ae21c3b54..9efe3d90a93 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]; //~ E0080
 }
 
 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 2a97945f266..9191dfa155c 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 d8ab48d1ec3..1d59e75a0f0 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 e94d1ff7793..2634157c806 100644
--- a/src/test/compile-fail/lint-exceeding-bitshifts.rs
+++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs
@@ -10,7 +10,7 @@
 
 #![deny(exceeding_bitshifts)]
 #![allow(unused_variables)]
-#![allow(dead_code)]
+#![allow(dead_code, const_err)]
 #![feature(const_indexing)]
 
 fn main() {
@@ -54,21 +54,5 @@ fn main() {
 
       let n = 1u8 << -8; //~ ERROR: bitshift exceeds the type's number of bits
 
-
-      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 = 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 00000000000..d95e1b370aa
--- /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)]
+#![allow(unused_variables, const_err)]
+#![allow(dead_code)]
+
+fn main() {
+      let n = 1u8 << (4+3);
+      let n = 1u8 << (4+4); //~ ERROR: bitshift exceeds the type's number of bits
+      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: bitshift exceeds the type's number of bits
+      let n = 1_usize << BITS; //~ ERROR: bitshift exceeds the type's number of bits
+}
diff --git a/src/test/compile-fail/lint-type-overflow2.rs b/src/test/compile-fail/lint-type-overflow2.rs
index f7cf8a68d56..9178d8d2f6e 100644
--- a/src/test/compile-fail/lint-type-overflow2.rs
+++ b/src/test/compile-fail/lint-type-overflow2.rs
@@ -17,6 +17,7 @@
 #[rustc_error]
 fn main() { //~ ERROR: compilation successful
     let x2: i8 = --128; //~ warn: literal out of range for i8
+    //~^ WARN constant evaluation error
 
     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 737f80372de..fe88ab4e117 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 fd888b659f1..ca9af78dd99 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,7 @@ fn main() {
     let x = 0.0;
     match x {
         f32::INFINITY => { }
-        //~^ WARNING floating-point 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/const-index-feature-gate.rs b/src/test/run-pass/const-index-feature-gate.rs
index 4f92770df28..2e60634d15e 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/float-int-invalid-const-cast.rs b/src/test/run-pass/float-int-invalid-const-cast.rs
new file mode 100644
index 00000000000..80ab12482cb
--- /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/issue-43197.rs b/src/test/ui/const-eval/issue-43197.rs
index 86c5e873df8..e87b2caa49f 100644
--- a/src/test/ui/const-eval/issue-43197.rs
+++ b/src/test/ui/const-eval/issue-43197.rs
@@ -18,4 +18,6 @@ fn main() {
     const X: u32 = 0-1; //~ ERROR constant evaluation error
     const Y: u32 = foo(0-1); //~ ERROR constant evaluation error
     println!("{} {}", X, Y);
+    //~^ ERROR constant evaluation error
+    //~| ERROR constant evaluation error
 }
diff --git a/src/test/ui/const-len-underflow-separate-spans.rs b/src/test/ui/const-len-underflow-separate-spans.rs
index 7582d0efa81..35e3ba9ce09 100644
--- a/src/test/ui/const-len-underflow-separate-spans.rs
+++ b/src/test/ui/const-len-underflow-separate-spans.rs
@@ -15,6 +15,7 @@
 const ONE: usize = 1;
 const TWO: usize = 2;
 const LEN: usize = ONE - TWO;
+//~^ ERROR E0080
 
 fn main() {
     let a: [i8; LEN] = unimplemented!();
diff --git a/src/test/ui/error-codes/E0030.rs b/src/test/ui/error-codes/E0030.rs
index ef3bded4bef..896dd2599bf 100644
--- a/src/test/ui/error-codes/E0030.rs
+++ b/src/test/ui/error-codes/E0030.rs
@@ -10,7 +10,7 @@
 
 
 fn main() {
-    match 5u32 {
+    match 5u32 { //~ ERROR non-exhaustive patterns
         1000 ... 5 => {}
         //~^ ERROR lower range bound must be less than or equal to upper
     }
diff --git a/src/test/ui/error-codes/E0080.rs b/src/test/ui/error-codes/E0080.rs
index 2f199c48e46..6e525d4ea9e 100644
--- a/src/test/ui/error-codes/E0080.rs
+++ b/src/test/ui/error-codes/E0080.rs
@@ -10,9 +10,10 @@
 
 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
+    //~| divide by zero
 }
 
 fn main() {