From 50076b00c2790a7941772cc97ee371e15b2cb776 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Fri, 4 Aug 2017 00:41:44 +0300
Subject: [PATCH 1/7] rustc: intern ConstVal's in TyCtxt.

---
 src/librustc/hir/mod.rs                       |   2 +-
 src/librustc/ich/impls_ty.rs                  |  38 ++---
 src/librustc/middle/const_val.rs              |  54 +++++--
 src/librustc/mir/mod.rs                       |  15 +-
 src/librustc/mir/visit.rs                     |   4 +-
 src/librustc/ty/context.rs                    |  38 ++++-
 src/librustc/ty/mod.rs                        |   4 +-
 src/librustc_const_eval/_match.rs             |  47 +++---
 src/librustc_const_eval/check_match.rs        |   4 +-
 src/librustc_const_eval/eval.rs               | 142 ++++++++++--------
 src/librustc_const_eval/pattern.rs            |  59 ++++----
 src/librustc_lint/types.rs                    |   4 +-
 src/librustc_metadata/decoder.rs              |  15 ++
 src/librustc_mir/build/expr/as_rvalue.rs      |  10 +-
 src/librustc_mir/build/matches/mod.rs         |   6 +-
 src/librustc_mir/build/matches/test.rs        |  38 ++---
 src/librustc_mir/build/misc.rs                |  14 +-
 src/librustc_mir/build/mod.rs                 |   6 +-
 src/librustc_mir/hair/cx/block.rs             |   5 +-
 src/librustc_mir/hair/cx/expr.rs              |  13 +-
 src/librustc_mir/hair/cx/mod.rs               |  28 +++-
 src/librustc_mir/shim.rs                      |   8 +-
 src/librustc_mir/transform/elaborate_drops.rs |   4 +-
 src/librustc_mir/transform/generator.rs       |   6 +-
 .../transform/simplify_branches.rs            |   2 +-
 src/librustc_mir/transform/type_check.rs      |   2 +-
 src/librustc_mir/util/elaborate_drops.rs      |   4 +-
 src/librustc_passes/mir_stats.rs              |   2 +-
 src/librustc_trans/mir/analyze.rs             |   2 +-
 src/librustc_trans/mir/constant.rs            |   9 +-
 src/librustc_typeck/collect.rs                |   2 +-
 31 files changed, 347 insertions(+), 240 deletions(-)

diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index d254d50e8bd05..dd2a3978d8844 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -611,7 +611,7 @@ pub enum BindingAnnotation {
   RefMut,
 }
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum RangeEnd {
     Included,
     Excluded,
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 077905b3ac0ae..0d8aead0b36b8 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -16,7 +16,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                            StableHasherResult};
 use std::hash as std_hash;
 use std::mem;
-use syntax_pos::symbol::InternedString;
 use middle::region;
 use ty;
 
@@ -272,52 +271,49 @@ for ::middle::const_val::ConstVal<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
                                           hasher: &mut StableHasher<W>) {
-        use middle::const_val::ConstVal;
+        use middle::const_val::ConstVal::*;
+        use middle::const_val::ConstAggregate::*;
 
         mem::discriminant(self).hash_stable(hcx, hasher);
 
         match *self {
-            ConstVal::Float(ref value) => {
+            Float(ref value) => {
                 value.hash_stable(hcx, hasher);
             }
-            ConstVal::Integral(ref value) => {
+            Integral(ref value) => {
                 value.hash_stable(hcx, hasher);
             }
-            ConstVal::Str(ref value) => {
+            Str(ref value) => {
                 value.hash_stable(hcx, hasher);
             }
-            ConstVal::ByteStr(ref value) => {
+            ByteStr(ref value) => {
                 value.hash_stable(hcx, hasher);
             }
-            ConstVal::Bool(value) => {
+            Bool(value) => {
                 value.hash_stable(hcx, hasher);
             }
-            ConstVal::Char(value) => {
+            Char(value) => {
                 value.hash_stable(hcx, hasher);
             }
-            ConstVal::Variant(def_id) => {
+            Variant(def_id) => {
                 def_id.hash_stable(hcx, hasher);
             }
-            ConstVal::Function(def_id, substs) => {
+            Function(def_id, substs) => {
                 def_id.hash_stable(hcx, hasher);
                 substs.hash_stable(hcx, hasher);
             }
-            ConstVal::Struct(ref name_value_map) => {
-                let mut values: Vec<(InternedString, &ConstVal)> =
-                    name_value_map.iter()
-                                  .map(|(name, val)| (name.as_str(), val))
-                                  .collect();
-
+            Aggregate(Struct(ref name_values)) => {
+                let mut values = name_values.to_vec();
                 values.sort_unstable_by_key(|&(ref name, _)| name.clone());
                 values.hash_stable(hcx, hasher);
             }
-            ConstVal::Tuple(ref value) => {
+            Aggregate(Tuple(ref value)) => {
                 value.hash_stable(hcx, hasher);
             }
-            ConstVal::Array(ref value) => {
+            Aggregate(Array(ref value)) => {
                 value.hash_stable(hcx, hasher);
             }
-            ConstVal::Repeat(ref value, times) => {
+            Aggregate(Repeat(ref value, times)) => {
                 value.hash_stable(hcx, hasher);
                 times.hash_stable(hcx, hasher);
             }
@@ -325,6 +321,10 @@ for ::middle::const_val::ConstVal<'gcx> {
     }
 }
 
+impl_stable_hash_for!(struct ::middle::const_val::ByteArray<'tcx> {
+    data
+});
+
 impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs });
 
 impl_stable_hash_for!(struct ty::GeneratorInterior<'tcx> { witness });
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index b6b1648f39687..8eac44966bb7e 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use self::ConstVal::*;
+use self::ConstAggregate::*;
 pub use rustc_const_math::ConstInt;
 
 use hir;
@@ -22,30 +23,55 @@ use rustc_const_math::*;
 
 use graphviz::IntoCow;
 use errors::DiagnosticBuilder;
+use serialize::{self, Encodable, Encoder, Decodable, Decoder};
 use syntax::symbol::InternedString;
 use syntax::ast;
 use syntax_pos::Span;
 
 use std::borrow::Cow;
-use std::collections::BTreeMap;
-use std::rc::Rc;
 
-pub type EvalResult<'tcx> = Result<ConstVal<'tcx>, ConstEvalErr<'tcx>>;
+pub type EvalResult<'tcx> = Result<&'tcx ConstVal<'tcx>, ConstEvalErr<'tcx>>;
 
-#[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
 pub enum ConstVal<'tcx> {
     Float(ConstFloat),
     Integral(ConstInt),
     Str(InternedString),
-    ByteStr(Rc<Vec<u8>>),
+    ByteStr(ByteArray<'tcx>),
     Bool(bool),
     Char(char),
     Variant(DefId),
     Function(DefId, &'tcx Substs<'tcx>),
-    Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
-    Tuple(Vec<ConstVal<'tcx>>),
-    Array(Vec<ConstVal<'tcx>>),
-    Repeat(Box<ConstVal<'tcx>>, u64),
+    Aggregate(ConstAggregate<'tcx>),
+}
+
+impl<'tcx> serialize::UseSpecializedDecodable for &'tcx ConstVal<'tcx> {}
+
+#[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)]
+pub struct ByteArray<'tcx> {
+    pub data: &'tcx [u8],
+}
+
+impl<'tcx> serialize::UseSpecializedDecodable for ByteArray<'tcx> {}
+
+#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
+pub enum ConstAggregate<'tcx> {
+    Struct(&'tcx [(ast::Name, &'tcx ConstVal<'tcx>)]),
+    Tuple(&'tcx [&'tcx ConstVal<'tcx>]),
+    Array(&'tcx [&'tcx ConstVal<'tcx>]),
+    Repeat(&'tcx ConstVal<'tcx>, u64),
+}
+
+impl<'tcx> Encodable for ConstAggregate<'tcx> {
+    fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> {
+        bug!("should never encode ConstAggregate::{:?}", self)
+    }
+}
+
+impl<'tcx> Decodable for ConstAggregate<'tcx> {
+    fn decode<D: Decoder>(_: &mut D) -> Result<Self, D::Error> {
+        bug!("should never decode ConstAggregate")
+    }
 }
 
 impl<'tcx> ConstVal<'tcx> {
@@ -58,11 +84,11 @@ impl<'tcx> ConstVal<'tcx> {
             Bool(_) => "boolean",
             Char(..) => "char",
             Variant(_) => "enum variant",
-            Struct(_) => "struct",
-            Tuple(_) => "tuple",
+            Aggregate(Struct(_)) => "struct",
+            Aggregate(Tuple(_)) => "tuple",
             Function(..) => "function definition",
-            Array(..) => "array",
-            Repeat(..) => "repeat",
+            Aggregate(Array(..)) => "array",
+            Aggregate(Repeat(..)) => "repeat",
         }
     }
 
@@ -233,7 +259,7 @@ pub fn eval_length(tcx: TyCtxt,
     let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
     let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
     match tcx.at(count_expr.span).const_eval(param_env.and((count_def_id, substs))) {
-        Ok(Integral(Usize(count))) => {
+        Ok(&Integral(Usize(count))) => {
             let val = count.as_u64(tcx.sess.target.uint_type);
             assert_eq!(val as usize as u64, val);
             Ok(val as usize)
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index e63162c68c0f1..a7c4e529d24e1 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1190,7 +1190,9 @@ impl<'tcx> Operand<'tcx> {
         Operand::Constant(box Constant {
             span,
             ty: tcx.type_of(def_id).subst(tcx, substs),
-            literal: Literal::Value { value: ConstVal::Function(def_id, substs) },
+            literal: Literal::Value {
+                value: tcx.mk_const(ConstVal::Function(def_id, substs))
+            },
         })
     }
 
@@ -1478,7 +1480,7 @@ pub enum Literal<'tcx> {
         substs: &'tcx Substs<'tcx>,
     },
     Value {
-        value: ConstVal<'tcx>,
+        value: &'tcx ConstVal<'tcx>,
     },
     Promoted {
         // Index into the `promoted` vector of `Mir`.
@@ -1516,9 +1518,9 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
     match *const_val {
         Float(f) => write!(fmt, "{:?}", f),
         Integral(n) => write!(fmt, "{}", n),
-        Str(ref s) => write!(fmt, "{:?}", s),
-        ByteStr(ref bytes) => {
-            let escaped: String = bytes
+        Str(s) => write!(fmt, "{:?}", s),
+        ByteStr(bytes) => {
+            let escaped: String = bytes.data
                 .iter()
                 .flat_map(|&ch| ascii::escape_default(ch).map(|c| c as char))
                 .collect();
@@ -1528,8 +1530,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
         Char(c) => write!(fmt, "{:?}", c),
         Variant(def_id) |
         Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
-        Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
-            bug!("ConstVal `{:?}` should not be in MIR", const_val),
+        Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val),
     }
 }
 
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index f26505c6d0237..d2719224e3783 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -233,7 +233,7 @@ macro_rules! make_mir_visitor {
             }
 
             fn visit_const_val(&mut self,
-                               const_val: & $($mutability)* ConstVal,
+                               const_val: & $($mutability)* &'tcx ConstVal<'tcx>,
                                _: Location) {
                 self.super_const_val(const_val);
             }
@@ -760,7 +760,7 @@ macro_rules! make_mir_visitor {
                                     _substs: & $($mutability)* ClosureSubsts<'tcx>) {
             }
 
-            fn super_const_val(&mut self, _const_val: & $($mutability)* ConstVal) {
+            fn super_const_val(&mut self, _const_val: & $($mutability)* &'tcx ConstVal<'tcx>) {
             }
 
             fn super_const_int(&mut self, _const_int: &ConstInt) {
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 2a0dc455f470f..5d15e3a8cab72 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -21,6 +21,7 @@ use hir::map as hir_map;
 use hir::map::DefPathHash;
 use lint::{self, Lint};
 use ich::{self, StableHashingContext, NodeIdHashingMode};
+use middle::const_val::ConstVal;
 use middle::free_region::FreeRegionMap;
 use middle::lang_items;
 use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
@@ -108,6 +109,7 @@ pub struct CtxtInterners<'tcx> {
     region: RefCell<FxHashSet<Interned<'tcx, RegionKind>>>,
     existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
     predicates: RefCell<FxHashSet<Interned<'tcx, Slice<Predicate<'tcx>>>>>,
+    const_: RefCell<FxHashSet<Interned<'tcx, ConstVal<'tcx>>>>,
 }
 
 impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
@@ -120,6 +122,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
             region: RefCell::new(FxHashSet()),
             existential_predicates: RefCell::new(FxHashSet()),
             predicates: RefCell::new(FxHashSet()),
+            const_: RefCell::new(FxHashSet()),
         }
     }
 
@@ -934,6 +937,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.global_arenas.adt_def.alloc(def)
     }
 
+    pub fn alloc_byte_array(self, bytes: &[u8]) -> &'gcx [u8] {
+        if bytes.is_empty() {
+            &[]
+        } else {
+            self.global_interners.arena.alloc_slice(bytes)
+        }
+    }
+
+    pub fn alloc_constval_slice(self, values: &[&'tcx ConstVal<'gcx>])
+                                -> &'gcx [&'tcx ConstVal<'gcx>] {
+        if values.is_empty() {
+            &[]
+        } else {
+            self.global_interners.arena.alloc_slice(values)
+        }
+    }
+
+    pub fn alloc_name_constval_slice(self, values: &[(ast::Name, &'tcx ConstVal<'gcx>)])
+                                     -> &'gcx [(ast::Name, &'tcx ConstVal<'gcx>)] {
+        if values.is_empty() {
+            &[]
+        } else {
+            self.global_interners.arena.alloc_slice(values)
+        }
+    }
+
     pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability {
         if let Some(st) = self.stability_interner.borrow().get(&stab) {
             return st;
@@ -1507,6 +1536,12 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Predicate<'lcx>]>
     }
 }
 
+impl<'tcx: 'lcx, 'lcx> Borrow<ConstVal<'lcx>> for Interned<'tcx, ConstVal<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a ConstVal<'lcx> {
+        &self.0
+    }
+}
+
 macro_rules! intern_method {
     ($lt_tcx:tt, $name:ident: $method:ident($alloc:ty,
                                             $alloc_method:ident,
@@ -1587,7 +1622,8 @@ direct_interners!('tcx,
             &ty::ReVar(_) | &ty::ReSkolemized(..) => true,
             _ => false
         }
-    }) -> RegionKind
+    }) -> RegionKind,
+    const_: mk_const(/*|c: &Const| keep_local(&c.ty)*/ |_| false) -> ConstVal<'tcx>
 );
 
 macro_rules! slice_interners {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 8b7ae79f151cc..9be12195952f9 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1601,7 +1601,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
             if let VariantDiscr::Explicit(expr_did) = v.discr {
                 let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
                 match tcx.const_eval(param_env.and((expr_did, substs))) {
-                    Ok(ConstVal::Integral(v)) => {
+                    Ok(&ConstVal::Integral(v)) => {
                         discr = v;
                     }
                     err => {
@@ -1641,7 +1641,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
                 ty::VariantDiscr::Explicit(expr_did) => {
                     let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
                     match tcx.const_eval(param_env.and((expr_did, substs))) {
-                        Ok(ConstVal::Integral(v)) => {
+                        Ok(&ConstVal::Integral(v)) => {
                             explicit_value = v;
                             break;
                         }
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index bc9aa9665c103..aea1f454d8141 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -182,13 +182,13 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
         self.byte_array_map.entry(pat).or_insert_with(|| {
             match pat.kind {
                 box PatternKind::Constant {
-                    value: ConstVal::ByteStr(ref data)
+                    value: &ConstVal::ByteStr(b)
                 } => {
-                    data.iter().map(|c| &*pattern_arena.alloc(Pattern {
+                    b.data.iter().map(|&b| &*pattern_arena.alloc(Pattern {
                         ty: tcx.types.u8,
                         span: pat.span,
                         kind: box PatternKind::Constant {
-                            value: ConstVal::Integral(ConstInt::U8(*c))
+                            value: tcx.mk_const(ConstVal::Integral(ConstInt::U8(b)))
                         }
                     })).collect()
                 }
@@ -228,9 +228,9 @@ pub enum Constructor<'tcx> {
     /// Enum variants.
     Variant(DefId),
     /// Literal values.
-    ConstantValue(ConstVal<'tcx>),
+    ConstantValue(&'tcx ConstVal<'tcx>),
     /// Ranges of literal values (`2...5` and `2..5`).
-    ConstantRange(ConstVal<'tcx>, ConstVal<'tcx>, RangeEnd),
+    ConstantRange(&'tcx ConstVal<'tcx>, &'tcx ConstVal<'tcx>, RangeEnd),
     /// Array patterns of length n.
     Slice(usize),
 }
@@ -370,7 +370,7 @@ impl<'tcx> Witness<'tcx> {
 
                 _ => {
                     match *ctor {
-                        ConstantValue(ref v) => PatternKind::Constant { value: v.clone() },
+                        ConstantValue(value) => PatternKind::Constant { value },
                         _ => PatternKind::Wild,
                     }
                 }
@@ -404,8 +404,11 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
 {
     debug!("all_constructors({:?})", pcx.ty);
     match pcx.ty.sty {
-        ty::TyBool =>
-            [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
+        ty::TyBool => {
+            [true, false].iter().map(|&b| {
+                ConstantValue(cx.tcx.mk_const(ConstVal::Bool(b)))
+            }).collect()
+        }
         ty::TySlice(ref sub_ty) => {
             if cx.is_uninhabited(sub_ty) {
                 vec![Slice(0)]
@@ -511,8 +514,8 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
 
     for row in patterns {
         match *row.kind {
-            PatternKind::Constant { value: ConstVal::ByteStr(ref data) } => {
-                max_fixed_len = cmp::max(max_fixed_len, data.len());
+            PatternKind::Constant { value: &ConstVal::ByteStr(b) } => {
+                max_fixed_len = cmp::max(max_fixed_len, b.data.len());
             }
             PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
                 let fixed_len = prefix.len() + suffix.len();
@@ -715,10 +718,10 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
             Some(vec![Single]),
         PatternKind::Variant { adt_def, variant_index, .. } =>
             Some(vec![Variant(adt_def.variants[variant_index].did)]),
-        PatternKind::Constant { ref value } =>
-            Some(vec![ConstantValue(value.clone())]),
-        PatternKind::Range { ref lo, ref hi, ref end } =>
-            Some(vec![ConstantRange(lo.clone(), hi.clone(), end.clone())]),
+        PatternKind::Constant { value } =>
+            Some(vec![ConstantValue(value)]),
+        PatternKind::Range { lo, hi, end } =>
+            Some(vec![ConstantRange(lo, hi, end)]),
         PatternKind::Array { .. } => match pcx.ty.sty {
             ty::TyArray(_, length) => Some(vec![Slice(length)]),
             _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
@@ -806,7 +809,7 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
                                     suffix: &[Pattern])
                                     -> Result<bool, ErrorReported> {
     let data = match *ctor {
-        ConstantValue(ConstVal::ByteStr(ref data)) => data,
+        ConstantValue(&ConstVal::ByteStr(b)) => b.data,
         _ => bug!()
     };
 
@@ -820,7 +823,7 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
             data[data.len()-suffix.len()..].iter().zip(suffix))
     {
         match pat.kind {
-            box PatternKind::Constant { ref value } => match *value {
+            box PatternKind::Constant { value } => match *value {
                 ConstVal::Integral(ConstInt::U8(u)) => {
                     if u != *ch {
                         return Ok(false);
@@ -843,19 +846,19 @@ fn constructor_covered_by_range(tcx: TyCtxt, span: Span,
     let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less);
     let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to);
     match *ctor {
-        ConstantValue(ref value) => {
+        ConstantValue(value) => {
             let to = cmp_to(value)?;
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Included && to == Ordering::Equal);
             Ok(cmp_from(value)? && end)
         },
-        ConstantRange(ref from, ref to, RangeEnd::Included) => {
+        ConstantRange(from, to, RangeEnd::Included) => {
             let to = cmp_to(to)?;
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Included && to == Ordering::Equal);
             Ok(cmp_from(from)? && end)
         },
-        ConstantRange(ref from, ref to, RangeEnd::Excluded) => {
+        ConstantRange(from, to, RangeEnd::Excluded) => {
             let to = cmp_to(to)?;
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Excluded && to == Ordering::Equal);
@@ -919,11 +922,11 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
             Some(vec![subpattern])
         }
 
-        PatternKind::Constant { ref value } => {
+        PatternKind::Constant { value } => {
             match *constructor {
                 Slice(..) => match *value {
-                    ConstVal::ByteStr(ref data) => {
-                        if wild_patterns.len() == data.len() {
+                    ConstVal::ByteStr(b) => {
+                        if wild_patterns.len() == b.data.len() {
                             Some(cx.lower_byte_str_pattern(pat))
                         } else {
                             None
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index d832ad0ab1d20..0339969f2b45a 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -140,7 +140,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
     fn check_match(
         &self,
         scrut: &hir::Expr,
-        arms: &[hir::Arm],
+        arms: &'tcx [hir::Arm],
         source: hir::MatchSource)
     {
         for arm in arms {
@@ -231,7 +231,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
         }
     }
 
-    fn check_irrefutable(&self, pat: &Pat, origin: &str) {
+    fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) {
         let module = self.tcx.hir.get_module_parent(pat.id);
         MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
             let mut patcx = PatternContext::new(self.tcx,
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index c71c121ca50c3..5f0a070229177 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -9,8 +9,9 @@
 // except according to those terms.
 
 use rustc::middle::const_val::ConstVal::*;
+use rustc::middle::const_val::ConstAggregate::*;
 use rustc::middle::const_val::ErrKind::*;
-use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind};
+use rustc::middle::const_val::{ByteArray, ConstVal, ConstEvalErr, EvalResult, ErrKind};
 
 use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks::FnLikeNode;
@@ -88,7 +89,7 @@ pub struct ConstContext<'a, 'tcx: 'a> {
     tables: &'a ty::TypeckTables<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     substs: &'tcx Substs<'tcx>,
-    fn_args: Option<NodeMap<ConstVal<'tcx>>>
+    fn_args: Option<NodeMap<&'tcx ConstVal<'tcx>>>
 }
 
 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
@@ -107,7 +108,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
 
     /// Evaluate a constant expression in a context where the expression isn't
     /// guaranteed to be evaluable.
-    pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> {
+    pub fn eval(&self, e: &'tcx Expr) -> EvalResult<'tcx> {
         if self.tables.tainted_by_errors {
             signal!(e, TypeckError);
         }
@@ -118,7 +119,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
 type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
 
 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
-                                     e: &Expr) -> EvalResult<'tcx> {
+                                     e: &'tcx Expr) -> EvalResult<'tcx> {
     let tcx = cx.tcx;
     let ety = cx.tables.expr_ty(e).subst(tcx, cx.substs);
 
@@ -133,57 +134,66 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
             const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
             const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
             const I128_OVERFLOW: u128 = i128::min_value() as u128;
-            match (&lit.node, &ety.sty) {
+            let negated = match (&lit.node, &ety.sty) {
                 (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
                 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
-                    return Ok(Integral(I8(i8::min_value())))
+                    Some(I8(i8::min_value()))
                 },
                 (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
                 (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
-                    return Ok(Integral(I16(i16::min_value())))
+                    Some(I16(i16::min_value()))
                 },
                 (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
                 (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
-                    return Ok(Integral(I32(i32::min_value())))
+                    Some(I32(i32::min_value()))
                 },
                 (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
                 (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
-                    return Ok(Integral(I64(i64::min_value())))
+                    Some(I64(i64::min_value()))
                 },
                 (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
                 (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
-                    return Ok(Integral(I128(i128::min_value())))
+                    Some(I128(i128::min_value()))
                 },
                 (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) |
                 (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
                     match tcx.sess.target.int_type {
                         IntTy::I16 => if n == I16_OVERFLOW {
-                            return Ok(Integral(Isize(Is16(i16::min_value()))));
+                            Some(Isize(Is16(i16::min_value())))
+                        } else {
+                            None
                         },
                         IntTy::I32 => if n == I32_OVERFLOW {
-                            return Ok(Integral(Isize(Is32(i32::min_value()))));
+                            Some(Isize(Is32(i32::min_value())))
+                        } else {
+                            None
                         },
                         IntTy::I64 => if n == I64_OVERFLOW {
-                            return Ok(Integral(Isize(Is64(i64::min_value()))));
+                            Some(Isize(Is64(i64::min_value())))
+                        } else {
+                            None
                         },
                         _ => span_bug!(e.span, "typeck error")
                     }
                 },
-                _ => {},
+                _ => None
+            };
+            if let Some(i) = negated {
+                return Ok(tcx.mk_const(Integral(i)));
             }
         }
-        match cx.eval(inner)? {
+        tcx.mk_const(match *cx.eval(inner)? {
           Float(f) => Float(-f),
           Integral(i) => Integral(math!(e, -i)),
           const_val => signal!(e, NegateOn(const_val)),
-        }
+        })
       }
       hir::ExprUnary(hir::UnNot, ref inner) => {
-        match cx.eval(inner)? {
+        tcx.mk_const(match *cx.eval(inner)? {
           Integral(i) => Integral(math!(e, !i)),
           Bool(b) => Bool(!b),
           const_val => signal!(e, NotOn(const_val)),
-        }
+        })
       }
       hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
       hir::ExprBinary(op, ref a, ref b) => {
@@ -191,7 +201,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         // gives us a type through a type-suffix, cast or const def type
         // we need to re-eval the other value of the BinOp if it was
         // not inferred
-        match (cx.eval(a)?, cx.eval(b)?) {
+        tcx.mk_const(match (*cx.eval(a)?, *cx.eval(b)?) {
           (Float(a), Float(b)) => {
             use std::cmp::Ordering::*;
             match op.node {
@@ -260,7 +270,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           }
 
           _ => signal!(e, MiscBinaryOp),
-        }
+        })
       }
       hir::ExprCast(ref base, _) => {
         let base_val = cx.eval(base)?;
@@ -268,8 +278,8 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         if ety == base_ty {
             base_val
         } else {
-            match cast_const(tcx, base_val, ety) {
-                Ok(val) => val,
+            match cast_const(tcx, *base_val, ety) {
+                Ok(val) => tcx.mk_const(val),
                 Err(kind) => signal!(e, kind),
             }
         }
@@ -291,32 +301,32 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                     }
               },
               Def::VariantCtor(variant_def, CtorKind::Const) => {
-                Variant(variant_def)
+                tcx.mk_const(Variant(variant_def))
               }
               Def::VariantCtor(_, CtorKind::Fn) => {
                   signal!(e, UnimplementedConstVal("enum variants"));
               }
               Def::StructCtor(_, CtorKind::Const) => {
-                  ConstVal::Struct(Default::default())
+                  tcx.mk_const(Aggregate(Struct(&[])))
               }
               Def::StructCtor(_, CtorKind::Fn) => {
                   signal!(e, UnimplementedConstVal("tuple struct constructors"))
               }
               Def::Local(id) => {
                   debug!("Def::Local({:?}): {:?}", id, cx.fn_args);
-                  if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&id)) {
-                      val.clone()
+                  if let Some(&val) = cx.fn_args.as_ref().and_then(|args| args.get(&id)) {
+                      val
                   } else {
                       signal!(e, NonConstPath);
                   }
               },
-              Def::Method(id) | Def::Fn(id) => Function(id, substs),
+              Def::Method(id) | Def::Fn(id) => tcx.mk_const(Function(id, substs)),
               Def::Err => span_bug!(e.span, "typeck error"),
               _ => signal!(e, NonConstPath),
           }
       }
       hir::ExprCall(ref callee, ref args) => {
-          let (def_id, substs) = match cx.eval(callee)? {
+          let (def_id, substs) = match *cx.eval(callee)? {
               Function(def_id, substs) => (def_id, substs),
               _ => signal!(e, TypeckError),
           };
@@ -329,14 +339,14 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
             };
             match &tcx.item_name(def_id)[..] {
                 "size_of" => {
-                    let size = layout_of(substs.type_at(0))?.size(tcx);
-                    return Ok(Integral(Usize(ConstUsize::new(size.bytes(),
-                        tcx.sess.target.uint_type).unwrap())));
+                    let size = layout_of(substs.type_at(0))?.size(tcx).bytes();
+                    return Ok(tcx.mk_const(Integral(Usize(ConstUsize::new(size,
+                        tcx.sess.target.uint_type).unwrap()))));
                 }
                 "min_align_of" => {
-                    let align = layout_of(substs.type_at(0))?.align(tcx);
-                    return Ok(Integral(Usize(ConstUsize::new(align.abi(),
-                        tcx.sess.target.uint_type).unwrap())));
+                    let align = layout_of(substs.type_at(0))?.align(tcx).abi();
+                    return Ok(tcx.mk_const(Integral(Usize(ConstUsize::new(align,
+                        tcx.sess.target.uint_type).unwrap()))));
                 }
                 _ => signal!(e, TypeckError)
             }
@@ -385,38 +395,39 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           callee_cx.eval(&body.value)?
       },
       hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
-          Ok(val) => val,
+          Ok(val) => tcx.mk_const(val),
           Err(err) => signal!(e, err),
       },
       hir::ExprBlock(ref block) => {
         match block.expr {
             Some(ref expr) => cx.eval(expr)?,
-            None => Tuple(vec![]),
+            None => tcx.mk_const(Aggregate(Tuple(&[]))),
         }
       }
       hir::ExprType(ref e, _) => cx.eval(e)?,
       hir::ExprTup(ref fields) => {
-        Tuple(fields.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
+        let values = fields.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
+        tcx.mk_const(Aggregate(Tuple(tcx.alloc_constval_slice(&values))))
       }
       hir::ExprStruct(_, ref fields, _) => {
-        Struct(fields.iter().map(|f| {
+        tcx.mk_const(Aggregate(Struct(tcx.alloc_name_constval_slice(&fields.iter().map(|f| {
             cx.eval(&f.expr).map(|v| (f.name.node, v))
-        }).collect::<Result<_, _>>()?)
+        }).collect::<Result<Vec<_>, _>>()?))))
       }
       hir::ExprIndex(ref arr, ref idx) => {
         if !tcx.sess.features.borrow().const_indexing {
             signal!(e, IndexOpFeatureGated);
         }
         let arr = cx.eval(arr)?;
-        let idx = match cx.eval(idx)? {
+        let idx = match *cx.eval(idx)? {
             Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
             _ => signal!(idx, IndexNotUsize),
         };
         assert_eq!(idx as usize as u64, idx);
-        match arr {
-            Array(ref v) => {
-                if let Some(elem) = v.get(idx as usize) {
-                    elem.clone()
+        match *arr {
+            Aggregate(Array(v)) => {
+                if let Some(&elem) = v.get(idx as usize) {
+                    elem
                 } else {
                     let n = v.len() as u64;
                     assert_eq!(n as usize as u64, n);
@@ -424,44 +435,43 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                 }
             }
 
-            Repeat(.., n) if idx >= n => {
+            Aggregate(Repeat(.., n)) if idx >= n => {
                 signal!(e, IndexOutOfBounds { len: n, index: idx })
             }
-            Repeat(ref elem, _) => (**elem).clone(),
+            Aggregate(Repeat(elem, _)) => elem,
 
-            ByteStr(ref data) if idx >= data.len() as u64 => {
-                signal!(e, IndexOutOfBounds { len: data.len() as u64, index: idx })
+            ByteStr(b) if idx >= b.data.len() as u64 => {
+                signal!(e, IndexOutOfBounds { len: b.data.len() as u64, index: idx })
             }
-            ByteStr(data) => {
-                Integral(U8(data[idx as usize]))
+            ByteStr(b) => {
+                tcx.mk_const(Integral(U8(b.data[idx as usize])))
             },
 
             _ => signal!(e, IndexedNonVec),
         }
       }
       hir::ExprArray(ref v) => {
-        Array(v.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
+        let values = v.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
+        tcx.mk_const(Aggregate(Array(tcx.alloc_constval_slice(&values))))
       }
       hir::ExprRepeat(ref elem, _) => {
           let n = match ety.sty {
             ty::TyArray(_, n) => n as u64,
             _ => span_bug!(e.span, "typeck error")
           };
-          Repeat(Box::new(cx.eval(elem)?), n)
+          tcx.mk_const(Aggregate(Repeat(cx.eval(elem)?, n)))
       },
       hir::ExprTupField(ref base, index) => {
-        let c = cx.eval(base)?;
-        if let Tuple(ref fields) = c {
-            fields[index.node].clone()
+        if let Aggregate(Tuple(fields)) = *cx.eval(base)? {
+            fields[index.node]
         } else {
             signal!(base, ExpectedConstTuple);
         }
       }
       hir::ExprField(ref base, field_name) => {
-        let c = cx.eval(base)?;
-        if let Struct(ref fields) = c {
-            if let Some(f) = fields.get(&field_name.node) {
-                f.clone()
+        if let Aggregate(Struct(fields)) = *cx.eval(base)? {
+            if let Some(&(_, f)) = fields.iter().find(|&&(name, _)| name == field_name.node) {
+                f
             } else {
                 signal!(e, MissingStructField);
             }
@@ -625,7 +635,7 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
             },
             ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
-                ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)),
+                ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.data.len() => Ok(val),
                 ty::TySlice(_) => {
                     Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
                 },
@@ -645,7 +655,7 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
+fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           mut ty: Ty<'tcx>)
                           -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
@@ -660,7 +670,7 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
 
     match *lit {
         LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
-        LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
+        LitKind::ByteStr(ref data) => Ok(ByteStr(ByteArray { data })),
         LitKind::Byte(n) => Ok(Integral(U8(n))),
         LitKind::Int(n, hint) => {
             match (&ty.sty, hint) {
@@ -708,8 +718,8 @@ pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
         (&Float(a), &Float(b)) => a.try_cmp(b).ok(),
         (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
         (&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
-        (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
-        (&Char(a), &Char(ref b)) => Some(a.cmp(b)),
+        (&ByteStr(a), &ByteStr(b)) => Some(a.data.cmp(b.data)),
+        (&Char(a), &Char(b)) => Some(a.cmp(&b)),
         _ => None,
     };
 
@@ -729,8 +739,8 @@ pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
     pub fn compare_lit_exprs(&self,
                              span: Span,
-                             a: &Expr,
-                             b: &Expr) -> Result<Ordering, ErrorReported> {
+                             a: &'tcx Expr,
+                             b: &'tcx Expr) -> Result<Ordering, ErrorReported> {
         let tcx = self.tcx;
         let a = match self.eval(a) {
             Ok(a) => a,
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 692778f94e758..e824c4789c7c6 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -83,12 +83,12 @@ pub enum PatternKind<'tcx> {
     },
 
     Constant {
-        value: ConstVal<'tcx>,
+        value: &'tcx ConstVal<'tcx>,
     },
 
     Range {
-        lo: ConstVal<'tcx>,
-        hi: ConstVal<'tcx>,
+        lo: &'tcx ConstVal<'tcx>,
+        hi: &'tcx ConstVal<'tcx>,
         end: RangeEnd,
     },
 
@@ -112,15 +112,12 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
         ConstVal::Float(ref x) => write!(f, "{}", x),
         ConstVal::Integral(ref i) => write!(f, "{}", i),
         ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]),
-        ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]),
+        ConstVal::ByteStr(b) => write!(f, "{:?}", b.data),
         ConstVal::Bool(b) => write!(f, "{:?}", b),
         ConstVal::Char(c) => write!(f, "{:?}", c),
         ConstVal::Variant(_) |
-        ConstVal::Struct(_) |
-        ConstVal::Tuple(_) |
         ConstVal::Function(..) |
-        ConstVal::Array(..) |
-        ConstVal::Repeat(..) => bug!("{:?} not printable in a pattern", value)
+        ConstVal::Aggregate(_) => bug!("{:?} not printable in a pattern", value)
     }
 }
 
@@ -230,12 +227,12 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
                 }
                 write!(f, "{}", subpattern)
             }
-            PatternKind::Constant { ref value } => {
+            PatternKind::Constant { value } => {
                 print_const_val(value, f)
             }
-            PatternKind::Range { ref lo, ref hi, ref end } => {
+            PatternKind::Range { lo, hi, end } => {
                 print_const_val(lo, f)?;
-                match *end {
+                match end {
                     RangeEnd::Included => write!(f, "...")?,
                     RangeEnd::Excluded => write!(f, "..")?,
                 }
@@ -278,7 +275,7 @@ impl<'a, 'tcx> Pattern<'tcx> {
     pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
                     tables: &'a ty::TypeckTables<'tcx>,
-                    pat: &hir::Pat) -> Self {
+                    pat: &'tcx hir::Pat) -> Self {
         let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables);
         let result = pcx.lower_pattern(pat);
         if !pcx.errors.is_empty() {
@@ -302,7 +299,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
         }
     }
 
-    pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
+    pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
         let mut ty = self.tables.node_id_to_type(pat.hir_id);
 
         let kind = match pat.node {
@@ -310,11 +307,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
 
             PatKind::Lit(ref value) => self.lower_lit(value),
 
-            PatKind::Range(ref lo, ref hi, ref end) => {
+            PatKind::Range(ref lo, ref hi, end) => {
                 match (self.lower_lit(lo), self.lower_lit(hi)) {
                     (PatternKind::Constant { value: lo },
                      PatternKind::Constant { value: hi }) => {
-                        PatternKind::Range { lo: lo, hi: hi, end: end.clone() }
+                        PatternKind::Range { lo, hi, end }
                     }
                     _ => PatternKind::Wild
                 }
@@ -474,11 +471,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
         }
     }
 
-    fn lower_patterns(&mut self, pats: &[P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
+    fn lower_patterns(&mut self, pats: &'tcx [P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
         pats.iter().map(|p| self.lower_pattern(p)).collect()
     }
 
-    fn lower_opt_pattern(&mut self, pat: &Option<P<hir::Pat>>) -> Option<Pattern<'tcx>>
+    fn lower_opt_pattern(&mut self, pat: &'tcx Option<P<hir::Pat>>) -> Option<Pattern<'tcx>>
     {
         pat.as_ref().map(|p| self.lower_pattern(p))
     }
@@ -521,9 +518,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
         &mut self,
         span: Span,
         ty: Ty<'tcx>,
-        prefix: &[P<hir::Pat>],
-        slice: &Option<P<hir::Pat>>,
-        suffix: &[P<hir::Pat>])
+        prefix: &'tcx [P<hir::Pat>],
+        slice: &'tcx Option<P<hir::Pat>>,
+        suffix: &'tcx [P<hir::Pat>])
         -> PatternKind<'tcx>
     {
         let prefix = self.lower_patterns(prefix);
@@ -631,17 +628,17 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
         }
     }
 
-    fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
+    fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
         let const_cx = eval::ConstContext::new(self.tcx,
                                                self.param_env.and(self.substs),
                                                self.tables);
         match const_cx.eval(expr) {
             Ok(value) => {
-                if let ConstVal::Variant(def_id) = value {
+                if let ConstVal::Variant(def_id) = *value {
                     let ty = self.tables.expr_ty(expr);
                     self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![])
                 } else {
-                    PatternKind::Constant { value: value }
+                    PatternKind::Constant { value }
                 }
             }
             Err(e) => {
@@ -652,7 +649,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
     }
 
     fn lower_const_expr(&mut self,
-                        expr: &hir::Expr,
+                        expr: &'tcx hir::Expr,
                         pat_id: ast::NodeId,
                         span: Span)
                         -> Pattern<'tcx> {
@@ -819,8 +816,8 @@ macro_rules! CloneImpls {
 }
 
 CloneImpls!{ <'tcx>
-    Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region<'tcx>,
-    Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
+    Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ConstVal<'tcx>,
+    Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
     &'tcx Substs<'tcx>, &'tcx Kind<'tcx>
 }
 
@@ -892,18 +889,18 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
                 subpattern: subpattern.fold_with(folder),
             },
             PatternKind::Constant {
-                ref value
+                value
             } => PatternKind::Constant {
                 value: value.fold_with(folder)
             },
             PatternKind::Range {
-                ref lo,
-                ref hi,
-                ref end,
+                lo,
+                hi,
+                end,
             } => PatternKind::Range {
                 lo: lo.fold_with(folder),
                 hi: hi.fold_with(folder),
-                end: end.clone(),
+                end,
             },
             PatternKind::Slice {
                 ref prefix,
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index ccd3194b5e388..46a33ce807d7d 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -76,7 +76,7 @@ impl LintPass for TypeLimits {
 }
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
-    fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) {
         match e.node {
             hir::ExprUnary(hir::UnNeg, ref expr) => {
                 // propagate negation, if the negation itself isn't negated
@@ -117,7 +117,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                                                              cx.param_env.and(substs),
                                                              cx.tables);
                             match const_cx.eval(&r) {
-                                Ok(ConstVal::Integral(i)) => {
+                                Ok(&ConstVal::Integral(i)) => {
                                     i.is_negative() ||
                                     i.to_u64()
                                         .map(|i| i >= bits)
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 73f1ae253cd29..b475b02ccfeaa 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -16,6 +16,7 @@ use schema::*;
 use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
 use rustc::hir;
 
+use rustc::middle::const_val::{ByteArray, ConstVal};
 use rustc::middle::cstore::LinkagePreference;
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -377,6 +378,20 @@ impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>
     }
 }
 
+impl<'a, 'tcx> SpecializedDecoder<ByteArray<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<ByteArray<'tcx>, Self::Error> {
+        Ok(ByteArray {
+            data: self.tcx().alloc_byte_array(&Vec::decode(self)?)
+        })
+    }
+}
+
+impl<'a, 'tcx> SpecializedDecoder<&'tcx ConstVal<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<&'tcx ConstVal<'tcx>, Self::Error> {
+        Ok(self.tcx().mk_const(Decodable::decode(self)?))
+    }
+}
+
 impl<'a, 'tcx> MetadataBlob {
     pub fn is_compatible(&self) -> bool {
         self.raw_bytes().starts_with(METADATA_HEADER)
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index c83283ee38e1f..c5f83b029ce00 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -197,7 +197,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         span: expr_span,
                         ty: this.hir.tcx().types.u32,
                         literal: Literal::Value {
-                            value: ConstVal::Integral(ConstInt::U32(0)),
+                            value: this.hir.tcx().mk_const(ConstVal::Integral(ConstInt::U32(0))),
                         },
                     }));
                     box AggregateKind::Generator(closure_id, substs, interior)
@@ -391,7 +391,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     }
                 };
 
-                Literal::Value { value: ConstVal::Integral(val) }
+                Literal::Value {
+                    value: self.hir.tcx().mk_const(ConstVal::Integral(val))
+                }
             }
             _ => {
                 span_bug!(span, "Invalid type for neg_1_literal: `{:?}`", ty)
@@ -424,7 +426,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     }
                 };
 
-                Literal::Value { value: ConstVal::Integral(val) }
+                Literal::Value {
+                    value: self.hir.tcx().mk_const(ConstVal::Integral(val))
+                }
             }
             _ => {
                 span_bug!(span, "Invalid type for minval_literal: `{:?}`", ty)
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index ec2e487b4e74c..2d029f1a5b7f7 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -301,13 +301,13 @@ enum TestKind<'tcx> {
     // test the branches of enum
     SwitchInt {
         switch_ty: Ty<'tcx>,
-        options: Vec<ConstVal<'tcx>>,
-        indices: FxHashMap<ConstVal<'tcx>, usize>,
+        options: Vec<&'tcx ConstVal<'tcx>>,
+        indices: FxHashMap<&'tcx ConstVal<'tcx>, usize>,
     },
 
     // test for equality
     Eq {
-        value: ConstVal<'tcx>,
+        value: &'tcx ConstVal<'tcx>,
         ty: Ty<'tcx>,
     },
 
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 0b91e08fc6d70..5553e2f4c9ca1 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -61,24 +61,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 }
             }
 
-            PatternKind::Constant { ref value } => {
+            PatternKind::Constant { value } => {
                 Test {
                     span: match_pair.pattern.span,
                     kind: TestKind::Eq {
-                        value: value.clone(),
+                        value,
                         ty: match_pair.pattern.ty.clone()
                     }
                 }
             }
 
-            PatternKind::Range { ref lo, ref hi, ref end } => {
+            PatternKind::Range { lo, hi, end } => {
                 Test {
                     span: match_pair.pattern.span,
                     kind: TestKind::Range {
-                        lo: Literal::Value { value: lo.clone() },
-                        hi: Literal::Value { value: hi.clone() },
+                        lo: Literal::Value { value: lo },
+                        hi: Literal::Value { value: hi },
                         ty: match_pair.pattern.ty.clone(),
-                        end: end.clone(),
+                        end,
                     },
                 }
             }
@@ -112,8 +112,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                      test_lvalue: &Lvalue<'tcx>,
                                      candidate: &Candidate<'pat, 'tcx>,
                                      switch_ty: Ty<'tcx>,
-                                     options: &mut Vec<ConstVal<'tcx>>,
-                                     indices: &mut FxHashMap<ConstVal<'tcx>, usize>)
+                                     options: &mut Vec<&'tcx ConstVal<'tcx>>,
+                                     indices: &mut FxHashMap<&'tcx ConstVal<'tcx>, usize>)
                                      -> bool
     {
         let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
@@ -122,13 +122,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         };
 
         match *match_pair.pattern.kind {
-            PatternKind::Constant { ref value } => {
+            PatternKind::Constant { value } => {
                 // if the lvalues match, the type should match
                 assert_eq!(match_pair.pattern.ty, switch_ty);
 
-                indices.entry(value.clone())
+                indices.entry(value)
                        .or_insert_with(|| {
-                           options.push(value.clone());
+                           options.push(value);
                            options.len() - 1
                        });
                 true
@@ -228,9 +228,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     assert!(options.len() > 0 && options.len() <= 2);
                     let (true_bb, false_bb) = (self.cfg.start_new_block(),
                                                self.cfg.start_new_block());
-                    let ret = match &options[0] {
-                        &ConstVal::Bool(true) => vec![true_bb, false_bb],
-                        &ConstVal::Bool(false) => vec![false_bb, true_bb],
+                    let ret = match *options[0] {
+                        ConstVal::Bool(true) => vec![true_bb, false_bb],
+                        ConstVal::Bool(false) => vec![false_bb, true_bb],
                         v => span_bug!(test.span, "expected boolean value but got {:?}", v)
                     };
                     (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Consume(lvalue.clone()),
@@ -258,12 +258,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 ret
             }
 
-            TestKind::Eq { ref value, mut ty } => {
+            TestKind::Eq { value, mut ty } => {
                 let mut val = Operand::Consume(lvalue.clone());
 
                 // If we're using b"..." as a pattern, we need to insert an
                 // unsizing coercion, as the byte string has the type &[u8; N].
-                let expect = if let ConstVal::ByteStr(ref bytes) = *value {
+                let expect = if let ConstVal::ByteStr(bytes) = *value {
                     let tcx = self.hir.tcx();
 
                     // Unsize the lvalue to &[u8], too, if necessary.
@@ -279,10 +279,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                     assert!(ty.is_slice());
 
-                    let array_ty = tcx.mk_array(tcx.types.u8, bytes.len());
+                    let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len());
                     let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty);
                     let array = self.literal_operand(test.span, array_ref, Literal::Value {
-                        value: value.clone()
+                        value
                     });
 
                     let slice = self.temp(ty, test.span);
@@ -291,7 +291,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     Operand::Consume(slice)
                 } else {
                     self.literal_operand(test.span, ty, Literal::Value {
-                        value: value.clone()
+                        value
                     })
                 };
 
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index 0e4aac4299111..12b9174f3a3a6 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -59,7 +59,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ty::TyBool => {
                 self.hir.false_literal()
             }
-            ty::TyChar => Literal::Value { value: ConstVal::Char('\0') },
+            ty::TyChar => {
+                Literal::Value {
+                    value: self.hir.tcx().mk_const(ConstVal::Char('\0'))
+                }
+            }
             ty::TyUint(ity) => {
                 let val = match ity {
                     ast::UintTy::U8  => ConstInt::U8(0),
@@ -74,7 +78,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     }
                 };
 
-                Literal::Value { value: ConstVal::Integral(val) }
+                Literal::Value {
+                    value: self.hir.tcx().mk_const(ConstVal::Integral(val))
+                }
             }
             ty::TyInt(ity) => {
                 let val = match ity {
@@ -90,7 +96,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     }
                 };
 
-                Literal::Value { value: ConstVal::Integral(val) }
+                Literal::Value {
+                    value: self.hir.tcx().mk_const(ConstVal::Integral(val))
+                }
             }
             _ => {
                 span_bug!(span, "Invalid type for zero_literal: `{:?}`", ty)
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index a245411002f8a..704d138b43b58 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -11,7 +11,6 @@
 
 use build;
 use hair::cx::Cx;
-use hair::Pattern;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::middle::region;
@@ -537,10 +536,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             let lvalue = Lvalue::Local(Local::new(index + 1));
 
             if let Some(pattern) = pattern {
-                let pattern = Pattern::from_hir(self.hir.tcx().global_tcx(),
-                                                self.hir.param_env.and(self.hir.identity_substs),
-                                                self.hir.tables(),
-                                                pattern);
+                let pattern = self.hir.pattern_from_hir(pattern);
                 scope = self.declare_bindings(scope, ast_body.span, &pattern);
                 unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
             }
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index 8b3031a3800a5..f6b847d6d6de5 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -64,10 +64,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                             first_statement_index: index as u32,
                         });
 
-                        let pattern = Pattern::from_hir(cx.tcx.global_tcx(),
-                                                        cx.param_env.and(cx.identity_substs),
-                                                        cx.tables(),
-                                                        &local.pat);
+                        let pattern = cx.pattern_from_hir(&local.pat);
                         result.push(StmtRef::Mirror(Box::new(Stmt {
                             kind: StmtKind::Let {
                                 remainder_scope: remainder_scope,
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 9de5262cd888c..0e4d2b9a5aefe 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -473,7 +473,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let def_id = cx.tcx.hir.body_owner_def_id(count);
             let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id);
             let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) {
-                Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
+                Ok(&ConstVal::Integral(ConstInt::Usize(u))) => u,
                 Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
                 Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
             };
@@ -597,7 +597,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         span: expr.span,
         kind: ExprKind::Literal {
             literal: Literal::Value {
-                value: ConstVal::Function(def_id, substs),
+                value: cx.tcx.mk_const(ConstVal::Function(def_id, substs)),
             },
         },
     }
@@ -612,12 +612,7 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
 
 fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
     Arm {
-        patterns: arm.pats.iter().map(|p| {
-            Pattern::from_hir(cx.tcx.global_tcx(),
-                              cx.param_env.and(cx.identity_substs),
-                              cx.tables(),
-                              p)
-        }).collect(),
+        patterns: arm.pats.iter().map(|p| cx.pattern_from_hir(p)).collect(),
         guard: arm.guard.to_ref(),
         body: arm.body.to_ref(),
     }
@@ -635,7 +630,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Def::StructCtor(def_id, CtorKind::Fn) |
         Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal {
             literal: Literal::Value {
-                value: ConstVal::Function(def_id, substs),
+                value: cx.tcx.mk_const(ConstVal::Function(def_id, substs)),
             },
         },
 
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 3cabd8f18c19e..9244ea14514fc 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -113,7 +113,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
 
     pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
         match ConstUsize::new(value, self.tcx.sess.target.uint_type) {
-            Ok(val) => Literal::Value { value: ConstVal::Integral(ConstInt::Usize(val)) },
+            Ok(val) => {
+                Literal::Value {
+                    value: self.tcx.mk_const(ConstVal::Integral(ConstInt::Usize(val)))
+                }
+            }
             Err(_) => bug!("usize literal out of range for target"),
         }
     }
@@ -127,11 +131,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     }
 
     pub fn true_literal(&mut self) -> Literal<'tcx> {
-        Literal::Value { value: ConstVal::Bool(true) }
+        Literal::Value { value: self.tcx.mk_const(ConstVal::Bool(true)) }
     }
 
     pub fn false_literal(&mut self) -> Literal<'tcx> {
-        Literal::Value { value: ConstVal::Bool(false) }
+        Literal::Value { value: self.tcx.mk_const(ConstVal::Bool(false)) }
     }
 
     pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
@@ -139,12 +143,24 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         let const_cx = ConstContext::new(tcx,
                                          self.param_env.and(self.identity_substs),
                                          self.tables());
-        match const_cx.eval(e) {
-            Ok(value) => Literal::Value { value: value },
+        match const_cx.eval(tcx.hir.expect_expr(e.id)) {
+            Ok(value) => Literal::Value { value },
             Err(s) => self.fatal_const_eval_err(&s, e.span, "expression")
         }
     }
 
+    pub fn pattern_from_hir(&mut self, p: &hir::Pat) -> Pattern<'tcx> {
+        let tcx = self.tcx.global_tcx();
+        let p = match tcx.hir.get(p.id) {
+            hir::map::NodePat(p) | hir::map::NodeBinding(p) => p,
+            node => bug!("pattern became {:?}", node)
+        };
+        Pattern::from_hir(tcx,
+                          self.param_env.and(self.identity_substs),
+                          self.tables(),
+                          p)
+    }
+
     pub fn fatal_const_eval_err(&mut self,
         err: &ConstEvalErr<'tcx>,
         primary_span: Span,
@@ -170,7 +186,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                 let method_ty = method_ty.subst(self.tcx, substs);
                 return (method_ty,
                         Literal::Value {
-                            value: ConstVal::Function(item.def_id, substs),
+                            value: self.tcx.mk_const(ConstVal::Function(item.def_id, substs)),
                         });
             }
         }
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index ec545443bcd90..d0a78b5721708 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -407,7 +407,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
             span: self.span,
             ty: tcx.mk_fn_def(self.def_id, substs),
             literal: Literal::Value {
-                value: ConstVal::Function(self.def_id, substs),
+                value: tcx.mk_const(ConstVal::Function(self.def_id, substs)),
             },
         });
 
@@ -472,7 +472,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
             span: self.span,
             ty: self.tcx.types.usize,
             literal: Literal::Value {
-                value: ConstVal::Integral(ConstInt::Usize(value))
+                value: self.tcx.mk_const(ConstVal::Integral(ConstInt::Usize(value)))
             }
         }
     }
@@ -711,8 +711,8 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
                 span,
                 ty: tcx.type_of(def_id),
                 literal: Literal::Value {
-                    value: ConstVal::Function(def_id,
-                        Substs::identity_for_item(tcx, def_id)),
+                    value: tcx.mk_const(ConstVal::Function(def_id,
+                        Substs::identity_for_item(tcx, def_id))),
                 },
             }),
             vec![rcvr]
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index d6477f2babf76..971df70a74e25 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -520,7 +520,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         Rvalue::Use(Operand::Constant(Box::new(Constant {
             span,
             ty: self.tcx.types.bool,
-            literal: Literal::Value { value: ConstVal::Bool(val) }
+            literal: Literal::Value {
+                value: self.tcx.mk_const(ConstVal::Bool(val))
+            }
         })))
     }
 
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 0fb34c96b062d..74edf510aa2e7 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -175,7 +175,7 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
             span: source_info.span,
             ty: self.tcx.types.u32,
             literal: Literal::Value {
-                value: ConstVal::Integral(ConstInt::U32(state_disc)),
+                value: self.tcx.mk_const(ConstVal::Integral(ConstInt::U32(state_disc))),
             },
         });
         Statement {
@@ -553,7 +553,7 @@ fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             span: mir.span,
             ty: tcx.types.bool,
             literal: Literal::Value {
-                value: ConstVal::Bool(false),
+                value: tcx.mk_const(ConstVal::Bool(false)),
             },
         }),
         expected: true,
@@ -603,7 +603,7 @@ fn create_generator_resume_function<'a, 'tcx>(
             span: mir.span,
             ty: tcx.types.bool,
             literal: Literal::Value {
-                value: ConstVal::Bool(false),
+                value: tcx.mk_const(ConstVal::Bool(false)),
             },
         }),
         expected: true,
diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs
index 1dcacb29c3ecc..6c0a44b763170 100644
--- a/src/librustc_mir/transform/simplify_branches.rs
+++ b/src/librustc_mir/transform/simplify_branches.rs
@@ -56,7 +56,7 @@ impl MirPass for SimplifyBranches {
                 },
                 TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
                     literal: Literal::Value {
-                        value: ConstVal::Bool(cond)
+                        value: &ConstVal::Bool(cond)
                     }, ..
                 }), expected, .. } if cond == expected => {
                     TerminatorKind::Goto { target: target }
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 7fbeb9610f471..eaafdb0ac4178 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -572,7 +572,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         match operand {
             &Operand::Constant(box Constant {
                 literal: Literal::Value {
-                    value: ConstVal::Function(def_id, _), ..
+                    value: &ConstVal::Function(def_id, _), ..
                 }, ..
             }) => {
                 Some(def_id) == self.tcx().lang_items().box_free_fn()
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index 8ea47c2991009..d770dbe6f4f47 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -922,7 +922,9 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
         Operand::Constant(box Constant {
             span: self.source_info.span,
             ty: self.tcx().types.usize,
-            literal: Literal::Value { value: ConstVal::Integral(self.tcx().const_usize(val)) }
+            literal: Literal::Value {
+                value: self.tcx().mk_const(ConstVal::Integral(self.tcx().const_usize(val)))
+            }
         })
     }
 
diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs
index 3273d66dd4f51..67176276f96fb 100644
--- a/src/librustc_passes/mir_stats.rs
+++ b/src/librustc_passes/mir_stats.rs
@@ -257,7 +257,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
     }
 
     fn visit_const_val(&mut self,
-                       const_val: &ConstVal,
+                       const_val: &&'tcx ConstVal<'tcx>,
                        _: Location) {
         self.record("ConstVal", const_val);
         self.super_const_val(const_val);
diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs
index 949b9fe71ca64..a843b4171bd80 100644
--- a/src/librustc_trans/mir/analyze.rs
+++ b/src/librustc_trans/mir/analyze.rs
@@ -110,7 +110,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
             mir::TerminatorKind::Call {
                 func: mir::Operand::Constant(box mir::Constant {
                     literal: Literal::Value {
-                        value: ConstVal::Function(def_id, _), ..
+                        value: &ConstVal::Function(def_id, _), ..
                     }, ..
                 }),
                 ref args, ..
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 1109f34a1482e..d43911df83a2b 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -90,11 +90,11 @@ impl<'tcx> Const<'tcx> {
 
     /// Translate ConstVal into a LLVM constant value.
     pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
-                             cv: ConstVal,
+                             cv: &ConstVal,
                              ty: Ty<'tcx>)
                              -> Const<'tcx> {
         let llty = type_of::type_of(ccx, ty);
-        let val = match cv {
+        let val = match *cv {
             ConstVal::Float(v) => {
                 let bits = match v.ty {
                     ast::FloatTy::F32 => C_u32(ccx, v.bits as u32),
@@ -105,12 +105,11 @@ impl<'tcx> Const<'tcx> {
             ConstVal::Bool(v) => C_bool(ccx, v),
             ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
             ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
-            ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
+            ConstVal::ByteStr(v) => consts::addr_of(ccx, C_bytes(ccx, v.data), 1, "byte_str"),
             ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
             ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)),
             ConstVal::Variant(_) |
-            ConstVal::Struct(_) | ConstVal::Tuple(_) |
-            ConstVal::Array(..) | ConstVal::Repeat(..) => {
+            ConstVal::Aggregate(..) => {
                 bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv)
             }
         };
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index e4ca0f82ea1a0..8c3cf481e5eee 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -572,7 +572,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
 
             match result {
-                Ok(ConstVal::Integral(x)) => Some(x),
+                Ok(&ConstVal::Integral(x)) => Some(x),
                 _ => None
             }
         } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {

From 932289c12d26803daf6b1990cb56bb974979bf9c Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Fri, 4 Aug 2017 11:25:13 +0300
Subject: [PATCH 2/7] rustc: introduce ty::Const { ConstVal, Ty }.

---
 src/librustc/ich/impls_ty.rs                  |  9 +-
 src/librustc/middle/const_val.rs              | 16 ++--
 src/librustc/mir/mod.rs                       | 14 ++-
 src/librustc/mir/visit.rs                     | 35 ++++---
 src/librustc/ty/context.rs                    | 58 +++++++-----
 src/librustc/ty/mod.rs                        |  6 +-
 src/librustc/ty/structural_impls.rs           | 93 +++++++++++++++++++
 src/librustc/ty/sty.rs                        | 12 +++
 src/librustc_const_eval/_match.rs             | 42 +++++----
 src/librustc_const_eval/eval.rs               | 61 ++++++------
 src/librustc_const_eval/pattern.rs            | 16 ++--
 src/librustc_lint/types.rs                    |  2 +-
 src/librustc_metadata/decoder.rs              |  6 +-
 src/librustc_mir/build/expr/as_rvalue.rs      | 15 ++-
 src/librustc_mir/build/matches/mod.rs         | 11 +--
 src/librustc_mir/build/matches/test.rs        | 10 +-
 src/librustc_mir/build/misc.rs                | 15 ++-
 src/librustc_mir/build/mod.rs                 | 20 ++++
 src/librustc_mir/hair/cx/expr.rs              | 15 ++-
 src/librustc_mir/hair/cx/mod.rs               | 24 ++++-
 src/librustc_mir/shim.rs                      | 33 ++++---
 src/librustc_mir/transform/elaborate_drops.rs |  5 +-
 src/librustc_mir/transform/erase_regions.rs   | 35 +++----
 src/librustc_mir/transform/generator.rs       | 15 ++-
 .../transform/simplify_branches.rs            |  6 +-
 src/librustc_mir/transform/type_check.rs      |  2 +-
 src/librustc_mir/util/elaborate_drops.rs      |  5 +-
 src/librustc_passes/mir_stats.rs              | 13 ++-
 src/librustc_trans/mir/analyze.rs             |  3 +-
 src/librustc_trans/mir/constant.rs            |  4 +-
 src/librustc_typeck/collect.rs                |  2 +-
 31 files changed, 409 insertions(+), 194 deletions(-)

diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 0d8aead0b36b8..c9fb754287fda 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -277,10 +277,10 @@ for ::middle::const_val::ConstVal<'gcx> {
         mem::discriminant(self).hash_stable(hcx, hasher);
 
         match *self {
-            Float(ref value) => {
+            Integral(ref value) => {
                 value.hash_stable(hcx, hasher);
             }
-            Integral(ref value) => {
+            Float(ref value) => {
                 value.hash_stable(hcx, hasher);
             }
             Str(ref value) => {
@@ -325,6 +325,11 @@ impl_stable_hash_for!(struct ::middle::const_val::ByteArray<'tcx> {
     data
 });
 
+impl_stable_hash_for!(struct ty::Const<'tcx> {
+    ty,
+    val
+});
+
 impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs });
 
 impl_stable_hash_for!(struct ty::GeneratorInterior<'tcx> { witness });
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index 8eac44966bb7e..01f050a1bd90a 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -30,12 +30,12 @@ use syntax_pos::Span;
 
 use std::borrow::Cow;
 
-pub type EvalResult<'tcx> = Result<&'tcx ConstVal<'tcx>, ConstEvalErr<'tcx>>;
+pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>;
 
 #[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
 pub enum ConstVal<'tcx> {
-    Float(ConstFloat),
     Integral(ConstInt),
+    Float(ConstFloat),
     Str(InternedString),
     ByteStr(ByteArray<'tcx>),
     Bool(bool),
@@ -45,8 +45,6 @@ pub enum ConstVal<'tcx> {
     Aggregate(ConstAggregate<'tcx>),
 }
 
-impl<'tcx> serialize::UseSpecializedDecodable for &'tcx ConstVal<'tcx> {}
-
 #[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)]
 pub struct ByteArray<'tcx> {
     pub data: &'tcx [u8],
@@ -56,10 +54,10 @@ impl<'tcx> serialize::UseSpecializedDecodable for ByteArray<'tcx> {}
 
 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
 pub enum ConstAggregate<'tcx> {
-    Struct(&'tcx [(ast::Name, &'tcx ConstVal<'tcx>)]),
-    Tuple(&'tcx [&'tcx ConstVal<'tcx>]),
-    Array(&'tcx [&'tcx ConstVal<'tcx>]),
-    Repeat(&'tcx ConstVal<'tcx>, u64),
+    Struct(&'tcx [(ast::Name, &'tcx ty::Const<'tcx>)]),
+    Tuple(&'tcx [&'tcx ty::Const<'tcx>]),
+    Array(&'tcx [&'tcx ty::Const<'tcx>]),
+    Repeat(&'tcx ty::Const<'tcx>, u64),
 }
 
 impl<'tcx> Encodable for ConstAggregate<'tcx> {
@@ -259,7 +257,7 @@ pub fn eval_length(tcx: TyCtxt,
     let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
     let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
     match tcx.at(count_expr.span).const_eval(param_env.and((count_def_id, substs))) {
-        Ok(&Integral(Usize(count))) => {
+        Ok(&ty::Const { val: Integral(Usize(count)), .. }) => {
             let val = count.as_u64(tcx.sess.target.uint_type);
             assert_eq!(val as usize as u64, val);
             Ok(val as usize)
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index a7c4e529d24e1..1985dcbd1f73d 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1187,11 +1187,15 @@ impl<'tcx> Operand<'tcx> {
         substs: &'tcx Substs<'tcx>,
         span: Span,
     ) -> Self {
+        let ty = tcx.type_of(def_id).subst(tcx, substs);
         Operand::Constant(box Constant {
             span,
-            ty: tcx.type_of(def_id).subst(tcx, substs),
+            ty,
             literal: Literal::Value {
-                value: tcx.mk_const(ConstVal::Function(def_id, substs))
+                value: tcx.mk_const(ty::Const {
+                    val: ConstVal::Function(def_id, substs),
+                    ty
+                })
             },
         })
     }
@@ -1480,7 +1484,7 @@ pub enum Literal<'tcx> {
         substs: &'tcx Substs<'tcx>,
     },
     Value {
-        value: &'tcx ConstVal<'tcx>,
+        value: &'tcx ty::Const<'tcx>,
     },
     Promoted {
         // Index into the `promoted` vector of `Mir`.
@@ -1501,9 +1505,9 @@ impl<'tcx> Debug for Literal<'tcx> {
             Item { def_id, substs } => {
                 ppaux::parameterized(fmt, substs, def_id, &[])
             }
-            Value { ref value } => {
+            Value { value } => {
                 write!(fmt, "const ")?;
-                fmt_const_val(fmt, value)
+                fmt_const_val(fmt, &value.val)
             }
             Promoted { index } => {
                 write!(fmt, "{:?}", index)
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index d2719224e3783..22d93c1a27650 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::const_val::ConstVal;
 use hir::def_id::DefId;
 use ty::subst::Substs;
 use ty::{ClosureSubsts, Region, Ty, GeneratorInterior};
@@ -214,6 +213,18 @@ macro_rules! make_mir_visitor {
                 self.super_ty(ty);
             }
 
+            fn visit_region(&mut self,
+                            region: & $($mutability)* ty::Region<'tcx>,
+                            _: Location) {
+                self.super_region(region);
+            }
+
+            fn visit_const(&mut self,
+                           constant: & $($mutability)* &'tcx ty::Const<'tcx>,
+                           _: Location) {
+                self.super_const(constant);
+            }
+
             fn visit_substs(&mut self,
                             substs: & $($mutability)* &'tcx Substs<'tcx>,
                             _: Location) {
@@ -232,12 +243,6 @@ macro_rules! make_mir_visitor {
                 self.super_generator_interior(interior);
             }
 
-            fn visit_const_val(&mut self,
-                               const_val: & $($mutability)* &'tcx ConstVal<'tcx>,
-                               _: Location) {
-                self.super_const_val(const_val);
-            }
-
             fn visit_const_int(&mut self,
                                const_int: &ConstInt,
                                _: Location) {
@@ -517,9 +522,10 @@ macro_rules! make_mir_visitor {
                         self.visit_const_usize(length, location);
                     }
 
-                    Rvalue::Ref(r, bk, ref $($mutability)* path) => {
+                    Rvalue::Ref(ref $($mutability)* r, bk, ref $($mutability)* path) => {
+                        self.visit_region(r, location);
                         self.visit_lvalue(path, LvalueContext::Borrow {
-                            region: r,
+                            region: *r,
                             kind: bk
                         }, location);
                     }
@@ -724,7 +730,7 @@ macro_rules! make_mir_visitor {
                         self.visit_substs(substs, location);
                     }
                     Literal::Value { ref $($mutability)* value } => {
-                        self.visit_const_val(value, location);
+                        self.visit_const(value, location);
                     }
                     Literal::Promoted { index: _ } => {}
                 }
@@ -749,6 +755,12 @@ macro_rules! make_mir_visitor {
             fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
             }
 
+            fn super_region(&mut self, _region: & $($mutability)* ty::Region<'tcx>) {
+            }
+
+            fn super_const(&mut self, _const: & $($mutability)* &'tcx ty::Const<'tcx>) {
+            }
+
             fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) {
             }
 
@@ -760,9 +772,6 @@ macro_rules! make_mir_visitor {
                                     _substs: & $($mutability)* ClosureSubsts<'tcx>) {
             }
 
-            fn super_const_val(&mut self, _const_val: & $($mutability)* &'tcx ConstVal<'tcx>) {
-            }
-
             fn super_const_int(&mut self, _const_int: &ConstInt) {
             }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 5d15e3a8cab72..8dee2675ee5cc 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -21,7 +21,6 @@ use hir::map as hir_map;
 use hir::map::DefPathHash;
 use lint::{self, Lint};
 use ich::{self, StableHashingContext, NodeIdHashingMode};
-use middle::const_val::ConstVal;
 use middle::free_region::FreeRegionMap;
 use middle::lang_items;
 use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
@@ -33,7 +32,7 @@ use ty::ReprOptions;
 use traits;
 use ty::{self, Ty, TypeAndMut};
 use ty::{TyS, TypeVariants, Slice};
-use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region};
+use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region, Const};
 use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate};
 use ty::RegionKind;
 use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
@@ -109,7 +108,7 @@ pub struct CtxtInterners<'tcx> {
     region: RefCell<FxHashSet<Interned<'tcx, RegionKind>>>,
     existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
     predicates: RefCell<FxHashSet<Interned<'tcx, Slice<Predicate<'tcx>>>>>,
-    const_: RefCell<FxHashSet<Interned<'tcx, ConstVal<'tcx>>>>,
+    const_: RefCell<FxHashSet<Interned<'tcx, Const<'tcx>>>>,
 }
 
 impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
@@ -945,21 +944,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn alloc_constval_slice(self, values: &[&'tcx ConstVal<'gcx>])
-                                -> &'gcx [&'tcx ConstVal<'gcx>] {
+    pub fn alloc_const_slice(self, values: &[&'tcx ty::Const<'tcx>])
+                             -> &'tcx [&'tcx ty::Const<'tcx>] {
         if values.is_empty() {
             &[]
         } else {
-            self.global_interners.arena.alloc_slice(values)
+            self.interners.arena.alloc_slice(values)
         }
     }
 
-    pub fn alloc_name_constval_slice(self, values: &[(ast::Name, &'tcx ConstVal<'gcx>)])
-                                     -> &'gcx [(ast::Name, &'tcx ConstVal<'gcx>)] {
+    pub fn alloc_name_const_slice(self, values: &[(ast::Name, &'tcx ty::Const<'tcx>)])
+                                  -> &'tcx [(ast::Name, &'tcx ty::Const<'tcx>)] {
         if values.is_empty() {
             &[]
         } else {
-            self.global_interners.arena.alloc_slice(values)
+            self.interners.arena.alloc_slice(values)
         }
     }
 
@@ -1216,13 +1215,10 @@ impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
-    type Lifted = &'tcx Substs<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> {
-        if self.len() == 0 {
-            return Some(Slice::empty());
-        }
-        if tcx.interners.arena.in_arena(&self[..] as *const _) {
+impl<'a, 'tcx> Lift<'tcx> for Region<'a> {
+    type Lifted = Region<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Region<'tcx>> {
+        if tcx.interners.arena.in_arena(*self as *const _) {
             return Some(unsafe { mem::transmute(*self) });
         }
         // Also try in the global tcx if we're not that.
@@ -1234,9 +1230,9 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for Region<'a> {
-    type Lifted = Region<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Region<'tcx>> {
+impl<'a, 'tcx> Lift<'tcx> for &'a Const<'a> {
+    type Lifted = &'tcx Const<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Const<'tcx>> {
         if tcx.interners.arena.in_arena(*self as *const _) {
             return Some(unsafe { mem::transmute(*self) });
         }
@@ -1249,6 +1245,24 @@ impl<'a, 'tcx> Lift<'tcx> for Region<'a> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
+    type Lifted = &'tcx Substs<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> {
+        if self.len() == 0 {
+            return Some(Slice::empty());
+        }
+        if tcx.interners.arena.in_arena(&self[..] as *const _) {
+            return Some(unsafe { mem::transmute(*self) });
+        }
+        // Also try in the global tcx if we're not that.
+        if !tcx.is_global() {
+            self.lift_to_tcx(tcx.global_tcx())
+        } else {
+            None
+        }
+    }
+}
+
 impl<'a, 'tcx> Lift<'tcx> for &'a Slice<Ty<'a>> {
     type Lifted = &'tcx Slice<Ty<'tcx>>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
@@ -1536,8 +1550,8 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Predicate<'lcx>]>
     }
 }
 
-impl<'tcx: 'lcx, 'lcx> Borrow<ConstVal<'lcx>> for Interned<'tcx, ConstVal<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a ConstVal<'lcx> {
+impl<'tcx: 'lcx, 'lcx> Borrow<Const<'lcx>> for Interned<'tcx, Const<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a Const<'lcx> {
         &self.0
     }
 }
@@ -1623,7 +1637,7 @@ direct_interners!('tcx,
             _ => false
         }
     }) -> RegionKind,
-    const_: mk_const(/*|c: &Const| keep_local(&c.ty)*/ |_| false) -> ConstVal<'tcx>
+    const_: mk_const(|c: &Const| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx>
 );
 
 macro_rules! slice_interners {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 9be12195952f9..7c8aca9a9b157 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -64,7 +64,7 @@ pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
 pub use self::sty::{ClosureSubsts, GeneratorInterior, TypeAndMut};
 pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
 pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
-pub use self::sty::{ExistentialProjection, PolyExistentialProjection};
+pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const};
 pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
 pub use self::sty::RegionKind;
 pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
@@ -1601,7 +1601,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
             if let VariantDiscr::Explicit(expr_did) = v.discr {
                 let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
                 match tcx.const_eval(param_env.and((expr_did, substs))) {
-                    Ok(&ConstVal::Integral(v)) => {
+                    Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => {
                         discr = v;
                     }
                     err => {
@@ -1641,7 +1641,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
                 ty::VariantDiscr::Explicit(expr_did) => {
                     let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
                     match tcx.const_eval(param_env.and((expr_did, substs))) {
-                        Ok(&ConstVal::Integral(v)) => {
+                        Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => {
                             explicit_value = v;
                             break;
                         }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 44b505e19658f..f260e20a3cd6c 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use infer::type_variable;
+use middle::const_val::{ConstVal, ConstAggregate};
 use ty::{self, Lift, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
@@ -1101,3 +1102,95 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
         }
     }
 }
+
+impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        match *self {
+            ConstVal::Integral(i) => ConstVal::Integral(i),
+            ConstVal::Float(f) => ConstVal::Float(f),
+            ConstVal::Str(s) => ConstVal::Str(s),
+            ConstVal::ByteStr(b) => ConstVal::ByteStr(b),
+            ConstVal::Bool(b) => ConstVal::Bool(b),
+            ConstVal::Char(c) => ConstVal::Char(c),
+            ConstVal::Variant(def_id) => ConstVal::Variant(def_id),
+            ConstVal::Function(def_id, substs) => {
+                ConstVal::Function(def_id, substs.fold_with(folder))
+            }
+            ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
+                let new_fields: Vec<_> = fields.iter().map(|&(name, v)| {
+                    (name, v.fold_with(folder))
+                }).collect();
+                let fields = if new_fields == fields {
+                    fields
+                } else {
+                    folder.tcx().alloc_name_const_slice(&new_fields)
+                };
+                ConstVal::Aggregate(ConstAggregate::Struct(fields))
+            }
+            ConstVal::Aggregate(ConstAggregate::Tuple(fields)) => {
+                let new_fields: Vec<_> = fields.iter().map(|v| {
+                    v.fold_with(folder)
+                }).collect();
+                let fields = if new_fields == fields {
+                    fields
+                } else {
+                    folder.tcx().alloc_const_slice(&new_fields)
+                };
+                ConstVal::Aggregate(ConstAggregate::Tuple(fields))
+            }
+            ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
+                let new_fields: Vec<_> = fields.iter().map(|v| {
+                    v.fold_with(folder)
+                }).collect();
+                let fields = if new_fields == fields {
+                    fields
+                } else {
+                    folder.tcx().alloc_const_slice(&new_fields)
+                };
+                ConstVal::Aggregate(ConstAggregate::Array(fields))
+            }
+            ConstVal::Aggregate(ConstAggregate::Repeat(v, count)) => {
+                let v = v.fold_with(folder);
+                ConstVal::Aggregate(ConstAggregate::Repeat(v, count))
+            }
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            ConstVal::Integral(_) |
+            ConstVal::Float(_) |
+            ConstVal::Str(_) |
+            ConstVal::ByteStr(_) |
+            ConstVal::Bool(_) |
+            ConstVal::Char(_) |
+            ConstVal::Variant(_) => false,
+            ConstVal::Function(_, substs) => substs.visit_with(visitor),
+            ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
+                fields.iter().any(|&(_, v)| v.visit_with(visitor))
+            }
+            ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
+            ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
+                fields.iter().any(|v| v.visit_with(visitor))
+            }
+            ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
+                v.visit_with(visitor)
+            }
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        let ty = self.ty.fold_with(folder);
+        let val = self.val.fold_with(folder);
+        folder.tcx().mk_const(ty::Const {
+            ty,
+            val
+        })
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.ty.visit_with(visitor) || self.val.visit_with(visitor)
+    }
+}
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 14ea66a1b67fa..f082e32ff6867 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -12,6 +12,7 @@
 
 use hir::def_id::DefId;
 
+use middle::const_val::ConstVal;
 use middle::region;
 use ty::subst::{Substs, Subst};
 use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
@@ -1458,3 +1459,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         }
     }
 }
+
+/// Typed constant value.
+#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
+pub struct Const<'tcx> {
+    pub ty: Ty<'tcx>,
+
+    // FIXME(eddyb) Replace this with a miri value.
+    pub val: ConstVal<'tcx>,
+}
+
+impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {}
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index aea1f454d8141..b1e3dcf53f0d8 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -182,13 +182,16 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
         self.byte_array_map.entry(pat).or_insert_with(|| {
             match pat.kind {
                 box PatternKind::Constant {
-                    value: &ConstVal::ByteStr(b)
+                    value: &ty::Const { val: ConstVal::ByteStr(b), .. }
                 } => {
                     b.data.iter().map(|&b| &*pattern_arena.alloc(Pattern {
                         ty: tcx.types.u8,
                         span: pat.span,
                         kind: box PatternKind::Constant {
-                            value: tcx.mk_const(ConstVal::Integral(ConstInt::U8(b)))
+                            value: tcx.mk_const(ty::Const {
+                                val: ConstVal::Integral(ConstInt::U8(b)),
+                                ty: tcx.types.u8
+                            })
                         }
                     })).collect()
                 }
@@ -228,9 +231,9 @@ pub enum Constructor<'tcx> {
     /// Enum variants.
     Variant(DefId),
     /// Literal values.
-    ConstantValue(&'tcx ConstVal<'tcx>),
+    ConstantValue(&'tcx ty::Const<'tcx>),
     /// Ranges of literal values (`2...5` and `2..5`).
-    ConstantRange(&'tcx ConstVal<'tcx>, &'tcx ConstVal<'tcx>, RangeEnd),
+    ConstantRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
     /// Array patterns of length n.
     Slice(usize),
 }
@@ -406,7 +409,10 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
     match pcx.ty.sty {
         ty::TyBool => {
             [true, false].iter().map(|&b| {
-                ConstantValue(cx.tcx.mk_const(ConstVal::Bool(b)))
+                ConstantValue(cx.tcx.mk_const(ty::Const {
+                    val: ConstVal::Bool(b),
+                    ty: cx.tcx.types.bool
+                }))
             }).collect()
         }
         ty::TySlice(ref sub_ty) => {
@@ -514,7 +520,7 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
 
     for row in patterns {
         match *row.kind {
-            PatternKind::Constant { value: &ConstVal::ByteStr(b) } => {
+            PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => {
                 max_fixed_len = cmp::max(max_fixed_len, b.data.len());
             }
             PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
@@ -809,7 +815,7 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
                                     suffix: &[Pattern])
                                     -> Result<bool, ErrorReported> {
     let data = match *ctor {
-        ConstantValue(&ConstVal::ByteStr(b)) => b.data,
+        ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data,
         _ => bug!()
     };
 
@@ -823,7 +829,7 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
             data[data.len()-suffix.len()..].iter().zip(suffix))
     {
         match pat.kind {
-            box PatternKind::Constant { value } => match *value {
+            box PatternKind::Constant { value } => match value.val {
                 ConstVal::Integral(ConstInt::U8(u)) => {
                     if u != *ch {
                         return Ok(false);
@@ -847,22 +853,22 @@ fn constructor_covered_by_range(tcx: TyCtxt, span: Span,
     let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to);
     match *ctor {
         ConstantValue(value) => {
-            let to = cmp_to(value)?;
+            let to = cmp_to(&value.val)?;
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Included && to == Ordering::Equal);
-            Ok(cmp_from(value)? && end)
+            Ok(cmp_from(&value.val)? && end)
         },
         ConstantRange(from, to, RangeEnd::Included) => {
-            let to = cmp_to(to)?;
+            let to = cmp_to(&to.val)?;
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Included && to == Ordering::Equal);
-            Ok(cmp_from(from)? && end)
+            Ok(cmp_from(&from.val)? && end)
         },
         ConstantRange(from, to, RangeEnd::Excluded) => {
-            let to = cmp_to(to)?;
+            let to = cmp_to(&to.val)?;
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Excluded && to == Ordering::Equal);
-            Ok(cmp_from(from)? && end)
+            Ok(cmp_from(&from.val)? && end)
         }
         Single => Ok(true),
         _ => bug!(),
@@ -924,7 +930,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
 
         PatternKind::Constant { value } => {
             match *constructor {
-                Slice(..) => match *value {
+                Slice(..) => match value.val {
                     ConstVal::ByteStr(b) => {
                         if wild_patterns.len() == b.data.len() {
                             Some(cx.lower_byte_str_pattern(pat))
@@ -937,7 +943,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                 },
                 _ => {
                     match constructor_covered_by_range(
-                        cx.tcx, pat.span, constructor, value, value, RangeEnd::Included
+                        cx.tcx, pat.span, constructor, &value.val, &value.val, RangeEnd::Included
                             ) {
                         Ok(true) => Some(vec![]),
                         Ok(false) => None,
@@ -947,9 +953,9 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
             }
         }
 
-        PatternKind::Range { ref lo, ref hi, ref end } => {
+        PatternKind::Range { lo, hi, ref end } => {
             match constructor_covered_by_range(
-                cx.tcx, pat.span, constructor, lo, hi, end.clone()
+                cx.tcx, pat.span, constructor, &lo.val, &hi.val, end.clone()
             ) {
                 Ok(true) => Some(vec![]),
                 Ok(false) => None,
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 5f0a070229177..2aa333c1f039c 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -89,7 +89,7 @@ pub struct ConstContext<'a, 'tcx: 'a> {
     tables: &'a ty::TypeckTables<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     substs: &'tcx Substs<'tcx>,
-    fn_args: Option<NodeMap<&'tcx ConstVal<'tcx>>>
+    fn_args: Option<NodeMap<&'tcx ty::Const<'tcx>>>
 }
 
 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
@@ -121,7 +121,8 @@ type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                                      e: &'tcx Expr) -> EvalResult<'tcx> {
     let tcx = cx.tcx;
-    let ety = cx.tables.expr_ty(e).subst(tcx, cx.substs);
+    let ty = cx.tables.expr_ty(e).subst(tcx, cx.substs);
+    let mk_const = |val| tcx.mk_const(ty::Const { val, ty });
 
     let result = match e.node {
       hir::ExprUnary(hir::UnNeg, ref inner) => {
@@ -134,7 +135,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
             const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
             const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
             const I128_OVERFLOW: u128 = i128::min_value() as u128;
-            let negated = match (&lit.node, &ety.sty) {
+            let negated = match (&lit.node, &ty.sty) {
                 (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
                 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
                     Some(I8(i8::min_value()))
@@ -179,17 +180,17 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                 _ => None
             };
             if let Some(i) = negated {
-                return Ok(tcx.mk_const(Integral(i)));
+                return Ok(mk_const(Integral(i)));
             }
         }
-        tcx.mk_const(match *cx.eval(inner)? {
+        mk_const(match cx.eval(inner)?.val {
           Float(f) => Float(-f),
           Integral(i) => Integral(math!(e, -i)),
           const_val => signal!(e, NegateOn(const_val)),
         })
       }
       hir::ExprUnary(hir::UnNot, ref inner) => {
-        tcx.mk_const(match *cx.eval(inner)? {
+        mk_const(match cx.eval(inner)?.val {
           Integral(i) => Integral(math!(e, !i)),
           Bool(b) => Bool(!b),
           const_val => signal!(e, NotOn(const_val)),
@@ -201,7 +202,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         // gives us a type through a type-suffix, cast or const def type
         // we need to re-eval the other value of the BinOp if it was
         // not inferred
-        tcx.mk_const(match (*cx.eval(a)?, *cx.eval(b)?) {
+        mk_const(match (cx.eval(a)?.val, cx.eval(b)?.val) {
           (Float(a), Float(b)) => {
             use std::cmp::Ordering::*;
             match op.node {
@@ -275,11 +276,11 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       hir::ExprCast(ref base, _) => {
         let base_val = cx.eval(base)?;
         let base_ty = cx.tables.expr_ty(base).subst(tcx, cx.substs);
-        if ety == base_ty {
+        if ty == base_ty {
             base_val
         } else {
-            match cast_const(tcx, *base_val, ety) {
-                Ok(val) => tcx.mk_const(val),
+            match cast_const(tcx, base_val.val, ty) {
+                Ok(val) => mk_const(val),
                 Err(kind) => signal!(e, kind),
             }
         }
@@ -301,13 +302,13 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                     }
               },
               Def::VariantCtor(variant_def, CtorKind::Const) => {
-                tcx.mk_const(Variant(variant_def))
+                mk_const(Variant(variant_def))
               }
               Def::VariantCtor(_, CtorKind::Fn) => {
                   signal!(e, UnimplementedConstVal("enum variants"));
               }
               Def::StructCtor(_, CtorKind::Const) => {
-                  tcx.mk_const(Aggregate(Struct(&[])))
+                  mk_const(Aggregate(Struct(&[])))
               }
               Def::StructCtor(_, CtorKind::Fn) => {
                   signal!(e, UnimplementedConstVal("tuple struct constructors"))
@@ -320,13 +321,13 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                       signal!(e, NonConstPath);
                   }
               },
-              Def::Method(id) | Def::Fn(id) => tcx.mk_const(Function(id, substs)),
+              Def::Method(id) | Def::Fn(id) => mk_const(Function(id, substs)),
               Def::Err => span_bug!(e.span, "typeck error"),
               _ => signal!(e, NonConstPath),
           }
       }
       hir::ExprCall(ref callee, ref args) => {
-          let (def_id, substs) = match *cx.eval(callee)? {
+          let (def_id, substs) = match cx.eval(callee)?.val {
               Function(def_id, substs) => (def_id, substs),
               _ => signal!(e, TypeckError),
           };
@@ -340,12 +341,12 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
             match &tcx.item_name(def_id)[..] {
                 "size_of" => {
                     let size = layout_of(substs.type_at(0))?.size(tcx).bytes();
-                    return Ok(tcx.mk_const(Integral(Usize(ConstUsize::new(size,
+                    return Ok(mk_const(Integral(Usize(ConstUsize::new(size,
                         tcx.sess.target.uint_type).unwrap()))));
                 }
                 "min_align_of" => {
                     let align = layout_of(substs.type_at(0))?.align(tcx).abi();
-                    return Ok(tcx.mk_const(Integral(Usize(ConstUsize::new(align,
+                    return Ok(mk_const(Integral(Usize(ConstUsize::new(align,
                         tcx.sess.target.uint_type).unwrap()))));
                 }
                 _ => signal!(e, TypeckError)
@@ -394,23 +395,23 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           };
           callee_cx.eval(&body.value)?
       },
-      hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
-          Ok(val) => tcx.mk_const(val),
+      hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty) {
+          Ok(val) => mk_const(val),
           Err(err) => signal!(e, err),
       },
       hir::ExprBlock(ref block) => {
         match block.expr {
             Some(ref expr) => cx.eval(expr)?,
-            None => tcx.mk_const(Aggregate(Tuple(&[]))),
+            None => mk_const(Aggregate(Tuple(&[]))),
         }
       }
       hir::ExprType(ref e, _) => cx.eval(e)?,
       hir::ExprTup(ref fields) => {
         let values = fields.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
-        tcx.mk_const(Aggregate(Tuple(tcx.alloc_constval_slice(&values))))
+        mk_const(Aggregate(Tuple(tcx.alloc_const_slice(&values))))
       }
       hir::ExprStruct(_, ref fields, _) => {
-        tcx.mk_const(Aggregate(Struct(tcx.alloc_name_constval_slice(&fields.iter().map(|f| {
+        mk_const(Aggregate(Struct(tcx.alloc_name_const_slice(&fields.iter().map(|f| {
             cx.eval(&f.expr).map(|v| (f.name.node, v))
         }).collect::<Result<Vec<_>, _>>()?))))
       }
@@ -419,12 +420,12 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
             signal!(e, IndexOpFeatureGated);
         }
         let arr = cx.eval(arr)?;
-        let idx = match *cx.eval(idx)? {
+        let idx = match cx.eval(idx)?.val {
             Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
             _ => signal!(idx, IndexNotUsize),
         };
         assert_eq!(idx as usize as u64, idx);
-        match *arr {
+        match arr.val {
             Aggregate(Array(v)) => {
                 if let Some(&elem) = v.get(idx as usize) {
                     elem
@@ -444,7 +445,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                 signal!(e, IndexOutOfBounds { len: b.data.len() as u64, index: idx })
             }
             ByteStr(b) => {
-                tcx.mk_const(Integral(U8(b.data[idx as usize])))
+                mk_const(Integral(U8(b.data[idx as usize])))
             },
 
             _ => signal!(e, IndexedNonVec),
@@ -452,24 +453,24 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       }
       hir::ExprArray(ref v) => {
         let values = v.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
-        tcx.mk_const(Aggregate(Array(tcx.alloc_constval_slice(&values))))
+        mk_const(Aggregate(Array(tcx.alloc_const_slice(&values))))
       }
       hir::ExprRepeat(ref elem, _) => {
-          let n = match ety.sty {
+          let n = match ty.sty {
             ty::TyArray(_, n) => n as u64,
             _ => span_bug!(e.span, "typeck error")
           };
-          tcx.mk_const(Aggregate(Repeat(cx.eval(elem)?, n)))
+          mk_const(Aggregate(Repeat(cx.eval(elem)?, n)))
       },
       hir::ExprTupField(ref base, index) => {
-        if let Aggregate(Tuple(fields)) = *cx.eval(base)? {
+        if let Aggregate(Tuple(fields)) = cx.eval(base)?.val {
             fields[index.node]
         } else {
             signal!(base, ExpectedConstTuple);
         }
       }
       hir::ExprField(ref base, field_name) => {
-        if let Aggregate(Struct(fields)) = *cx.eval(base)? {
+        if let Aggregate(Struct(fields)) = cx.eval(base)?.val {
             if let Some(&(_, f)) = fields.iter().find(|&&(name, _)| name == field_name.node) {
                 f
             } else {
@@ -756,7 +757,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
                 return Err(ErrorReported);
             }
         };
-        compare_const_vals(tcx, span, &a, &b)
+        compare_const_vals(tcx, span, &a.val, &b.val)
     }
 }
 
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index e824c4789c7c6..cf42d61e136ad 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -83,12 +83,12 @@ pub enum PatternKind<'tcx> {
     },
 
     Constant {
-        value: &'tcx ConstVal<'tcx>,
+        value: &'tcx ty::Const<'tcx>,
     },
 
     Range {
-        lo: &'tcx ConstVal<'tcx>,
-        hi: &'tcx ConstVal<'tcx>,
+        lo: &'tcx ty::Const<'tcx>,
+        hi: &'tcx ty::Const<'tcx>,
         end: RangeEnd,
     },
 
@@ -228,15 +228,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
                 write!(f, "{}", subpattern)
             }
             PatternKind::Constant { value } => {
-                print_const_val(value, f)
+                print_const_val(&value.val, f)
             }
             PatternKind::Range { lo, hi, end } => {
-                print_const_val(lo, f)?;
+                print_const_val(&lo.val, f)?;
                 match end {
                     RangeEnd::Included => write!(f, "...")?,
                     RangeEnd::Excluded => write!(f, "..")?,
                 }
-                print_const_val(hi, f)
+                print_const_val(&hi.val, f)
             }
             PatternKind::Slice { ref prefix, ref slice, ref suffix } |
             PatternKind::Array { ref prefix, ref slice, ref suffix } => {
@@ -634,7 +634,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                                                self.tables);
         match const_cx.eval(expr) {
             Ok(value) => {
-                if let ConstVal::Variant(def_id) = *value {
+                if let ConstVal::Variant(def_id) = value.val {
                     let ty = self.tables.expr_ty(expr);
                     self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![])
                 } else {
@@ -816,7 +816,7 @@ macro_rules! CloneImpls {
 }
 
 CloneImpls!{ <'tcx>
-    Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ConstVal<'tcx>,
+    Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
     Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
     &'tcx Substs<'tcx>, &'tcx Kind<'tcx>
 }
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 46a33ce807d7d..e6af47952b371 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -117,7 +117,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                                                              cx.param_env.and(substs),
                                                              cx.tables);
                             match const_cx.eval(&r) {
-                                Ok(&ConstVal::Integral(i)) => {
+                                Ok(&ty::Const { val: ConstVal::Integral(i), .. }) => {
                                     i.is_negative() ||
                                     i.to_u64()
                                         .map(|i| i >= bits)
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index b475b02ccfeaa..689f9f5b24430 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -16,7 +16,7 @@ use schema::*;
 use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
 use rustc::hir;
 
-use rustc::middle::const_val::{ByteArray, ConstVal};
+use rustc::middle::const_val::ByteArray;
 use rustc::middle::cstore::LinkagePreference;
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -386,8 +386,8 @@ impl<'a, 'tcx> SpecializedDecoder<ByteArray<'tcx>> for DecodeContext<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<&'tcx ConstVal<'tcx>> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<&'tcx ConstVal<'tcx>, Self::Error> {
+impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Const<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         Ok(self.tcx().mk_const(Decodable::decode(self)?))
     }
 }
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index c5f83b029ce00..2bda4524d23af 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -197,7 +197,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         span: expr_span,
                         ty: this.hir.tcx().types.u32,
                         literal: Literal::Value {
-                            value: this.hir.tcx().mk_const(ConstVal::Integral(ConstInt::U32(0))),
+                            value: this.hir.tcx().mk_const(ty::Const {
+                                val: ConstVal::Integral(ConstInt::U32(0)),
+                                ty: this.hir.tcx().types.u32
+                            }),
                         },
                     }));
                     box AggregateKind::Generator(closure_id, substs, interior)
@@ -392,7 +395,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 };
 
                 Literal::Value {
-                    value: self.hir.tcx().mk_const(ConstVal::Integral(val))
+                    value: self.hir.tcx().mk_const(ty::Const {
+                        val: ConstVal::Integral(val),
+                        ty
+                    })
                 }
             }
             _ => {
@@ -427,7 +433,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 };
 
                 Literal::Value {
-                    value: self.hir.tcx().mk_const(ConstVal::Integral(val))
+                    value: self.hir.tcx().mk_const(ty::Const {
+                        val: ConstVal::Integral(val),
+                        ty
+                    })
                 }
             }
             _ => {
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 2d029f1a5b7f7..f560fa426e22e 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -16,8 +16,7 @@
 use build::{BlockAnd, BlockAndExtension, Builder};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::bitvec::BitVector;
-use rustc::middle::const_val::ConstVal;
-use rustc::ty::{AdtDef, Ty};
+use rustc::ty::{self, Ty};
 use rustc::mir::*;
 use rustc::hir;
 use hair::*;
@@ -294,20 +293,20 @@ pub struct MatchPair<'pat, 'tcx:'pat> {
 enum TestKind<'tcx> {
     // test the branches of enum
     Switch {
-        adt_def: &'tcx AdtDef,
+        adt_def: &'tcx ty::AdtDef,
         variants: BitVector,
     },
 
     // test the branches of enum
     SwitchInt {
         switch_ty: Ty<'tcx>,
-        options: Vec<&'tcx ConstVal<'tcx>>,
-        indices: FxHashMap<&'tcx ConstVal<'tcx>, usize>,
+        options: Vec<&'tcx ty::Const<'tcx>>,
+        indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
     },
 
     // test for equality
     Eq {
-        value: &'tcx ConstVal<'tcx>,
+        value: &'tcx ty::Const<'tcx>,
         ty: Ty<'tcx>,
     },
 
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 5553e2f4c9ca1..965a443d9ac1b 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -112,8 +112,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                      test_lvalue: &Lvalue<'tcx>,
                                      candidate: &Candidate<'pat, 'tcx>,
                                      switch_ty: Ty<'tcx>,
-                                     options: &mut Vec<&'tcx ConstVal<'tcx>>,
-                                     indices: &mut FxHashMap<&'tcx ConstVal<'tcx>, usize>)
+                                     options: &mut Vec<&'tcx ty::Const<'tcx>>,
+                                     indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>)
                                      -> bool
     {
         let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
@@ -228,7 +228,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     assert!(options.len() > 0 && options.len() <= 2);
                     let (true_bb, false_bb) = (self.cfg.start_new_block(),
                                                self.cfg.start_new_block());
-                    let ret = match *options[0] {
+                    let ret = match options[0].val {
                         ConstVal::Bool(true) => vec![true_bb, false_bb],
                         ConstVal::Bool(false) => vec![false_bb, true_bb],
                         v => span_bug!(test.span, "expected boolean value but got {:?}", v)
@@ -245,7 +245,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                .chain(Some(otherwise))
                                .collect();
                     let values: Vec<_> = options.iter().map(|v|
-                        v.to_const_int().expect("switching on integral")
+                        v.val.to_const_int().expect("switching on integral")
                     ).collect();
                     (targets.clone(), TerminatorKind::SwitchInt {
                         discr: Operand::Consume(lvalue.clone()),
@@ -263,7 +263,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                 // If we're using b"..." as a pattern, we need to insert an
                 // unsizing coercion, as the byte string has the type &[u8; N].
-                let expect = if let ConstVal::ByteStr(bytes) = *value {
+                let expect = if let ConstVal::ByteStr(bytes) = value.val {
                     let tcx = self.hir.tcx();
 
                     // Unsize the lvalue to &[u8], too, if necessary.
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index 12b9174f3a3a6..bf9ad78481164 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -61,7 +61,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
             ty::TyChar => {
                 Literal::Value {
-                    value: self.hir.tcx().mk_const(ConstVal::Char('\0'))
+                    value: self.hir.tcx().mk_const(ty::Const {
+                        val: ConstVal::Char('\0'),
+                        ty
+                    })
                 }
             }
             ty::TyUint(ity) => {
@@ -79,7 +82,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 };
 
                 Literal::Value {
-                    value: self.hir.tcx().mk_const(ConstVal::Integral(val))
+                    value: self.hir.tcx().mk_const(ty::Const {
+                        val: ConstVal::Integral(val),
+                        ty
+                    })
                 }
             }
             ty::TyInt(ity) => {
@@ -97,7 +103,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 };
 
                 Literal::Value {
-                    value: self.hir.tcx().mk_const(ConstVal::Integral(val))
+                    value: self.hir.tcx().mk_const(ty::Const {
+                        val: ConstVal::Integral(val),
+                        ty
+                    })
                 }
             }
             _ => {
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 704d138b43b58..be6f8c9e56c40 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -166,6 +166,26 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
         }
     }
 
+    fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) {
+        if let Some(lifted) = self.tcx.lift(region) {
+            *region = lifted;
+        } else {
+            span_bug!(self.span,
+                      "found region `{:?}` with inference types/regions in MIR",
+                      region);
+        }
+    }
+
+    fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) {
+        if let Some(lifted) = self.tcx.lift(constant) {
+            *constant = lifted;
+        } else {
+            span_bug!(self.span,
+                      "found constant `{:?}` with inference types/regions in MIR",
+                      constant);
+        }
+    }
+
     fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, _: Location) {
         if let Some(lifted) = self.tcx.lift(substs) {
             *substs = lifted;
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 0e4d2b9a5aefe..23e6fbd2b7e23 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -473,7 +473,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let def_id = cx.tcx.hir.body_owner_def_id(count);
             let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id);
             let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) {
-                Ok(&ConstVal::Integral(ConstInt::Usize(u))) => u,
+                Ok(&ty::Const { val: ConstVal::Integral(ConstInt::Usize(u)), .. }) => u,
                 Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
                 Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
             };
@@ -591,13 +591,17 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         (cx.tables().type_dependent_defs()[expr.hir_id].def_id(),
          cx.tables().node_substs(expr.hir_id))
     });
+    let ty = cx.tcx().mk_fn_def(def_id, substs);
     Expr {
         temp_lifetime,
-        ty: cx.tcx().mk_fn_def(def_id, substs),
+        ty,
         span: expr.span,
         kind: ExprKind::Literal {
             literal: Literal::Value {
-                value: cx.tcx.mk_const(ConstVal::Function(def_id, substs)),
+                value: cx.tcx.mk_const(ty::Const {
+                    val: ConstVal::Function(def_id, substs),
+                    ty
+                }),
             },
         },
     }
@@ -630,7 +634,10 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Def::StructCtor(def_id, CtorKind::Fn) |
         Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal {
             literal: Literal::Value {
-                value: cx.tcx.mk_const(ConstVal::Function(def_id, substs)),
+                value: cx.tcx.mk_const(ty::Const {
+                    val: ConstVal::Function(def_id, substs),
+                    ty: cx.tables().node_id_to_type(expr.hir_id)
+                }),
             },
         },
 
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 9244ea14514fc..85607c04c98c8 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -115,7 +115,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         match ConstUsize::new(value, self.tcx.sess.target.uint_type) {
             Ok(val) => {
                 Literal::Value {
-                    value: self.tcx.mk_const(ConstVal::Integral(ConstInt::Usize(val)))
+                    value: self.tcx.mk_const(ty::Const {
+                        val: ConstVal::Integral(ConstInt::Usize(val)),
+                        ty: self.tcx.types.usize
+                    })
                 }
             }
             Err(_) => bug!("usize literal out of range for target"),
@@ -131,11 +134,21 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     }
 
     pub fn true_literal(&mut self) -> Literal<'tcx> {
-        Literal::Value { value: self.tcx.mk_const(ConstVal::Bool(true)) }
+        Literal::Value {
+            value: self.tcx.mk_const(ty::Const {
+                val: ConstVal::Bool(true),
+                ty: self.tcx.types.bool
+            })
+        }
     }
 
     pub fn false_literal(&mut self) -> Literal<'tcx> {
-        Literal::Value { value: self.tcx.mk_const(ConstVal::Bool(false)) }
+        Literal::Value {
+            value: self.tcx.mk_const(ty::Const {
+                val: ConstVal::Bool(false),
+                ty: self.tcx.types.bool
+            })
+        }
     }
 
     pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
@@ -186,7 +199,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                 let method_ty = method_ty.subst(self.tcx, substs);
                 return (method_ty,
                         Literal::Value {
-                            value: self.tcx.mk_const(ConstVal::Function(item.def_id, substs)),
+                            value: self.tcx.mk_const(ty::Const {
+                                val: ConstVal::Function(item.def_id, substs),
+                                ty: method_ty
+                            }),
                         });
             }
         }
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index d0a78b5721708..cc0ea5911a070 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -403,11 +403,15 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
         );
 
         // `func == Clone::clone(&ty) -> ty`
+        let func_ty = tcx.mk_fn_def(self.def_id, substs);
         let func = Operand::Constant(box Constant {
             span: self.span,
-            ty: tcx.mk_fn_def(self.def_id, substs),
+            ty: func_ty,
             literal: Literal::Value {
-                value: tcx.mk_const(ConstVal::Function(self.def_id, substs)),
+                value: tcx.mk_const(ty::Const {
+                    val: ConstVal::Function(self.def_id, substs),
+                    ty: func_ty
+                }),
             },
         });
 
@@ -472,7 +476,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
             span: self.span,
             ty: self.tcx.types.usize,
             literal: Literal::Value {
-                value: self.tcx.mk_const(ConstVal::Integral(ConstInt::Usize(value)))
+                value: self.tcx.mk_const(ty::Const {
+                    val: ConstVal::Integral(ConstInt::Usize(value)),
+                    ty: self.tcx.types.usize,
+                })
             }
         }
     }
@@ -706,17 +713,21 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
 
     let (callee, mut args) = match call_kind {
         CallKind::Indirect => (rcvr, vec![]),
-        CallKind::Direct(def_id) => (
-            Operand::Constant(box Constant {
+        CallKind::Direct(def_id) => {
+            let ty = tcx.type_of(def_id);
+            (Operand::Constant(box Constant {
                 span,
-                ty: tcx.type_of(def_id),
+                ty,
                 literal: Literal::Value {
-                    value: tcx.mk_const(ConstVal::Function(def_id,
-                        Substs::identity_for_item(tcx, def_id))),
+                    value: tcx.mk_const(ty::Const {
+                        val: ConstVal::Function(def_id,
+                            Substs::identity_for_item(tcx, def_id)),
+                        ty
+                    }),
                 },
-            }),
-            vec![rcvr]
-        )
+             }),
+             vec![rcvr])
+        }
     };
 
     if let Some(untuple_args) = untuple_args {
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index 971df70a74e25..1077f3b014616 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -521,7 +521,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             span,
             ty: self.tcx.types.bool,
             literal: Literal::Value {
-                value: self.tcx.mk_const(ConstVal::Bool(val))
+                value: self.tcx.mk_const(ty::Const {
+                    val: ConstVal::Bool(val),
+                    ty: self.tcx.types.bool
+                })
             }
         })))
     }
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index fa51cd91be1b6..dc18cdd8f0dd6 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -15,7 +15,7 @@
 //! "types-as-contracts"-validation, namely, AcquireValid, ReleaseValid, and EndRegion.
 
 use rustc::ty::subst::Substs;
-use rustc::ty::{Ty, TyCtxt, ClosureSubsts};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::mir::*;
 use rustc::mir::visit::{MutVisitor, Lookup};
 use rustc::mir::transform::{MirPass, MirSource};
@@ -37,38 +37,25 @@ impl<'a, 'tcx> EraseRegionsVisitor<'a, 'tcx> {
 impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
     fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: Lookup) {
         if !self.in_validation_statement {
-            *ty = self.tcx.erase_regions(&{*ty});
+            *ty = self.tcx.erase_regions(ty);
         }
         self.super_ty(ty);
     }
 
-    fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, _: Location) {
-        *substs = self.tcx.erase_regions(&{*substs});
+    fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) {
+        *region = self.tcx.types.re_erased;
     }
 
-    fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
-        match *rvalue {
-            Rvalue::Ref(ref mut r, _, _) => {
-                *r = self.tcx.types.re_erased;
-            }
-            Rvalue::Use(..) |
-            Rvalue::Repeat(..) |
-            Rvalue::Len(..) |
-            Rvalue::Cast(..) |
-            Rvalue::BinaryOp(..) |
-            Rvalue::CheckedBinaryOp(..) |
-            Rvalue::UnaryOp(..) |
-            Rvalue::Discriminant(..) |
-            Rvalue::NullaryOp(..) |
-            Rvalue::Aggregate(..) => {
-                // These variants don't contain regions.
-            }
-        }
-        self.super_rvalue(rvalue, location);
+    fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) {
+        *constant = self.tcx.erase_regions(constant);
+    }
+
+    fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, _: Location) {
+        *substs = self.tcx.erase_regions(substs);
     }
 
     fn visit_closure_substs(&mut self,
-                            substs: &mut ClosureSubsts<'tcx>,
+                            substs: &mut ty::ClosureSubsts<'tcx>,
                             _: Location) {
         *substs = self.tcx.erase_regions(substs);
     }
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 74edf510aa2e7..a52656becd745 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -175,7 +175,10 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
             span: source_info.span,
             ty: self.tcx.types.u32,
             literal: Literal::Value {
-                value: self.tcx.mk_const(ConstVal::Integral(ConstInt::U32(state_disc))),
+                value: self.tcx.mk_const(ty::Const {
+                    val: ConstVal::Integral(ConstInt::U32(state_disc)),
+                    ty: self.tcx.types.u32
+                }),
             },
         });
         Statement {
@@ -553,7 +556,10 @@ fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             span: mir.span,
             ty: tcx.types.bool,
             literal: Literal::Value {
-                value: tcx.mk_const(ConstVal::Bool(false)),
+                value: tcx.mk_const(ty::Const {
+                    val: ConstVal::Bool(false),
+                    ty: tcx.types.bool
+                }),
             },
         }),
         expected: true,
@@ -603,7 +609,10 @@ fn create_generator_resume_function<'a, 'tcx>(
             span: mir.span,
             ty: tcx.types.bool,
             literal: Literal::Value {
-                value: tcx.mk_const(ConstVal::Bool(false)),
+                value: tcx.mk_const(ty::Const {
+                    val: ConstVal::Bool(false),
+                    ty: tcx.types.bool
+                }),
             },
         }),
         expected: true,
diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs
index 6c0a44b763170..0dff145ecbce9 100644
--- a/src/librustc_mir/transform/simplify_branches.rs
+++ b/src/librustc_mir/transform/simplify_branches.rs
@@ -10,7 +10,7 @@
 
 //! A pass that simplifies branches when their condition is known.
 
-use rustc::ty::TyCtxt;
+use rustc::ty::{self, TyCtxt};
 use rustc::middle::const_val::ConstVal;
 use rustc::mir::transform::{MirPass, MirSource};
 use rustc::mir::*;
@@ -40,7 +40,7 @@ impl MirPass for SimplifyBranches {
                 TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
                     literal: Literal::Value { ref value }, ..
                 }), ref values, ref targets, .. } => {
-                    if let Some(ref constint) = value.to_const_int() {
+                    if let Some(ref constint) = value.val.to_const_int() {
                         let (otherwise, targets) = targets.split_last().unwrap();
                         let mut ret = TerminatorKind::Goto { target: *otherwise };
                         for (v, t) in values.iter().zip(targets.iter()) {
@@ -56,7 +56,7 @@ impl MirPass for SimplifyBranches {
                 },
                 TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
                     literal: Literal::Value {
-                        value: &ConstVal::Bool(cond)
+                        value: &ty::Const { val: ConstVal::Bool(cond), .. }
                     }, ..
                 }), expected, .. } if cond == expected => {
                     TerminatorKind::Goto { target: target }
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index eaafdb0ac4178..3c77668e729c6 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -572,7 +572,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         match operand {
             &Operand::Constant(box Constant {
                 literal: Literal::Value {
-                    value: &ConstVal::Function(def_id, _), ..
+                    value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, ..
                 }, ..
             }) => {
                 Some(def_id) == self.tcx().lang_items().box_free_fn()
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index d770dbe6f4f47..4a11ac1168090 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -923,7 +923,10 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
             span: self.source_info.span,
             ty: self.tcx().types.usize,
             literal: Literal::Value {
-                value: self.tcx().mk_const(ConstVal::Integral(self.tcx().const_usize(val)))
+                value: self.tcx().mk_const(ty::Const {
+                    val: ConstVal::Integral(self.tcx().const_usize(val)),
+                    ty: self.tcx().types.usize
+                })
             }
         })
     }
diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs
index 67176276f96fb..91203a91be51d 100644
--- a/src/librustc_passes/mir_stats.rs
+++ b/src/librustc_passes/mir_stats.rs
@@ -13,7 +13,6 @@
 // completely accurate (some things might be counted twice, others missed).
 
 use rustc_const_math::{ConstUsize};
-use rustc::middle::const_val::{ConstVal};
 use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData};
 use rustc::mir::{Constant, Literal, Location, LocalDecl};
 use rustc::mir::{Lvalue, LvalueElem, LvalueProjection};
@@ -21,7 +20,7 @@ use rustc::mir::{Mir, Operand, ProjectionElem};
 use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind};
 use rustc::mir::{Terminator, TerminatorKind, VisibilityScope, VisibilityScopeData};
 use rustc::mir::visit as mir_visit;
-use rustc::ty::{ClosureSubsts, TyCtxt};
+use rustc::ty::{self, ClosureSubsts, TyCtxt};
 use rustc::util::nodemap::{FxHashMap};
 
 struct NodeData {
@@ -256,11 +255,11 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
         self.super_closure_substs(substs);
     }
 
-    fn visit_const_val(&mut self,
-                       const_val: &&'tcx ConstVal<'tcx>,
-                       _: Location) {
-        self.record("ConstVal", const_val);
-        self.super_const_val(const_val);
+    fn visit_const(&mut self,
+                   constant: &&'tcx ty::Const<'tcx>,
+                   _: Location) {
+        self.record("Const", constant);
+        self.super_const(constant);
     }
 
     fn visit_const_usize(&mut self,
diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs
index a843b4171bd80..1017ec6b3c3f8 100644
--- a/src/librustc_trans/mir/analyze.rs
+++ b/src/librustc_trans/mir/analyze.rs
@@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal;
 use rustc::mir::{self, Location, TerminatorKind, Literal};
 use rustc::mir::visit::{Visitor, LvalueContext};
 use rustc::mir::traversal;
+use rustc::ty;
 use common;
 use super::MirContext;
 
@@ -110,7 +111,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
             mir::TerminatorKind::Call {
                 func: mir::Operand::Constant(box mir::Constant {
                     literal: Literal::Value {
-                        value: &ConstVal::Function(def_id, _), ..
+                        value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, ..
                     }, ..
                 }),
                 ref args, ..
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index d43911df83a2b..21c935ae63817 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -522,7 +522,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                         MirConstContext::new(self.ccx, mir, self.substs, IndexVec::new()).trans()
                     }
                     mir::Literal::Value { value } => {
-                        Ok(Const::from_constval(self.ccx, value, ty))
+                        Ok(Const::from_constval(self.ccx, &value.val, ty))
                     }
                 }
             }
@@ -971,7 +971,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 MirConstContext::new(bcx.ccx, mir, self.param_substs, IndexVec::new()).trans()
             }
             mir::Literal::Value { value } => {
-                Ok(Const::from_constval(bcx.ccx, value, ty))
+                Ok(Const::from_constval(bcx.ccx, &value.val, ty))
             }
         };
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 8c3cf481e5eee..1735ec7cc698c 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -572,7 +572,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
 
             match result {
-                Ok(&ConstVal::Integral(x)) => Some(x),
+                Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => Some(x),
                 _ => None
             }
         } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {

From 3ce31eb99076261291c1a0ae4b542f52e6ca0f0a Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Sat, 5 Aug 2017 12:27:28 +0300
Subject: [PATCH 3/7] rustc: replace usize with u64 and ConstUsize.

---
 src/librustc/middle/const_val.rs             | 11 ++--
 src/librustc/middle/mem_categorization.rs    |  2 +-
 src/librustc/mir/tcx.rs                      | 12 ++---
 src/librustc/session/config.rs               | 10 ++--
 src/librustc/ty/context.rs                   |  4 +-
 src/librustc/ty/error.rs                     |  4 +-
 src/librustc/ty/inhabitedness/mod.rs         |  2 +-
 src/librustc/ty/layout.rs                    |  6 +--
 src/librustc/ty/mod.rs                       |  4 +-
 src/librustc/ty/relate.rs                    |  2 +-
 src/librustc/ty/sty.rs                       |  4 +-
 src/librustc/ty/util.rs                      |  6 +--
 src/librustc_const_eval/_match.rs            | 34 ++++++------
 src/librustc_const_eval/eval.rs              | 23 ++++----
 src/librustc_const_eval/pattern.rs           |  2 +-
 src/librustc_const_math/int.rs               |  8 +--
 src/librustc_const_math/is.rs                | 26 +++++----
 src/librustc_const_math/us.rs                | 26 +++++----
 src/librustc_driver/test.rs                  | 22 ++++----
 src/librustc_lint/types.rs                   | 16 +++---
 src/librustc_mir/build/expr/as_rvalue.rs     |  4 +-
 src/librustc_mir/build/matches/test.rs       |  2 +-
 src/librustc_mir/build/misc.rs               |  4 +-
 src/librustc_mir/hair/cx/mod.rs              |  2 +-
 src/librustc_mir/shim.rs                     |  8 +--
 src/librustc_mir/transform/qualify_consts.rs |  4 +-
 src/librustc_mir/transform/type_check.rs     |  3 +-
 src/librustc_trans/abi.rs                    |  6 +--
 src/librustc_trans/adt.rs                    |  6 +--
 src/librustc_trans/base.rs                   | 10 ++--
 src/librustc_trans/common.rs                 | 49 +++++++----------
 src/librustc_trans/context.rs                | 20 +++----
 src/librustc_trans/debuginfo/metadata.rs     |  4 +-
 src/librustc_trans/glue.rs                   | 16 +++---
 src/librustc_trans/intrinsic.rs              | 18 +++----
 src/librustc_trans/machine.rs                |  2 +-
 src/librustc_trans/meth.rs                   |  6 +--
 src/librustc_trans/mir/constant.rs           | 55 +++++++++-----------
 src/librustc_trans/mir/lvalue.rs             | 24 ++++-----
 src/librustc_trans/mir/rvalue.rs             | 19 ++++---
 src/librustc_trans/tvec.rs                   |  4 +-
 src/librustc_trans/type_.rs                  |  8 +--
 src/librustc_trans/type_of.rs                |  3 +-
 src/librustc_typeck/astconv.rs               |  2 +-
 src/librustc_typeck/check/_match.rs          |  3 +-
 src/librustc_typeck/check/intrinsic.rs       |  2 +-
 src/librustc_typeck/check/mod.rs             | 23 ++++----
 src/librustdoc/clean/mod.rs                  |  6 +--
 src/librustdoc/html/format.rs                |  2 +-
 49 files changed, 265 insertions(+), 274 deletions(-)

diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index 01f050a1bd90a..d213bc1de20a5 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -250,20 +250,15 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
 pub fn eval_length(tcx: TyCtxt,
                    count: hir::BodyId,
                    reason: &str)
-                   -> Result<usize, ErrorReported>
+                   -> Result<ConstUsize, ErrorReported>
 {
     let count_expr = &tcx.hir.body(count).value;
     let count_def_id = tcx.hir.body_owner_def_id(count);
     let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
     let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
     match tcx.at(count_expr.span).const_eval(param_env.and((count_def_id, substs))) {
-        Ok(&ty::Const { val: Integral(Usize(count)), .. }) => {
-            let val = count.as_u64(tcx.sess.target.uint_type);
-            assert_eq!(val as usize as u64, val);
-            Ok(val as usize)
-        },
-        Ok(_) |
-        Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported),
+        Ok(&ty::Const { val: Integral(Usize(count)), .. }) => Ok(count),
+        Ok(_) | Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported),
         Err(err) => {
             let mut diag = err.struct_error(tcx, count_expr.span, reason);
 
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 8bf942c1ae34f..1a4d0dcd929c3 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -876,7 +876,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
         // Always promote `[T; 0]` (even when e.g. borrowed mutably).
         let promotable = match expr_ty.sty {
-            ty::TyArray(_, 0) => true,
+            ty::TyArray(_, len) if len.as_u64() == 0 => true,
             _ => promotable,
         };
 
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index eb403442f4639..7469402daf90f 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -70,7 +70,8 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
                 LvalueTy::Ty {
                     ty: match ty.sty {
                         ty::TyArray(inner, size) => {
-                            tcx.mk_array(inner, size-(from as usize)-(to as usize))
+                            let len = size.as_u64() - (from as u64) - (to as u64);
+                            tcx.mk_array(inner, len)
                         }
                         ty::TySlice(..) => ty,
                         _ => {
@@ -146,11 +147,8 @@ impl<'tcx> Rvalue<'tcx> {
     {
         match *self {
             Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
-            Rvalue::Repeat(ref operand, ref count) => {
-                let op_ty = operand.ty(local_decls, tcx);
-                let count = count.as_u64(tcx.sess.target.uint_type);
-                assert_eq!(count as usize as u64, count);
-                tcx.mk_array(op_ty, count as usize)
+            Rvalue::Repeat(ref operand, count) => {
+                tcx.mk_array(operand.ty(local_decls, tcx), count.as_u64())
             }
             Rvalue::Ref(reg, bk, ref lv) => {
                 let lv_ty = lv.ty(local_decls, tcx).to_ty(tcx);
@@ -193,7 +191,7 @@ impl<'tcx> Rvalue<'tcx> {
             Rvalue::Aggregate(ref ak, ref ops) => {
                 match **ak {
                     AggregateKind::Array(ty) => {
-                        tcx.mk_array(ty, ops.len())
+                        tcx.mk_array(ty, ops.len() as u64)
                     }
                     AggregateKind::Tuple => {
                         tcx.mk_tup(
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 577c905a1d5a6..b7e07f94f3df1 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -48,8 +48,8 @@ use std::path::PathBuf;
 
 pub struct Config {
     pub target: Target,
-    pub int_type: IntTy,
-    pub uint_type: UintTy,
+    pub isize_ty: IntTy,
+    pub usize_ty: UintTy,
 }
 
 #[derive(Clone, Hash, Debug)]
@@ -1149,7 +1149,7 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
         }
     };
 
-    let (int_type, uint_type) = match &target.target_pointer_width[..] {
+    let (isize_ty, usize_ty) = match &target.target_pointer_width[..] {
         "16" => (ast::IntTy::I16, ast::UintTy::U16),
         "32" => (ast::IntTy::I32, ast::UintTy::U32),
         "64" => (ast::IntTy::I64, ast::UintTy::U64),
@@ -1159,8 +1159,8 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
 
     Config {
         target,
-        int_type,
-        uint_type,
+        isize_ty,
+        usize_ty,
     }
 }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 8dee2675ee5cc..7a671b5ebc6e0 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -49,6 +49,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                            StableHasherResult};
 
 use arena::{TypedArena, DroplessArena};
+use rustc_const_math::ConstUsize;
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::borrow::Borrow;
 use std::cell::{Cell, RefCell};
@@ -1754,7 +1755,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_imm_ptr(self.mk_nil())
     }
 
-    pub fn mk_array(self, ty: Ty<'tcx>, n: usize) -> Ty<'tcx> {
+    pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
+        let n = ConstUsize::new(n, self.sess.target.usize_ty).unwrap();
         self.mk_ty(TyArray(ty, n))
     }
 
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 49d7f40000f07..3234a9de8c791 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -18,6 +18,8 @@ use syntax::ast;
 use errors::DiagnosticBuilder;
 use syntax_pos::Span;
 
+use rustc_const_math::ConstUsize;
+
 use hir;
 
 #[derive(Clone, Copy, Debug)]
@@ -34,7 +36,7 @@ pub enum TypeError<'tcx> {
     AbiMismatch(ExpectedFound<abi::Abi>),
     Mutability,
     TupleSize(ExpectedFound<usize>),
-    FixedArraySize(ExpectedFound<usize>),
+    FixedArraySize(ExpectedFound<ConstUsize>),
     ArgCount,
 
     RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs
index 900197f3dbd17..bb8ef28bbf593 100644
--- a/src/librustc/ty/inhabitedness/mod.rs
+++ b/src/librustc/ty/inhabitedness/mod.rs
@@ -205,7 +205,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
                 }))
             },
             TyArray(ty, len) => {
-                if len == 0 {
+                if len.as_u64() == 0 {
                     DefIdForest::empty()
                 } else {
                     ty.uninhabited_from(visited, tcx)
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 2348c4ae76731..4d94021d2c8c5 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -837,7 +837,7 @@ impl<'a, 'tcx> Struct {
 
             // Is this a fixed-size array of something non-zero
             // with at least one element?
-            (_, &ty::TyArray(ety, d)) if d > 0 => {
+            (_, &ty::TyArray(ety, d)) if d.as_u64() > 0 => {
                 Struct::non_zero_field_paths(
                     tcx,
                     param_env,
@@ -1177,9 +1177,7 @@ impl<'a, 'tcx> Layout {
             ty::TyArray(element, count) => {
                 let element = element.layout(tcx, param_env)?;
                 let element_size = element.size(dl);
-                // FIXME(eddyb) Don't use host `usize` for array lengths.
-                let usize_count: usize = count;
-                let count = usize_count as u64;
+                let count = count.as_u64();
                 if element_size.checked_mul(count, dl).is_none() {
                     return Err(LayoutError::SizeOverflow(ty));
                 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 7c8aca9a9b157..6634af59e787e 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1665,11 +1665,11 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         match repr_type {
             attr::UnsignedInt(ty) => {
                 ConstInt::new_unsigned_truncating(discr, ty,
-                                                  tcx.sess.target.uint_type)
+                                                  tcx.sess.target.usize_ty)
             }
             attr::SignedInt(ty) => {
                 ConstInt::new_signed_truncating(discr as i128, ty,
-                                                tcx.sess.target.int_type)
+                                                tcx.sess.target.isize_ty)
             }
         }
     }
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 0ff3199689c19..0acb8a2c1d159 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -429,7 +429,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
         {
             let t = relation.relate(&a_t, &b_t)?;
             if sz_a == sz_b {
-                Ok(tcx.mk_array(t, sz_a))
+                Ok(tcx.mk_array(t, sz_a.as_u64()))
             } else {
                 Err(TypeError::FixedArraySize(expected_found(relation, &sz_a, &sz_b)))
             }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index f082e32ff6867..e01f9f24235c5 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -27,6 +27,8 @@ use syntax::ast::{self, Name};
 use syntax::symbol::keywords;
 use util::nodemap::FxHashMap;
 
+use rustc_const_math::ConstUsize;
+
 use serialize;
 
 use hir;
@@ -110,7 +112,7 @@ pub enum TypeVariants<'tcx> {
     TyStr,
 
     /// An array with the given length. Written as `[T; n]`.
-    TyArray(Ty<'tcx>, usize),
+    TyArray(Ty<'tcx>, ConstUsize),
 
     /// The pointee of an array slice.  Written as `[T]`.
     TySlice(Ty<'tcx>),
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index f21fc8414e78b..de4481116d6e1 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -53,7 +53,7 @@ macro_rules! typed_literal {
             SignedInt(ast::IntTy::I32)   => ConstInt::I32($lit),
             SignedInt(ast::IntTy::I64)   => ConstInt::I64($lit),
             SignedInt(ast::IntTy::I128)   => ConstInt::I128($lit),
-            SignedInt(ast::IntTy::Is) => match $tcx.sess.target.int_type {
+            SignedInt(ast::IntTy::Is) => match $tcx.sess.target.isize_ty {
                 ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16($lit)),
                 ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32($lit)),
                 ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64($lit)),
@@ -64,7 +64,7 @@ macro_rules! typed_literal {
             UnsignedInt(ast::UintTy::U32) => ConstInt::U32($lit),
             UnsignedInt(ast::UintTy::U64) => ConstInt::U64($lit),
             UnsignedInt(ast::UintTy::U128) => ConstInt::U128($lit),
-            UnsignedInt(ast::UintTy::Us) => match $tcx.sess.target.uint_type {
+            UnsignedInt(ast::UintTy::Us) => match $tcx.sess.target.usize_ty {
                 ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16($lit)),
                 ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32($lit)),
                 ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64($lit)),
@@ -638,7 +638,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn const_usize(&self, val: u16) -> ConstInt {
-        match self.sess.target.uint_type {
+        match self.sess.target.usize_ty {
             ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(val as u16)),
             ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(val as u32)),
             ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(val as u64)),
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index b1e3dcf53f0d8..429332873c05b 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -235,7 +235,7 @@ pub enum Constructor<'tcx> {
     /// Ranges of literal values (`2...5` and `2..5`).
     ConstantRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
     /// Array patterns of length n.
-    Slice(usize),
+    Slice(u64),
 }
 
 impl<'tcx> Constructor<'tcx> {
@@ -276,7 +276,7 @@ pub enum WitnessPreference {
 #[derive(Copy, Clone, Debug)]
 struct PatternContext<'tcx> {
     ty: Ty<'tcx>,
-    max_slice_length: usize,
+    max_slice_length: u64,
 }
 
 /// A stack of patterns in reverse order of construction
@@ -330,8 +330,8 @@ impl<'tcx> Witness<'tcx> {
     {
         let arity = constructor_arity(cx, ctor, ty);
         let pat = {
-            let len = self.0.len();
-            let mut pats = self.0.drain(len-arity..).rev();
+            let len = self.0.len() as u64;
+            let mut pats = self.0.drain((len-arity) as usize..).rev();
 
             match ty.sty {
                 ty::TyAdt(..) |
@@ -423,10 +423,10 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
             }
         }
         ty::TyArray(ref sub_ty, length) => {
-            if length > 0 && cx.is_uninhabited(sub_ty) {
+            if length.as_u64() > 0 && cx.is_uninhabited(sub_ty) {
                 vec![]
             } else {
-                vec![Slice(length)]
+                vec![Slice(length.as_u64())]
             }
         }
         ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => {
@@ -447,7 +447,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
 
 fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
     _cx: &mut MatchCheckCtxt<'a, 'tcx>,
-    patterns: I) -> usize
+    patterns: I) -> u64
     where I: Iterator<Item=&'p Pattern<'tcx>>
 {
     // The exhaustiveness-checking paper does not include any details on
@@ -521,15 +521,15 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
     for row in patterns {
         match *row.kind {
             PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => {
-                max_fixed_len = cmp::max(max_fixed_len, b.data.len());
+                max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64);
             }
             PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
-                let fixed_len = prefix.len() + suffix.len();
+                let fixed_len = prefix.len() as u64 + suffix.len() as u64;
                 max_fixed_len = cmp::max(max_fixed_len, fixed_len);
             }
             PatternKind::Slice { ref prefix, slice: Some(_), ref suffix } => {
-                max_prefix_len = cmp::max(max_prefix_len, prefix.len());
-                max_suffix_len = cmp::max(max_suffix_len, suffix.len());
+                max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64);
+                max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64);
             }
             _ => {}
         }
@@ -729,11 +729,11 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
         PatternKind::Range { lo, hi, end } =>
             Some(vec![ConstantRange(lo, hi, end)]),
         PatternKind::Array { .. } => match pcx.ty.sty {
-            ty::TyArray(_, length) => Some(vec![Slice(length)]),
+            ty::TyArray(_, length) => Some(vec![Slice(length.as_u64())]),
             _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
         },
         PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
-            let pat_len = prefix.len() + suffix.len();
+            let pat_len = prefix.len() as u64 + suffix.len() as u64;
             if slice.is_some() {
                 Some((pat_len..pcx.max_slice_length+1).map(Slice).collect())
             } else {
@@ -748,10 +748,10 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
 ///
 /// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
 /// A struct pattern's arity is the number of fields it contains, etc.
-fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize {
+fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
     debug!("constructor_arity({:?}, {:?})", ctor, ty);
     match ty.sty {
-        ty::TyTuple(ref fs, _) => fs.len(),
+        ty::TyTuple(ref fs, _) => fs.len() as u64,
         ty::TySlice(..) | ty::TyArray(..) => match *ctor {
             Slice(length) => length,
             ConstantValue(_) => 0,
@@ -759,7 +759,7 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize
         },
         ty::TyRef(..) => 1,
         ty::TyAdt(adt, _) => {
-            adt.variants[ctor.variant_index_for_adt(adt)].fields.len()
+            adt.variants[ctor.variant_index_for_adt(adt)].fields.len() as u64
         }
         _ => 0
     }
@@ -777,7 +777,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
     match ty.sty {
         ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(),
         ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor {
-            Slice(length) => repeat(ty).take(length).collect(),
+            Slice(length) => (0..length).map(|_| ty).collect(),
             ConstantValue(_) => vec![],
             _ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
         },
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 2aa333c1f039c..9dab067f942e8 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -158,7 +158,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                 },
                 (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) |
                 (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
-                    match tcx.sess.target.int_type {
+                    match tcx.sess.target.isize_ty {
                         IntTy::I16 => if n == I16_OVERFLOW {
                             Some(Isize(Is16(i16::min_value())))
                         } else {
@@ -342,12 +342,12 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                 "size_of" => {
                     let size = layout_of(substs.type_at(0))?.size(tcx).bytes();
                     return Ok(mk_const(Integral(Usize(ConstUsize::new(size,
-                        tcx.sess.target.uint_type).unwrap()))));
+                        tcx.sess.target.usize_ty).unwrap()))));
                 }
                 "min_align_of" => {
                     let align = layout_of(substs.type_at(0))?.align(tcx).abi();
                     return Ok(mk_const(Integral(Usize(ConstUsize::new(align,
-                        tcx.sess.target.uint_type).unwrap()))));
+                        tcx.sess.target.usize_ty).unwrap()))));
                 }
                 _ => signal!(e, TypeckError)
             }
@@ -421,7 +421,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         }
         let arr = cx.eval(arr)?;
         let idx = match cx.eval(idx)?.val {
-            Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
+            Integral(Usize(i)) => i.as_u64(),
             _ => signal!(idx, IndexNotUsize),
         };
         assert_eq!(idx as usize as u64, idx);
@@ -431,7 +431,6 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                     elem
                 } else {
                     let n = v.len() as u64;
-                    assert_eq!(n as usize as u64, n);
                     signal!(e, IndexOutOfBounds { len: n, index: idx })
                 }
             }
@@ -457,7 +456,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       }
       hir::ExprRepeat(ref elem, _) => {
           let n = match ty.sty {
-            ty::TyArray(_, n) => n as u64,
+            ty::TyArray(_, n) => n.as_u64(),
             _ => span_bug!(e.span, "typeck error")
           };
           mk_const(Aggregate(Repeat(cx.eval(elem)?, n)))
@@ -562,7 +561,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))),
         ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))),
         ty::TyInt(ast::IntTy::Is) => {
-            Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.int_type))))
+            Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.isize_ty))))
         },
         ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
         ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
@@ -570,7 +569,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
         ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))),
         ty::TyUint(ast::UintTy::Us) => {
-            Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
+            Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.usize_ty))))
         },
         ty::TyFloat(fty) => {
             if let Some(i) = val.to_u128() {
@@ -636,7 +635,9 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
             },
             ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
-                ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.data.len() => Ok(val),
+                ty::TyArray(ty, n) if ty == tcx.types.u8 && n.as_u64() == b.data.len() as u64 => {
+                    Ok(val)
+                }
                 ty::TySlice(_) => {
                     Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
                 },
@@ -678,12 +679,12 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
                 (&ty::TyInt(ity), _) |
                 (_, Signed(ity)) => {
                     Ok(Integral(ConstInt::new_signed_truncating(n as i128,
-                        ity, tcx.sess.target.int_type)))
+                        ity, tcx.sess.target.isize_ty)))
                 }
                 (&ty::TyUint(uty), _) |
                 (_, Unsigned(uty)) => {
                     Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
-                        uty, tcx.sess.target.uint_type)))
+                        uty, tcx.sess.target.usize_ty)))
                 }
                 _ => bug!()
             }
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index cf42d61e136ad..6274796145e1f 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -537,7 +537,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
 
             ty::TyArray(_, len) => {
                 // fixed-length array
-                assert!(len >= prefix.len() + suffix.len());
+                assert!(len.as_u64() >= prefix.len() as u64 + suffix.len() as u64);
                 PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
             }
 
diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs
index 65471416e8007..08473d729e4e5 100644
--- a/src/librustc_const_math/int.rs
+++ b/src/librustc_const_math/int.rs
@@ -311,17 +311,13 @@ impl ::std::fmt::Display for ConstInt {
             I32(i) => write!(fmt, "{}i32", i),
             I64(i) => write!(fmt, "{}i64", i),
             I128(i) => write!(fmt, "{}i128", i),
-            Isize(ConstIsize::Is64(i)) => write!(fmt, "{}isize", i),
-            Isize(ConstIsize::Is32(i)) => write!(fmt, "{}isize", i),
-            Isize(ConstIsize::Is16(i)) => write!(fmt, "{}isize", i),
+            Isize(i) => write!(fmt, "{}isize", i),
             U8(i) => write!(fmt, "{}u8", i),
             U16(i) => write!(fmt, "{}u16", i),
             U32(i) => write!(fmt, "{}u32", i),
             U64(i) => write!(fmt, "{}u64", i),
             U128(i) => write!(fmt, "{}u128", i),
-            Usize(ConstUsize::Us64(i)) => write!(fmt, "{}usize", i),
-            Usize(ConstUsize::Us32(i)) => write!(fmt, "{}usize", i),
-            Usize(ConstUsize::Us16(i)) => write!(fmt, "{}usize", i),
+            Usize(i) => write!(fmt, "{}usize", i),
         }
     }
 }
diff --git a/src/librustc_const_math/is.rs b/src/librustc_const_math/is.rs
index 8f28ba14c6aef..50dfb60112991 100644
--- a/src/librustc_const_math/is.rs
+++ b/src/librustc_const_math/is.rs
@@ -21,18 +21,22 @@ pub enum ConstIsize {
 }
 pub use self::ConstIsize::*;
 
+impl ::std::fmt::Display for ConstIsize {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
+        write!(fmt, "{}", self.as_i64())
+    }
+}
+
 impl ConstIsize {
-    pub fn as_i64(self, target_int_ty: ast::IntTy) -> i64 {
-        match (self, target_int_ty) {
-            (Is16(i), ast::IntTy::I16) => i as i64,
-            (Is32(i), ast::IntTy::I32) => i as i64,
-            (Is64(i), ast::IntTy::I64) => i,
-            _ => panic!("unable to convert self ({:?}) to target isize ({:?})",
-                        self, target_int_ty),
+    pub fn as_i64(self) -> i64 {
+        match self {
+            Is16(i) => i as i64,
+            Is32(i) => i as i64,
+            Is64(i) => i,
         }
     }
-    pub fn new(i: i64, target_int_ty: ast::IntTy) -> Result<Self, ConstMathErr> {
-        match target_int_ty {
+    pub fn new(i: i64, isize_ty: ast::IntTy) -> Result<Self, ConstMathErr> {
+        match isize_ty {
             ast::IntTy::I16 if i as i16 as i64 == i => Ok(Is16(i as i16)),
             ast::IntTy::I16 => Err(LitOutOfRange(ast::IntTy::Is)),
             ast::IntTy::I32 if i as i32 as i64 == i => Ok(Is32(i as i32)),
@@ -41,8 +45,8 @@ impl ConstIsize {
             _ => unreachable!(),
         }
     }
-    pub fn new_truncating(i: i128, target_int_ty: ast::IntTy) -> Self {
-        match target_int_ty {
+    pub fn new_truncating(i: i128, isize_ty: ast::IntTy) -> Self {
+        match isize_ty {
             ast::IntTy::I16 => Is16(i as i16),
             ast::IntTy::I32 => Is32(i as i32),
             ast::IntTy::I64 => Is64(i as i64),
diff --git a/src/librustc_const_math/us.rs b/src/librustc_const_math/us.rs
index 76443f584abac..9876bc4d779a0 100644
--- a/src/librustc_const_math/us.rs
+++ b/src/librustc_const_math/us.rs
@@ -21,18 +21,22 @@ pub enum ConstUsize {
 }
 pub use self::ConstUsize::*;
 
+impl ::std::fmt::Display for ConstUsize {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
+        write!(fmt, "{}", self.as_u64())
+    }
+}
+
 impl ConstUsize {
-    pub fn as_u64(self, target_uint_ty: ast::UintTy) -> u64 {
-        match (self, target_uint_ty) {
-            (Us16(i), ast::UintTy::U16) => i as u64,
-            (Us32(i), ast::UintTy::U32) => i as u64,
-            (Us64(i), ast::UintTy::U64) => i,
-            _ => panic!("unable to convert self ({:?}) to target usize ({:?})",
-                        self, target_uint_ty),
+    pub fn as_u64(self) -> u64 {
+        match self {
+            Us16(i) => i as u64,
+            Us32(i) => i as u64,
+            Us64(i) => i,
         }
     }
-    pub fn new(i: u64, target_uint_ty: ast::UintTy) -> Result<Self, ConstMathErr> {
-        match target_uint_ty {
+    pub fn new(i: u64, usize_ty: ast::UintTy) -> Result<Self, ConstMathErr> {
+        match usize_ty {
             ast::UintTy::U16 if i as u16 as u64 == i => Ok(Us16(i as u16)),
             ast::UintTy::U16 => Err(ULitOutOfRange(ast::UintTy::Us)),
             ast::UintTy::U32 if i as u32 as u64 == i => Ok(Us32(i as u32)),
@@ -41,8 +45,8 @@ impl ConstUsize {
             _ => unreachable!(),
         }
     }
-    pub fn new_truncating(i: u128, target_uint_ty: ast::UintTy) -> Self {
-        match target_uint_ty {
+    pub fn new_truncating(i: u128, usize_ty: ast::UintTy) -> Self {
+        match usize_ty {
             ast::UintTy::U16 => Us16(i as u16),
             ast::UintTy::U32 => Us32(i as u32),
             ast::UintTy::U64 => Us64(i as u64),
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 8038045f762d5..9259474ee27c4 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -801,13 +801,13 @@ fn walk_ty() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
         let tcx = env.infcx.tcx;
         let int_ty = tcx.types.isize;
-        let uint_ty = tcx.types.usize;
-        let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty], false);
-        let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty], false);
+        let usize_ty = tcx.types.usize;
+        let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty], false);
+        let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty], false);
         let walked: Vec<_> = tup2_ty.walk().collect();
         assert_eq!(walked,
-                   [tup2_ty, tup1_ty, int_ty, uint_ty, int_ty, uint_ty, tup1_ty, int_ty,
-                    uint_ty, int_ty, uint_ty, uint_ty]);
+                   [tup2_ty, tup1_ty, int_ty, usize_ty, int_ty, usize_ty, tup1_ty, int_ty,
+                    usize_ty, int_ty, usize_ty, usize_ty]);
     })
 }
 
@@ -816,20 +816,20 @@ fn walk_ty_skip_subtree() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
         let tcx = env.infcx.tcx;
         let int_ty = tcx.types.isize;
-        let uint_ty = tcx.types.usize;
-        let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty], false);
-        let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty], false);
+        let usize_ty = tcx.types.usize;
+        let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty], false);
+        let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty], false);
 
         // types we expect to see (in order), plus a boolean saying
         // whether to skip the subtree.
         let mut expected = vec![(tup2_ty, false),
                                 (tup1_ty, false),
                                 (int_ty, false),
-                                (uint_ty, false),
+                                (usize_ty, false),
                                 (int_ty, false),
-                                (uint_ty, false),
+                                (usize_ty, false),
                                 (tup1_ty, true), // skip the isize/usize/isize/usize
-                                (uint_ty, false)];
+                                (usize_ty, false)];
         expected.reverse();
 
         let mut walker = tup2_ty.walk();
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index e6af47952b371..d3a5d52b295af 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -93,8 +93,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
 
                 if binop.node.is_shift() {
                     let opt_ty_bits = match cx.tables.node_id_to_type(l.hir_id).sty {
-                        ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
-                        ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
+                        ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.isize_ty)),
+                        ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.usize_ty)),
                         _ => None,
                     };
 
@@ -141,7 +141,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                             ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
                             ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => {
                                 let int_type = if let ast::IntTy::Is = t {
-                                    cx.sess().target.int_type
+                                    cx.sess().target.isize_ty
                                 } else {
                                     t
                                 };
@@ -164,7 +164,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                     }
                     ty::TyUint(t) => {
                         let uint_type = if let ast::UintTy::Us = t {
-                            cx.sess().target.uint_type
+                            cx.sess().target.usize_ty
                         } else {
                             t
                         };
@@ -250,9 +250,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
             }
         }
 
-        fn int_ty_bits(int_ty: ast::IntTy, target_int_ty: ast::IntTy) -> u64 {
+        fn int_ty_bits(int_ty: ast::IntTy, isize_ty: ast::IntTy) -> u64 {
             match int_ty {
-                ast::IntTy::Is => int_ty_bits(target_int_ty, target_int_ty),
+                ast::IntTy::Is => int_ty_bits(isize_ty, isize_ty),
                 ast::IntTy::I8 => 8,
                 ast::IntTy::I16 => 16 as u64,
                 ast::IntTy::I32 => 32,
@@ -261,9 +261,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
             }
         }
 
-        fn uint_ty_bits(uint_ty: ast::UintTy, target_uint_ty: ast::UintTy) -> u64 {
+        fn uint_ty_bits(uint_ty: ast::UintTy, usize_ty: ast::UintTy) -> u64 {
             match uint_ty {
-                ast::UintTy::Us => uint_ty_bits(target_uint_ty, target_uint_ty),
+                ast::UintTy::Us => uint_ty_bits(usize_ty, usize_ty),
                 ast::UintTy::U8 => 8,
                 ast::UintTy::U16 => 16,
                 ast::UintTy::U32 => 32,
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 2bda4524d23af..eeae4bce335ca 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -388,7 +388,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     ast::IntTy::I64 => ConstInt::I64(-1),
                     ast::IntTy::I128 => ConstInt::I128(-1),
                     ast::IntTy::Is => {
-                        let int_ty = self.hir.tcx().sess.target.int_type;
+                        let int_ty = self.hir.tcx().sess.target.isize_ty;
                         let val = ConstIsize::new(-1, int_ty).unwrap();
                         ConstInt::Isize(val)
                     }
@@ -420,7 +420,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     ast::IntTy::I64 => ConstInt::I64(i64::min_value()),
                     ast::IntTy::I128 => ConstInt::I128(i128::min_value()),
                     ast::IntTy::Is => {
-                        let int_ty = self.hir.tcx().sess.target.int_type;
+                        let int_ty = self.hir.tcx().sess.target.isize_ty;
                         let min = match int_ty {
                             ast::IntTy::I16 => std::i16::MIN as i64,
                             ast::IntTy::I32 => std::i32::MIN as i64,
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 965a443d9ac1b..7b91c43aa3722 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -279,7 +279,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                     assert!(ty.is_slice());
 
-                    let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len());
+                    let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len() as u64);
                     let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty);
                     let array = self.literal_operand(test.span, array_ref, Literal::Value {
                         value
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index bf9ad78481164..1976b70ac0a23 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -75,7 +75,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     ast::UintTy::U64 => ConstInt::U64(0),
                     ast::UintTy::U128 => ConstInt::U128(0),
                     ast::UintTy::Us => {
-                        let uint_ty = self.hir.tcx().sess.target.uint_type;
+                        let uint_ty = self.hir.tcx().sess.target.usize_ty;
                         let val = ConstUsize::new(0, uint_ty).unwrap();
                         ConstInt::Usize(val)
                     }
@@ -96,7 +96,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     ast::IntTy::I64 => ConstInt::I64(0),
                     ast::IntTy::I128 => ConstInt::I128(0),
                     ast::IntTy::Is => {
-                        let int_ty = self.hir.tcx().sess.target.int_type;
+                        let int_ty = self.hir.tcx().sess.target.isize_ty;
                         let val = ConstIsize::new(0, int_ty).unwrap();
                         ConstInt::Isize(val)
                     }
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 85607c04c98c8..f5e15979006af 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -112,7 +112,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     }
 
     pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
-        match ConstUsize::new(value, self.tcx.sess.target.uint_type) {
+        match ConstUsize::new(value, self.tcx.sess.target.usize_ty) {
             Ok(val) => {
                 Literal::Value {
                     value: self.tcx.mk_const(ty::Const {
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index cc0ea5911a070..eddd4f39f4333 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -292,7 +292,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
 
     match self_ty.sty {
         _ if is_copy => builder.copy_shim(),
-        ty::TyArray(ty, len) => builder.array_shim(ty, len),
+        ty::TyArray(ty, len) => builder.array_shim(ty, len.as_u64()),
         ty::TyTuple(tys, _) => builder.tuple_shim(tys),
         _ => {
             bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty);
@@ -470,8 +470,8 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
         );
     }
 
-    fn make_usize(&self, value: usize) -> Box<Constant<'tcx>> {
-        let value = ConstUsize::new(value as u64, self.tcx.sess.target.uint_type).unwrap();
+    fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
+        let value = ConstUsize::new(value, self.tcx.sess.target.usize_ty).unwrap();
         box Constant {
             span: self.span,
             ty: self.tcx.types.usize,
@@ -484,7 +484,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
         }
     }
 
-    fn array_shim(&mut self, ty: ty::Ty<'tcx>, len: usize) {
+    fn array_shim(&mut self, ty: ty::Ty<'tcx>, len: u64) {
         let tcx = self.tcx;
         let span = self.span;
         let rcvr = Lvalue::Local(Local::new(1+0)).deref();
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index f891c991321c8..30074becb09c7 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -695,8 +695,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                             }
                             _ => false
                         }
-                    } else if let ty::TyArray(_, 0) = ty.sty {
-                        self.mode == Mode::Fn
+                    } else if let ty::TyArray(_, len) = ty.sty {
+                        len.as_u64() == 0 && self.mode == Mode::Fn
                     } else {
                         false
                     };
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 3c77668e729c6..07134451a4e29 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -209,7 +209,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                 LvalueTy::Ty {
                     ty: match base_ty.sty {
                         ty::TyArray(inner, size) => {
-                            let min_size = (from as usize) + (to as usize);
+                            let size = size.as_u64();
+                            let min_size = (from as u64) + (to as u64);
                             if let Some(rest_size) = size.checked_sub(min_size) {
                                 tcx.mk_array(inner, rest_size)
                             } else {
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 5e50696b56009..4211c8df5ca03 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -11,7 +11,7 @@
 use llvm::{self, ValueRef, AttributePlace};
 use base;
 use builder::Builder;
-use common::{instance_ty, ty_fn_sig, type_is_fat_ptr, C_uint};
+use common::{instance_ty, ty_fn_sig, type_is_fat_ptr, C_usize};
 use context::CrateContext;
 use cabi_x86;
 use cabi_x86_64;
@@ -527,7 +527,7 @@ impl<'a, 'tcx> ArgType<'tcx> {
         }
         let ccx = bcx.ccx;
         if self.is_indirect() {
-            let llsz = C_uint(ccx, self.layout.size(ccx).bytes());
+            let llsz = C_usize(ccx, self.layout.size(ccx).bytes());
             let llalign = self.layout.align(ccx).abi();
             base::call_memcpy(bcx, dst, val, llsz, llalign as u32);
         } else if let Some(ty) = self.cast {
@@ -564,7 +564,7 @@ impl<'a, 'tcx> ArgType<'tcx> {
                 base::call_memcpy(bcx,
                                   bcx.pointercast(dst, Type::i8p(ccx)),
                                   bcx.pointercast(llscratch, Type::i8p(ccx)),
-                                  C_uint(ccx, self.layout.size(ccx).bytes()),
+                                  C_usize(ccx, self.layout.size(ccx).bytes()),
                                   cmp::min(self.layout.align(ccx).abi() as u32,
                                            llalign_of_min(ccx, ty)));
 
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 11db23732fba3..23a45a7962abf 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -397,11 +397,11 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu
     match *l {
         layout::CEnum{ discr, min, max, .. } => {
             assert_discr_in_range(min, max, to);
-            bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true),
+            bcx.store(C_int(Type::from_integer(bcx.ccx, discr), to as i64),
                   val, None);
         }
         layout::General{ discr, .. } => {
-            bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true),
+            bcx.store(C_int(Type::from_integer(bcx.ccx, discr), to as i64),
                   bcx.struct_gep(val, 0), None);
         }
         layout::Univariant { .. }
@@ -423,7 +423,7 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu
                     // than storing null to single target field.
                     let llptr = bcx.pointercast(val, Type::i8(bcx.ccx).ptr_to());
                     let fill_byte = C_u8(bcx.ccx, 0);
-                    let size = C_uint(bcx.ccx, nonnull.stride().bytes());
+                    let size = C_usize(bcx.ccx, nonnull.stride().bytes());
                     let align = C_i32(bcx.ccx, nonnull.align.abi() as i32);
                     base::call_memset(bcx, llptr, fill_byte, size, align, false);
                 } else {
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 6cfde9c7bbc73..96499424be1f6 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -53,7 +53,7 @@ use mir::lvalue::LvalueRef;
 use attributes;
 use builder::Builder;
 use callee;
-use common::{C_bool, C_bytes_in_context, C_i32, C_uint};
+use common::{C_bool, C_bytes_in_context, C_i32, C_usize};
 use collector::{self, TransItemCollectionMode};
 use common::{C_struct_in_context, C_u64, C_undef, C_array};
 use common::CrateContext;
@@ -201,7 +201,7 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
                                 -> ValueRef {
     let (source, target) = ccx.tcx().struct_lockstep_tails(source, target);
     match (&source.sty, &target.sty) {
-        (&ty::TyArray(_, len), &ty::TySlice(_)) => C_uint(ccx, len),
+        (&ty::TyArray(_, len), &ty::TySlice(_)) => C_usize(ccx, len.as_u64()),
         (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
             // For now, upcasts are limited to changes in marker
             // traits, and hence never actually require an actual
@@ -524,7 +524,7 @@ pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>,
     let memcpy = ccx.get_intrinsic(&key);
     let src_ptr = b.pointercast(src, Type::i8p(ccx));
     let dst_ptr = b.pointercast(dst, Type::i8p(ccx));
-    let size = b.intcast(n_bytes, ccx.int_type(), false);
+    let size = b.intcast(n_bytes, ccx.isize_ty(), false);
     let align = C_i32(ccx, align as i32);
     let volatile = C_bool(ccx, false);
     b.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
@@ -545,7 +545,7 @@ pub fn memcpy_ty<'a, 'tcx>(
     }
 
     let align = align.unwrap_or_else(|| ccx.align_of(t));
-    call_memcpy(bcx, dst, src, C_uint(ccx, size), align);
+    call_memcpy(bcx, dst, src, C_usize(ccx, size), align);
 }
 
 pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>,
@@ -696,7 +696,7 @@ fn maybe_create_entry_wrapper(ccx: &CrateContext) {
                        sp: Span,
                        rust_main: ValueRef,
                        use_start_lang_item: bool) {
-        let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()], &ccx.int_type());
+        let llfty = Type::func(&[ccx.isize_ty(), Type::i8p(ccx).ptr_to()], &ccx.isize_ty());
 
         if declare::get_defined_value(ccx, "main").is_some() {
             // FIXME: We should be smart and show a better diagnostic here.
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index d947cd8e71974..67c95b92e523b 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -221,9 +221,15 @@ pub fn C_undef(t: Type) -> ValueRef {
     }
 }
 
-pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef {
+pub fn C_int(t: Type, i: i64) -> ValueRef {
     unsafe {
-        llvm::LLVMConstInt(t.to_ref(), u, sign_extend as Bool)
+        llvm::LLVMConstInt(t.to_ref(), i as u64, True)
+    }
+}
+
+pub fn C_uint(t: Type, i: u64) -> ValueRef {
+    unsafe {
+        llvm::LLVMConstInt(t.to_ref(), i, False)
     }
 }
 
@@ -239,49 +245,34 @@ pub fn C_nil(ccx: &CrateContext) -> ValueRef {
 }
 
 pub fn C_bool(ccx: &CrateContext, val: bool) -> ValueRef {
-    C_integral(Type::i1(ccx), val as u64, false)
+    C_uint(Type::i1(ccx), val as u64)
 }
 
 pub fn C_i32(ccx: &CrateContext, i: i32) -> ValueRef {
-    C_integral(Type::i32(ccx), i as u64, true)
+    C_int(Type::i32(ccx), i as i64)
 }
 
 pub fn C_u32(ccx: &CrateContext, i: u32) -> ValueRef {
-    C_integral(Type::i32(ccx), i as u64, false)
+    C_uint(Type::i32(ccx), i as u64)
 }
 
 pub fn C_u64(ccx: &CrateContext, i: u64) -> ValueRef {
-    C_integral(Type::i64(ccx), i, false)
+    C_uint(Type::i64(ccx), i)
 }
 
-pub fn C_uint<I: AsU64>(ccx: &CrateContext, i: I) -> ValueRef {
-    let v = i.as_u64();
-
-    let bit_size = machine::llbitsize_of_real(ccx, ccx.int_type());
+pub fn C_usize(ccx: &CrateContext, i: u64) -> ValueRef {
+    let bit_size = machine::llbitsize_of_real(ccx, ccx.isize_ty());
 
     if bit_size < 64 {
         // make sure it doesn't overflow
-        assert!(v < (1<<bit_size));
+        assert!(i < (1<<bit_size));
     }
 
-    C_integral(ccx.int_type(), v, false)
+    C_uint(ccx.isize_ty(), i)
 }
 
-pub trait AsI64 { fn as_i64(self) -> i64; }
-pub trait AsU64 { fn as_u64(self) -> u64; }
-
-// FIXME: remove the intptr conversions, because they
-// are host-architecture-dependent
-impl AsI64 for i64 { fn as_i64(self) -> i64 { self as i64 }}
-impl AsI64 for i32 { fn as_i64(self) -> i64 { self as i64 }}
-impl AsI64 for isize { fn as_i64(self) -> i64 { self as i64 }}
-
-impl AsU64 for u64  { fn as_u64(self) -> u64 { self as u64 }}
-impl AsU64 for u32  { fn as_u64(self) -> u64 { self as u64 }}
-impl AsU64 for usize { fn as_u64(self) -> u64 { self as u64 }}
-
 pub fn C_u8(ccx: &CrateContext, i: u8) -> ValueRef {
-    C_integral(Type::i8(ccx), i as u64, false)
+    C_uint(Type::i8(ccx), i as u64)
 }
 
 
@@ -315,7 +306,7 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va
 pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef {
     let len = s.len();
     let cs = consts::ptrcast(C_cstr(cx, s, false), Type::i8p(cx));
-    C_named_struct(cx.str_slice_type(), &[cs, C_uint(cx, len)])
+    C_named_struct(cx.str_slice_type(), &[cs, C_usize(cx, len as u64)])
 }
 
 pub fn C_struct(cx: &CrateContext, elts: &[ValueRef], packed: bool) -> ValueRef {
@@ -482,9 +473,9 @@ pub fn shift_mask_val<'a, 'tcx>(
             // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
             let val = llty.int_width() - 1;
             if invert {
-                C_integral(mask_llty, !val, true)
+                C_int(mask_llty, !val as i64)
             } else {
-                C_integral(mask_llty, val, false)
+                C_uint(mask_llty, val)
             }
         },
         TypeKind::Vector => {
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index a5830eb17edb1..77bddc7731b5b 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -136,7 +136,7 @@ pub struct LocalCrateContext<'a, 'tcx: 'a> {
     used_statics: RefCell<Vec<ValueRef>>,
 
     lltypes: RefCell<FxHashMap<Ty<'tcx>, Type>>,
-    int_type: Type,
+    isize_ty: Type,
     opaque_vec_type: Type,
     str_slice_type: Type,
 
@@ -398,7 +398,7 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
                 statics_to_rauw: RefCell::new(Vec::new()),
                 used_statics: RefCell::new(Vec::new()),
                 lltypes: RefCell::new(FxHashMap()),
-                int_type: Type::from_ref(ptr::null_mut()),
+                isize_ty: Type::from_ref(ptr::null_mut()),
                 opaque_vec_type: Type::from_ref(ptr::null_mut()),
                 str_slice_type: Type::from_ref(ptr::null_mut()),
                 dbg_cx,
@@ -410,23 +410,23 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
                 placeholder: PhantomData,
             };
 
-            let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = {
+            let (isize_ty, opaque_vec_type, str_slice_ty, mut local_ccx) = {
                 // Do a little dance to create a dummy CrateContext, so we can
                 // create some things in the LLVM module of this codegen unit
                 let mut local_ccxs = vec![local_ccx];
-                let (int_type, opaque_vec_type, str_slice_ty) = {
+                let (isize_ty, opaque_vec_type, str_slice_ty) = {
                     let dummy_ccx = LocalCrateContext::dummy_ccx(shared,
                                                                  local_ccxs.as_mut_slice());
                     let mut str_slice_ty = Type::named_struct(&dummy_ccx, "str_slice");
                     str_slice_ty.set_struct_body(&[Type::i8p(&dummy_ccx),
-                                                   Type::int(&dummy_ccx)],
+                                                   Type::isize(&dummy_ccx)],
                                                  false);
-                    (Type::int(&dummy_ccx), Type::opaque_vec(&dummy_ccx), str_slice_ty)
+                    (Type::isize(&dummy_ccx), Type::opaque_vec(&dummy_ccx), str_slice_ty)
                 };
-                (int_type, opaque_vec_type, str_slice_ty, local_ccxs.pop().unwrap())
+                (isize_ty, opaque_vec_type, str_slice_ty, local_ccxs.pop().unwrap())
             };
 
-            local_ccx.int_type = int_type;
+            local_ccx.isize_ty = isize_ty;
             local_ccx.opaque_vec_type = opaque_vec_type;
             local_ccx.str_slice_type = str_slice_ty;
 
@@ -549,8 +549,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         &self.local().stats
     }
 
-    pub fn int_type(&self) -> Type {
-        self.local().int_type
+    pub fn isize_ty(&self) -> Type {
+        self.local().isize_ty
     }
 
     pub fn str_slice_type(&self) -> Type {
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 8bd835ac5d114..0ef93e73c4bc8 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -366,7 +366,7 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                          -> bool {
         member_llvm_types.len() == 2 &&
         member_llvm_types[0] == type_of::type_of(cx, element_type).ptr_to() &&
-        member_llvm_types[1] == cx.int_type()
+        member_llvm_types[1] == cx.isize_ty()
     }
 }
 
@@ -530,7 +530,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             MetadataCreationResult::new(basic_type_metadata(cx, t), false)
         }
         ty::TyArray(typ, len) => {
-            fixed_vec_metadata(cx, unique_type_id, typ, Some(len as u64), usage_site_span)
+            fixed_vec_metadata(cx, unique_type_id, typ, Some(len.as_u64()), usage_site_span)
         }
         ty::TySlice(typ) => {
             fixed_vec_metadata(cx, unique_type_id, typ, None, usage_site_span)
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index c2f44c089a2d6..8dd0b4e466ce4 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -70,8 +70,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
         let align = bcx.ccx.align_of(t);
         debug!("size_and_align_of_dst t={} info={:?} size: {} align: {}",
                t, Value(info), size, align);
-        let size = C_uint(bcx.ccx, size);
-        let align = C_uint(bcx.ccx, align);
+        let size = C_usize(bcx.ccx, size);
+        let align = C_usize(bcx.ccx, align as u64);
         return (size, align);
     }
     assert!(!info.is_null());
@@ -96,8 +96,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
             };
             debug!("DST {} statically sized prefix size: {} align: {}",
                    t, sized_size, sized_align);
-            let sized_size = C_uint(ccx, sized_size);
-            let sized_align = C_uint(ccx, sized_align);
+            let sized_size = C_usize(ccx, sized_size);
+            let sized_align = C_usize(ccx, sized_align);
 
             // Recurse to get the size of the dynamically sized field (must be
             // the last field).
@@ -128,7 +128,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
                 (Some(sized_align), Some(unsized_align)) => {
                     // If both alignments are constant, (the sized_align should always be), then
                     // pick the correct alignment statically.
-                    C_uint(ccx, std::cmp::max(sized_align, unsized_align) as u64)
+                    C_usize(ccx, std::cmp::max(sized_align, unsized_align) as u64)
                 }
                 _ => bcx.select(bcx.icmp(llvm::IntUGT, sized_align, unsized_align),
                                 sized_align,
@@ -146,7 +146,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
             //
             //   `(size + (align-1)) & -align`
 
-            let addend = bcx.sub(align, C_uint(bcx.ccx, 1_u64));
+            let addend = bcx.sub(align, C_usize(bcx.ccx, 1));
             let size = bcx.and(bcx.add(size, addend), bcx.neg(align));
 
             (size, align)
@@ -159,8 +159,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
             let unit = t.sequence_element_type(bcx.tcx());
             // The info in this case is the length of the str, so the size is that
             // times the unit size.
-            (bcx.mul(info, C_uint(bcx.ccx, bcx.ccx.size_of(unit))),
-             C_uint(bcx.ccx, bcx.ccx.align_of(unit)))
+            (bcx.mul(info, C_usize(bcx.ccx, bcx.ccx.size_of(unit))),
+             C_usize(bcx.ccx, bcx.ccx.align_of(unit) as u64))
         }
         _ => bug!("Unexpected unsized type, found {}", t)
     }
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 8f968a8a6c609..f78d80a197ca9 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -135,7 +135,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
         "size_of" => {
             let tp_ty = substs.type_at(0);
             let lltp_ty = type_of::type_of(ccx, tp_ty);
-            C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
+            C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
         }
         "size_of_val" => {
             let tp_ty = substs.type_at(0);
@@ -145,12 +145,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                 llsize
             } else {
                 let lltp_ty = type_of::type_of(ccx, tp_ty);
-                C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
+                C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
             }
         }
         "min_align_of" => {
             let tp_ty = substs.type_at(0);
-            C_uint(ccx, ccx.align_of(tp_ty))
+            C_usize(ccx, ccx.align_of(tp_ty) as u64)
         }
         "min_align_of_val" => {
             let tp_ty = substs.type_at(0);
@@ -159,13 +159,13 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                     glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
                 llalign
             } else {
-                C_uint(ccx, ccx.align_of(tp_ty))
+                C_usize(ccx, ccx.align_of(tp_ty) as u64)
             }
         }
         "pref_align_of" => {
             let tp_ty = substs.type_at(0);
             let lltp_ty = type_of::type_of(ccx, tp_ty);
-            C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty))
+            C_usize(ccx, machine::llalign_of_pref(ccx, lltp_ty) as u64)
         }
         "type_name" => {
             let tp_ty = substs.type_at(0);
@@ -182,7 +182,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                 // If we store a zero constant, LLVM will drown in vreg allocation for large data
                 // structures, and the generated code will be awful. (A telltale sign of this is
                 // large quantities of `mov [byte ptr foo],0` in the generated code.)
-                memset_intrinsic(bcx, false, ty, llresult, C_u8(ccx, 0), C_uint(ccx, 1usize));
+                memset_intrinsic(bcx, false, ty, llresult, C_u8(ccx, 0), C_usize(ccx, 1));
             }
             C_nil(ccx)
         }
@@ -386,10 +386,10 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
 
         "align_offset" => {
             // `ptr as usize`
-            let ptr_val = bcx.ptrtoint(llargs[0], bcx.ccx.int_type());
+            let ptr_val = bcx.ptrtoint(llargs[0], bcx.ccx.isize_ty());
             // `ptr_val % align`
             let offset = bcx.urem(ptr_val, llargs[1]);
-            let zero = C_null(bcx.ccx.int_type());
+            let zero = C_null(bcx.ccx.isize_ty());
             // `offset == 0`
             let is_zero = bcx.icmp(llvm::IntPredicate::IntEQ, offset, zero);
             // `if offset == 0 { 0 } else { offset - align }`
@@ -688,7 +688,7 @@ fn copy_intrinsic<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
     let lltp_ty = type_of::type_of(ccx, tp_ty);
     let align = C_i32(ccx, ccx.align_of(tp_ty) as i32);
     let size = machine::llsize_of(ccx, lltp_ty);
-    let int_size = machine::llbitsize_of_real(ccx, ccx.int_type());
+    let int_size = machine::llbitsize_of_real(ccx, ccx.isize_ty());
 
     let operation = if allow_overlap {
         "memmove"
diff --git a/src/librustc_trans/machine.rs b/src/librustc_trans/machine.rs
index cd31f02842add..bc383abc7e0ec 100644
--- a/src/librustc_trans/machine.rs
+++ b/src/librustc_trans/machine.rs
@@ -48,7 +48,7 @@ pub fn llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
     // there's no need for that contrivance.  The instruction
     // selection DAG generator would flatten that GEP(1) node into a
     // constant of the type's alloc size, so let's save it some work.
-    return C_uint(cx, llsize_of_alloc(cx, ty));
+    return C_usize(cx, llsize_of_alloc(cx, ty));
 }
 
 // Returns the preferred alignment of the given type for the current target.
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index f5f924178589a..6eedd53974e70 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -46,7 +46,7 @@ impl<'a, 'tcx> VirtualIndex {
         // Load the data pointer from the object.
         debug!("get_int({:?}, {:?})", Value(llvtable), self);
 
-        let llvtable = bcx.pointercast(llvtable, Type::int(bcx.ccx).ptr_to());
+        let llvtable = bcx.pointercast(llvtable, Type::isize(bcx.ccx).ptr_to());
         let ptr = bcx.load(bcx.gepi(llvtable, &[self.0]), None);
         // Vtable loads are invariant
         bcx.set_invariant_load(ptr);
@@ -81,8 +81,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     let mut components: Vec<_> = [
         callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.shared(), ty)),
-        C_uint(ccx, ccx.size_of(ty)),
-        C_uint(ccx, ccx.align_of(ty))
+        C_usize(ccx, ccx.size_of(ty)),
+        C_usize(ccx, ccx.align_of(ty) as u64)
     ].iter().cloned().collect();
 
     if let Some(trait_ref) = trait_ref {
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 21c935ae63817..f75c949fefe3a 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -26,8 +26,8 @@ use abi::{self, Abi};
 use callee;
 use builder::Builder;
 use common::{self, CrateContext, const_get_elt, val_ty};
-use common::{C_array, C_bool, C_bytes, C_integral, C_big_integral, C_u32, C_u64};
-use common::{C_null, C_struct, C_str_slice, C_undef, C_uint, C_vector, is_undef};
+use common::{C_array, C_bool, C_bytes, C_int, C_uint, C_big_integral, C_u32, C_u64};
+use common::{C_null, C_struct, C_str_slice, C_undef, C_usize, C_vector, is_undef};
 use common::const_to_opt_u128;
 use consts;
 use monomorphize;
@@ -66,24 +66,18 @@ impl<'tcx> Const<'tcx> {
     -> Const<'tcx> {
         let tcx = ccx.tcx();
         let (llval, ty) = match *ci {
-            I8(v) => (C_integral(Type::i8(ccx), v as u64, true), tcx.types.i8),
-            I16(v) => (C_integral(Type::i16(ccx), v as u64, true), tcx.types.i16),
-            I32(v) => (C_integral(Type::i32(ccx), v as u64, true), tcx.types.i32),
-            I64(v) => (C_integral(Type::i64(ccx), v as u64, true), tcx.types.i64),
+            I8(v) => (C_int(Type::i8(ccx), v as i64), tcx.types.i8),
+            I16(v) => (C_int(Type::i16(ccx), v as i64), tcx.types.i16),
+            I32(v) => (C_int(Type::i32(ccx), v as i64), tcx.types.i32),
+            I64(v) => (C_int(Type::i64(ccx), v as i64), tcx.types.i64),
             I128(v) => (C_big_integral(Type::i128(ccx), v as u128), tcx.types.i128),
-            Isize(v) => {
-                let i = v.as_i64(ccx.tcx().sess.target.int_type);
-                (C_integral(Type::int(ccx), i as u64, true), tcx.types.isize)
-            },
-            U8(v) => (C_integral(Type::i8(ccx), v as u64, false), tcx.types.u8),
-            U16(v) => (C_integral(Type::i16(ccx), v as u64, false), tcx.types.u16),
-            U32(v) => (C_integral(Type::i32(ccx), v as u64, false), tcx.types.u32),
-            U64(v) => (C_integral(Type::i64(ccx), v, false), tcx.types.u64),
+            Isize(v) => (C_int(Type::isize(ccx), v.as_i64()), tcx.types.isize),
+            U8(v) => (C_uint(Type::i8(ccx), v as u64), tcx.types.u8),
+            U16(v) => (C_uint(Type::i16(ccx), v as u64), tcx.types.u16),
+            U32(v) => (C_uint(Type::i32(ccx), v as u64), tcx.types.u32),
+            U64(v) => (C_uint(Type::i64(ccx), v), tcx.types.u64),
             U128(v) => (C_big_integral(Type::i128(ccx), v), tcx.types.u128),
-            Usize(v) => {
-                let u = v.as_u64(ccx.tcx().sess.target.uint_type);
-                (C_integral(Type::int(ccx), u, false), tcx.types.usize)
-            },
+            Usize(v) => (C_uint(Type::isize(ccx), v.as_u64()), tcx.types.usize),
         };
         Const { llval: llval, ty: ty }
     }
@@ -106,7 +100,7 @@ impl<'tcx> Const<'tcx> {
             ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
             ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
             ConstVal::ByteStr(v) => consts::addr_of(ccx, C_bytes(ccx, v.data), 1, "byte_str"),
-            ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
+            ConstVal::Char(c) => C_uint(Type::char(ccx), c as u64),
             ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)),
             ConstVal::Variant(_) |
             ConstVal::Aggregate(..) => {
@@ -206,7 +200,7 @@ impl<'tcx> ConstLvalue<'tcx> {
 
     pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
         match self.ty.sty {
-            ty::TyArray(_, n) => C_uint(ccx, n),
+            ty::TyArray(_, n) => C_usize(ccx, n.as_u64()),
             ty::TySlice(_) | ty::TyStr => {
                 assert!(self.llextra != ptr::null_mut());
                 self.llextra
@@ -366,13 +360,13 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                         let result = if fn_ty.fn_sig(tcx).abi() == Abi::RustIntrinsic {
                             match &tcx.item_name(def_id)[..] {
                                 "size_of" => {
-                                    let llval = C_uint(self.ccx,
+                                    let llval = C_usize(self.ccx,
                                         self.ccx.size_of(substs.type_at(0)));
                                     Ok(Const::new(llval, tcx.types.usize))
                                 }
                                 "min_align_of" => {
-                                    let llval = C_uint(self.ccx,
-                                        self.ccx.align_of(substs.type_at(0)));
+                                    let llval = C_usize(self.ccx,
+                                        self.ccx.align_of(substs.type_at(0)) as u64);
                                     Ok(Const::new(llval, tcx.types.usize))
                                 }
                                 _ => span_bug!(span, "{:?} in constant", terminator.kind)
@@ -556,9 +550,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
         let val = match *rvalue {
             mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?,
 
-            mir::Rvalue::Repeat(ref elem, ref count) => {
+            mir::Rvalue::Repeat(ref elem, count) => {
                 let elem = self.const_operand(elem, span)?;
-                let size = count.as_u64(tcx.sess.target.uint_type);
+                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)
             }
@@ -835,7 +830,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
 
             mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => {
                 assert!(self.ccx.shared().type_is_sized(ty));
-                let llval = C_uint(self.ccx, self.ccx.size_of(ty));
+                let llval = C_usize(self.ccx, self.ccx.size_of(ty));
                 Const::new(llval, tcx.types.usize)
             }
 
@@ -853,10 +848,10 @@ fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
     match t.sty {
         ty::TyInt(int_type) => const_to_opt_u128(value, true)
             .and_then(|input| ConstInt::new_signed(input as i128, int_type,
-                                                   tcx.sess.target.int_type)),
+                                                   tcx.sess.target.isize_ty)),
         ty::TyUint(uint_type) => const_to_opt_u128(value, false)
             .and_then(|input| ConstInt::new_unsigned(input, uint_type,
-                                                     tcx.sess.target.uint_type)),
+                                                     tcx.sess.target.usize_ty)),
         _ => None
 
     }
@@ -1037,11 +1032,11 @@ fn trans_const<'a, 'tcx>(
             };
             assert_eq!(vals.len(), 0);
             adt::assert_discr_in_range(min, max, discr);
-            C_integral(Type::from_integer(ccx, d), discr, true)
+            C_int(Type::from_integer(ccx, d), discr as i64)
         }
         layout::General { discr: d, ref variants, .. } => {
             let variant = &variants[variant_index];
-            let lldiscr = C_integral(Type::from_integer(ccx, d), variant_index as u64, true);
+            let lldiscr = C_int(Type::from_integer(ccx, d), variant_index as i64);
             let mut vals_with_discr = vec![lldiscr];
             vals_with_discr.extend_from_slice(vals);
             let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs
index 8155303b0d3fc..d34885a1e9326 100644
--- a/src/librustc_trans/mir/lvalue.rs
+++ b/src/librustc_trans/mir/lvalue.rs
@@ -16,7 +16,7 @@ use rustc::mir::tcx::LvalueTy;
 use rustc_data_structures::indexed_vec::Idx;
 use adt;
 use builder::Builder;
-use common::{self, CrateContext, C_uint};
+use common::{self, CrateContext, C_usize};
 use consts;
 use machine;
 use type_of;
@@ -106,7 +106,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
     pub fn len(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
         let ty = self.ty.to_ty(ccx.tcx());
         match ty.sty {
-            ty::TyArray(_, n) => common::C_uint(ccx, n),
+            ty::TyArray(_, n) => common::C_usize(ccx, n.as_u64()),
             ty::TySlice(_) | ty::TyStr => {
                 assert!(self.llextra != ptr::null_mut());
                 self.llextra
@@ -186,7 +186,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
 
 
         let offset = st.offsets[ix].bytes();
-        let unaligned_offset = C_uint(bcx.ccx, offset);
+        let unaligned_offset = C_usize(bcx.ccx, offset);
 
         // Get the alignment of the field
         let (_, align) = glue::size_and_align_of_dst(bcx, fty, meta);
@@ -197,7 +197,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
         //   (unaligned offset + (align - 1)) & -align
 
         // Calculate offset
-        let align_sub_1 = bcx.sub(align, C_uint(bcx.ccx, 1u64));
+        let align_sub_1 = bcx.sub(align, C_usize(bcx.ccx, 1));
         let offset = bcx.and(bcx.add(unaligned_offset, align_sub_1),
         bcx.neg(align));
 
@@ -276,7 +276,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
             // Slices already point to the array element type.
             bcx.inbounds_gep(self.llval, &[llindex])
         } else {
-            let zero = common::C_uint(bcx.ccx, 0u64);
+            let zero = common::C_usize(bcx.ccx, 0);
             bcx.inbounds_gep(self.llval, &[zero, llindex])
         }
     }
@@ -342,19 +342,19 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                     mir::ProjectionElem::ConstantIndex { offset,
                                                          from_end: false,
                                                          min_length: _ } => {
-                        let lloffset = C_uint(bcx.ccx, offset);
+                        let lloffset = C_usize(bcx.ccx, offset as u64);
                         ((tr_base.project_index(bcx, lloffset), align), ptr::null_mut())
                     }
                     mir::ProjectionElem::ConstantIndex { offset,
                                                          from_end: true,
                                                          min_length: _ } => {
-                        let lloffset = C_uint(bcx.ccx, offset);
+                        let lloffset = C_usize(bcx.ccx, offset as u64);
                         let lllen = tr_base.len(bcx.ccx);
                         let llindex = bcx.sub(lllen, lloffset);
                         ((tr_base.project_index(bcx, llindex), align), ptr::null_mut())
                     }
                     mir::ProjectionElem::Subslice { from, to } => {
-                        let llbase = tr_base.project_index(bcx, C_uint(bcx.ccx, from));
+                        let llbase = tr_base.project_index(bcx, C_usize(bcx.ccx, from as u64));
 
                         let base_ty = tr_base.ty.to_ty(bcx.tcx());
                         match base_ty.sty {
@@ -369,7 +369,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                             ty::TySlice(..) => {
                                 assert!(tr_base.llextra != ptr::null_mut());
                                 let lllen = bcx.sub(tr_base.llextra,
-                                                    C_uint(bcx.ccx, from+to));
+                                                    C_usize(bcx.ccx, (from as u64)+(to as u64)));
                                 ((llbase, align), lllen)
                             }
                             _ => bug!("unexpected type {:?} in Subslice", base_ty)
@@ -397,11 +397,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
     /// nmatsakis: is this still necessary? Not sure.
     fn prepare_index(&mut self, bcx: &Builder<'a, 'tcx>, llindex: ValueRef) -> ValueRef {
         let index_size = machine::llbitsize_of_real(bcx.ccx, common::val_ty(llindex));
-        let int_size = machine::llbitsize_of_real(bcx.ccx, bcx.ccx.int_type());
+        let int_size = machine::llbitsize_of_real(bcx.ccx, bcx.ccx.isize_ty());
         if index_size < int_size {
-            bcx.zext(llindex, bcx.ccx.int_type())
+            bcx.zext(llindex, bcx.ccx.isize_ty())
         } else if index_size > int_size {
-            bcx.trunc(llindex, bcx.ccx.int_type())
+            bcx.trunc(llindex, bcx.ccx.isize_ty())
         } else {
             llindex
         }
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 34dec57543a2b..0f2d0c7f29617 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -19,8 +19,7 @@ use rustc::middle::lang_items::ExchangeMallocFnLangItem;
 use base;
 use builder::Builder;
 use callee;
-use common::{self, val_ty, C_bool, C_null, C_uint};
-use common::{C_integral, C_i32};
+use common::{self, val_ty, C_bool, C_i32, C_null, C_usize, C_uint};
 use adt;
 use machine;
 use monomorphize;
@@ -92,7 +91,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 bcx
             }
 
-            mir::Rvalue::Repeat(ref elem, ref count) => {
+            mir::Rvalue::Repeat(ref elem, count) => {
                 let dest_ty = dest.ty.to_ty(bcx.tcx());
 
                 // No need to inizialize memory of a zero-sized slice
@@ -101,8 +100,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 }
 
                 let tr_elem = self.trans_operand(&bcx, elem);
-                let size = count.as_u64(bcx.tcx().sess.target.uint_type);
-                let size = C_uint(bcx.ccx, size);
+                let size = count.as_u64();
+                let size = C_usize(bcx.ccx, size);
                 let base = base::get_dataptr(&bcx, dest.llval);
                 let align = dest.alignment.to_align();
 
@@ -113,7 +112,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                         let align = C_i32(bcx.ccx, align as i32);
                         let ty = type_of::type_of(bcx.ccx, dest_ty);
                         let size = machine::llsize_of(bcx.ccx, ty);
-                        let fill = C_integral(Type::i8(bcx.ccx), 0, false);
+                        let fill = C_uint(Type::i8(bcx.ccx), 0);
                         base::call_memset(&bcx, base, fill, size, align, false);
                         return bcx;
                     }
@@ -301,7 +300,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                                 base::call_assume(&bcx, bcx.icmp(
                                     llvm::IntULE,
                                     llval,
-                                    C_integral(common::val_ty(llval), max, false)
+                                    C_uint(common::val_ty(llval), max)
                                 ));
                             }
 
@@ -464,7 +463,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
 
             mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => {
                 assert!(bcx.ccx.shared().type_is_sized(ty));
-                let val = C_uint(bcx.ccx, bcx.ccx.size_of(ty));
+                let val = C_usize(bcx.ccx, bcx.ccx.size_of(ty));
                 let tcx = bcx.tcx();
                 (bcx, OperandRef {
                     val: OperandValue::Immediate(val),
@@ -477,7 +476,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 let llty = type_of::type_of(bcx.ccx, content_ty);
                 let llsize = machine::llsize_of(bcx.ccx, llty);
                 let align = bcx.ccx.align_of(content_ty);
-                let llalign = C_uint(bcx.ccx, align);
+                let llalign = C_usize(bcx.ccx, align as u64);
                 let llty_ptr = llty.ptr_to();
                 let box_ty = bcx.tcx().mk_box(content_ty);
 
@@ -522,7 +521,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
             if let LocalRef::Operand(Some(op)) = self.locals[index] {
                 if common::type_is_zero_size(bcx.ccx, op.ty) {
                     if let ty::TyArray(_, n) = op.ty.sty {
-                        return common::C_uint(bcx.ccx, n);
+                        return common::C_usize(bcx.ccx, n.as_u64());
                     }
                 }
             }
diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs
index de4d217c73534..da4a4e55a67f4 100644
--- a/src/librustc_trans/tvec.rs
+++ b/src/librustc_trans/tvec.rs
@@ -34,7 +34,7 @@ pub fn slice_for_each<'a, 'tcx, F>(
     let next_bcx = bcx.build_sibling_block("slice_loop_next");
 
     let start = if zst {
-        C_uint(bcx.ccx, 0usize)
+        C_usize(bcx.ccx, 1)
     } else {
         data_ptr
     };
@@ -46,7 +46,7 @@ pub fn slice_for_each<'a, 'tcx, F>(
     let keep_going = header_bcx.icmp(llvm::IntNE, current, end);
     header_bcx.cond_br(keep_going, body_bcx.llbb(), next_bcx.llbb());
 
-    let next = add(&body_bcx, current, C_uint(bcx.ccx, 1usize));
+    let next = add(&body_bcx, current, C_usize(bcx.ccx, 1));
     f(&body_bcx, if zst { data_ptr } else { current }, header_bcx.llbb());
     header_bcx.add_incoming_to_phi(current, next, body_bcx.llbb());
     next_bcx
diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs
index b8a8068d36af7..e5e532703d7d0 100644
--- a/src/librustc_trans/type_.rs
+++ b/src/librustc_trans/type_.rs
@@ -131,7 +131,7 @@ impl Type {
         Type::i8_llcx(llcx).ptr_to()
     }
 
-    pub fn int(ccx: &CrateContext) -> Type {
+    pub fn isize(ccx: &CrateContext) -> Type {
         match &ccx.tcx().sess.target.target.target_pointer_width[..] {
             "16" => Type::i16(ccx),
             "32" => Type::i32(ccx),
@@ -142,7 +142,7 @@ impl Type {
 
     pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> Type {
         match t {
-            ast::IntTy::Is => ccx.int_type(),
+            ast::IntTy::Is => ccx.isize_ty(),
             ast::IntTy::I8 => Type::i8(ccx),
             ast::IntTy::I16 => Type::i16(ccx),
             ast::IntTy::I32 => Type::i32(ccx),
@@ -153,7 +153,7 @@ impl Type {
 
     pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> Type {
         match t {
-            ast::UintTy::Us => ccx.int_type(),
+            ast::UintTy::Us => ccx.isize_ty(),
             ast::UintTy::U8 => Type::i8(ccx),
             ast::UintTy::U16 => Type::i16(ccx),
             ast::UintTy::U32 => Type::i32(ccx),
@@ -207,7 +207,7 @@ impl Type {
 
     pub fn vec(ccx: &CrateContext, ty: &Type) -> Type {
         Type::struct_(ccx,
-            &[Type::array(ty, 0), Type::int(ccx)],
+            &[Type::array(ty, 0), Type::isize(ccx)],
         false)
     }
 
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 38c49833e0d75..149a55f8c05d5 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -148,9 +148,8 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
       }
 
       ty::TyArray(ty, size) => {
-          let size = size as u64;
           let llty = in_memory_type_of(cx, ty);
-          Type::array(&llty, size)
+          Type::array(&llty, size.as_u64())
       }
 
       // Unsized slice types (and str) have the type of their element, and
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 2583d18652dc5..fc05ce4cd662c 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1083,7 +1083,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
             hir::TyArray(ref ty, length) => {
                 if let Ok(length) = eval_length(tcx, length, "array length") {
-                    tcx.mk_array(self.ast_ty_to_ty(&ty), length)
+                    tcx.mk_array(self.ast_ty_to_ty(&ty), length.as_u64())
                 } else {
                     self.tcx().types.err
                 }
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index cc84f73a42c80..02017652a6c71 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -264,7 +264,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let expected_ty = self.structurally_resolved_type(pat.span, expected);
                 let (inner_ty, slice_ty) = match expected_ty.sty {
                     ty::TyArray(inner_ty, size) => {
-                        let min_len = before.len() + after.len();
+                        let size = size.as_u64();
+                        let min_len = before.len() as u64 + after.len() as u64;
                         if slice.is_none() {
                             if min_len != size {
                                 struct_span_err!(
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 6fee7e58633fc..fa8d3b9bcc1cb 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -360,7 +360,7 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             match name["simd_shuffle".len()..].parse() {
                 Ok(n) => {
                     let params = vec![param(0), param(0),
-                                      tcx.mk_ty(ty::TyArray(tcx.types.u32, n))];
+                                      tcx.mk_array(tcx.types.u32, n)];
                     (2, params, param(1))
                 }
                 Err(_) => {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 19879ff8b150f..0adfca6e886a7 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2636,7 +2636,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             ast::LitKind::Str(..) => tcx.mk_static_str(),
             ast::LitKind::ByteStr(ref v) => {
                 tcx.mk_imm_ref(tcx.types.re_static,
-                                tcx.mk_array(tcx.types.u8, v.len()))
+                                tcx.mk_array(tcx.types.u8, v.len() as u64))
             }
             ast::LitKind::Byte(_) => tcx.types.u8,
             ast::LitKind::Char(_) => tcx.types.char,
@@ -3895,11 +3895,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               } else {
                   self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))
               };
-              tcx.mk_array(element_ty, args.len())
+              tcx.mk_array(element_ty, args.len() as u64)
           }
           hir::ExprRepeat(ref element, count) => {
-            let count = eval_length(self.tcx, count, "repeat count")
-                  .unwrap_or(0);
+            let count = eval_length(self.tcx, count, "repeat count");
 
             let uty = match expected {
                 ExpectHasType(uty) => {
@@ -3923,17 +3922,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             };
 
-            if count > 1 {
-                // For [foo, ..n] where n > 1, `foo` must have
-                // Copy type:
-                let lang_item = self.tcx.require_lang_item(lang_items::CopyTraitLangItem);
-                self.require_type_meets(t, expr.span, traits::RepeatVec, lang_item);
+            if let Ok(count) = count {
+                if count.as_u64() > 1 {
+                    // For [foo, ..n] where n > 1, `foo` must have
+                    // Copy type:
+                    let lang_item = self.tcx.require_lang_item(lang_items::CopyTraitLangItem);
+                    self.require_type_meets(t, expr.span, traits::RepeatVec, lang_item);
+                }
             }
 
             if element_ty.references_error() {
                 tcx.types.err
+            } else if let Ok(count) = count {
+                tcx.mk_ty(ty::TyArray(t, count))
             } else {
-                tcx.mk_array(t, count)
+                tcx.types.err
             }
           }
           hir::ExprTup(ref elts) => {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 88a0d3ad4ac1e..a78f15dd283c3 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1555,7 +1555,7 @@ pub enum Type {
     BareFunction(Box<BareFunctionDecl>),
     Tuple(Vec<Type>),
     Slice(Box<Type>),
-    Array(Box<Type>, usize),
+    Array(Box<Type>, String),
     Never,
     Unique(Box<Type>),
     RawPointer(Mutability, Box<Type>),
@@ -1785,7 +1785,7 @@ impl Clean<Type> for hir::Ty {
             TyArray(ref ty, length) => {
                 use rustc::middle::const_val::eval_length;
                 let n = eval_length(cx.tcx, length, "array length").unwrap();
-                Array(box ty.clean(cx), n)
+                Array(box ty.clean(cx), n.to_string())
             },
             TyTup(ref tys) => Tuple(tys.clean(cx)),
             TyPath(hir::QPath::Resolved(None, ref path)) => {
@@ -1895,7 +1895,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
             ty::TyFloat(float_ty) => Primitive(float_ty.into()),
             ty::TyStr => Primitive(PrimitiveType::Str),
             ty::TySlice(ty) => Slice(box ty.clean(cx)),
-            ty::TyArray(ty, n) => Array(box ty.clean(cx), n),
+            ty::TyArray(ty, n) => Array(box ty.clean(cx), n.to_string()),
             ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
             ty::TyRef(r, mt) => BorrowedRef {
                 lifetime: r.clean(cx),
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 10a3878073e97..6303fd662bf2b 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -633,7 +633,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
             fmt::Display::fmt(t, f)?;
             primitive_link(f, PrimitiveType::Slice, "]")
         }
-        clean::Array(ref t, n) => {
+        clean::Array(ref t, ref n) => {
             primitive_link(f, PrimitiveType::Array, "[")?;
             fmt::Display::fmt(t, f)?;
             primitive_link(f, PrimitiveType::Array, &format!("; {}]", n))

From 8a9b78f5cca1a0585e52a19d79ea9503f5534345 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Sat, 5 Aug 2017 16:11:24 +0300
Subject: [PATCH 4/7] rustc: use ty::Const for the length of TyArray.

---
 src/librustc/middle/const_val.rs             | 17 +++++---
 src/librustc/middle/mem_categorization.rs    |  2 +-
 src/librustc/mir/tcx.rs                      |  5 ++-
 src/librustc/ty/context.rs                   | 12 +++++-
 src/librustc/ty/error.rs                     | 13 ++++--
 src/librustc/ty/flags.rs                     | 38 ++++++++++++++++-
 src/librustc/ty/inhabitedness/mod.rs         |  2 +-
 src/librustc/ty/layout.rs                    |  4 +-
 src/librustc/ty/relate.rs                    | 10 +++--
 src/librustc/ty/structural_impls.rs          |  4 +-
 src/librustc/ty/sty.rs                       |  4 +-
 src/librustc/ty/util.rs                      |  4 +-
 src/librustc/ty/walk.rs                      | 43 +++++++++++++++++---
 src/librustc/ty/wf.rs                        | 13 +++++-
 src/librustc/util/ppaux.rs                   | 15 ++++++-
 src/librustc_const_eval/_match.rs            | 11 +++--
 src/librustc_const_eval/eval.rs              | 11 +++--
 src/librustc_const_eval/pattern.rs           |  3 +-
 src/librustc_mir/shim.rs                     |  5 ++-
 src/librustc_mir/transform/qualify_consts.rs |  3 +-
 src/librustc_mir/transform/type_check.rs     |  2 +-
 src/librustc_trans/base.rs                   |  4 +-
 src/librustc_trans/debuginfo/metadata.rs     |  3 +-
 src/librustc_trans/debuginfo/type_names.rs   |  2 +-
 src/librustc_trans/mir/constant.rs           |  4 +-
 src/librustc_trans/mir/lvalue.rs             |  4 +-
 src/librustc_trans/mir/rvalue.rs             |  3 +-
 src/librustc_trans/trans_item.rs             |  3 +-
 src/librustc_trans/type_of.rs                |  3 +-
 src/librustc_typeck/astconv.rs               |  2 +-
 src/librustc_typeck/check/_match.rs          |  2 +-
 src/librustc_typeck/check/mod.rs             |  5 ++-
 src/librustdoc/clean/mod.rs                  | 18 +++++++-
 src/librustdoc/lib.rs                        |  1 +
 34 files changed, 215 insertions(+), 60 deletions(-)

diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index d213bc1de20a5..05e4f0da001cf 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -247,18 +247,23 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
 }
 
 /// Returns the value of the length-valued expression
-pub fn eval_length(tcx: TyCtxt,
-                   count: hir::BodyId,
-                   reason: &str)
-                   -> Result<ConstUsize, ErrorReported>
+pub fn eval_length<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                   count: hir::BodyId,
+                                   reason: &str)
+                                   -> Result<&'gcx ty::Const<'gcx>, ErrorReported>
 {
     let count_expr = &tcx.hir.body(count).value;
     let count_def_id = tcx.hir.body_owner_def_id(count);
     let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
     let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
     match tcx.at(count_expr.span).const_eval(param_env.and((count_def_id, substs))) {
-        Ok(&ty::Const { val: Integral(Usize(count)), .. }) => Ok(count),
-        Ok(_) | Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported),
+        Ok(count) => {
+            // Elsewhere in the compiler this is enforced even in the presence
+            // of erroneous code (type mismatch error has already been emitted).
+            assert_eq!(count.ty, tcx.types.usize);
+            Ok(count)
+        }
+        Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported),
         Err(err) => {
             let mut diag = err.struct_error(tcx, count_expr.span, reason);
 
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 1a4d0dcd929c3..a270e0873c1dd 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -876,7 +876,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
         // Always promote `[T; 0]` (even when e.g. borrowed mutably).
         let promotable = match expr_ty.sty {
-            ty::TyArray(_, len) if len.as_u64() == 0 => true,
+            ty::TyArray(_, len) if len.val.to_const_int().unwrap().to_u64().unwrap() == 0 => true,
             _ => promotable,
         };
 
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 7469402daf90f..d645a00e15781 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -70,7 +70,8 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
                 LvalueTy::Ty {
                     ty: match ty.sty {
                         ty::TyArray(inner, size) => {
-                            let len = size.as_u64() - (from as u64) - (to as u64);
+                            let size = size.val.to_const_int().unwrap().to_u64().unwrap();
+                            let len = size - (from as u64) - (to as u64);
                             tcx.mk_array(inner, len)
                         }
                         ty::TySlice(..) => ty,
@@ -148,7 +149,7 @@ impl<'tcx> Rvalue<'tcx> {
         match *self {
             Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
             Rvalue::Repeat(ref operand, count) => {
-                tcx.mk_array(operand.ty(local_decls, tcx), count.as_u64())
+                tcx.mk_array_const_usize(operand.ty(local_decls, tcx), count)
             }
             Rvalue::Ref(reg, bk, ref lv) => {
                 let lv_ty = lv.ty(local_decls, tcx).to_ty(tcx);
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 7a671b5ebc6e0..e02493add31fb 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -21,6 +21,7 @@ use hir::map as hir_map;
 use hir::map::DefPathHash;
 use lint::{self, Lint};
 use ich::{self, StableHashingContext, NodeIdHashingMode};
+use middle::const_val::ConstVal;
 use middle::free_region::FreeRegionMap;
 use middle::lang_items;
 use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
@@ -49,7 +50,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                            StableHasherResult};
 
 use arena::{TypedArena, DroplessArena};
-use rustc_const_math::ConstUsize;
+use rustc_const_math::{ConstInt, ConstUsize};
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::borrow::Borrow;
 use std::cell::{Cell, RefCell};
@@ -1757,7 +1758,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
         let n = ConstUsize::new(n, self.sess.target.usize_ty).unwrap();
-        self.mk_ty(TyArray(ty, n))
+        self.mk_array_const_usize(ty, n)
+    }
+
+    pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> {
+        self.mk_ty(TyArray(ty, self.mk_const(ty::Const {
+            val: ConstVal::Integral(ConstInt::Usize(n)),
+            ty: self.types.usize
+        })))
     }
 
     pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> {
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 3234a9de8c791..52a8389bd8f5f 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -10,6 +10,7 @@
 
 use hir::def_id::DefId;
 use infer::type_variable;
+use middle::const_val::ConstVal;
 use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt};
 
 use std::fmt;
@@ -18,7 +19,7 @@ use syntax::ast;
 use errors::DiagnosticBuilder;
 use syntax_pos::Span;
 
-use rustc_const_math::ConstUsize;
+use rustc_const_math::ConstInt;
 
 use hir;
 
@@ -36,7 +37,7 @@ pub enum TypeError<'tcx> {
     AbiMismatch(ExpectedFound<abi::Abi>),
     Mutability,
     TupleSize(ExpectedFound<usize>),
-    FixedArraySize(ExpectedFound<ConstUsize>),
+    FixedArraySize(ExpectedFound<u64>),
     ArgCount,
 
     RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
@@ -181,7 +182,13 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
             ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(),
 
             ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
-            ty::TyArray(_, n) => format!("array of {} elements", n),
+            ty::TyArray(_, n) => {
+                if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
+                    format!("array of {} elements", n)
+                } else {
+                    "array".to_string()
+                }
+            }
             ty::TySlice(_) => "slice".to_string(),
             ty::TyRawPtr(_) => "*-ptr".to_string(),
             ty::TyRef(region, tymut) => {
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 27b8d245396c9..62e39a507f2bd 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use middle::const_val::{ConstVal, ConstAggregate};
 use ty::subst::Substs;
 use ty::{self, Ty, TypeFlags, TypeFoldable};
 
@@ -145,7 +146,12 @@ impl FlagComputation {
                 self.add_region(r);
             }
 
-            &ty::TyArray(tt, _) | &ty::TySlice(tt) => {
+            &ty::TyArray(tt, len) => {
+                self.add_ty(tt);
+                self.add_const(len);
+            }
+
+            &ty::TySlice(tt) => {
                 self.add_ty(tt)
             }
 
@@ -202,6 +208,36 @@ impl FlagComputation {
         }
     }
 
+    fn add_const(&mut self, constant: &ty::Const) {
+        self.add_ty(constant.ty);
+        match constant.val {
+            ConstVal::Integral(_) |
+            ConstVal::Float(_) |
+            ConstVal::Str(_) |
+            ConstVal::ByteStr(_) |
+            ConstVal::Bool(_) |
+            ConstVal::Char(_) |
+            ConstVal::Variant(_) => {}
+            ConstVal::Function(_, substs) => {
+                self.add_substs(substs);
+            }
+            ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
+                for &(_, v) in fields {
+                    self.add_const(v);
+                }
+            }
+            ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
+            ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
+                for v in fields {
+                    self.add_const(v);
+                }
+            }
+            ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
+                self.add_const(v);
+            }
+        }
+    }
+
     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection) {
         self.add_substs(projection.substs);
         self.add_ty(projection.ty);
diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs
index bb8ef28bbf593..e10a4fb9f9308 100644
--- a/src/librustc/ty/inhabitedness/mod.rs
+++ b/src/librustc/ty/inhabitedness/mod.rs
@@ -205,7 +205,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
                 }))
             },
             TyArray(ty, len) => {
-                if len.as_u64() == 0 {
+                if len.val.to_const_int().unwrap().to_u64().unwrap() == 0 {
                     DefIdForest::empty()
                 } else {
                     ty.uninhabited_from(visited, tcx)
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 4d94021d2c8c5..bb16413c17fae 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -837,7 +837,7 @@ impl<'a, 'tcx> Struct {
 
             // Is this a fixed-size array of something non-zero
             // with at least one element?
-            (_, &ty::TyArray(ety, d)) if d.as_u64() > 0 => {
+            (_, &ty::TyArray(ety, d)) if d.val.to_const_int().unwrap().to_u64().unwrap() != 0 => {
                 Struct::non_zero_field_paths(
                     tcx,
                     param_env,
@@ -1177,7 +1177,7 @@ impl<'a, 'tcx> Layout {
             ty::TyArray(element, count) => {
                 let element = element.layout(tcx, param_env)?;
                 let element_size = element.size(dl);
-                let count = count.as_u64();
+                let count = count.val.to_const_int().unwrap().to_u64().unwrap();
                 if element_size.checked_mul(count, dl).is_none() {
                     return Err(LayoutError::SizeOverflow(ty));
                 }
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 0acb8a2c1d159..eb465ed16a264 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -428,10 +428,14 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
         (&ty::TyArray(a_t, sz_a), &ty::TyArray(b_t, sz_b)) =>
         {
             let t = relation.relate(&a_t, &b_t)?;
-            if sz_a == sz_b {
-                Ok(tcx.mk_array(t, sz_a.as_u64()))
+            assert_eq!(sz_a.ty, tcx.types.usize);
+            assert_eq!(sz_b.ty, tcx.types.usize);
+            let sz_a_u64 = sz_a.val.to_const_int().unwrap().to_u64().unwrap();
+            let sz_b_u64 = sz_b.val.to_const_int().unwrap().to_u64().unwrap();
+            if sz_a_u64 == sz_b_u64 {
+                Ok(tcx.mk_ty(ty::TyArray(t, sz_a)))
             } else {
-                Err(TypeError::FixedArraySize(expected_found(relation, &sz_a, &sz_b)))
+                Err(TypeError::FixedArraySize(expected_found(relation, &sz_a_u64, &sz_b_u64)))
             }
         }
 
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index f260e20a3cd6c..758edd7d0c3bc 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -552,7 +552,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         let sty = match self.sty {
             ty::TyRawPtr(tm) => ty::TyRawPtr(tm.fold_with(folder)),
-            ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz),
+            ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz.fold_with(folder)),
             ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)),
             ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)),
             ty::TyDynamic(ref trait_ty, ref region) =>
@@ -590,7 +590,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         match self.sty {
             ty::TyRawPtr(ref tm) => tm.visit_with(visitor),
-            ty::TyArray(typ, _sz) => typ.visit_with(visitor),
+            ty::TyArray(typ, sz) => typ.visit_with(visitor) || sz.visit_with(visitor),
             ty::TySlice(typ) => typ.visit_with(visitor),
             ty::TyAdt(_, substs) => substs.visit_with(visitor),
             ty::TyDynamic(ref trait_ty, ref reg) =>
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index e01f9f24235c5..f17f81ca06bea 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -27,8 +27,6 @@ use syntax::ast::{self, Name};
 use syntax::symbol::keywords;
 use util::nodemap::FxHashMap;
 
-use rustc_const_math::ConstUsize;
-
 use serialize;
 
 use hir;
@@ -112,7 +110,7 @@ pub enum TypeVariants<'tcx> {
     TyStr,
 
     /// An array with the given length. Written as `[T; n]`.
-    TyArray(Ty<'tcx>, ConstUsize),
+    TyArray(Ty<'tcx>, &'tcx ty::Const<'tcx>),
 
     /// The pointee of an array slice.  Written as `[T]`.
     TySlice(Ty<'tcx>),
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index de4481116d6e1..95618717e0ea3 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -697,7 +697,9 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
             TyInt(i) => self.hash(i),
             TyUint(u) => self.hash(u),
             TyFloat(f) => self.hash(f),
-            TyArray(_, n) => self.hash(n),
+            TyArray(_, n) => {
+                self.hash(n.val.to_const_int().unwrap().to_u64().unwrap())
+            }
             TyRawPtr(m) |
             TyRef(_, m) => self.hash(m.mutbl),
             TyClosure(def_id, _) |
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index bfabacdb17214..4d7eb37ca26ed 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -11,6 +11,7 @@
 //! An iterator over the type substructure.
 //! WARNING: this does not keep track of the region depth.
 
+use middle::const_val::{ConstVal, ConstAggregate};
 use ty::{self, Ty};
 use rustc_data_structures::small_vec::SmallVec;
 use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
@@ -83,7 +84,11 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
         ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
         ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => {
         }
-        ty::TyArray(ty, _) | ty::TySlice(ty) => {
+        ty::TyArray(ty, len) => {
+            push_const(stack, len);
+            stack.push(ty);
+        }
+        ty::TySlice(ty) => {
             stack.push(ty);
         }
         ty::TyRawPtr(ref mt) | ty::TyRef(_, ref mt) => {
@@ -122,13 +127,39 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
         ty::TyFnDef(_, substs) => {
             stack.extend(substs.types().rev());
         }
-        ty::TyFnPtr(ft) => {
-            push_sig_subtypes(stack, ft);
+        ty::TyFnPtr(sig) => {
+            stack.push(sig.skip_binder().output());
+            stack.extend(sig.skip_binder().inputs().iter().cloned().rev());
         }
     }
 }
 
-fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: ty::PolyFnSig<'tcx>) {
-    stack.push(sig.skip_binder().output());
-    stack.extend(sig.skip_binder().inputs().iter().cloned().rev());
+fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const<'tcx>) {
+    match constant.val {
+        ConstVal::Integral(_) |
+        ConstVal::Float(_) |
+        ConstVal::Str(_) |
+        ConstVal::ByteStr(_) |
+        ConstVal::Bool(_) |
+        ConstVal::Char(_) |
+        ConstVal::Variant(_) => {}
+        ConstVal::Function(_, substs) => {
+            stack.extend(substs.types().rev());
+        }
+        ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
+            for &(_, v) in fields.iter().rev() {
+                push_const(stack, v);
+            }
+        }
+        ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
+        ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
+            for v in fields.iter().rev() {
+                push_const(stack, v);
+            }
+        }
+        ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
+            push_const(stack, v);
+        }
+    }
+    stack.push(constant.ty);
 }
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 3516f7dfb25b0..4d2b15b6bf069 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -207,6 +207,10 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
         }
     }
 
+    /// Pushes the obligations required for a constant value to be WF
+    /// into `self.out`.
+    fn compute_const(&mut self, _constant: &'tcx ty::Const<'tcx>) {}
+
     fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
         if !subty.has_escaping_regions() {
             let cause = self.cause(cause);
@@ -239,9 +243,14 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
                     // WfScalar, WfParameter, etc
                 }
 
-                ty::TySlice(subty) |
-                ty::TyArray(subty, _) => {
+                ty::TySlice(subty) => {
+                    self.require_sized(subty, traits::SliceOrArrayElem);
+                }
+
+                ty::TyArray(subty, len) => {
                     self.require_sized(subty, traits::SliceOrArrayElem);
+                    assert_eq!(len.ty, self.infcx.tcx.types.usize);
+                    self.compute_const(len);
                 }
 
                 ty::TyTuple(ref tys, _) => {
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 9cc978a057bf6..6b74022806cf5 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -10,6 +10,7 @@
 
 use hir::def_id::DefId;
 use hir::map::definitions::DefPathData;
+use middle::const_val::ConstVal;
 use middle::region::{self, BlockRemainder};
 use ty::subst::{self, Subst};
 use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
@@ -24,6 +25,7 @@ use std::cell::Cell;
 use std::fmt;
 use std::usize;
 
+use rustc_const_math::ConstInt;
 use syntax::abi::Abi;
 use syntax::ast::CRATE_NODE_ID;
 use syntax::symbol::Symbol;
@@ -886,7 +888,18 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
 
                 write!(f, "]")
             }),
-            TyArray(ty, sz) => write!(f, "[{}; {}]",  ty, sz),
+            TyArray(ty, sz) => {
+                write!(f, "[{}; ", ty)?;
+                match sz.val {
+                    ConstVal::Integral(ConstInt::Usize(sz)) => {
+                        write!(f, "{}", sz)?;
+                    }
+                    _ => {
+                        write!(f, "{:?}", sz)?;
+                    }
+                }
+                write!(f, "]")
+            }
             TySlice(ty) => write!(f, "[{}]",  ty)
         }
     }
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index 429332873c05b..efe6cfb5464ef 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -422,11 +422,12 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                 (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect()
             }
         }
-        ty::TyArray(ref sub_ty, length) => {
-            if length.as_u64() > 0 && cx.is_uninhabited(sub_ty) {
+        ty::TyArray(ref sub_ty, len) => {
+            let len = len.val.to_const_int().unwrap().to_u64().unwrap();
+            if len != 0 && cx.is_uninhabited(sub_ty) {
                 vec![]
             } else {
-                vec![Slice(length.as_u64())]
+                vec![Slice(len)]
             }
         }
         ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => {
@@ -729,7 +730,9 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
         PatternKind::Range { lo, hi, end } =>
             Some(vec![ConstantRange(lo, hi, end)]),
         PatternKind::Array { .. } => match pcx.ty.sty {
-            ty::TyArray(_, length) => Some(vec![Slice(length.as_u64())]),
+            ty::TyArray(_, length) => Some(vec![
+                Slice(length.val.to_const_int().unwrap().to_u64().unwrap())
+            ]),
             _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
         },
         PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 9dab067f942e8..1e3d118128163 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -456,7 +456,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       }
       hir::ExprRepeat(ref elem, _) => {
           let n = match ty.sty {
-            ty::TyArray(_, n) => n.as_u64(),
+            ty::TyArray(_, n) => n.val.to_const_int().unwrap().to_u64().unwrap(),
             _ => span_bug!(e.span, "typeck error")
           };
           mk_const(Aggregate(Repeat(cx.eval(elem)?, n)))
@@ -635,8 +635,13 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
             },
             ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
-                ty::TyArray(ty, n) if ty == tcx.types.u8 && n.as_u64() == b.data.len() as u64 => {
-                    Ok(val)
+                ty::TyArray(ty, n) => {
+                    let n = n.val.to_const_int().unwrap().to_u64().unwrap();
+                    if ty == tcx.types.u8 && n == b.data.len() as u64 {
+                        Ok(val)
+                    } else {
+                        Err(CannotCast)
+                    }
                 }
                 ty::TySlice(_) => {
                     Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 6274796145e1f..0a2e78dd51a35 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -537,7 +537,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
 
             ty::TyArray(_, len) => {
                 // fixed-length array
-                assert!(len.as_u64() >= prefix.len() as u64 + suffix.len() as u64);
+                let len = len.val.to_const_int().unwrap().to_u64().unwrap();
+                assert!(len >= prefix.len() as u64 + suffix.len() as u64);
                 PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
             }
 
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index eddd4f39f4333..00ee417e02b55 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -292,7 +292,10 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
 
     match self_ty.sty {
         _ if is_copy => builder.copy_shim(),
-        ty::TyArray(ty, len) => builder.array_shim(ty, len.as_u64()),
+        ty::TyArray(ty, len) => {
+            let len = len.val.to_const_int().unwrap().to_u64().unwrap();
+            builder.array_shim(ty, len)
+        }
         ty::TyTuple(tys, _) => builder.tuple_shim(tys),
         _ => {
             bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty);
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 30074becb09c7..2267e611531f3 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -696,7 +696,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                             _ => false
                         }
                     } else if let ty::TyArray(_, len) = ty.sty {
-                        len.as_u64() == 0 && self.mode == Mode::Fn
+                        len.val.to_const_int().unwrap().to_u64().unwrap() == 0 &&
+                            self.mode == Mode::Fn
                     } else {
                         false
                     };
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 07134451a4e29..ab5998a34805b 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -209,7 +209,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                 LvalueTy::Ty {
                     ty: match base_ty.sty {
                         ty::TyArray(inner, size) => {
-                            let size = size.as_u64();
+                            let size = size.val.to_const_int().unwrap().to_u64().unwrap();
                             let min_size = (from as u64) + (to as u64);
                             if let Some(rest_size) = size.checked_sub(min_size) {
                                 tcx.mk_array(inner, rest_size)
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 96499424be1f6..73209affe994b 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -201,7 +201,9 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
                                 -> ValueRef {
     let (source, target) = ccx.tcx().struct_lockstep_tails(source, target);
     match (&source.sty, &target.sty) {
-        (&ty::TyArray(_, len), &ty::TySlice(_)) => C_usize(ccx, len.as_u64()),
+        (&ty::TyArray(_, len), &ty::TySlice(_)) => {
+            C_usize(ccx, len.val.to_const_int().unwrap().to_u64().unwrap())
+        }
         (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
             // For now, upcasts are limited to changes in marker
             // traits, and hence never actually require an actual
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 0ef93e73c4bc8..3c87bc293b5b5 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -530,7 +530,8 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             MetadataCreationResult::new(basic_type_metadata(cx, t), false)
         }
         ty::TyArray(typ, len) => {
-            fixed_vec_metadata(cx, unique_type_id, typ, Some(len.as_u64()), usage_site_span)
+            let len = len.val.to_const_int().unwrap().to_u64().unwrap();
+            fixed_vec_metadata(cx, unique_type_id, typ, Some(len), usage_site_span)
         }
         ty::TySlice(typ) => {
             fixed_vec_metadata(cx, unique_type_id, typ, None, usage_site_span)
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index 6eda865751933..7bf9d39ea2f25 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -96,7 +96,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         ty::TyArray(inner_type, len) => {
             output.push('[');
             push_debuginfo_type_name(cx, inner_type, true, output);
-            output.push_str(&format!("; {}", len));
+            output.push_str(&format!("; {}", len.val.to_const_int().unwrap().to_u64().unwrap()));
             output.push(']');
         },
         ty::TySlice(inner_type) => {
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index f75c949fefe3a..072d351dd617a 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -200,7 +200,9 @@ impl<'tcx> ConstLvalue<'tcx> {
 
     pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
         match self.ty.sty {
-            ty::TyArray(_, n) => C_usize(ccx, n.as_u64()),
+            ty::TyArray(_, n) => {
+                C_usize(ccx, n.val.to_const_int().unwrap().to_u64().unwrap())
+            }
             ty::TySlice(_) | ty::TyStr => {
                 assert!(self.llextra != ptr::null_mut());
                 self.llextra
diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs
index d34885a1e9326..6799e52904d34 100644
--- a/src/librustc_trans/mir/lvalue.rs
+++ b/src/librustc_trans/mir/lvalue.rs
@@ -106,7 +106,9 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
     pub fn len(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
         let ty = self.ty.to_ty(ccx.tcx());
         match ty.sty {
-            ty::TyArray(_, n) => common::C_usize(ccx, n.as_u64()),
+            ty::TyArray(_, n) => {
+                common::C_usize(ccx, n.val.to_const_int().unwrap().to_u64().unwrap())
+            }
             ty::TySlice(_) | ty::TyStr => {
                 assert!(self.llextra != ptr::null_mut());
                 self.llextra
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 0f2d0c7f29617..20ed4ab50a00f 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -521,7 +521,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
             if let LocalRef::Operand(Some(op)) = self.locals[index] {
                 if common::type_is_zero_size(bcx.ccx, op.ty) {
                     if let ty::TyArray(_, n) = op.ty.sty {
-                        return common::C_usize(bcx.ccx, n.as_u64());
+                        let n = n.val.to_const_int().unwrap().to_u64().unwrap();
+                        return common::C_usize(bcx.ccx, n);
                     }
                 }
             }
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 672fa32aa8591..1f27eb9fcb309 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -446,7 +446,8 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
             ty::TyArray(inner_type, len) => {
                 output.push('[');
                 self.push_type_name(inner_type, output);
-                write!(output, "; {}", len).unwrap();
+                write!(output, "; {}",
+                    len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap();
                 output.push(']');
             },
             ty::TySlice(inner_type) => {
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 149a55f8c05d5..992c74b9020c3 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -149,7 +149,8 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
 
       ty::TyArray(ty, size) => {
           let llty = in_memory_type_of(cx, ty);
-          Type::array(&llty, size.as_u64())
+          let size = size.val.to_const_int().unwrap().to_u64().unwrap();
+          Type::array(&llty, size)
       }
 
       // Unsized slice types (and str) have the type of their element, and
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index fc05ce4cd662c..6759b6a422d09 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1083,7 +1083,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
             hir::TyArray(ref ty, length) => {
                 if let Ok(length) = eval_length(tcx, length, "array length") {
-                    tcx.mk_array(self.ast_ty_to_ty(&ty), length.as_u64())
+                    tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length))
                 } else {
                     self.tcx().types.err
                 }
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 02017652a6c71..cbf58209d056a 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -264,7 +264,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let expected_ty = self.structurally_resolved_type(pat.span, expected);
                 let (inner_ty, slice_ty) = match expected_ty.sty {
                     ty::TyArray(inner_ty, size) => {
-                        let size = size.as_u64();
+                        let size = size.val.to_const_int().unwrap().to_u64().unwrap();
                         let min_len = before.len() as u64 + after.len() as u64;
                         if slice.is_none() {
                             if min_len != size {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0adfca6e886a7..0ed3cc1e905cb 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3923,7 +3923,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             };
 
             if let Ok(count) = count {
-                if count.as_u64() > 1 {
+                let zero_or_one = count.val.to_const_int().and_then(|count| {
+                    count.to_u64().map(|count| count <= 1)
+                }).unwrap_or(false);
+                if !zero_or_one {
                     // For [foo, ..n] where n > 1, `foo` must have
                     // Copy type:
                     let lang_item = self.tcx.require_lang_item(lang_items::CopyTraitLangItem);
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index a78f15dd283c3..69c05050dacc9 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -27,6 +27,7 @@ use syntax::ptr::P;
 use syntax::symbol::keywords;
 use syntax_pos::{self, DUMMY_SP, Pos};
 
+use rustc::middle::const_val::ConstVal;
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::resolve_lifetime as rl;
 use rustc::middle::lang_items;
@@ -40,6 +41,7 @@ use rustc_typeck::hir_ty_to_ty;
 
 use rustc::hir;
 
+use rustc_const_math::ConstInt;
 use std::{mem, slice, vec};
 use std::path::PathBuf;
 use std::rc::Rc;
@@ -1785,7 +1787,12 @@ impl Clean<Type> for hir::Ty {
             TyArray(ref ty, length) => {
                 use rustc::middle::const_val::eval_length;
                 let n = eval_length(cx.tcx, length, "array length").unwrap();
-                Array(box ty.clean(cx), n.to_string())
+                let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
+                    n.to_string()
+                } else {
+                    format!("{:?}", n)
+                };
+                Array(box ty.clean(cx), n)
             },
             TyTup(ref tys) => Tuple(tys.clean(cx)),
             TyPath(hir::QPath::Resolved(None, ref path)) => {
@@ -1895,7 +1902,14 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
             ty::TyFloat(float_ty) => Primitive(float_ty.into()),
             ty::TyStr => Primitive(PrimitiveType::Str),
             ty::TySlice(ty) => Slice(box ty.clean(cx)),
-            ty::TyArray(ty, n) => Array(box ty.clean(cx), n.to_string()),
+            ty::TyArray(ty, n) => {
+                let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
+                    n.to_string()
+                } else {
+                    format!("{:?}", n)
+                };
+                Array(box ty.clean(cx), n)
+            }
             ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
             ty::TyRef(r, mt) => BorrowedRef {
                 lifetime: r.clean(cx),
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index d04b6d3417a5a..9563ccfcc65fd 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -32,6 +32,7 @@ extern crate html_diff;
 extern crate libc;
 extern crate rustc;
 extern crate rustc_data_structures;
+extern crate rustc_const_math;
 extern crate rustc_trans;
 extern crate rustc_driver;
 extern crate rustc_resolve;

From 88217618ecf430c3588536a4af2e3dd0b790e49c Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Tue, 15 Aug 2017 18:35:31 +0300
Subject: [PATCH 5/7] rustc: remove obsolete
 const_val::ErrKind::{Negate,Not}On.

---
 src/librustc/middle/const_val.rs       | 24 ------------------------
 src/librustc_const_eval/diagnostics.rs |  2 +-
 src/librustc_const_eval/eval.rs        | 10 ++++------
 3 files changed, 5 insertions(+), 31 deletions(-)

diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index 05e4f0da001cf..469aed7e8ce68 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use self::ConstVal::*;
-use self::ConstAggregate::*;
 pub use rustc_const_math::ConstInt;
 
 use hir;
@@ -73,23 +71,6 @@ impl<'tcx> Decodable for ConstAggregate<'tcx> {
 }
 
 impl<'tcx> ConstVal<'tcx> {
-    pub fn description(&self) -> &'static str {
-        match *self {
-            Float(f) => f.description(),
-            Integral(i) => i.description(),
-            Str(_) => "string literal",
-            ByteStr(_) => "byte string literal",
-            Bool(_) => "boolean",
-            Char(..) => "char",
-            Variant(_) => "enum variant",
-            Aggregate(Struct(_)) => "struct",
-            Aggregate(Tuple(_)) => "tuple",
-            Function(..) => "function definition",
-            Aggregate(Array(..)) => "array",
-            Aggregate(Repeat(..)) => "repeat",
-        }
-    }
-
     pub fn to_const_int(&self) -> Option<ConstInt> {
         match *self {
             ConstVal::Integral(i) => Some(i),
@@ -110,8 +91,6 @@ pub struct ConstEvalErr<'tcx> {
 pub enum ErrKind<'tcx> {
     CannotCast,
     MissingStructField,
-    NegateOn(ConstVal<'tcx>),
-    NotOn(ConstVal<'tcx>),
 
     NonConstPath,
     UnimplementedConstVal(&'static str),
@@ -170,9 +149,6 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
 
         match self.kind {
             CannotCast => simple!("can't cast this type"),
-            NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
-            NotOn(ref const_val) => simple!("not on {}", const_val.description()),
-
             MissingStructField  => simple!("nonexistent struct field"),
             NonConstPath        => simple!("non-constant path in constant expression"),
             UnimplementedConstVal(what) =>
diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs
index 56d08184a0f17..d01b3c45f7fd1 100644
--- a/src/librustc_const_eval/diagnostics.rs
+++ b/src/librustc_const_eval/diagnostics.rs
@@ -565,7 +565,7 @@ See also https://github.com/rust-lang/rust/issues/14587
 
 
 register_diagnostics! {
-    E0298, // cannot compare constants
+//  E0298, // cannot compare constants
 //  E0299, // mismatched types between arms
 //  E0471, // constant evaluation error (in pattern)
 }
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 1e3d118128163..1ad00a9e7b34e 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -186,14 +186,14 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         mk_const(match cx.eval(inner)?.val {
           Float(f) => Float(-f),
           Integral(i) => Integral(math!(e, -i)),
-          const_val => signal!(e, NegateOn(const_val)),
+          _ => signal!(e, TypeckError)
         })
       }
       hir::ExprUnary(hir::UnNot, ref inner) => {
         mk_const(match cx.eval(inner)?.val {
           Integral(i) => Integral(math!(e, !i)),
           Bool(b) => Bool(!b),
-          const_val => signal!(e, NotOn(const_val)),
+          _ => signal!(e, TypeckError)
         })
       }
       hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
@@ -734,10 +734,8 @@ pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
         Some(result) => Ok(result),
         None => {
             // FIXME: can this ever be reached?
-            span_err!(tcx.sess, span, E0298,
-                      "type mismatch comparing {} and {}",
-                      a.description(),
-                      b.description());
+            tcx.sess.delay_span_bug(span,
+                &format!("type mismatch comparing {:?} and {:?}", a, b));
             Err(ErrorReported)
         }
     }

From 74349fa2884013389ace2ed0a098cb08983d8740 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Mon, 7 Aug 2017 08:08:53 +0300
Subject: [PATCH 6/7] rustc: evaluate fixed-length array length expressions
 lazily.

---
 src/librustc/ich/impls_ty.rs                  |   8 ++
 src/librustc/infer/mod.rs                     |   5 +-
 src/librustc/middle/const_val.rs              |  39 +-----
 src/librustc/middle/free_region.rs            |   3 +-
 src/librustc/middle/mem_categorization.rs     |   3 +-
 src/librustc/mir/mod.rs                       |   1 +
 src/librustc/traits/error_reporting.rs        |  17 +++
 src/librustc/traits/fulfill.rs                |  25 +++-
 src/librustc/traits/mod.rs                    |   2 +
 src/librustc/traits/object_safety.rs          |   6 +-
 src/librustc/traits/project.rs                |  40 +++++-
 src/librustc/traits/select.rs                 |  15 +++
 src/librustc/traits/structural_impls.rs       |   3 +
 src/librustc/traits/trans/mod.rs              |   4 +-
 src/librustc/traits/util.rs                   |   7 +
 src/librustc/ty/context.rs                    |  12 --
 src/librustc/ty/flags.rs                      |   4 +
 src/librustc/ty/fold.rs                       |  22 +++-
 src/librustc/ty/inhabitedness/mod.rs          |   2 +-
 src/librustc/ty/layout.rs                     |  31 ++++-
 src/librustc/ty/maps.rs                       |  11 +-
 src/librustc/ty/mod.rs                        |  11 +-
 src/librustc/ty/relate.rs                     |  46 ++++++-
 src/librustc/ty/structural_impls.rs           | 120 +++++++++++++++++-
 src/librustc/ty/util.rs                       |  11 +-
 src/librustc/ty/walk.rs                       |   3 +
 src/librustc/ty/wf.rs                         |  47 ++++++-
 src/librustc/util/ppaux.rs                    |  11 ++
 src/librustc_const_eval/_match.rs             |  18 +--
 src/librustc_const_eval/eval.rs               |   3 +-
 src/librustc_const_eval/pattern.rs            |   3 +-
 src/librustc_metadata/encoder.rs              |  13 +-
 src/librustc_trans/mir/constant.rs            |   3 +-
 src/librustc_typeck/astconv.rs                |  15 ++-
 src/librustc_typeck/check/closure.rs          |   1 +
 src/librustc_typeck/check/method/probe.rs     |   3 +-
 src/librustc_typeck/check/mod.rs              |  10 +-
 src/librustc_typeck/check/regionck.rs         |   3 +-
 src/librustdoc/clean/mod.rs                   |  10 +-
 .../const-block-non-item-statement-3.rs       |  15 +++
 .../const-block-non-item-statement.rs         |   4 -
 src/test/compile-fail/const-fn-error.rs       |   2 +-
 .../const-len-underflow-separate-spans.rs     |   2 +-
 src/test/compile-fail/const-size_of-cycle.rs  |   3 +-
 src/test/compile-fail/issue-22933-2.rs        |   3 -
 src/test/compile-fail/issue-22933-3.rs        |  14 ++
 src/test/compile-fail/issue-39559.rs          |   3 +-
 src/test/ui/issue-38875/issue_38875.stderr    |   2 +-
 48 files changed, 517 insertions(+), 122 deletions(-)
 create mode 100644 src/test/compile-fail/const-block-non-item-statement-3.rs
 create mode 100644 src/test/compile-fail/issue-22933-3.rs

diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index c9fb754287fda..e933ca4c2b551 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -235,6 +235,10 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Pr
                 def_id.hash_stable(hcx, hasher);
                 closure_kind.hash_stable(hcx, hasher);
             }
+            ty::Predicate::ConstEvaluatable(def_id, substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
         }
     }
 }
@@ -317,6 +321,10 @@ for ::middle::const_val::ConstVal<'gcx> {
                 value.hash_stable(hcx, hasher);
                 times.hash_stable(hcx, hasher);
             }
+            Unevaluated(def_id, substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
         }
     }
 }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 3fe3a3dc58560..6ccf7e42fd5fd 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -442,6 +442,7 @@ macro_rules! impl_trans_normalize {
 
 impl_trans_normalize!('gcx,
     Ty<'gcx>,
+    &'gcx ty::Const<'gcx>,
     &'gcx Substs<'gcx>,
     ty::FnSig<'gcx>,
     ty::PolyFnSig<'gcx>,
@@ -493,7 +494,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
         let param_env = ty::ParamEnv::empty(Reveal::All);
         let value = self.erase_regions(value);
 
-        if !value.has_projection_types() {
+        if !value.has_projections() {
             return value;
         }
 
@@ -515,7 +516,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
 
         let value = self.erase_regions(value);
 
-        if !value.has_projection_types() {
+        if !value.has_projections() {
             return value;
         }
 
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index 469aed7e8ce68..7b23998046730 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -10,13 +10,9 @@
 
 pub use rustc_const_math::ConstInt;
 
-use hir;
-use hir::def::Def;
 use hir::def_id::DefId;
-use traits::Reveal;
 use ty::{self, TyCtxt, layout};
 use ty::subst::Substs;
-use util::common::ErrorReported;
 use rustc_const_math::*;
 
 use graphviz::IntoCow;
@@ -41,6 +37,7 @@ pub enum ConstVal<'tcx> {
     Variant(DefId),
     Function(DefId, &'tcx Substs<'tcx>),
     Aggregate(ConstAggregate<'tcx>),
+    Unevaluated(DefId, &'tcx Substs<'tcx>),
 }
 
 #[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)]
@@ -221,37 +218,3 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
         self.struct_error(tcx, primary_span, primary_kind).emit();
     }
 }
-
-/// Returns the value of the length-valued expression
-pub fn eval_length<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                   count: hir::BodyId,
-                                   reason: &str)
-                                   -> Result<&'gcx ty::Const<'gcx>, ErrorReported>
-{
-    let count_expr = &tcx.hir.body(count).value;
-    let count_def_id = tcx.hir.body_owner_def_id(count);
-    let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
-    let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
-    match tcx.at(count_expr.span).const_eval(param_env.and((count_def_id, substs))) {
-        Ok(count) => {
-            // Elsewhere in the compiler this is enforced even in the presence
-            // of erroneous code (type mismatch error has already been emitted).
-            assert_eq!(count.ty, tcx.types.usize);
-            Ok(count)
-        }
-        Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported),
-        Err(err) => {
-            let mut diag = err.struct_error(tcx, count_expr.span, reason);
-
-            if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
-                if let Def::Local(..) = path.def {
-                    diag.note(&format!("`{}` is a variable",
-                                       tcx.hir.node_to_pretty_string(count_expr.id)));
-                }
-            }
-
-            diag.emit();
-            Err(ErrorReported)
-        }
-    }
-}
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index d4cee25bb8fa2..4de86b669160e 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -147,7 +147,8 @@ impl<'tcx> FreeRegionMap<'tcx> {
                 ty::Predicate::WellFormed(..) |
                 ty::Predicate::ObjectSafe(..) |
                 ty::Predicate::ClosureKind(..) |
-                ty::Predicate::TypeOutlives(..) => {
+                ty::Predicate::TypeOutlives(..) |
+                ty::Predicate::ConstEvaluatable(..) => {
                     // No region bounds here
                 }
                 ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index a270e0873c1dd..5102b41598d6f 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -876,7 +876,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
         // Always promote `[T; 0]` (even when e.g. borrowed mutably).
         let promotable = match expr_ty.sty {
-            ty::TyArray(_, len) if len.val.to_const_int().unwrap().to_u64().unwrap() == 0 => true,
+            ty::TyArray(_, len) if
+                len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true,
             _ => promotable,
         };
 
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 1985dcbd1f73d..d9ca5ddf46b05 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1535,6 +1535,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
         Variant(def_id) |
         Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
         Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val),
+        Unevaluated(..) => write!(fmt, "{:?}", const_val)
     }
 }
 
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index cfbd4ba055e3c..b491baadd7c2b 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -19,6 +19,7 @@ use super::{
     OnUnimplementedNote,
     OutputTypeParameterMismatch,
     TraitNotObjectSafe,
+    ConstEvalFailure,
     PredicateObligation,
     Reveal,
     SelectionContext,
@@ -31,6 +32,7 @@ use hir;
 use hir::def_id::DefId;
 use infer::{self, InferCtxt};
 use infer::type_variable::TypeVariableOrigin;
+use middle::const_val;
 use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
 use std::fmt;
 use syntax::ast;
@@ -698,6 +700,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         // (which may fail).
                         span_bug!(span, "WF predicate not satisfied for {:?}", ty);
                     }
+
+                    ty::Predicate::ConstEvaluatable(..) => {
+                        // Errors for `ConstEvaluatable` predicates show up as
+                        // `SelectionError::ConstEvalFailure`,
+                        // not `Unimplemented`.
+                        span_bug!(span,
+                            "const-evaluatable requirement gave wrong error: `{:?}`", obligation)
+                    }
                 }
             }
 
@@ -762,6 +772,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 self.tcx.report_object_safety_error(span, did,
                                                     violations)
             }
+
+            ConstEvalFailure(ref err) => {
+                if let const_val::ErrKind::TypeckError = err.kind {
+                    return;
+                }
+                err.struct_error(self.tcx, span, "constant expression")
+            }
         };
         self.note_obligation_cause(&mut err, obligation);
         err.emit();
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index fbc393cbd96f2..cc2506d1afc50 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -25,7 +25,7 @@ use super::{FulfillmentError, FulfillmentErrorCode};
 use super::{ObligationCause, PredicateObligation, Obligation};
 use super::project;
 use super::select::SelectionContext;
-use super::Unimplemented;
+use super::{Unimplemented, ConstEvalFailure};
 
 impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
     type Predicate = ty::Predicate<'tcx>;
@@ -540,6 +540,29 @@ fn process_predicate<'a, 'gcx, 'tcx>(
                 }
             }
         }
+
+        ty::Predicate::ConstEvaluatable(def_id, substs) => {
+            match selcx.tcx().lift_to_global(&obligation.param_env) {
+                None => {
+                    Ok(None)
+                }
+                Some(param_env) => {
+                    match selcx.tcx().lift_to_global(&substs) {
+                        None => {
+                            pending_obligation.stalled_on = substs.types().collect();
+                            Ok(None)
+                        }
+                        Some(substs) => {
+                            match selcx.tcx().at(obligation.cause.span)
+                                             .const_eval(param_env.and((def_id, substs))) {
+                                Ok(_) => Ok(Some(vec![])),
+                                Err(e) => Err(CodeSelectionError(ConstEvalFailure(e)))
+                            }
+                        }
+                    }
+                }
+            }
+        }
     }
 }
 
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 22c92776c5e4e..fb71d9cc49b9e 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -17,6 +17,7 @@ pub use self::ObligationCauseCode::*;
 
 use hir;
 use hir::def_id::DefId;
+use middle::const_val::ConstEvalErr;
 use middle::region;
 use middle::free_region::FreeRegionMap;
 use ty::subst::Substs;
@@ -218,6 +219,7 @@ pub enum SelectionError<'tcx> {
                                 ty::PolyTraitRef<'tcx>,
                                 ty::error::TypeError<'tcx>),
     TraitNotObjectSafe(DefId),
+    ConstEvalFailure(ConstEvalErr<'tcx>),
 }
 
 pub struct FulfillmentError<'tcx> {
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index fd6d5a86a7fd1..1e9816095ea2e 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -169,7 +169,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     ty::Predicate::RegionOutlives(..) |
                     ty::Predicate::ClosureKind(..) |
                     ty::Predicate::Subtype(..) |
-                    ty::Predicate::Equate(..) => {
+                    ty::Predicate::Equate(..) |
+                    ty::Predicate::ConstEvaluatable(..) => {
                         false
                     }
                 }
@@ -203,7 +204,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     ty::Predicate::WellFormed(..) |
                     ty::Predicate::ObjectSafe(..) |
                     ty::Predicate::ClosureKind(..) |
-                    ty::Predicate::TypeOutlives(..) => {
+                    ty::Predicate::TypeOutlives(..) |
+                    ty::Predicate::ConstEvaluatable(..) => {
                         false
                     }
                 }
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 9a0d76144368a..54e31aed272a3 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -27,10 +27,11 @@ use super::util;
 use hir::def_id::DefId;
 use infer::{InferCtxt, InferOk};
 use infer::type_variable::TypeVariableOrigin;
+use middle::const_val::ConstVal;
 use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
 use syntax::ast;
 use syntax::symbol::Symbol;
-use ty::subst::Subst;
+use ty::subst::{Subst, Substs};
 use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder};
 use util::common::FN_OUTPUT_NAME;
@@ -260,7 +261,7 @@ impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
     fn fold<T:TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
         let value = self.selcx.infcx().resolve_type_vars_if_possible(value);
 
-        if !value.has_projection_types() {
+        if !value.has_projections() {
             value.clone()
         } else {
             value.fold_with(self)
@@ -332,6 +333,39 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
             }
         }
     }
+
+    fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+        if let ConstVal::Unevaluated(def_id, substs) = constant.val {
+            if substs.needs_infer() {
+                let identity_substs = Substs::identity_for_item(self.tcx(), def_id);
+                let data = self.param_env.and((def_id, identity_substs));
+                match self.tcx().lift_to_global(&data) {
+                    Some(data) => {
+                        match self.tcx().const_eval(data) {
+                            Ok(evaluated) => {
+                                let evaluated = evaluated.subst(self.tcx(), substs);
+                                return self.fold_const(evaluated);
+                            }
+                            Err(_) => {}
+                        }
+                    }
+                    None => {}
+                }
+            } else {
+                let data = self.param_env.and((def_id, substs));
+                match self.tcx().lift_to_global(&data) {
+                    Some(data) => {
+                        match self.tcx().const_eval(data) {
+                            Ok(evaluated) => return self.fold_const(evaluated),
+                            Err(_) => {}
+                        }
+                    }
+                    None => {}
+                }
+            }
+        }
+        constant
+    }
 }
 
 #[derive(Clone)]
@@ -520,7 +554,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                    depth,
                    obligations);
 
-            let result = if projected_ty.has_projection_types() {
+            let result = if projected_ty.has_projections() {
                 let mut normalizer = AssociatedTypeNormalizer::new(selcx,
                                                                    param_env,
                                                                    cause,
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 98bb3fb0ba94a..f5f69ad0a7cec 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -732,6 +732,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     }
                 }
             }
+
+            ty::Predicate::ConstEvaluatable(def_id, substs) => {
+                match self.tcx().lift_to_global(&(obligation.param_env, substs)) {
+                    Some((param_env, substs)) => {
+                        match self.tcx().const_eval(param_env.and((def_id, substs))) {
+                            Ok(_) => EvaluatedToOk,
+                            Err(_) => EvaluatedToErr
+                        }
+                    }
+                    None => {
+                        // Inference variables still left in param_env or substs.
+                        EvaluatedToAmbig
+                    }
+                }
+            }
         }
     }
 
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 674da297cd959..19ed03aa14917 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -173,6 +173,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> {
             super::TraitNotObjectSafe(def_id) => {
                 Some(super::TraitNotObjectSafe(def_id))
             }
+            super::ConstEvalFailure(ref err) => {
+                tcx.lift(err).map(super::ConstEvalFailure)
+            }
         }
     }
 }
diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs
index 827a5092c0042..9c4a260b35d49 100644
--- a/src/librustc/traits/trans/mod.rs
+++ b/src/librustc/traits/trans/mod.rs
@@ -120,7 +120,7 @@ impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> {
     }
 
     fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
-        if !value.has_projection_types() {
+        if !value.has_projections() {
             value.clone()
         } else {
             value.fold_with(self)
@@ -134,7 +134,7 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
     }
 
     fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
-        if !ty.has_projection_types() {
+        if !ty.has_projections() {
             ty
         } else {
             self.tcx.trans_trait_caches.project_cache.memoize(ty, || {
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index b0d6f4d5a3130..42e0834e8e43b 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -48,6 +48,9 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 
         ty::Predicate::Subtype(ref data) =>
             ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)),
+
+        ty::Predicate::ConstEvaluatable(def_id, substs) =>
+            ty::Predicate::ConstEvaluatable(def_id, substs),
     }
 }
 
@@ -175,6 +178,10 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
             ty::Predicate::ClosureKind(..) => {
                 // Nothing to elaborate when waiting for a closure's kind to be inferred.
             }
+            ty::Predicate::ConstEvaluatable(..) => {
+                // Currently, we do not elaborate const-evaluatable
+                // predicates.
+            }
 
             ty::Predicate::RegionOutlives(..) => {
                 // Nothing to elaborate from `'a: 'b`.
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index e02493add31fb..6d12731307d63 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1190,18 +1190,6 @@ pub trait Lift<'tcx> {
     fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted>;
 }
 
-impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
-    type Lifted = ty::ParamEnv<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<ty::ParamEnv<'tcx>> {
-        self.caller_bounds.lift_to_tcx(tcx).and_then(|caller_bounds| {
-            Some(ty::ParamEnv {
-                reveal: self.reveal,
-                caller_bounds,
-            })
-        })
-    }
-}
-
 impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
     type Lifted = Ty<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 62e39a507f2bd..9ece719c76470 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -235,6 +235,10 @@ impl FlagComputation {
             ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
                 self.add_const(v);
             }
+            ConstVal::Unevaluated(_, substs) => {
+                self.add_flags(TypeFlags::HAS_PROJECTION);
+                self.add_substs(substs);
+            }
         }
     }
 
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index a1cd92c760915..543e8f3e2f04d 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -39,6 +39,7 @@
 //! These methods return true to indicate that the visitor has found what it is looking for
 //! and does not need to visit anything else.
 
+use middle::const_val::ConstVal;
 use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
 
 use std::fmt;
@@ -67,7 +68,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     fn has_type_flags(&self, flags: TypeFlags) -> bool {
         self.visit_with(&mut HasTypeFlagsVisitor { flags: flags })
     }
-    fn has_projection_types(&self) -> bool {
+    fn has_projections(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_PROJECTION)
     }
     fn references_error(&self) -> bool {
@@ -139,6 +140,10 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         r.super_fold_with(self)
     }
+
+    fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+        c.super_fold_with(self)
+    }
 }
 
 pub trait TypeVisitor<'tcx> : Sized {
@@ -153,6 +158,10 @@ pub trait TypeVisitor<'tcx> : Sized {
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
         r.super_visit_with(self)
     }
+
+    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
+        c.super_visit_with(self)
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -603,6 +612,17 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
         debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags);
         flags.intersects(self.flags)
     }
+
+    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
+        if let ConstVal::Unevaluated(..) = c.val {
+            let projection_flags = TypeFlags::HAS_NORMALIZABLE_PROJECTION |
+                TypeFlags::HAS_PROJECTION;
+            if projection_flags.intersects(self.flags) {
+                return true;
+            }
+        }
+        c.super_visit_with(self)
+    }
 }
 
 /// Collects all the late-bound regions it finds into a hash set.
diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs
index e10a4fb9f9308..a829814e0905b 100644
--- a/src/librustc/ty/inhabitedness/mod.rs
+++ b/src/librustc/ty/inhabitedness/mod.rs
@@ -205,7 +205,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
                 }))
             },
             TyArray(ty, len) => {
-                if len.val.to_const_int().unwrap().to_u64().unwrap() == 0 {
+                if len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) {
                     DefIdForest::empty()
                 } else {
                     ty.uninhabited_from(visited, tcx)
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index bb16413c17fae..0106d98b64130 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -837,12 +837,22 @@ impl<'a, 'tcx> Struct {
 
             // Is this a fixed-size array of something non-zero
             // with at least one element?
-            (_, &ty::TyArray(ety, d)) if d.val.to_const_int().unwrap().to_u64().unwrap() != 0 => {
-                Struct::non_zero_field_paths(
-                    tcx,
-                    param_env,
-                    Some(ety).into_iter(),
-                    None)
+            (_, &ty::TyArray(ety, mut count)) => {
+                if count.has_projections() {
+                    count = tcx.normalize_associated_type_in_env(&count, param_env);
+                    if count.has_projections() {
+                        return Err(LayoutError::Unknown(ty));
+                    }
+                }
+                if count.val.to_const_int().unwrap().to_u64().unwrap() != 0 {
+                    Struct::non_zero_field_paths(
+                        tcx,
+                        param_env,
+                        Some(ety).into_iter(),
+                        None)
+                } else {
+                    Ok(None)
+                }
             }
 
             (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
@@ -1174,7 +1184,14 @@ impl<'a, 'tcx> Layout {
             }
 
             // Arrays and slices.
-            ty::TyArray(element, count) => {
+            ty::TyArray(element, mut count) => {
+                if count.has_projections() {
+                    count = tcx.normalize_associated_type_in_env(&count, param_env);
+                    if count.has_projections() {
+                        return Err(LayoutError::Unknown(ty));
+                    }
+                }
+
                 let element = element.layout(tcx, param_env)?;
                 let element_size = element.size(dl);
                 let count = count.val.to_const_int().unwrap().to_u64().unwrap();
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 48b92d101edb3..83b4fbb4f803a 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -159,7 +159,7 @@ impl Key for (MirSuite, MirPassIndex, DefId) {
     }
 }
 
-impl<'tcx, T: Clone + Hash + Eq + Debug> Key for ty::ParamEnvAnd<'tcx, T> {
+impl<'tcx> Key for Ty<'tcx> {
     fn map_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -168,6 +168,15 @@ impl<'tcx, T: Clone + Hash + Eq + Debug> Key for ty::ParamEnvAnd<'tcx, T> {
     }
 }
 
+impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
+    fn map_crate(&self) -> CrateNum {
+        self.value.map_crate()
+    }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        self.value.default_span(tcx)
+    }
+}
+
 trait Value<'tcx>: Sized {
     fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 6634af59e787e..bdd4c003de7ad 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -846,6 +846,9 @@ pub enum Predicate<'tcx> {
 
     /// `T1 <: T2`
     Subtype(PolySubtypePredicate<'tcx>),
+
+    /// Constant initializer must evaluate successfully.
+    ConstEvaluatable(DefId, &'tcx Substs<'tcx>),
 }
 
 impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
@@ -938,6 +941,8 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
                 Predicate::ObjectSafe(trait_def_id),
             Predicate::ClosureKind(closure_def_id, kind) =>
                 Predicate::ClosureKind(closure_def_id, kind),
+            Predicate::ConstEvaluatable(def_id, const_substs) =>
+                Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)),
         }
     }
 }
@@ -1120,6 +1125,9 @@ impl<'tcx> Predicate<'tcx> {
             ty::Predicate::ClosureKind(_closure_def_id, _kind) => {
                 vec![]
             }
+            ty::Predicate::ConstEvaluatable(_, substs) => {
+                substs.types().collect()
+            }
         };
 
         // The only reason to collect into a vector here is that I was
@@ -1142,7 +1150,8 @@ impl<'tcx> Predicate<'tcx> {
             Predicate::WellFormed(..) |
             Predicate::ObjectSafe(..) |
             Predicate::ClosureKind(..) |
-            Predicate::TypeOutlives(..) => {
+            Predicate::TypeOutlives(..) |
+            Predicate::ConstEvaluatable(..) => {
                 None
             }
         }
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index eb465ed16a264..309880ba06333 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -14,9 +14,12 @@
 //! type equality, etc.
 
 use hir::def_id::DefId;
+use middle::const_val::ConstVal;
+use traits::Reveal;
 use ty::subst::{Kind, Substs};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::error::{ExpectedFound, TypeError};
+use util::common::ErrorReported;
 use std::rc::Rc;
 use std::iter;
 use syntax::abi;
@@ -430,12 +433,43 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
             let t = relation.relate(&a_t, &b_t)?;
             assert_eq!(sz_a.ty, tcx.types.usize);
             assert_eq!(sz_b.ty, tcx.types.usize);
-            let sz_a_u64 = sz_a.val.to_const_int().unwrap().to_u64().unwrap();
-            let sz_b_u64 = sz_b.val.to_const_int().unwrap().to_u64().unwrap();
-            if sz_a_u64 == sz_b_u64 {
-                Ok(tcx.mk_ty(ty::TyArray(t, sz_a)))
-            } else {
-                Err(TypeError::FixedArraySize(expected_found(relation, &sz_a_u64, &sz_b_u64)))
+            let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
+                match x.val {
+                    ConstVal::Integral(x) => Ok(x.to_u64().unwrap()),
+                    ConstVal::Unevaluated(def_id, substs) => {
+                        // FIXME(eddyb) get the right param_env.
+                        let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
+                        match tcx.lift_to_global(&substs) {
+                            Some(substs) => {
+                                match tcx.const_eval(param_env.and((def_id, substs))) {
+                                    Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => {
+                                        return Ok(x.to_u64().unwrap());
+                                    }
+                                    _ => {}
+                                }
+                            }
+                            None => {}
+                        }
+                        tcx.sess.delay_span_bug(tcx.def_span(def_id),
+                            "array length could not be evaluated");
+                        Err(ErrorReported)
+                    }
+                    _ => bug!("arrays should not have {:?} as length", x)
+                }
+            };
+            match (to_u64(sz_a), to_u64(sz_b)) {
+                (Ok(sz_a_u64), Ok(sz_b_u64)) => {
+                    if sz_a_u64 == sz_b_u64 {
+                        Ok(tcx.mk_ty(ty::TyArray(t, sz_a)))
+                    } else {
+                        Err(TypeError::FixedArraySize(
+                            expected_found(relation, &sz_a_u64, &sz_b_u64)))
+                    }
+                }
+                // We reported an error or will ICE, so we can return TyError.
+                (Err(ErrorReported), _) | (_, Err(ErrorReported)) => {
+                    Ok(tcx.types.err)
+                }
             }
         }
 
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 758edd7d0c3bc..54d55748c8e3a 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use infer::type_variable;
-use middle::const_val::{ConstVal, ConstAggregate};
+use middle::const_val::{self, ConstVal, ConstAggregate, ConstEvalErr};
 use ty::{self, Lift, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
@@ -59,6 +59,13 @@ impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result<T, E> {
     }
 }
 
+impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box<T> {
+    type Lifted = Box<T::Lifted>;
+    fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&**self).map(Box::new)
+    }
+}
+
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] {
     type Lifted = Vec<T::Lifted>;
     fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
@@ -210,6 +217,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> {
             ty::Predicate::ObjectSafe(trait_def_id) => {
                 Some(ty::Predicate::ObjectSafe(trait_def_id))
             }
+            ty::Predicate::ConstEvaluatable(def_id, substs) => {
+                tcx.lift(&substs).map(|substs| {
+                    ty::Predicate::ConstEvaluatable(def_id, substs)
+                })
+            }
         }
     }
 }
@@ -221,6 +233,32 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
+    type Lifted = ty::ParamEnv<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.caller_bounds).map(|caller_bounds| {
+            ty::ParamEnv {
+                reveal: self.reveal,
+                caller_bounds,
+            }
+        })
+    }
+}
+
+impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::ParamEnvAnd<'a, T> {
+    type Lifted = ty::ParamEnvAnd<'tcx, T::Lifted>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.param_env).and_then(|param_env| {
+            tcx.lift(&self.value).map(|value| {
+                ty::ParamEnvAnd {
+                    param_env,
+                    value,
+                }
+            })
+        })
+    }
+}
+
 impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> {
     type Lifted = ty::ClosureSubsts<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
@@ -395,6 +433,64 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> {
+    type Lifted = ConstEvalErr<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.kind).map(|kind| {
+            ConstEvalErr {
+                span: self.span,
+                kind,
+            }
+        })
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> {
+    type Lifted = const_val::ErrKind<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        use middle::const_val::ErrKind::*;
+
+        Some(match *self {
+            CannotCast => CannotCast,
+            MissingStructField => MissingStructField,
+            NonConstPath => NonConstPath,
+            UnimplementedConstVal(s) => UnimplementedConstVal(s),
+            ExpectedConstTuple => ExpectedConstTuple,
+            ExpectedConstStruct => ExpectedConstStruct,
+            IndexedNonVec => IndexedNonVec,
+            IndexNotUsize => IndexNotUsize,
+            IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index },
+            MiscBinaryOp => MiscBinaryOp,
+            MiscCatchAll => MiscCatchAll,
+            IndexOpFeatureGated => IndexOpFeatureGated,
+            Math(ref e) => Math(e.clone()),
+
+            LayoutError(ref e) => {
+                return tcx.lift(e).map(LayoutError)
+            }
+            ErroneousReferencedConstant(ref e) => {
+                return tcx.lift(e).map(ErroneousReferencedConstant)
+            }
+
+            TypeckError => TypeckError,
+        })
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for ty::layout::LayoutError<'a> {
+    type Lifted = ty::layout::LayoutError<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        match *self {
+            ty::layout::LayoutError::Unknown(ref ty) => {
+                tcx.lift(ty).map(ty::layout::LayoutError::Unknown)
+            }
+            ty::layout::LayoutError::SizeOverflow(ref ty) => {
+                tcx.lift(ty).map(ty::layout::LayoutError::SizeOverflow)
+            }
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // TypeFoldable implementations.
 //
@@ -409,6 +505,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
 macro_rules! CopyImpls {
     ($($ty:ty),+) => {
         $(
+            impl<'tcx> Lift<'tcx> for $ty {
+                type Lifted = Self;
+                fn lift_to_tcx<'a, 'gcx>(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self> {
+                    Some(*self)
+                }
+            }
+
             impl<'tcx> TypeFoldable<'tcx> for $ty {
                 fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> $ty {
                     *self
@@ -866,6 +969,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
                 ty::Predicate::ClosureKind(closure_def_id, kind),
             ty::Predicate::ObjectSafe(trait_def_id) =>
                 ty::Predicate::ObjectSafe(trait_def_id),
+            ty::Predicate::ConstEvaluatable(def_id, substs) =>
+                ty::Predicate::ConstEvaluatable(def_id, substs.fold_with(folder)),
         }
     }
 
@@ -880,6 +985,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
             ty::Predicate::WellFormed(data) => data.visit_with(visitor),
             ty::Predicate::ClosureKind(_closure_def_id, _kind) => false,
             ty::Predicate::ObjectSafe(_trait_def_id) => false,
+            ty::Predicate::ConstEvaluatable(_def_id, substs) => substs.visit_with(visitor),
         }
     }
 }
@@ -1153,6 +1259,9 @@ impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> {
                 let v = v.fold_with(folder);
                 ConstVal::Aggregate(ConstAggregate::Repeat(v, count))
             }
+            ConstVal::Unevaluated(def_id, substs) => {
+                ConstVal::Unevaluated(def_id, substs.fold_with(folder))
+            }
         }
     }
 
@@ -1176,6 +1285,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> {
             ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
                 v.visit_with(visitor)
             }
+            ConstVal::Unevaluated(_, substs) => substs.visit_with(visitor),
         }
     }
 }
@@ -1190,7 +1300,15 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
         })
     }
 
+    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        folder.fold_const(*self)
+    }
+
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         self.ty.visit_with(visitor) || self.val.visit_with(visitor)
     }
+
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        visitor.visit_const(self)
+    }
 }
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 95618717e0ea3..16ae3cdbf1796 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -13,6 +13,7 @@
 use hir::def_id::{DefId, LOCAL_CRATE};
 use hir::map::DefPathData;
 use ich::{StableHashingContext, NodeIdHashingMode};
+use middle::const_val::ConstVal;
 use traits::{self, Reveal};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::fold::TypeVisitor;
@@ -388,7 +389,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     ty::Predicate::WellFormed(..) |
                     ty::Predicate::ObjectSafe(..) |
                     ty::Predicate::ClosureKind(..) |
-                    ty::Predicate::RegionOutlives(..) => {
+                    ty::Predicate::RegionOutlives(..) |
+                    ty::Predicate::ConstEvaluatable(..) => {
                         None
                     }
                     ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => {
@@ -698,7 +700,12 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
             TyUint(u) => self.hash(u),
             TyFloat(f) => self.hash(f),
             TyArray(_, n) => {
-                self.hash(n.val.to_const_int().unwrap().to_u64().unwrap())
+                self.hash_discriminant_u8(&n.val);
+                match n.val {
+                    ConstVal::Integral(x) => self.hash(x.to_u64().unwrap()),
+                    ConstVal::Unevaluated(def_id, _) => self.def_id(def_id),
+                    _ => bug!("arrays should not have {:?} as length", n)
+                }
             }
             TyRawPtr(m) |
             TyRef(_, m) => self.hash(m.mutbl),
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index 4d7eb37ca26ed..df07844ccebaf 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -160,6 +160,9 @@ fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const
         ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
             push_const(stack, v);
         }
+        ConstVal::Unevaluated(_, substs) => {
+            stack.extend(substs.types().rev());
+        }
     }
     stack.push(constant.ty);
 }
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 4d2b15b6bf069..41e27fca3f320 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use hir::def_id::DefId;
+use middle::const_val::{ConstVal, ConstAggregate};
 use infer::InferCtxt;
 use ty::subst::Substs;
 use traits;
@@ -101,6 +102,14 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
             wf.compute(data.skip_binder().a); // (*)
             wf.compute(data.skip_binder().b); // (*)
         }
+        ty::Predicate::ConstEvaluatable(def_id, substs) => {
+            let obligations = wf.nominal_obligations(def_id, substs);
+            wf.out.extend(obligations);
+
+            for ty in substs.types() {
+                wf.compute(ty);
+            }
+        }
     }
 
     wf.normalize()
@@ -209,7 +218,43 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
 
     /// Pushes the obligations required for a constant value to be WF
     /// into `self.out`.
-    fn compute_const(&mut self, _constant: &'tcx ty::Const<'tcx>) {}
+    fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) {
+        self.require_sized(constant.ty, traits::ConstSized);
+        match constant.val {
+            ConstVal::Integral(_) |
+            ConstVal::Float(_) |
+            ConstVal::Str(_) |
+            ConstVal::ByteStr(_) |
+            ConstVal::Bool(_) |
+            ConstVal::Char(_) |
+            ConstVal::Variant(_) |
+            ConstVal::Function(..) => {}
+            ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
+                for &(_, v) in fields {
+                    self.compute_const(v);
+                }
+            }
+            ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
+            ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
+                for v in fields {
+                    self.compute_const(v);
+                }
+            }
+            ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
+                self.compute_const(v);
+            }
+            ConstVal::Unevaluated(def_id, substs) => {
+                let obligations = self.nominal_obligations(def_id, substs);
+                self.out.extend(obligations);
+
+                let predicate = ty::Predicate::ConstEvaluatable(def_id, substs);
+                let cause = self.cause(traits::MiscObligation);
+                self.out.push(traits::Obligation::new(cause,
+                                                      self.param_env,
+                                                      predicate));
+            }
+        }
+    }
 
     fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
         if !subty.has_escaping_regions() {
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 6b74022806cf5..cf7a29d2845ac 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -430,6 +430,9 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
             ty::Predicate::ClosureKind(closure_def_id, kind) => {
                 write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind)
             }
+            ty::Predicate::ConstEvaluatable(def_id, substs) => {
+                write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
+            }
         }
     }
 }
@@ -894,6 +897,9 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                     ConstVal::Integral(ConstInt::Usize(sz)) => {
                         write!(f, "{}", sz)?;
                     }
+                    ConstVal::Unevaluated(_def_id, substs) => {
+                        write!(f, "<unevaluated{:?}>", &substs[..])?;
+                    }
                     _ => {
                         write!(f, "{:?}", sz)?;
                     }
@@ -1048,6 +1054,11 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> {
                     write!(f, "the closure `{}` implements the trait `{}`",
                            tcx.item_path_str(closure_def_id), kind)
                 }),
+            ty::Predicate::ConstEvaluatable(def_id, substs) => {
+                write!(f, "the constant `")?;
+                parameterized(f, substs, def_id, &[])?;
+                write!(f, "` can be evaluated")
+            }
         }
     }
 }
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index efe6cfb5464ef..b836b71e74bf6 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -415,14 +415,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                 }))
             }).collect()
         }
-        ty::TySlice(ref sub_ty) => {
-            if cx.is_uninhabited(sub_ty) {
-                vec![Slice(0)]
-            } else {
-                (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect()
-            }
-        }
-        ty::TyArray(ref sub_ty, len) => {
+        ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => {
             let len = len.val.to_const_int().unwrap().to_u64().unwrap();
             if len != 0 && cx.is_uninhabited(sub_ty) {
                 vec![]
@@ -430,6 +423,15 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                 vec![Slice(len)]
             }
         }
+        // Treat arrays of a constant but unknown length like slices.
+        ty::TyArray(ref sub_ty, _) |
+        ty::TySlice(ref sub_ty) => {
+            if cx.is_uninhabited(sub_ty) {
+                vec![Slice(0)]
+            } else {
+                (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect()
+            }
+        }
         ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => {
             def.variants.iter()
                 .filter(|v| !cx.is_variant_uninhabited(v, substs))
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 1ad00a9e7b34e..61eb5dfd18b9c 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -334,7 +334,8 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
 
           if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic {
             let layout_of = |ty: Ty<'tcx>| {
-                ty.layout(tcx, cx.param_env).map_err(|err| {
+                let ty = tcx.erase_regions(&ty);
+                tcx.at(e.span).layout_raw(cx.param_env.reveal_all().and(ty)).map_err(|err| {
                     ConstEvalErr { span: e.span, kind: LayoutError(err) }
                 })
             };
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 0a2e78dd51a35..a87fa0c2746a3 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -117,7 +117,8 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
         ConstVal::Char(c) => write!(f, "{:?}", c),
         ConstVal::Variant(_) |
         ConstVal::Function(..) |
-        ConstVal::Aggregate(_) => bug!("{:?} not printable in a pattern", value)
+        ConstVal::Aggregate(_) |
+        ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
     }
 }
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 3b07177b1b5c8..c96615064c80b 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1521,9 +1521,16 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
     }
 
     fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
-        if let hir::TyImplTrait(_) = ty.node {
-            let def_id = self.tcx.hir.local_def_id(ty.id);
-            self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id);
+        match ty.node {
+            hir::TyImplTrait(_) => {
+                let def_id = self.tcx.hir.local_def_id(ty.id);
+                self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id);
+            }
+            hir::TyArray(_, len) => {
+                let def_id = self.tcx.hir.body_owner_def_id(len);
+                self.record(def_id, IsolatedEncoder::encode_info_for_embedded_const, def_id);
+            }
+            _ => {}
         }
     }
 
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 072d351dd617a..6e975941e8e89 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -103,7 +103,8 @@ impl<'tcx> Const<'tcx> {
             ConstVal::Char(c) => C_uint(Type::char(ccx), c as u64),
             ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)),
             ConstVal::Variant(_) |
-            ConstVal::Aggregate(..) => {
+            ConstVal::Aggregate(..) |
+            ConstVal::Unevaluated(..) => {
                 bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv)
             }
         };
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 6759b6a422d09..8f8663385b020 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -12,7 +12,7 @@
 //! representation.  The main routine here is `ast_ty_to_ty()`: each use
 //! is parameterized by an instance of `AstConv`.
 
-use rustc::middle::const_val::eval_length;
+use rustc::middle::const_val::ConstVal;
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 use hir;
 use hir::def::Def;
@@ -1082,11 +1082,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
             }
             hir::TyArray(ref ty, length) => {
-                if let Ok(length) = eval_length(tcx, length, "array length") {
-                    tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length))
-                } else {
-                    self.tcx().types.err
-                }
+                let length_def_id = tcx.hir.body_owner_def_id(length);
+                let substs = Substs::identity_for_item(tcx, length_def_id);
+                let length = tcx.mk_const(ty::Const {
+                    val: ConstVal::Unevaluated(length_def_id, substs),
+                    ty: tcx.types.usize
+                });
+                let array_ty = tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length));
+                self.normalize_ty(ast_ty.span, array_ty)
             }
             hir::TyTypeof(ref _e) => {
                 struct_span_err!(tcx.sess, ast_ty.span, E0516,
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index aa2b9c1e03815..07159770d5ba2 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -192,6 +192,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     ty::Predicate::TypeOutlives(..) => None,
                     ty::Predicate::WellFormed(..) => None,
                     ty::Predicate::ObjectSafe(..) => None,
+                    ty::Predicate::ConstEvaluatable(..) => None,
 
                     // NB: This predicate is created by breaking down a
                     // `ClosureType: FnFoo()` predicate, where
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 3771d330f6dd3..7b94781832512 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -590,7 +590,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                     ty::Predicate::WellFormed(..) |
                     ty::Predicate::ObjectSafe(..) |
                     ty::Predicate::ClosureKind(..) |
-                    ty::Predicate::TypeOutlives(..) => None,
+                    ty::Predicate::TypeOutlives(..) |
+                    ty::Predicate::ConstEvaluatable(..) => None,
                 }
             })
             .collect();
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0ed3cc1e905cb..ae2430990ba57 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -128,7 +128,6 @@ use rustc::hir::map::Node;
 use rustc::hir::{self, PatKind};
 use rustc::middle::lang_items;
 use rustc_back::slice;
-use rustc::middle::const_val::eval_length;
 use rustc_const_math::ConstInt;
 
 mod autoderef;
@@ -3898,7 +3897,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               tcx.mk_array(element_ty, args.len() as u64)
           }
           hir::ExprRepeat(ref element, count) => {
-            let count = eval_length(self.tcx, count, "repeat count");
+            let count_def_id = tcx.hir.body_owner_def_id(count);
+            let param_env = ty::ParamEnv::empty(traits::Reveal::UserFacing);
+            let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
+            let count = tcx.const_eval(param_env.and((count_def_id, substs)));
+
+            if let Err(ref err) = count {
+               err.report(tcx, tcx.def_span(count_def_id), "constant expression");
+            }
 
             let uty = match expected {
                 ExpectHasType(uty) => {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index d475c37ed8c94..609af638e97c6 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -511,7 +511,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                             ty::Predicate::Subtype(..) |
                             ty::Predicate::Projection(..) |
                             ty::Predicate::ClosureKind(..) |
-                            ty::Predicate::ObjectSafe(..) =>
+                            ty::Predicate::ObjectSafe(..) |
+                            ty::Predicate::ConstEvaluatable(..) =>
                                 vec![],
 
                             ty::Predicate::WellFormed(subty) => {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 69c05050dacc9..ce3bf896256ec 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -33,6 +33,7 @@ use rustc::middle::resolve_lifetime as rl;
 use rustc::middle::lang_items;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc::traits::Reveal;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, AdtKind};
 use rustc::middle::stability;
@@ -936,6 +937,7 @@ impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
             Predicate::WellFormed(_) => panic!("not user writable"),
             Predicate::ObjectSafe(_) => panic!("not user writable"),
             Predicate::ClosureKind(..) => panic!("not user writable"),
+            Predicate::ConstEvaluatable(..) => panic!("not user writable"),
         }
     }
 }
@@ -1784,9 +1786,11 @@ impl Clean<Type> for hir::Ty {
                              type_: box m.ty.clean(cx)}
             }
             TySlice(ref ty) => Slice(box ty.clean(cx)),
-            TyArray(ref ty, length) => {
-                use rustc::middle::const_val::eval_length;
-                let n = eval_length(cx.tcx, length, "array length").unwrap();
+            TyArray(ref ty, n) => {
+                let def_id = cx.tcx.hir.body_owner_def_id(n);
+                let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
+                let substs = Substs::identity_for_item(cx.tcx, def_id);
+                let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap();
                 let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
                     n.to_string()
                 } else {
diff --git a/src/test/compile-fail/const-block-non-item-statement-3.rs b/src/test/compile-fail/const-block-non-item-statement-3.rs
new file mode 100644
index 0000000000000..707037911015c
--- /dev/null
+++ b/src/test/compile-fail/const-block-non-item-statement-3.rs
@@ -0,0 +1,15 @@
+// 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.
+
+type Array = [u32; {  let x = 2; 5 }];
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+//~^^ ERROR: blocks in constants are limited to items and tail expressions
+
+pub fn main() {}
diff --git a/src/test/compile-fail/const-block-non-item-statement.rs b/src/test/compile-fail/const-block-non-item-statement.rs
index bdc69c937c637..802e660b9048d 100644
--- a/src/test/compile-fail/const-block-non-item-statement.rs
+++ b/src/test/compile-fail/const-block-non-item-statement.rs
@@ -14,8 +14,4 @@ enum Foo {
     //~^^ ERROR: blocks in constants are limited to items and tail expressions
 }
 
-type Array = [u32; {  let x = 2; 5 }];
-//~^ ERROR: blocks in constants are limited to items and tail expressions
-//~^^ ERROR: blocks in constants are limited to items and tail expressions
-
 pub fn main() {}
diff --git a/src/test/compile-fail/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs
index dd0f058f2c95c..385daef44dfe5 100644
--- a/src/test/compile-fail/const-fn-error.rs
+++ b/src/test/compile-fail/const-fn-error.rs
@@ -23,5 +23,5 @@ const fn f(x: usize) -> usize {
 
 #[allow(unused_variables)]
 fn main() {
-    let a : [i32; f(X)]; //~ NOTE for array length here
+    let a : [i32; f(X)]; //~ NOTE for constant expression here
 }
diff --git a/src/test/compile-fail/const-len-underflow-separate-spans.rs b/src/test/compile-fail/const-len-underflow-separate-spans.rs
index c01bb82676304..3c84810554214 100644
--- a/src/test/compile-fail/const-len-underflow-separate-spans.rs
+++ b/src/test/compile-fail/const-len-underflow-separate-spans.rs
@@ -20,5 +20,5 @@ const LEN: usize = ONE - TWO;
 
 fn main() {
     let a: [i8; LEN] = unimplemented!();
-    //~^ NOTE for array length here
+    //~^ NOTE for constant expression here
 }
diff --git a/src/test/compile-fail/const-size_of-cycle.rs b/src/test/compile-fail/const-size_of-cycle.rs
index a58be33b1ae6c..cbeafdfe6acc9 100644
--- a/src/test/compile-fail/const-size_of-cycle.rs
+++ b/src/test/compile-fail/const-size_of-cycle.rs
@@ -8,11 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// error-pattern: unsupported cyclic reference between types/traits detected
+
 #![feature(const_fn)]
 
 struct Foo {
     bytes: [u8; std::mem::size_of::<Foo>()]
-    //~^ ERROR unsupported cyclic reference between types/traits detected
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-22933-2.rs b/src/test/compile-fail/issue-22933-2.rs
index c78e1f7f53095..97456c2da87fe 100644
--- a/src/test/compile-fail/issue-22933-2.rs
+++ b/src/test/compile-fail/issue-22933-2.rs
@@ -15,7 +15,4 @@ enum Delicious {
     //~^ ERROR no associated item named `PIE` found for type `Delicious`
 }
 
-const FOO: [u32; u8::MIN as usize] = [];
-//~^ ERROR no associated item named `MIN` found for type `u8`
-
 fn main() {}
diff --git a/src/test/compile-fail/issue-22933-3.rs b/src/test/compile-fail/issue-22933-3.rs
new file mode 100644
index 0000000000000..62adae41adfc8
--- /dev/null
+++ b/src/test/compile-fail/issue-22933-3.rs
@@ -0,0 +1,14 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const FOO: [u32; u8::MIN as usize] = [];
+//~^ ERROR no associated item named `MIN` found for type `u8`
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-39559.rs b/src/test/compile-fail/issue-39559.rs
index 8bc1cc7bd1ace..2da21fb14bd3c 100644
--- a/src/test/compile-fail/issue-39559.rs
+++ b/src/test/compile-fail/issue-39559.rs
@@ -21,8 +21,9 @@ impl Dim for Dim3 {
 }
 
 pub struct Vector<T, D: Dim> {
-    entries: [T; D::dim()]
+    entries: [T; D::dim()],
     //~^ ERROR no function or associated item named `dim` found for type `D` in the current scope
+    _dummy: D,
 }
 
 fn main() {}
diff --git a/src/test/ui/issue-38875/issue_38875.stderr b/src/test/ui/issue-38875/issue_38875.stderr
index 10bb61ee22a61..d49741f25b9f5 100644
--- a/src/test/ui/issue-38875/issue_38875.stderr
+++ b/src/test/ui/issue-38875/issue_38875.stderr
@@ -4,7 +4,7 @@ error[E0080]: constant evaluation error
 11 | pub const FOO: usize = *&0;
    |                        ^^^ unimplemented constant expression: deref operation
    |
-note: for repeat count here
+note: for constant expression here
   --> $DIR/issue_38875.rs:16:22
    |
 16 |     let test_x = [0; issue_38875_b::FOO];

From 57ebd28fdb69d7cc4df3de343664e6698a4b55f0 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Sun, 3 Sep 2017 20:34:48 +0300
Subject: [PATCH 7/7] rustc: use ConstVal::Unevaluated instead of
 mir::Literal::Item.

---
 src/librustc/ich/impls_mir.rs                |  4 ----
 src/librustc/mir/mod.rs                      | 18 +++++-----------
 src/librustc/mir/visit.rs                    |  5 -----
 src/librustc_mir/hair/cx/expr.rs             |  8 ++++---
 src/librustc_mir/transform/qualify_consts.rs |  9 +++++---
 src/librustc_passes/mir_stats.rs             |  1 -
 src/librustc_trans/collector.rs              | 16 +++++---------
 src/librustc_trans/mir/constant.rs           | 22 +++++++++++---------
 8 files changed, 33 insertions(+), 50 deletions(-)

diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index 9a061da177eba..dce1639b375b7 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -493,10 +493,6 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::L
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
-            mir::Literal::Item { def_id, substs } => {
-                def_id.hash_stable(hcx, hasher);
-                substs.hash_stable(hcx, hasher);
-            }
             mir::Literal::Value { ref value } => {
                 value.hash_stable(hcx, hasher);
             }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index d9ca5ddf46b05..38dfe010c153c 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1479,10 +1479,6 @@ newtype_index!(Promoted, "promoted");
 
 #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum Literal<'tcx> {
-    Item {
-        def_id: DefId,
-        substs: &'tcx Substs<'tcx>,
-    },
     Value {
         value: &'tcx ty::Const<'tcx>,
     },
@@ -1502,9 +1498,6 @@ impl<'tcx> Debug for Literal<'tcx> {
     fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
         use self::Literal::*;
         match *self {
-            Item { def_id, substs } => {
-                ppaux::parameterized(fmt, substs, def_id, &[])
-            }
             Value { value } => {
                 write!(fmt, "const ")?;
                 fmt_const_val(fmt, &value.val)
@@ -2002,17 +1995,16 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
 impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
-            Literal::Item { def_id, substs } => Literal::Item {
-                def_id,
-                substs: substs.fold_with(folder)
+            Literal::Value { value } => Literal::Value {
+                value: value.fold_with(folder)
             },
-            _ => self.clone()
+            Literal::Promoted { index } => Literal::Promoted { index }
         }
     }
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         match *self {
-            Literal::Item { substs, .. } => substs.visit_with(visitor),
-            _ => false
+            Literal::Value { value } => value.visit_with(visitor),
+            Literal::Promoted { .. } => false
         }
     }
 }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 22d93c1a27650..37c97ad3dad90 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -724,11 +724,6 @@ macro_rules! make_mir_visitor {
                              literal: & $($mutability)* Literal<'tcx>,
                              location: Location) {
                 match *literal {
-                    Literal::Item { ref $($mutability)* def_id,
-                                    ref $($mutability)* substs } => {
-                        self.visit_def_id(def_id, location);
-                        self.visit_substs(substs, location);
-                    }
                     Literal::Value { ref $($mutability)* value } => {
                         self.visit_const(value, location);
                     }
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 23e6fbd2b7e23..45449103c8083 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -643,9 +643,11 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
         Def::Const(def_id) |
         Def::AssociatedConst(def_id) => ExprKind::Literal {
-            literal: Literal::Item {
-                def_id,
-                substs,
+            literal: Literal::Value {
+                value: cx.tcx.mk_const(ty::Const {
+                    val: ConstVal::Unevaluated(def_id, substs),
+                    ty: cx.tables().node_id_to_type(expr.hir_id)
+                }),
             },
         },
 
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 2267e611531f3..5550fb2788eaf 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -20,6 +20,7 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use rustc::hir;
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
+use rustc::middle::const_val::ConstVal;
 use rustc::traits::{self, Reveal};
 use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
 use rustc::ty::cast::CastTy;
@@ -622,10 +623,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                 }
             }
             Operand::Constant(ref constant) => {
-                if let Literal::Item { def_id, substs: _ } = constant.literal {
+                if let Literal::Value {
+                    value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty }
+                } = constant.literal {
                     // Don't peek inside trait associated constants.
                     if self.tcx.trait_of_item(def_id).is_some() {
-                        self.add_type(constant.ty);
+                        self.add_type(ty);
                     } else {
                         let (bits, _) = self.tcx.at(constant.span).mir_const_qualif(def_id);
 
@@ -635,7 +638,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                         // Just in case the type is more specific than
                         // the definition, e.g. impl associated const
                         // with type parameters, take it into account.
-                        self.qualif.restrict(constant.ty, self.tcx, self.param_env);
+                        self.qualif.restrict(ty, self.tcx, self.param_env);
                     }
 
                     // Let `const fn` transitively have destructors,
diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs
index 91203a91be51d..1fa49614580a3 100644
--- a/src/librustc_passes/mir_stats.rs
+++ b/src/librustc_passes/mir_stats.rs
@@ -235,7 +235,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
                      location: Location) {
         self.record("Literal", literal);
         self.record(match *literal {
-            Literal::Item { .. } => "Literal::Item",
             Literal::Value { .. } => "Literal::Value",
             Literal::Promoted { .. } => "Literal::Promoted",
         }, literal);
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index b56fa34e348e5..3bf709ff7ba9d 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -193,6 +193,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::middle::lang_items::{ExchangeMallocFnLangItem};
 use rustc::traits;
 use rustc::ty::subst::Substs;
@@ -564,24 +565,17 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
         self.super_rvalue(rvalue, location);
     }
 
-    fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) {
-        debug!("visiting constant {:?} @ {:?}", *constant, location);
+    fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
+        debug!("visiting const {:?} @ {:?}", *constant, location);
 
-        if let ty::TyFnDef(..) = constant.ty.sty {
-            // function definitions are zero-sized, and only generate
-            // IR when they are called/reified.
-            self.super_constant(constant, location);
-            return
-        }
-
-        if let mir::Literal::Item { def_id, substs } = constant.literal {
+        if let ConstVal::Unevaluated(def_id, substs) = constant.val {
             let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs,
                                                                  &substs);
             let instance = monomorphize::resolve(self.scx, def_id, substs);
             collect_neighbours(self.scx, instance, true, self.output);
         }
 
-        self.super_constant(constant, location);
+        self.super_const(constant);
     }
 
     fn visit_terminator_kind(&mut self,
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 6e975941e8e89..4c3326a466d3a 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -510,16 +510,17 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
             mir::Operand::Constant(ref constant) => {
                 let ty = self.monomorphize(&constant.ty);
                 match constant.literal.clone() {
-                    mir::Literal::Item { def_id, substs } => {
-                        let substs = self.monomorphize(&substs);
-                        MirConstContext::trans_def(self.ccx, def_id, substs, IndexVec::new())
-                    }
                     mir::Literal::Promoted { index } => {
                         let mir = &self.mir.promoted[index];
                         MirConstContext::new(self.ccx, mir, self.substs, IndexVec::new()).trans()
                     }
                     mir::Literal::Value { value } => {
-                        Ok(Const::from_constval(self.ccx, &value.val, ty))
+                        if let ConstVal::Unevaluated(def_id, substs) = value.val {
+                            let substs = self.monomorphize(&substs);
+                            MirConstContext::trans_def(self.ccx, def_id, substs, IndexVec::new())
+                        } else {
+                            Ok(Const::from_constval(self.ccx, &value.val, ty))
+                        }
                     }
                 }
             }
@@ -960,16 +961,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
         debug!("trans_constant({:?})", constant);
         let ty = self.monomorphize(&constant.ty);
         let result = match constant.literal.clone() {
-            mir::Literal::Item { def_id, substs } => {
-                let substs = self.monomorphize(&substs);
-                MirConstContext::trans_def(bcx.ccx, def_id, substs, IndexVec::new())
-            }
             mir::Literal::Promoted { index } => {
                 let mir = &self.mir.promoted[index];
                 MirConstContext::new(bcx.ccx, mir, self.param_substs, IndexVec::new()).trans()
             }
             mir::Literal::Value { value } => {
-                Ok(Const::from_constval(bcx.ccx, &value.val, ty))
+                if let ConstVal::Unevaluated(def_id, substs) = value.val {
+                    let substs = self.monomorphize(&substs);
+                    MirConstContext::trans_def(bcx.ccx, def_id, substs, IndexVec::new())
+                } else {
+                    Ok(Const::from_constval(bcx.ccx, &value.val, ty))
+                }
             }
         };