about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-03-14 11:38:23 -0700
committerbors <bors@rust-lang.org>2016-03-14 11:38:23 -0700
commit01118928fc2b280e96189ed394af749d65cbcffe (patch)
treeadbe12b4955b12035e86ca81a1735766a4b1e3b2
parentd19f1b629918a556709e6b89a1929305db6449dc (diff)
parentf665c399a013ce27991fafb2203a5420e75f9cfc (diff)
downloadrust-01118928fc2b280e96189ed394af749d65cbcffe.tar.gz
rust-01118928fc2b280e96189ed394af749d65cbcffe.zip
Auto merge of #30587 - oli-obk:eager_const_eval2, r=nikomatsakis
typestrong const integers

~~It would be great if someone could run crater on this PR, as this has a high danger of breaking valid code~~ Crater ran. Good to go.

----

So this PR does a few things:

1. ~~const eval array values when const evaluating an array expression~~
2. ~~const eval repeat value when const evaluating a repeat expression~~
3. ~~const eval all struct and tuple fields when evaluating a struct/tuple expression~~
4. remove the `ConstVal::Int` and `ConstVal::Uint` variants and replace them with a single enum (`ConstInt`) which has variants for all integral types
  * `usize`/`isize` are also enums with variants for 32 and 64 bit. At creation and various usage steps there are assertions in place checking if the target bitwidth matches with the chosen enum variant
5. enum discriminants (`ty::Disr`) are now `ConstInt`
6. trans has its own `Disr` type now (newtype around `u64`)

This obviously can't be done without breaking changes (the ones that are noticable in stable)
We could probably write lints that find those situations and error on it for a cycle or two. But then again, those situations are rare and really bugs imo anyway:

```rust
let v10 = 10 as i8;
let v4 = 4 as isize;
assert_eq!(v10 << v4 as usize, 160 as i8);
 ```

stops compiling because 160 is not a valid i8

```rust
struct S<T, S> {
    a: T,
    b: u8,
    c: S
}
let s = S { a: 0xff_ff_ff_ffu32, b: 1, c: 0xaa_aa_aa_aa as i32 };
```

stops compiling because `0xaa_aa_aa_aa` is not a valid i32

----

cc @eddyb @pnkfelix

related: https://github.com/rust-lang/rfcs/issues/1071
-rw-r--r--mk/crates.mk16
-rw-r--r--src/librustc/Cargo.toml1
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/middle/check_match.rs2
-rw-r--r--src/librustc/middle/const_eval.rs948
-rw-r--r--src/librustc/middle/ty/context.rs8
-rw-r--r--src/librustc/middle/ty/mod.rs7
-rw-r--r--src/librustc/middle/ty/util.rs171
-rw-r--r--src/librustc/mir/repr.rs11
-rw-r--r--src/librustc/mir/tcx.rs11
-rw-r--r--src/librustc_const_eval/Cargo.toml14
-rw-r--r--src/librustc_const_eval/err.rs85
-rw-r--r--src/librustc_const_eval/int.rs569
-rw-r--r--src/librustc_const_eval/is.rs39
-rw-r--r--src/librustc_const_eval/lib.rs42
-rw-r--r--src/librustc_const_eval/us.rs39
-rw-r--r--src/librustc_lint/types.rs7
-rw-r--r--src/librustc_metadata/Cargo.toml1
-rw-r--r--src/librustc_metadata/decoder.rs8
-rw-r--r--src/librustc_metadata/encoder.rs21
-rw-r--r--src/librustc_metadata/lib.rs1
-rw-r--r--src/librustc_mir/Cargo.toml1
-rw-r--r--src/librustc_mir/build/matches/mod.rs2
-rw-r--r--src/librustc_mir/build/matches/test.rs2
-rw-r--r--src/librustc_mir/build/misc.rs2
-rw-r--r--src/librustc_mir/build/scope.rs6
-rw-r--r--src/librustc_mir/hair/cx/expr.rs41
-rw-r--r--src/librustc_mir/hair/cx/mod.rs8
-rw-r--r--src/librustc_mir/hair/cx/pattern.rs2
-rw-r--r--src/librustc_mir/lib.rs1
-rw-r--r--src/librustc_passes/consts.rs2
-rw-r--r--src/librustc_trans/Cargo.toml1
-rw-r--r--src/librustc_trans/lib.rs1
-rw-r--r--src/librustc_trans/trans/adt.rs2
-rw-r--r--src/librustc_trans/trans/consts.rs146
-rw-r--r--src/librustc_trans/trans/debuginfo/metadata.rs2
-rw-r--r--src/librustc_trans/trans/disr.rs2
-rw-r--r--src/librustc_trans/trans/mir/constant.rs26
-rw-r--r--src/librustc_trans/trans/mir/rvalue.rs5
-rw-r--r--src/librustc_typeck/Cargo.toml1
-rw-r--r--src/librustc_typeck/astconv.rs28
-rw-r--r--src/librustc_typeck/check/mod.rs52
-rw-r--r--src/librustc_typeck/collect.rs71
-rw-r--r--src/librustc_typeck/lib.rs1
-rw-r--r--src/librustdoc/clean/inline.rs6
-rw-r--r--src/test/auxiliary/dummy_mir_pass.rs8
-rw-r--r--src/test/compile-fail/const-err.rs4
-rw-r--r--src/test/compile-fail/const-eval-overflow-2.rs3
-rw-r--r--src/test/compile-fail/const-eval-overflow-3.rs1
-rw-r--r--src/test/compile-fail/const-eval-overflow-4b.rs5
-rw-r--r--src/test/compile-fail/const-eval-overflow.rs32
-rw-r--r--src/test/compile-fail/const-integer-bool-ops.rs22
-rw-r--r--src/test/compile-fail/const-len-underflow-separate-spans.rs2
-rw-r--r--src/test/compile-fail/const-len-underflow-subspans.rs2
-rw-r--r--src/test/compile-fail/const-tup-index-span.rs2
-rw-r--r--src/test/compile-fail/discrim-overflow-2.rs4
-rw-r--r--src/test/compile-fail/discrim-overflow.rs4
-rw-r--r--src/test/compile-fail/enum-discrim-too-small.rs36
-rw-r--r--src/test/compile-fail/enum-discrim-too-small2.rs47
-rw-r--r--src/test/compile-fail/eval-enum.rs3
-rw-r--r--src/test/compile-fail/feature-gate-negate-unsigned.rs19
-rw-r--r--src/test/compile-fail/feature-gate-negate-unsigned0.rs31
-rw-r--r--src/test/compile-fail/issue-15524.rs6
-rw-r--r--src/test/compile-fail/issue-8460-const.rs20
-rw-r--r--src/test/compile-fail/issue-8761.rs12
-rw-r--r--src/test/compile-fail/lint-type-limits.rs13
-rw-r--r--src/test/compile-fail/lint-type-limits2.rs24
-rw-r--r--src/test/compile-fail/lint-type-limits3.rs22
-rw-r--r--src/test/compile-fail/lint-type-overflow.rs6
-rw-r--r--src/test/compile-fail/lint-type-overflow2.rs22
-rw-r--r--src/test/compile-fail/repeat_count.rs12
-rw-r--r--src/test/run-pass/const-fn.rs12
-rw-r--r--src/test/run-pass/const-negation.rs42
-rw-r--r--src/test/run-pass/enum-discrim-autosizing.rs10
-rw-r--r--src/test/run-pass/issue-23833.rs25
75 files changed, 1823 insertions, 1041 deletions
diff --git a/mk/crates.mk b/mk/crates.mk
index d8e0390504b..1c7f141627b 100644
--- a/mk/crates.mk
+++ b/mk/crates.mk
@@ -53,7 +53,7 @@ TARGET_CRATES := libc std term \
                  getopts collections test rand \
                  core alloc \
                  rustc_unicode rustc_bitflags \
-		 alloc_system alloc_jemalloc
+		 alloc_system alloc_jemalloc rustc_const_eval
 RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
                 rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
                 rustc_data_structures rustc_front rustc_platform_intrinsics \
@@ -91,8 +91,11 @@ DEPS_test := std getopts term native:rust_test_helpers
 DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode
 DEPS_syntax_ext := syntax fmt_macros
 
+DEPS_rustc_const_eval := std syntax
+
 DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml rustc_front\
-              log graphviz rustc_llvm rustc_back rustc_data_structures
+              log graphviz rustc_llvm rustc_back rustc_data_structures\
+		  	  rustc_const_eval
 DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
 DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
 DEPS_rustc_data_structures := std log serialize
@@ -103,16 +106,17 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo
 DEPS_rustc_front := std syntax log serialize
 DEPS_rustc_lint := rustc log syntax
 DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
-DEPS_rustc_metadata := rustc rustc_front syntax rbml
+DEPS_rustc_metadata := rustc rustc_front syntax rbml rustc_const_eval
 DEPS_rustc_passes := syntax rustc core rustc_front
-DEPS_rustc_mir := rustc rustc_front syntax
+DEPS_rustc_mir := rustc rustc_front syntax rustc_const_eval
 DEPS_rustc_resolve := arena rustc rustc_front log syntax
 DEPS_rustc_platform_intrinsics := rustc rustc_llvm
 DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
 DEPS_rustc_privacy := rustc rustc_front log syntax
 DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
-                    log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
-DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics
+                    log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics \
+					rustc_const_eval
+DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics rustc_const_eval
 
 DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
                 test rustc_lint rustc_front
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index e65b4355e9d..1f000c2af68 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -18,6 +18,7 @@ log = { path = "../liblog" }
 rbml = { path = "../librbml" }
 rustc_back = { path = "../librustc_back" }
 rustc_bitflags = { path = "../librustc_bitflags" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_front = { path = "../librustc_front" }
 rustc_llvm = { path = "../librustc_llvm" }
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 4ff3b21dc83..3988545c201 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -55,6 +55,7 @@ extern crate rustc_front;
 extern crate rustc_data_structures;
 extern crate serialize;
 extern crate collections;
+extern crate rustc_const_eval;
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
 #[macro_use] #[no_link] extern crate rustc_bitflags;
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 1f79e76f3ac..51985be96db 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -476,7 +476,7 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
                     Some(Def::AssociatedConst(did)) |
                     Some(Def::Const(did)) => match lookup_const_by_id(self.tcx, did,
                                                                     Some(pat.id), None) {
-                        Some(const_expr) => {
+                        Some((const_expr, _const_ty)) => {
                             const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
 
                                 if let Some(ref mut renaming_map) = self.renaming_map {
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 06030c00211..d97df585edc 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -23,10 +23,9 @@ use middle::subst::Subst;
 use middle::def_id::DefId;
 use middle::pat_util::def_to_path;
 use middle::ty::{self, Ty, TyCtxt};
+use middle::ty::util::IntTypeExt;
 use middle::astconv_util::ast_ty_to_prim_ty;
-use util::num::ToPrimitive;
 use util::nodemap::NodeMap;
-use session::Session;
 
 use graphviz::IntoCow;
 use syntax::ast;
@@ -37,16 +36,27 @@ use syntax::codemap::Span;
 use syntax::parse::token::InternedString;
 use syntax::ptr::P;
 use syntax::codemap;
+use syntax::attr::IntType;
 
 use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::collections::hash_map::Entry::Vacant;
 use std::hash;
 use std::mem::transmute;
-use std::{i8, i16, i32, i64, u8, u16, u32, u64};
 use std::rc::Rc;
 
-fn lookup_variant_by_id<'a>(tcx: &'a TyCtxt,
+use rustc_const_eval::*;
+
+macro_rules! math {
+    ($e:expr, $op:expr) => {
+        match $op {
+            Ok(val) => val,
+            Err(e) => signal!($e, Math(e)),
+        }
+    }
+}
+
+fn lookup_variant_by_id<'a>(tcx: &'a ty::TyCtxt,
                             enum_def: DefId,
                             variant_def: DefId)
                             -> Option<&'a Expr> {
@@ -88,13 +98,13 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                                         def_id: DefId,
                                         maybe_ref_id: Option<ast::NodeId>,
                                         param_substs: Option<&'tcx subst::Substs<'tcx>>)
-                                        -> Option<&'tcx Expr> {
+                                        -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)> {
     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
         match tcx.map.find(node_id) {
             None => None,
             Some(ast_map::NodeItem(it)) => match it.node {
-                hir::ItemConst(_, ref const_expr) => {
-                    Some(&const_expr)
+                hir::ItemConst(ref ty, ref const_expr) => {
+                    Some((&const_expr, ast_ty_to_prim_ty(tcx, ty)))
                 }
                 _ => None
             },
@@ -113,8 +123,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                             if let Some(param_substs) = param_substs {
                                 substs = substs.subst(tcx, param_substs);
                             }
-                            resolve_trait_associated_const(tcx, ti, trait_id,
-                                                           substs)
+                            resolve_trait_associated_const(tcx, ti, trait_id, substs)
                         }
                         // Technically, without knowing anything about the
                         // expression that generates the obligation, we could
@@ -128,8 +137,8 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                 _ => None
             },
             Some(ast_map::NodeImplItem(ii)) => match ii.node {
-                hir::ImplItemKind::Const(_, ref expr) => {
-                    Some(&expr)
+                hir::ImplItemKind::Const(ref ty, ref expr) => {
+                    Some((&expr, ast_ty_to_prim_ty(tcx, ty)))
                 }
                 _ => None
             },
@@ -137,16 +146,18 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
         }
     } else {
         match tcx.extern_const_statics.borrow().get(&def_id) {
-            Some(&ast::DUMMY_NODE_ID) => return None,
-            Some(&expr_id) => {
-                return Some(tcx.map.expect_expr(expr_id));
+            Some(&None) => return None,
+            Some(&Some((expr_id, ty))) => {
+                return Some((tcx.map.expect_expr(expr_id), ty));
             }
             None => {}
         }
         let mut used_ref_id = false;
-        let expr_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
+        let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
             cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node {
-                hir::ItemConst(_, ref const_expr) => Some(const_expr.id),
+                hir::ItemConst(ref ty, ref const_expr) => {
+                    Some((&**const_expr, ast_ty_to_prim_ty(tcx, ty)))
+                },
                 _ => None
             },
             cstore::FoundAst::Found(&InlinedItem::TraitItem(trait_id, ref ti)) => match ti.node {
@@ -163,8 +174,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                             if let Some(param_substs) = param_substs {
                                 substs = substs.subst(tcx, param_substs);
                             }
-                            resolve_trait_associated_const(tcx, ti, trait_id,
-                                                           substs).map(|e| e.id)
+                            resolve_trait_associated_const(tcx, ti, trait_id, substs)
                         }
                         None => None
                     }
@@ -172,7 +182,9 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                 _ => None
             },
             cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref ii)) => match ii.node {
-                hir::ImplItemKind::Const(_, ref expr) => Some(expr.id),
+                hir::ImplItemKind::Const(ref ty, ref expr) => {
+                    Some((&**expr, ast_ty_to_prim_ty(tcx, ty)))
+                },
                 _ => None
             },
             _ => None
@@ -182,10 +194,10 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
         // lookup with the same def_id may yield a different result.
         if !used_ref_id {
             tcx.extern_const_statics
-               .borrow_mut().insert(def_id,
-                                    expr_id.unwrap_or(ast::DUMMY_NODE_ID));
+               .borrow_mut()
+               .insert(def_id, expr_ty.map(|(e, t)| (e.id, t)));
         }
-        expr_id.map(|id| tcx.map.expect_expr(id))
+        expr_ty
     }
 }
 
@@ -248,8 +260,7 @@ pub fn lookup_const_fn_by_id<'tcx>(tcx: &TyCtxt<'tcx>, def_id: DefId)
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub enum ConstVal {
     Float(f64),
-    Int(i64),
-    Uint(u64),
+    Integral(ConstInt),
     Str(InternedString),
     ByteStr(Rc<Vec<u8>>),
     Bool(bool),
@@ -258,14 +269,18 @@ pub enum ConstVal {
     Function(DefId),
     Array(ast::NodeId, u64),
     Repeat(ast::NodeId, u64),
+    Char(char),
+    /// A value that only occurs in case `eval_const_expr` reported an error. You should never
+    /// handle this case. Its sole purpose is to allow more errors to be reported instead of
+    /// causing a fatal error.
+    Dummy,
 }
 
 impl hash::Hash for ConstVal {
     fn hash<H: hash::Hasher>(&self, state: &mut H) {
         match *self {
             Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
-            Int(a) => a.hash(state),
-            Uint(a) => a.hash(state),
+            Integral(a) => a.hash(state),
             Str(ref a) => a.hash(state),
             ByteStr(ref a) => a.hash(state),
             Bool(a) => a.hash(state),
@@ -274,6 +289,8 @@ impl hash::Hash for ConstVal {
             Function(a) => a.hash(state),
             Array(a, n) => { a.hash(state); n.hash(state) },
             Repeat(a, n) => { a.hash(state); n.hash(state) },
+            Char(c) => c.hash(state),
+            Dummy => ().hash(state),
         }
     }
 }
@@ -286,8 +303,7 @@ impl PartialEq for ConstVal {
     fn eq(&self, other: &ConstVal) -> bool {
         match (self, other) {
             (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
-            (&Int(a), &Int(b)) => a == b,
-            (&Uint(a), &Uint(b)) => a == b,
+            (&Integral(a), &Integral(b)) => a == b,
             (&Str(ref a), &Str(ref b)) => a == b,
             (&ByteStr(ref a), &ByteStr(ref b)) => a == b,
             (&Bool(a), &Bool(b)) => a == b,
@@ -296,6 +312,8 @@ impl PartialEq for ConstVal {
             (&Function(a), &Function(b)) => a == b,
             (&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
             (&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
+            (&Char(a), &Char(b)) => a == b,
+            (&Dummy, &Dummy) => true, // FIXME: should this be false?
             _ => false,
         }
     }
@@ -307,9 +325,7 @@ impl ConstVal {
     pub fn description(&self) -> &'static str {
         match *self {
             Float(_) => "float",
-            Int(i) if i < 0 => "negative integer",
-            Int(_) => "positive integer",
-            Uint(_) => "unsigned integer",
+            Integral(i) => i.description(),
             Str(_) => "string literal",
             ByteStr(_) => "byte string literal",
             Bool(_) => "boolean",
@@ -318,6 +334,8 @@ impl ConstVal {
             Function(_) => "function definition",
             Array(..) => "array",
             Repeat(..) => "repeat",
+            Char(..) => "char",
+            Dummy => "dummy value",
         }
     }
 }
@@ -370,7 +388,7 @@ pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P<hir::Pat> {
                     PatKind::Path(path.clone()),
                 Some(Def::Const(def_id)) |
                 Some(Def::AssociatedConst(def_id)) => {
-                    let expr = lookup_const_by_id(tcx, def_id, Some(expr.id), None).unwrap();
+                    let (expr, _ty) = lookup_const_by_id(tcx, def_id, Some(expr.id), None).unwrap();
                     return const_expr_to_pat(tcx, expr, span);
                 },
                 _ => unreachable!(),
@@ -385,7 +403,12 @@ pub fn const_expr_to_pat(tcx: &TyCtxt, expr: &Expr, span: Span) -> P<hir::Pat> {
 pub fn eval_const_expr(tcx: &TyCtxt, e: &Expr) -> ConstVal {
     match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
         Ok(r) => r,
-        Err(s) => tcx.sess.span_fatal(s.span, &s.description())
+        // non-const path still needs to be a fatal error, because enums are funky
+        Err(ref s) if s.kind == NonConstPath => tcx.sess.span_fatal(s.span, &s.description()),
+        Err(s) => {
+            tcx.sess.span_err(s.span, &s.description());
+            Dummy
+        },
     }
 }
 
@@ -397,12 +420,11 @@ pub struct ConstEvalErr {
     pub kind: ErrKind,
 }
 
-#[derive(Clone)]
+#[derive(Clone, PartialEq)]
 pub enum ErrKind {
     CannotCast,
     CannotCastTo(&'static str),
     InvalidOpForInts(hir::BinOp_),
-    InvalidOpForUInts(hir::BinOp_),
     InvalidOpForBools(hir::BinOp_),
     InvalidOpForFloats(hir::BinOp_),
     InvalidOpForIntUint(hir::BinOp_),
@@ -442,6 +464,18 @@ pub enum ErrKind {
     MiscCatchAll,
 
     IndexOpFeatureGated,
+    Math(ConstMathErr),
+
+    IntermediateUnsignedNegative,
+    /// Expected, Got
+    TypeMismatch(String, ConstInt),
+    BadType(ConstVal),
+}
+
+impl From<ConstMathErr> for ErrKind {
+    fn from(err: ConstMathErr) -> ErrKind {
+        Math(err)
+    }
 }
 
 impl ConstEvalErr {
@@ -451,8 +485,7 @@ impl ConstEvalErr {
         match self.kind {
             CannotCast => "can't cast this type".into_cow(),
             CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(),
-            InvalidOpForInts(_) =>  "can't do this op on signed integrals".into_cow(),
-            InvalidOpForUInts(_) =>  "can't do this op on unsigned integrals".into_cow(),
+            InvalidOpForInts(_) =>  "can't do this op on integrals".into_cow(),
             InvalidOpForBools(_) =>  "can't do this op on bools".into_cow(),
             InvalidOpForFloats(_) => "can't do this op on floats".into_cow(),
             InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
@@ -492,6 +525,17 @@ impl ConstEvalErr {
             MiscBinaryOp => "bad operands for binary".into_cow(),
             MiscCatchAll => "unsupported constant expr".into_cow(),
             IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(),
+            Math(ref err) => err.description().into_cow(),
+
+            IntermediateUnsignedNegative => "during the computation of an unsigned a negative \
+                                             number was encountered. This is most likely a bug in\
+                                             the constant evaluator".into_cow(),
+
+            TypeMismatch(ref expected, ref got) => {
+                format!("mismatched types: expected `{}`, found `{}`",
+                        expected, got.description()).into_cow()
+            },
+            BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(),
         }
     }
 }
@@ -536,276 +580,12 @@ impl<'tcx> EvalHint<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum IntTy { I8, I16, I32, I64 }
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum UintTy { U8, U16, U32, U64 }
-
-impl IntTy {
-    pub fn from(tcx: &TyCtxt, t: ast::IntTy) -> IntTy {
-        let t = if let ast::IntTy::Is = t {
-            tcx.sess.target.int_type
-        } else {
-            t
-        };
-        match t {
-            ast::IntTy::Is => unreachable!(),
-            ast::IntTy::I8  => IntTy::I8,
-            ast::IntTy::I16 => IntTy::I16,
-            ast::IntTy::I32 => IntTy::I32,
-            ast::IntTy::I64 => IntTy::I64,
-        }
-    }
-}
-
-impl UintTy {
-    pub fn from(tcx: &TyCtxt, t: ast::UintTy) -> UintTy {
-        let t = if let ast::UintTy::Us = t {
-            tcx.sess.target.uint_type
-        } else {
-            t
-        };
-        match t {
-            ast::UintTy::Us => unreachable!(),
-            ast::UintTy::U8  => UintTy::U8,
-            ast::UintTy::U16 => UintTy::U16,
-            ast::UintTy::U32 => UintTy::U32,
-            ast::UintTy::U64 => UintTy::U64,
-        }
-    }
-}
-
 macro_rules! signal {
     ($e:expr, $exn:expr) => {
         return Err(ConstEvalErr { span: $e.span, kind: $exn })
     }
 }
 
-// The const_{int,uint}_checked_{neg,add,sub,mul,div,shl,shr} family
-// of functions catch and signal overflow errors during constant
-// evaluation.
-//
-// They all take the operator's arguments (`a` and `b` if binary), the
-// overall expression (`e`) and, if available, whole expression's
-// concrete type (`opt_ety`).
-//
-// If the whole expression's concrete type is None, then this is a
-// constant evaluation happening before type check (e.g. in the check
-// to confirm that a pattern range's left-side is not greater than its
-// right-side). We do not do arithmetic modulo the type's bitwidth in
-// such a case; we just do 64-bit arithmetic and assume that later
-// passes will do it again with the type information, and thus do the
-// overflow checks then.
-
-pub fn const_int_checked_neg<'a>(
-    a: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
-
-    let (min,max) = match opt_ety {
-        // (-i8::MIN is itself not an i8, etc, but this is an easy way
-        // to allow literals to pass the check. Of course that does
-        // not work for i64::MIN.)
-        Some(IntTy::I8) =>  (-(i8::MAX as i64), -(i8::MIN as i64)),
-        Some(IntTy::I16) => (-(i16::MAX as i64), -(i16::MIN as i64)),
-        Some(IntTy::I32) => (-(i32::MAX as i64), -(i32::MIN as i64)),
-        None | Some(IntTy::I64) => (-i64::MAX, -(i64::MIN+1)),
-    };
-
-    let oflo = a < min || a > max;
-    if oflo {
-        signal!(e, NegateWithOverflow(a));
-    } else {
-        Ok(Int(-a))
-    }
-}
-
-pub fn const_uint_checked_neg<'a>(
-    a: u64, _e: &'a Expr, _opt_ety: Option<UintTy>) -> EvalResult {
-    // This always succeeds, and by definition, returns `(!a)+1`.
-    Ok(Uint((!a).wrapping_add(1)))
-}
-
-fn const_uint_not(a: u64, opt_ety: Option<UintTy>) -> ConstVal {
-    let mask = match opt_ety {
-        Some(UintTy::U8) => u8::MAX as u64,
-        Some(UintTy::U16) => u16::MAX as u64,
-        Some(UintTy::U32) => u32::MAX as u64,
-        None | Some(UintTy::U64) => u64::MAX,
-    };
-    Uint(!a & mask)
-}
-
-macro_rules! overflow_checking_body {
-    ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident,
-     lhs: $to_8_lhs:ident $to_16_lhs:ident $to_32_lhs:ident,
-     rhs: $to_8_rhs:ident $to_16_rhs:ident $to_32_rhs:ident $to_64_rhs:ident,
-     $EnumTy:ident $T8: ident $T16: ident $T32: ident $T64: ident,
-     $result_type: ident) => { {
-        let (a,b,opt_ety) = ($a,$b,$ety);
-        match opt_ety {
-            Some($EnumTy::$T8) => match (a.$to_8_lhs(), b.$to_8_rhs()) {
-                (Some(a), Some(b)) => {
-                    let (a, oflo) = a.$overflowing_op(b);
-                    (a as $result_type, oflo)
-                }
-                (None, _) | (_, None) => (0, true)
-            },
-            Some($EnumTy::$T16) => match (a.$to_16_lhs(), b.$to_16_rhs()) {
-                (Some(a), Some(b)) => {
-                    let (a, oflo) = a.$overflowing_op(b);
-                    (a as $result_type, oflo)
-                }
-                (None, _) | (_, None) => (0, true)
-            },
-            Some($EnumTy::$T32) => match (a.$to_32_lhs(), b.$to_32_rhs()) {
-                (Some(a), Some(b)) => {
-                    let (a, oflo) = a.$overflowing_op(b);
-                    (a as $result_type, oflo)
-                }
-                (None, _) | (_, None) => (0, true)
-            },
-            None | Some($EnumTy::$T64) => match b.$to_64_rhs() {
-                Some(b) => a.$overflowing_op(b),
-                None => (0, true),
-            }
-        }
-    } }
-}
-
-macro_rules! int_arith_body {
-    ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
-        overflow_checking_body!(
-            $a, $b, $ety, $overflowing_op,
-            lhs: to_i8 to_i16 to_i32,
-            rhs: to_i8 to_i16 to_i32 to_i64, IntTy I8 I16 I32 I64, i64)
-    }
-}
-
-macro_rules! uint_arith_body {
-    ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
-        overflow_checking_body!(
-            $a, $b, $ety, $overflowing_op,
-            lhs: to_u8 to_u16 to_u32,
-            rhs: to_u8 to_u16 to_u32 to_u64, UintTy U8 U16 U32 U64, u64)
-    }
-}
-
-macro_rules! int_shift_body {
-    ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
-        overflow_checking_body!(
-            $a, $b, $ety, $overflowing_op,
-            lhs: to_i8 to_i16 to_i32,
-            rhs: to_u32 to_u32 to_u32 to_u32, IntTy I8 I16 I32 I64, i64)
-    }
-}
-
-macro_rules! uint_shift_body {
-    ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
-        overflow_checking_body!(
-            $a, $b, $ety, $overflowing_op,
-            lhs: to_u8 to_u16 to_u32,
-            rhs: to_u32 to_u32 to_u32 to_u32, UintTy U8 U16 U32 U64, u64)
-    }
-}
-
-macro_rules! pub_fn_checked_op {
-    {$fn_name:ident ($a:ident : $a_ty:ty, $b:ident : $b_ty:ty,.. $WhichTy:ident) {
-        $ret_oflo_body:ident $overflowing_op:ident
-            $const_ty:ident $signal_exn:expr
-    }} => {
-        pub fn $fn_name<'a>($a: $a_ty,
-                            $b: $b_ty,
-                            e: &'a Expr,
-                            opt_ety: Option<$WhichTy>) -> EvalResult {
-            let (ret, oflo) = $ret_oflo_body!($a, $b, opt_ety, $overflowing_op);
-            if !oflo { Ok($const_ty(ret)) } else { signal!(e, $signal_exn) }
-        }
-    }
-}
-
-pub_fn_checked_op!{ const_int_checked_add(a: i64, b: i64,.. IntTy) {
-           int_arith_body overflowing_add Int AddiWithOverflow(a, b)
-}}
-
-pub_fn_checked_op!{ const_int_checked_sub(a: i64, b: i64,.. IntTy) {
-           int_arith_body overflowing_sub Int SubiWithOverflow(a, b)
-}}
-
-pub_fn_checked_op!{ const_int_checked_mul(a: i64, b: i64,.. IntTy) {
-           int_arith_body overflowing_mul Int MuliWithOverflow(a, b)
-}}
-
-pub fn const_int_checked_div<'a>(
-    a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
-    if b == 0 { signal!(e, DivideByZero); }
-    let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_div);
-    if !oflo { Ok(Int(ret)) } else { signal!(e, DivideWithOverflow) }
-}
-
-pub fn const_int_checked_rem<'a>(
-    a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
-    if b == 0 { signal!(e, ModuloByZero); }
-    let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_rem);
-    if !oflo { Ok(Int(ret)) } else { signal!(e, ModuloWithOverflow) }
-}
-
-pub_fn_checked_op!{ const_int_checked_shl(a: i64, b: i64,.. IntTy) {
-           int_shift_body overflowing_shl Int ShiftLeftWithOverflow
-}}
-
-pub_fn_checked_op!{ const_int_checked_shl_via_uint(a: i64, b: u64,.. IntTy) {
-           int_shift_body overflowing_shl Int ShiftLeftWithOverflow
-}}
-
-pub_fn_checked_op!{ const_int_checked_shr(a: i64, b: i64,.. IntTy) {
-           int_shift_body overflowing_shr Int ShiftRightWithOverflow
-}}
-
-pub_fn_checked_op!{ const_int_checked_shr_via_uint(a: i64, b: u64,.. IntTy) {
-           int_shift_body overflowing_shr Int ShiftRightWithOverflow
-}}
-
-pub_fn_checked_op!{ const_uint_checked_add(a: u64, b: u64,.. UintTy) {
-           uint_arith_body overflowing_add Uint AdduWithOverflow(a, b)
-}}
-
-pub_fn_checked_op!{ const_uint_checked_sub(a: u64, b: u64,.. UintTy) {
-           uint_arith_body overflowing_sub Uint SubuWithOverflow(a, b)
-}}
-
-pub_fn_checked_op!{ const_uint_checked_mul(a: u64, b: u64,.. UintTy) {
-           uint_arith_body overflowing_mul Uint MuluWithOverflow(a, b)
-}}
-
-pub fn const_uint_checked_div<'a>(
-    a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
-    if b == 0 { signal!(e, DivideByZero); }
-    let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_div);
-    if !oflo { Ok(Uint(ret)) } else { signal!(e, DivideWithOverflow) }
-}
-
-pub fn const_uint_checked_rem<'a>(
-    a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
-    if b == 0 { signal!(e, ModuloByZero); }
-    let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_rem);
-    if !oflo { Ok(Uint(ret)) } else { signal!(e, ModuloWithOverflow) }
-}
-
-pub_fn_checked_op!{ const_uint_checked_shl(a: u64, b: u64,.. UintTy) {
-           uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
-}}
-
-pub_fn_checked_op!{ const_uint_checked_shl_via_int(a: u64, b: i64,.. UintTy) {
-           uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
-}}
-
-pub_fn_checked_op!{ const_uint_checked_shr(a: u64, b: u64,.. UintTy) {
-           uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
-}}
-
-pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
-           uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
-}}
-
 /// Evaluate a constant expression in a context where the expression isn't
 /// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
 /// but a few places need to evaluate constants during type-checking, like
@@ -833,34 +613,57 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
             tcx.expr_ty_opt(e)
         }
     };
-
-    // If type of expression itself is int or uint, normalize in these
-    // bindings so that isize/usize is mapped to a type with an
-    // inherently known bitwidth.
-    let expr_int_type = ety.and_then(|ty| {
-        if let ty::TyInt(t) = ty.sty {
-            Some(IntTy::from(tcx, t)) } else { None }
-    });
-    let expr_uint_type = ety.and_then(|ty| {
-        if let ty::TyUint(t) = ty.sty {
-            Some(UintTy::from(tcx, t)) } else { None }
-    });
-
     let result = match e.node {
       hir::ExprUnary(hir::UnNeg, ref inner) => {
+        // unary neg literals already got their sign during creation
+        if let hir::ExprLit(ref lit) = inner.node {
+            use syntax::ast::*;
+            use syntax::ast::LitIntType::*;
+            const I8_OVERFLOW: u64 = ::std::i8::MAX as u64 + 1;
+            const I16_OVERFLOW: u64 = ::std::i16::MAX as u64 + 1;
+            const I32_OVERFLOW: u64 = ::std::i32::MAX as u64 + 1;
+            const I64_OVERFLOW: u64 = ::std::i64::MAX as u64 + 1;
+            match (&lit.node, ety.map(|t| &t.sty)) {
+                (&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) |
+                (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
+                    return Ok(Integral(I8(::std::i8::MIN)))
+                },
+                (&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) |
+                (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
+                    return Ok(Integral(I16(::std::i16::MIN)))
+                },
+                (&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) |
+                (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
+                    return Ok(Integral(I32(::std::i32::MIN)))
+                },
+                (&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) |
+                (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
+                    return Ok(Integral(I64(::std::i64::MIN)))
+                },
+                (&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) |
+                (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
+                    match tcx.sess.target.int_type {
+                        IntTy::I32 => if n == I32_OVERFLOW {
+                            return Ok(Integral(Isize(Is32(::std::i32::MIN))));
+                        },
+                        IntTy::I64 => if n == I64_OVERFLOW {
+                            return Ok(Integral(Isize(Is64(::std::i64::MIN))));
+                        },
+                        _ => unreachable!(),
+                    }
+                },
+                _ => {},
+            }
+        }
         match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
           Float(f) => Float(-f),
-          Int(n) =>  try!(const_int_checked_neg(n, e, expr_int_type)),
-          Uint(i) => {
-              try!(const_uint_checked_neg(i, e, expr_uint_type))
-          }
+          Integral(i) => Integral(math!(e, -i)),
           const_val => signal!(e, NegateOn(const_val)),
         }
       }
       hir::ExprUnary(hir::UnNot, ref inner) => {
         match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
-          Int(i) => Int(!i),
-          Uint(i) => const_uint_not(i, expr_uint_type),
+          Integral(i) => Integral(math!(e, !i)),
           Bool(b) => Bool(!b),
           const_val => signal!(e, NotOn(const_val)),
         }
@@ -870,6 +673,10 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
             hir::BiShl | hir::BiShr => ty_hint.checked_or(tcx.types.usize),
             _ => ty_hint
         };
+        // technically, if we don't have type hints, but integral eval
+        // gives us a type through a type-suffix, cast or const def type
+        // we need to re-eval the other value of the BinOp if it was
+        // not inferred
         match (try!(eval_const_expr_partial(tcx, &a, ty_hint, fn_args)),
                try!(eval_const_expr_partial(tcx, &b, b_ty, fn_args))) {
           (Float(a), Float(b)) => {
@@ -888,63 +695,28 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
               _ => signal!(e, InvalidOpForFloats(op.node)),
             }
           }
-          (Int(a), Int(b)) => {
+          (Integral(a), Integral(b)) => {
+            use std::cmp::Ordering::*;
             match op.node {
-              hir::BiAdd => try!(const_int_checked_add(a,b,e,expr_int_type)),
-              hir::BiSub => try!(const_int_checked_sub(a,b,e,expr_int_type)),
-              hir::BiMul => try!(const_int_checked_mul(a,b,e,expr_int_type)),
-              hir::BiDiv => try!(const_int_checked_div(a,b,e,expr_int_type)),
-              hir::BiRem => try!(const_int_checked_rem(a,b,e,expr_int_type)),
-              hir::BiBitAnd => Int(a & b),
-              hir::BiBitOr => Int(a | b),
-              hir::BiBitXor => Int(a ^ b),
-              hir::BiShl => try!(const_int_checked_shl(a,b,e,expr_int_type)),
-              hir::BiShr => try!(const_int_checked_shr(a,b,e,expr_int_type)),
-              hir::BiEq => Bool(a == b),
-              hir::BiLt => Bool(a < b),
-              hir::BiLe => Bool(a <= b),
-              hir::BiNe => Bool(a != b),
-              hir::BiGe => Bool(a >= b),
-              hir::BiGt => Bool(a > b),
+              hir::BiAdd => Integral(math!(e, a + b)),
+              hir::BiSub => Integral(math!(e, a - b)),
+              hir::BiMul => Integral(math!(e, a * b)),
+              hir::BiDiv => Integral(math!(e, a / b)),
+              hir::BiRem => Integral(math!(e, a % b)),
+              hir::BiBitAnd => Integral(math!(e, a & b)),
+              hir::BiBitOr => Integral(math!(e, a | b)),
+              hir::BiBitXor => Integral(math!(e, a ^ b)),
+              hir::BiShl => Integral(math!(e, a << b)),
+              hir::BiShr => Integral(math!(e, a >> b)),
+              hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
+              hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
+              hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
+              hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
+              hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
+              hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
               _ => signal!(e, InvalidOpForInts(op.node)),
             }
           }
-          (Uint(a), Uint(b)) => {
-            match op.node {
-              hir::BiAdd => try!(const_uint_checked_add(a,b,e,expr_uint_type)),
-              hir::BiSub => try!(const_uint_checked_sub(a,b,e,expr_uint_type)),
-              hir::BiMul => try!(const_uint_checked_mul(a,b,e,expr_uint_type)),
-              hir::BiDiv => try!(const_uint_checked_div(a,b,e,expr_uint_type)),
-              hir::BiRem => try!(const_uint_checked_rem(a,b,e,expr_uint_type)),
-              hir::BiBitAnd => Uint(a & b),
-              hir::BiBitOr => Uint(a | b),
-              hir::BiBitXor => Uint(a ^ b),
-              hir::BiShl => try!(const_uint_checked_shl(a,b,e,expr_uint_type)),
-              hir::BiShr => try!(const_uint_checked_shr(a,b,e,expr_uint_type)),
-              hir::BiEq => Bool(a == b),
-              hir::BiLt => Bool(a < b),
-              hir::BiLe => Bool(a <= b),
-              hir::BiNe => Bool(a != b),
-              hir::BiGe => Bool(a >= b),
-              hir::BiGt => Bool(a > b),
-              _ => signal!(e, InvalidOpForUInts(op.node)),
-            }
-          }
-          // shifts can have any integral type as their rhs
-          (Int(a), Uint(b)) => {
-            match op.node {
-              hir::BiShl => try!(const_int_checked_shl_via_uint(a,b,e,expr_int_type)),
-              hir::BiShr => try!(const_int_checked_shr_via_uint(a,b,e,expr_int_type)),
-              _ => signal!(e, InvalidOpForIntUint(op.node)),
-            }
-          }
-          (Uint(a), Int(b)) => {
-            match op.node {
-              hir::BiShl => try!(const_uint_checked_shl_via_int(a,b,e,expr_uint_type)),
-              hir::BiShr => try!(const_uint_checked_shr_via_int(a,b,e,expr_uint_type)),
-              _ => signal!(e, InvalidOpForUintInt(op.node)),
-            }
-          }
           (Bool(a), Bool(b)) => {
             Bool(match op.node {
               hir::BiAnd => a && b,
@@ -962,7 +734,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
         }
       }
       hir::ExprCast(ref base, ref target_ty) => {
-        let ety = ety.or_else(|| ast_ty_to_prim_ty(tcx, &target_ty))
+        let ety = ast_ty_to_prim_ty(tcx, &target_ty).or_else(|| ety)
                 .unwrap_or_else(|| {
                     tcx.sess.span_fatal(target_ty.span,
                                         "target type not found for const cast")
@@ -971,16 +743,27 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
         let base_hint = if let ExprTypeChecked = ty_hint {
             ExprTypeChecked
         } else {
-            // FIXME (#23833): the type-hint can cause problems,
-            // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
-            // type to the sum, and thus no overflow is signaled.
             match tcx.expr_ty_opt(&base) {
                 Some(t) => UncheckedExprHint(t),
                 None => ty_hint
             }
         };
 
-        let val = try!(eval_const_expr_partial(tcx, &base, base_hint, fn_args));
+        let val = match eval_const_expr_partial(tcx, &base, base_hint, fn_args) {
+            Ok(val) => val,
+            Err(ConstEvalErr { kind: TypeMismatch(_, val), .. }) => {
+                // Something like `5i8 as usize` doesn't need a type hint for the base
+                // instead take the type hint from the inner value
+                let hint = match val.int_type() {
+                    Some(IntType::UnsignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_uint(ty)),
+                    Some(IntType::SignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_int(ty)),
+                    // we had a type hint, so we can't have an unknown type
+                    None => unreachable!(),
+                };
+                try!(eval_const_expr_partial(tcx, &base, hint, fn_args))
+            },
+            Err(e) => return Err(e),
+        };
         match cast_const(tcx, val, ety) {
             Ok(val) => val,
             Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
@@ -997,94 +780,49 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
               if def.depth != 0 {
                   signal!(e, UnresolvedPath);
               }
-              Some(def.full_def())
+              def.full_def()
           } else {
-              None
+              signal!(e, NonConstPath);
           };
-          let (const_expr, const_ty) = match opt_def {
-              Some(Def::Const(def_id)) => {
-                  if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
-                      match tcx.map.find(node_id) {
-                          Some(ast_map::NodeItem(it)) => match it.node {
-                              hir::ItemConst(ref ty, ref expr) => {
-                                  (Some(&**expr), Some(&**ty))
-                              }
-                              _ => (None, None)
-                          },
-                          _ => (None, None)
-                      }
+          match opt_def {
+              Def::Const(def_id) |
+              Def::AssociatedConst(def_id) => {
+                  let maybe_ref_id = if let ExprTypeChecked = ty_hint {
+                      Some(e.id)
                   } else {
-                      (lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
+                      None
+                  };
+                  if let Some((e, ty)) = lookup_const_by_id(tcx, def_id, maybe_ref_id, None) {
+                      let item_hint = match ty {
+                          Some(ty) => ty_hint.checked_or(ty),
+                          None => ty_hint,
+                      };
+                      try!(eval_const_expr_partial(tcx, e, item_hint, None))
+                  } else {
+                      signal!(e, NonConstPath);
                   }
-              }
-              Some(Def::AssociatedConst(def_id)) => {
-                  if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
-                      match impl_or_trait_container(tcx, def_id) {
-                          ty::TraitContainer(trait_id) => match tcx.map.find(node_id) {
-                              Some(ast_map::NodeTraitItem(ti)) => match ti.node {
-                                  hir::ConstTraitItem(ref ty, _) => {
-                                      if let ExprTypeChecked = ty_hint {
-                                          let substs = tcx.node_id_item_substs(e.id).substs;
-                                          (resolve_trait_associated_const(tcx,
-                                                                          ti,
-                                                                          trait_id,
-                                                                          substs),
-                                           Some(&**ty))
-                                       } else {
-                                           (None, None)
-                                       }
-                                  }
-                                  _ => (None, None)
-                              },
-                              _ => (None, None)
-                          },
-                          ty::ImplContainer(_) => match tcx.map.find(node_id) {
-                              Some(ast_map::NodeImplItem(ii)) => match ii.node {
-                                  hir::ImplItemKind::Const(ref ty, ref expr) => {
-                                      (Some(&**expr), Some(&**ty))
-                                  }
-                                  _ => (None, None)
-                              },
-                              _ => (None, None)
-                          },
-                      }
+              },
+              Def::Variant(enum_def, variant_def) => {
+                  if let Some(const_expr) = lookup_variant_by_id(tcx, enum_def, variant_def) {
+                      try!(eval_const_expr_partial(tcx, const_expr, ty_hint, None))
                   } else {
-                      (lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
+                      signal!(e, NonConstPath);
                   }
               }
-              Some(Def::Variant(enum_def, variant_def)) => {
-                  (lookup_variant_by_id(tcx, enum_def, variant_def), None)
+              Def::Struct(..) => {
+                  ConstVal::Struct(e.id)
               }
-              Some(Def::Struct(..)) => {
-                  return Ok(ConstVal::Struct(e.id))
-              }
-              Some(Def::Local(_, id)) => {
+              Def::Local(_, id) => {
                   debug!("Def::Local({:?}): {:?}", id, fn_args);
                   if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
-                      return Ok(val.clone());
+                      val.clone()
                   } else {
-                      (None, None)
+                      signal!(e, NonConstPath);
                   }
               },
-              Some(Def::Method(id)) | Some(Def::Fn(id)) => return Ok(Function(id)),
-              _ => (None, None)
-          };
-          let const_expr = match const_expr {
-              Some(actual_e) => actual_e,
-              None => signal!(e, NonConstPath)
-          };
-          let item_hint = if let UncheckedExprNoHint = ty_hint {
-              match const_ty {
-                  Some(ty) => match ast_ty_to_prim_ty(tcx, ty) {
-                      Some(ty) => UncheckedExprHint(ty),
-                      None => UncheckedExprNoHint
-                  },
-                  None => UncheckedExprNoHint
-              }
-          } else {
-              ty_hint
-          };
-          try!(eval_const_expr_partial(tcx, const_expr, item_hint, fn_args))
+              Def::Method(id) | Def::Fn(id) => Function(id),
+              _ => signal!(e, NonConstPath),
+          }
       }
       hir::ExprCall(ref callee, ref args) => {
           let sub_ty_hint = ty_hint.erase_hint();
@@ -1103,10 +841,11 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
 
           let mut call_args = NodeMap();
           for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) {
+              let arg_hint = ty_hint.erase_hint();
               let arg_val = try!(eval_const_expr_partial(
                   tcx,
                   arg_expr,
-                  sub_ty_hint,
+                  arg_hint,
                   fn_args
               ));
               debug!("const call arg: {:?}", arg);
@@ -1116,7 +855,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
           debug!("const call({:?})", call_args);
           try!(eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args)))
       },
-      hir::ExprLit(ref lit) => lit_to_const(tcx.sess, e.span, &lit, ety),
+      hir::ExprLit(ref lit) => try!(lit_to_const(&lit.node, tcx, ety, lit.span)),
       hir::ExprBlock(ref block) => {
         match block.expr {
             Some(ref expr) => try!(eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)),
@@ -1134,14 +873,15 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
         let arr = try!(eval_const_expr_partial(tcx, arr, arr_hint, fn_args));
         let idx_hint = ty_hint.checked_or(tcx.types.usize);
         let idx = match try!(eval_const_expr_partial(tcx, idx, idx_hint, fn_args)) {
-            Int(i) if i >= 0 => i as u64,
-            Int(_) => signal!(idx, IndexNegative),
-            Uint(i) => i,
+            Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
+            Integral(_) => unreachable!(),
             _ => signal!(idx, IndexNotInt),
         };
+        assert_eq!(idx as usize as u64, idx);
         match arr {
             Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
-            Array(v, _) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
+            Array(v, n) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
+                assert_eq!(n as usize as u64, n);
                 try!(eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args))
             } else {
                 unreachable!()
@@ -1155,13 +895,13 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
                 fn_args,
             )),
 
-            ByteStr(ref data) if idx as usize >= data.len()
-                => signal!(e, IndexOutOfBounds),
-            ByteStr(data) => Uint(data[idx as usize] as u64),
+            ByteStr(ref data) if idx >= data.len() as u64 => signal!(e, IndexOutOfBounds),
+            ByteStr(data) => {
+                Integral(U8(data[idx as usize]))
+            },
 
-            Str(ref s) if idx as usize >= s.len()
-                => signal!(e, IndexOutOfBounds),
-            Str(_) => unimplemented!(), // there's no const_char type
+            Str(ref s) if idx as usize >= s.len() => signal!(e, IndexOutOfBounds),
+            Str(_) => unimplemented!(), // FIXME: return a const char
             _ => signal!(e, IndexedNonVec),
         }
       }
@@ -1171,9 +911,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
           Repeat(
               e.id,
               match try!(eval_const_expr_partial(tcx, &n, len_hint, fn_args)) {
-                  Int(i) if i >= 0 => i as u64,
-                  Int(_) => signal!(e, RepeatCountNotNatural),
-                  Uint(i) => i,
+                  Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
+                  Integral(_) => signal!(e, RepeatCountNotNatural),
                   _ => signal!(e, RepeatCountNotInt),
               },
           )
@@ -1184,7 +923,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
         if let Tuple(tup_id) = c {
             if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
                 if index.node < fields.len() {
-                    return eval_const_expr_partial(tcx, &fields[index.node], base_hint, fn_args)
+                    try!(eval_const_expr_partial(tcx, &fields[index.node], ty_hint, fn_args))
                 } else {
                     signal!(e, TupleIndexOutOfBounds);
                 }
@@ -1205,7 +944,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
                 // if the idents are compared run-pass/issue-19244 fails
                 if let Some(f) = fields.iter().find(|f| f.name.node
                                                      == field_name.node) {
-                    return eval_const_expr_partial(tcx, &f.expr, base_hint, fn_args)
+                    try!(eval_const_expr_partial(tcx, &f.expr, ty_hint, fn_args))
                 } else {
                     signal!(e, MissingStructField);
                 }
@@ -1219,31 +958,89 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
       _ => signal!(e, MiscCatchAll)
     };
 
-    Ok(result)
+    match (ety.map(|t| &t.sty), result) {
+        (Some(ref ty_hint), Integral(i)) => Ok(Integral(try!(infer(i, tcx, ty_hint, e.span)))),
+        (_, result) => Ok(result),
+    }
 }
 
-fn impl_or_trait_container(tcx: &TyCtxt, def_id: DefId) -> ty::ImplOrTraitItemContainer {
-    // This is intended to be equivalent to tcx.impl_or_trait_item(def_id).container()
-    // for local def_id, but it can be called before tcx.impl_or_trait_items is complete.
-    if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
-        if let Some(ast_map::NodeItem(item)) = tcx.map.find(tcx.map.get_parent_node(node_id)) {
-            let container_id = tcx.map.local_def_id(item.id);
-            match item.node {
-                hir::ItemImpl(..) => return ty::ImplContainer(container_id),
-                hir::ItemTrait(..) => return ty::TraitContainer(container_id),
-                _ => ()
+fn infer<'tcx>(
+    i: ConstInt,
+    tcx: &TyCtxt<'tcx>,
+    ty_hint: &ty::TypeVariants<'tcx>,
+    span: Span
+) -> Result<ConstInt, ConstEvalErr> {
+    use syntax::ast::*;
+
+    let err = |e| ConstEvalErr {
+        span: span,
+        kind: e,
+    };
+
+    match (ty_hint, i) {
+        (&ty::TyInt(IntTy::I8), result @ I8(_)) => Ok(result),
+        (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result),
+        (&ty::TyInt(IntTy::I32), result @ I32(_)) => Ok(result),
+        (&ty::TyInt(IntTy::I64), result @ I64(_)) => Ok(result),
+        (&ty::TyInt(IntTy::Is), result @ Isize(_)) => Ok(result),
+
+        (&ty::TyUint(UintTy::U8), result @ U8(_)) => Ok(result),
+        (&ty::TyUint(UintTy::U16), result @ U16(_)) => Ok(result),
+        (&ty::TyUint(UintTy::U32), result @ U32(_)) => Ok(result),
+        (&ty::TyUint(UintTy::U64), result @ U64(_)) => Ok(result),
+        (&ty::TyUint(UintTy::Us), result @ Usize(_)) => Ok(result),
+
+        (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i64 as i8)),
+        (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i64 as i16)),
+        (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i64 as i32)),
+        (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i64)),
+        (&ty::TyInt(IntTy::Is), Infer(i)) => {
+            match ConstIsize::new(i as i64, tcx.sess.target.int_type) {
+                Ok(val) => Ok(Isize(val)),
+                Err(_) => Ok(Isize(ConstIsize::Is32(i as i64 as i32))),
             }
-        }
-        panic!("No impl or trait container for {:?}", def_id);
+        },
+
+        (&ty::TyInt(IntTy::I8), InferSigned(i)) => Ok(I8(i as i8)),
+        (&ty::TyInt(IntTy::I16), InferSigned(i)) => Ok(I16(i as i16)),
+        (&ty::TyInt(IntTy::I32), InferSigned(i)) => Ok(I32(i as i32)),
+        (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i)),
+        (&ty::TyInt(IntTy::Is), InferSigned(i)) => {
+            match ConstIsize::new(i, tcx.sess.target.int_type) {
+                Ok(val) => Ok(Isize(val)),
+                Err(_) => Ok(Isize(ConstIsize::Is32(i as i32))),
+            }
+        },
+
+        (&ty::TyUint(UintTy::U8), Infer(i)) => Ok(U8(i as u8)),
+        (&ty::TyUint(UintTy::U16), Infer(i)) => Ok(U16(i as u16)),
+        (&ty::TyUint(UintTy::U32), Infer(i)) => Ok(U32(i as u32)),
+        (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i)),
+        (&ty::TyUint(UintTy::Us), Infer(i)) => {
+            match ConstUsize::new(i, tcx.sess.target.uint_type) {
+                Ok(val) => Ok(Usize(val)),
+                Err(_) => Ok(Usize(ConstUsize::Us32(i as u32))),
+            }
+        },
+        (&ty::TyUint(_), InferSigned(_)) => Err(err(IntermediateUnsignedNegative)),
+
+        (&ty::TyInt(ity), i) => Err(err(TypeMismatch(ity.to_string(), i))),
+        (&ty::TyUint(ity), i) => Err(err(TypeMismatch(ity.to_string(), i))),
+
+        (&ty::TyEnum(ref adt, _), i) => {
+            let hints = tcx.lookup_repr_hints(adt.did);
+            let int_ty = tcx.enum_repr_type(hints.iter().next());
+            infer(i, tcx, &int_ty.to_ty(tcx).sty, span)
+        },
+        (_, i) => Err(err(BadType(ConstVal::Integral(i)))),
     }
-    panic!("{:?} is not local", def_id);
 }
 
 fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                                                 ti: &'tcx hir::TraitItem,
                                                 trait_id: DefId,
                                                 rcvr_substs: subst::Substs<'tcx>)
-                                                -> Option<&'tcx Expr>
+                                                -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>
 {
     let trait_ref = ty::Binder(
         rcvr_substs.erase_regions().to_trait_ref(tcx, trait_id)
@@ -1276,7 +1073,9 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
                      .iter().find(|ic| ic.name == ti.name) {
                 Some(ic) => lookup_const_by_id(tcx, ic.def_id, None, None),
                 None => match ti.node {
-                    hir::ConstTraitItem(_, Some(ref expr)) => Some(&*expr),
+                    hir::ConstTraitItem(ref ty, Some(ref expr)) => {
+                        Some((&*expr, ast_ty_to_prim_ty(tcx, ty)))
+                    },
                     _ => None,
                 },
             }
@@ -1289,100 +1088,141 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
     }
 }
 
-fn cast_const<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstVal, ty: Ty) -> CastResult {
-    macro_rules! convert_val {
-        ($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
-            match val {
-                Bool(b) => Ok($const_type(b as u64 as $intermediate_ty as $target_ty)),
-                Uint(u) => Ok($const_type(u as $intermediate_ty as $target_ty)),
-                Int(i) => Ok($const_type(i as $intermediate_ty as $target_ty)),
-                Float(f) => Ok($const_type(f as $intermediate_ty as $target_ty)),
-                _ => Err(ErrKind::CannotCastTo(stringify!($const_type))),
+fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult {
+    let v = val.to_u64_unchecked();
+    match ty.sty {
+        ty::TyBool if v == 0 => Ok(Bool(false)),
+        ty::TyBool if v == 1 => Ok(Bool(true)),
+        ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i64 as i8))),
+        ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i64 as i16))),
+        ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i64 as i32))),
+        ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i64))),
+        ty::TyInt(ast::IntTy::Is) => {
+            match ConstIsize::new(v as i64, tcx.sess.target.int_type) {
+                Ok(val) => Ok(Integral(Isize(val))),
+                Err(_) => Ok(Integral(Isize(ConstIsize::Is32(v as i64 as i32)))),
             }
-        }
+        },
+        ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
+        ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
+        ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
+        ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v))),
+        ty::TyUint(ast::UintTy::Us) => {
+            match ConstUsize::new(v, tcx.sess.target.uint_type) {
+                Ok(val) => Ok(Integral(Usize(val))),
+                Err(_) => Ok(Integral(Usize(ConstUsize::Us32(v as u32)))),
+            }
+        },
+        ty::TyFloat(ast::FloatTy::F64) if val.is_negative() => {
+            // FIXME: this could probably be prettier
+            // there's no easy way to turn an `Infer` into a f64
+            let val = try!((-val).map_err(Math));
+            let val = val.to_u64().unwrap() as f64;
+            let val = -val;
+            Ok(Float(val))
+        },
+        ty::TyFloat(ast::FloatTy::F64) => Ok(Float(val.to_u64().unwrap() as f64)),
+        ty::TyFloat(ast::FloatTy::F32) if val.is_negative() => {
+            let val = try!((-val).map_err(Math));
+            let val = val.to_u64().unwrap() as f32;
+            let val = -val;
+            Ok(Float(val as f64))
+        },
+        ty::TyFloat(ast::FloatTy::F32) => Ok(Float(val.to_u64().unwrap() as f32 as f64)),
+        _ => Err(CannotCast),
     }
+}
 
-    // Issue #23890: If isize/usize, then dispatch to appropriate target representation type
-    match (&ty.sty, tcx.sess.target.int_type, tcx.sess.target.uint_type) {
-        (&ty::TyInt(ast::IntTy::Is), ast::IntTy::I32, _) => return convert_val!(i32, Int, i64),
-        (&ty::TyInt(ast::IntTy::Is), ast::IntTy::I64, _) => return convert_val!(i64, Int, i64),
-        (&ty::TyInt(ast::IntTy::Is), _, _) => panic!("unexpected target.int_type"),
-
-        (&ty::TyUint(ast::UintTy::Us), _, ast::UintTy::U32) => return convert_val!(u32, Uint, u64),
-        (&ty::TyUint(ast::UintTy::Us), _, ast::UintTy::U64) => return convert_val!(u64, Uint, u64),
-        (&ty::TyUint(ast::UintTy::Us), _, _) => panic!("unexpected target.uint_type"),
-
-        _ => {}
+fn cast_const_float<'tcx>(tcx: &TyCtxt<'tcx>, f: f64, ty: ty::Ty) -> CastResult {
+    match ty.sty {
+        ty::TyInt(_) if f >= 0.0 => cast_const_int(tcx, Infer(f as u64), ty),
+        ty::TyInt(_) => cast_const_int(tcx, InferSigned(f as i64), ty),
+        ty::TyUint(_) if f >= 0.0 => cast_const_int(tcx, Infer(f as u64), ty),
+        ty::TyFloat(ast::FloatTy::F64) => Ok(Float(f)),
+        ty::TyFloat(ast::FloatTy::F32) => Ok(Float(f as f32 as f64)),
+        _ => Err(CannotCast),
     }
+}
 
-    match ty.sty {
-        ty::TyInt(ast::IntTy::Is) => unreachable!(),
-        ty::TyUint(ast::UintTy::Us) => unreachable!(),
-
-        ty::TyInt(ast::IntTy::I8) => convert_val!(i8, Int, i64),
-        ty::TyInt(ast::IntTy::I16) => convert_val!(i16, Int, i64),
-        ty::TyInt(ast::IntTy::I32) => convert_val!(i32, Int, i64),
-        ty::TyInt(ast::IntTy::I64) => convert_val!(i64, Int, i64),
-
-        ty::TyUint(ast::UintTy::U8) => convert_val!(u8, Uint, u64),
-        ty::TyUint(ast::UintTy::U16) => convert_val!(u16, Uint, u64),
-        ty::TyUint(ast::UintTy::U32) => convert_val!(u32, Uint, u64),
-        ty::TyUint(ast::UintTy::U64) => convert_val!(u64, Uint, u64),
-
-        ty::TyFloat(ast::FloatTy::F32) => convert_val!(f32, Float, f64),
-        ty::TyFloat(ast::FloatTy::F64) => convert_val!(f64, Float, f64),
-        _ => Err(ErrKind::CannotCast),
+fn cast_const<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult {
+    match val {
+        Integral(i) => cast_const_int(tcx, i, ty),
+        Bool(b) => cast_const_int(tcx, Infer(b as u64), ty),
+        Float(f) => cast_const_float(tcx, f, ty),
+        Char(c) => cast_const_int(tcx, Infer(c as u64), ty),
+        _ => Err(CannotCast),
     }
 }
 
-fn lit_to_const(sess: &Session, span: Span, lit: &ast::Lit, ty_hint: Option<Ty>) -> ConstVal {
-    match lit.node {
-        ast::LitKind::Str(ref s, _) => Str((*s).clone()),
-        ast::LitKind::ByteStr(ref data) => {
-            ByteStr(data.clone())
-        }
-        ast::LitKind::Byte(n) => Uint(n as u64),
-        ast::LitKind::Char(n) => Uint(n as u64),
-        ast::LitKind::Int(n, ast::LitIntType::Signed(_)) => Int(n as i64),
-        ast::LitKind::Int(n, ast::LitIntType::Unsuffixed) => {
-            match ty_hint.map(|ty| &ty.sty) {
-                Some(&ty::TyUint(_)) => Uint(n),
-                _ => Int(n as i64)
+fn lit_to_const<'tcx>(lit: &ast::LitKind,
+                      tcx: &TyCtxt<'tcx>,
+                      ty_hint: Option<Ty<'tcx>>,
+                      span: Span,
+                      ) -> Result<ConstVal, ConstEvalErr> {
+    use syntax::ast::*;
+    use syntax::ast::LitIntType::*;
+    match *lit {
+        LitKind::Str(ref s, _) => Ok(Str((*s).clone())),
+        LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
+        LitKind::Byte(n) => Ok(Integral(U8(n))),
+        LitKind::Int(n, Signed(ity)) => {
+            infer(InferSigned(n as i64), tcx, &ty::TyInt(ity), span).map(Integral)
+        },
+
+        LitKind::Int(n, Unsuffixed) => {
+            match ty_hint.map(|t| &t.sty) {
+                Some(&ty::TyInt(ity)) => {
+                    infer(InferSigned(n as i64), tcx, &ty::TyInt(ity), span).map(Integral)
+                },
+                Some(&ty::TyUint(uty)) => {
+                    infer(Infer(n), tcx, &ty::TyUint(uty), span).map(Integral)
+                },
+                None => Ok(Integral(Infer(n))),
+                Some(&ty::TyEnum(ref adt, _)) => {
+                    let hints = tcx.lookup_repr_hints(adt.did);
+                    let int_ty = tcx.enum_repr_type(hints.iter().next());
+                    infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty, span).map(Integral)
+                },
+                Some(ty_hint) => panic!("bad ty_hint: {:?}, {:?}", ty_hint, lit),
             }
-        }
-        ast::LitKind::Int(n, ast::LitIntType::Unsigned(_)) => Uint(n),
-        ast::LitKind::Float(ref n, _) |
-        ast::LitKind::FloatUnsuffixed(ref n) => {
+        },
+        LitKind::Int(n, Unsigned(ity)) => {
+            infer(Infer(n), tcx, &ty::TyUint(ity), span).map(Integral)
+        },
+
+        LitKind::Float(ref n, _) |
+        LitKind::FloatUnsuffixed(ref n) => {
             if let Ok(x) = n.parse::<f64>() {
-                Float(x)
+                Ok(Float(x))
             } else {
                 // FIXME(#31407) this is only necessary because float parsing is buggy
-                sess.span_bug(span, "could not evaluate float literal (see issue #31407)");
+                tcx.sess.span_bug(span, "could not evaluate float literal (see issue #31407)");
             }
         }
-        ast::LitKind::Bool(b) => Bool(b)
+        LitKind::Bool(b) => Ok(Bool(b)),
+        LitKind::Char(c) => Ok(Char(c)),
     }
 }
 
 pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
-    Some(match (a, b) {
-        (&Int(a), &Int(b)) => a.cmp(&b),
-        (&Uint(a), &Uint(b)) => a.cmp(&b),
+    match (a, b) {
+        (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
         (&Float(a), &Float(b)) => {
             // This is pretty bad but it is the existing behavior.
-            if a == b {
+            Some(if a == b {
                 Ordering::Equal
             } else if a < b {
                 Ordering::Less
             } else {
                 Ordering::Greater
-            }
+            })
         }
-        (&Str(ref a), &Str(ref b)) => a.cmp(b),
-        (&Bool(a), &Bool(b)) => a.cmp(&b),
-        (&ByteStr(ref a), &ByteStr(ref b)) => a.cmp(b),
-        _ => return None
-    })
+        (&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)),
+        _ => None,
+    }
 }
 
 pub fn compare_lit_exprs<'tcx>(tcx: &TyCtxt<'tcx>,
diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs
index 61a7f49f45d..03c13115aea 100644
--- a/src/librustc/middle/ty/context.rs
+++ b/src/librustc/middle/ty/context.rs
@@ -342,8 +342,12 @@ pub struct TyCtxt<'tcx> {
     /// FIXME(arielb1): why is this separate from populated_external_types?
     pub populated_external_primitive_impls: RefCell<DefIdSet>,
 
-    /// These caches are used by const_eval when decoding external constants.
-    pub extern_const_statics: RefCell<DefIdMap<NodeId>>,
+    /// Cache used by const_eval when decoding external constants.
+    /// Contains `None` when the constant has been fetched but doesn't exist.
+    /// Constains `Some(expr_id, type)` otherwise.
+    /// `type` is `None` in case it's not a primitive type
+    pub extern_const_statics: RefCell<DefIdMap<Option<(NodeId, Option<Ty<'tcx>>)>>>,
+    /// Cache used by const_eval when decoding extern const fns
     pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
 
     pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),
diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs
index b54b0b73ef2..2491da7f5f3 100644
--- a/src/librustc/middle/ty/mod.rs
+++ b/src/librustc/middle/ty/mod.rs
@@ -50,6 +50,8 @@ use syntax::attr::{self, AttrMetaMethods};
 use syntax::codemap::{DUMMY_SP, Span};
 use syntax::parse::token::InternedString;
 
+use rustc_const_eval::ConstInt;
+
 use rustc_front::hir;
 use rustc_front::hir::{ItemImpl, ItemTrait, PatKind};
 use rustc_front::intravisit::Visitor;
@@ -100,8 +102,7 @@ mod ivar;
 mod structural_impls;
 mod sty;
 
-pub type Disr = u64;
-pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
+pub type Disr = ConstInt;
 
 // Data types
 
@@ -1580,7 +1581,7 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
     /// Asserts this is a struct and returns the struct's unique
     /// variant.
     pub fn struct_variant(&self) -> &VariantDefData<'tcx, 'container> {
-        assert!(self.adt_kind() == AdtKind::Struct);
+        assert_eq!(self.adt_kind(), AdtKind::Struct);
         &self.variants[0]
     }
 
diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs
index 2b83aaccdc4..c91441a3f8a 100644
--- a/src/librustc/middle/ty/util.rs
+++ b/src/librustc/middle/ty/util.rs
@@ -21,7 +21,8 @@ use middle::traits;
 use middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
 use middle::ty::{Disr, ParameterEnvironment};
 use middle::ty::TypeVariants::*;
-use util::num::ToPrimitive;
+
+use rustc_const_eval::{ConstInt, ConstIsize, ConstUsize};
 
 use std::cmp;
 use std::hash::{Hash, SipHasher, Hasher};
@@ -34,11 +35,9 @@ use rustc_front::hir;
 
 pub trait IntTypeExt {
     fn to_ty<'tcx>(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx>;
-    fn i64_to_disr(&self, val: i64) -> Option<Disr>;
-    fn u64_to_disr(&self, val: u64) -> Option<Disr>;
     fn disr_incr(&self, val: Disr) -> Option<Disr>;
-    fn disr_string(&self, val: Disr) -> String;
-    fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr;
+    fn assert_ty_matches(&self, val: Disr);
+    fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr;
 }
 
 impl IntTypeExt for attr::IntType {
@@ -57,98 +56,48 @@ impl IntTypeExt for attr::IntType {
         }
     }
 
-    fn i64_to_disr(&self, val: i64) -> Option<Disr> {
+    fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr {
         match *self {
-            SignedInt(ast::IntTy::I8)    => val.to_i8()  .map(|v| v as Disr),
-            SignedInt(ast::IntTy::I16)   => val.to_i16() .map(|v| v as Disr),
-            SignedInt(ast::IntTy::I32)   => val.to_i32() .map(|v| v as Disr),
-            SignedInt(ast::IntTy::I64)   => val.to_i64() .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U8)  => val.to_u8()  .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U16) => val.to_u16() .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U32) => val.to_u32() .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U64) => val.to_u64() .map(|v| v as Disr),
-
-            UnsignedInt(ast::UintTy::Us) |
-            SignedInt(ast::IntTy::Is) => unreachable!(),
+            SignedInt(ast::IntTy::I8)    => ConstInt::I8(0),
+            SignedInt(ast::IntTy::I16)   => ConstInt::I16(0),
+            SignedInt(ast::IntTy::I32)   => ConstInt::I32(0),
+            SignedInt(ast::IntTy::I64)   => ConstInt::I64(0),
+            SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type {
+                ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)),
+                ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)),
+                _ => unreachable!(),
+            },
+            UnsignedInt(ast::UintTy::U8)  => ConstInt::U8(0),
+            UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0),
+            UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0),
+            UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0),
+            UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type {
+                ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)),
+                ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(0)),
+                _ => unreachable!(),
+            },
         }
     }
 
-    fn u64_to_disr(&self, val: u64) -> Option<Disr> {
-        match *self {
-            SignedInt(ast::IntTy::I8)    => val.to_i8()  .map(|v| v as Disr),
-            SignedInt(ast::IntTy::I16)   => val.to_i16() .map(|v| v as Disr),
-            SignedInt(ast::IntTy::I32)   => val.to_i32() .map(|v| v as Disr),
-            SignedInt(ast::IntTy::I64)   => val.to_i64() .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U8)  => val.to_u8()  .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U16) => val.to_u16() .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U32) => val.to_u32() .map(|v| v as Disr),
-            UnsignedInt(ast::UintTy::U64) => val.to_u64() .map(|v| v as Disr),
-
-            UnsignedInt(ast::UintTy::Us) |
-            SignedInt(ast::IntTy::Is) => unreachable!(),
+    fn assert_ty_matches(&self, val: Disr) {
+        match (*self, val) {
+            (SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
+            (SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
+            (SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
+            (SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
+            (SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {},
+            (UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
+            (UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
+            (UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
+            (UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
+            (UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {},
+            _ => panic!("disr type mismatch: {:?} vs {:?}", self, val),
         }
     }
 
     fn disr_incr(&self, val: Disr) -> Option<Disr> {
-        macro_rules! add1 {
-            ($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) }
-        }
-        match *self {
-            // SignedInt repr means we *want* to reinterpret the bits
-            // treating the highest bit of Disr as a sign-bit, so
-            // cast to i64 before range-checking.
-            SignedInt(ast::IntTy::I8)    => add1!((val as i64).to_i8()),
-            SignedInt(ast::IntTy::I16)   => add1!((val as i64).to_i16()),
-            SignedInt(ast::IntTy::I32)   => add1!((val as i64).to_i32()),
-            SignedInt(ast::IntTy::I64)   => add1!(Some(val as i64)),
-
-            UnsignedInt(ast::UintTy::U8)  => add1!(val.to_u8()),
-            UnsignedInt(ast::UintTy::U16) => add1!(val.to_u16()),
-            UnsignedInt(ast::UintTy::U32) => add1!(val.to_u32()),
-            UnsignedInt(ast::UintTy::U64) => add1!(Some(val)),
-
-            UnsignedInt(ast::UintTy::Us) |
-            SignedInt(ast::IntTy::Is) => unreachable!(),
-        }
-    }
-
-    // This returns a String because (1.) it is only used for
-    // rendering an error message and (2.) a string can represent the
-    // full range from `i64::MIN` through `u64::MAX`.
-    fn disr_string(&self, val: Disr) -> String {
-        match *self {
-            SignedInt(ast::IntTy::I8)    => format!("{}", val as i8 ),
-            SignedInt(ast::IntTy::I16)   => format!("{}", val as i16),
-            SignedInt(ast::IntTy::I32)   => format!("{}", val as i32),
-            SignedInt(ast::IntTy::I64)   => format!("{}", val as i64),
-            UnsignedInt(ast::UintTy::U8)  => format!("{}", val as u8 ),
-            UnsignedInt(ast::UintTy::U16) => format!("{}", val as u16),
-            UnsignedInt(ast::UintTy::U32) => format!("{}", val as u32),
-            UnsignedInt(ast::UintTy::U64) => format!("{}", val as u64),
-
-            UnsignedInt(ast::UintTy::Us) |
-            SignedInt(ast::IntTy::Is) => unreachable!(),
-        }
-    }
-
-    fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr {
-        macro_rules! add1 {
-            ($e:expr) => { ($e).wrapping_add(1) as Disr }
-        }
-        let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE);
-        match *self {
-            SignedInt(ast::IntTy::I8)    => add1!(val as i8 ),
-            SignedInt(ast::IntTy::I16)   => add1!(val as i16),
-            SignedInt(ast::IntTy::I32)   => add1!(val as i32),
-            SignedInt(ast::IntTy::I64)   => add1!(val as i64),
-            UnsignedInt(ast::UintTy::U8)  => add1!(val as u8 ),
-            UnsignedInt(ast::UintTy::U16) => add1!(val as u16),
-            UnsignedInt(ast::UintTy::U32) => add1!(val as u32),
-            UnsignedInt(ast::UintTy::U64) => add1!(val as u64),
-
-            UnsignedInt(ast::UintTy::Us) |
-            SignedInt(ast::IntTy::Is) => unreachable!(),
-        }
+        self.assert_ty_matches(val);
+        (val + ConstInt::Infer(1)).ok()
     }
 }
 
@@ -266,13 +215,11 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    /// Returns `(normalized_type, ty)`, where `normalized_type` is the
-    /// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8},
-    /// and `ty` is the original type (i.e. may include `isize` or
-    /// `usize`).
-    pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>)
-                          -> (attr::IntType, Ty<'tcx>) {
-        let repr_type = match opt_hint {
+    /// Returns the IntType representation.
+    /// This used to ensure `int_ty` doesn't contain `usize` and `isize`
+    /// by converting them to their actual types. That doesn't happen anymore.
+    pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType {
+        match opt_hint {
             // Feed in the given type
             Some(&attr::ReprInt(_, int_t)) => int_t,
             // ... but provide sensible default if none provided
@@ -280,18 +227,7 @@ impl<'tcx> TyCtxt<'tcx> {
             // NB. Historically `fn enum_variants` generate i64 here, while
             // rustc_typeck::check would generate isize.
             _ => SignedInt(ast::IntTy::Is),
-        };
-
-        let repr_type_ty = repr_type.to_ty(self);
-        let repr_type = match repr_type {
-            SignedInt(ast::IntTy::Is) =>
-                SignedInt(self.sess.target.int_type),
-            UnsignedInt(ast::UintTy::Us) =>
-                UnsignedInt(self.sess.target.uint_type),
-            other => other
-        };
-
-        (repr_type, repr_type_ty)
+        }
     }
 
     /// Returns the deeply last field of nested structures, or the same type,
@@ -335,15 +271,16 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize {
         let hint = UncheckedExprHint(self.types.usize);
         match const_eval::eval_const_expr_partial(self, count_expr, hint, None) {
-            Ok(val) => {
-                let found = match val {
-                    ConstVal::Uint(count) => return count as usize,
-                    ConstVal::Int(count) if count >= 0 => return count as usize,
-                    const_val => const_val.description(),
-                };
+            Ok(ConstVal::Integral(ConstInt::Usize(count))) => {
+                let val = count.as_u64(self.sess.target.uint_type);
+                assert_eq!(val as usize as u64, val);
+                val as usize
+            },
+            Ok(const_val) => {
                 span_err!(self.sess, count_expr.span, E0306,
-                    "expected positive integer for repeat count, found {}",
-                    found);
+                          "expected positive integer for repeat count, found {}",
+                          const_val.description());
+                0
             }
             Err(err) => {
                 let err_msg = match count_expr.node {
@@ -360,9 +297,9 @@ impl<'tcx> TyCtxt<'tcx> {
                 };
                 span_err!(self.sess, count_expr.span, E0307,
                     "expected constant integer for repeat count, {}", err_msg);
+                0
             }
         }
-        0
     }
 
     /// Given a set of predicates that apply to an object type, returns
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 127cc96859a..11bb381ec33 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -10,6 +10,7 @@
 
 use graphviz::IntoCow;
 use middle::const_eval::ConstVal;
+use rustc_const_eval::{ConstUsize, ConstInt};
 use middle::def_id::DefId;
 use middle::subst::Substs;
 use middle::ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
@@ -851,13 +852,12 @@ pub struct Constant<'tcx> {
 pub struct TypedConstVal<'tcx> {
     pub ty: Ty<'tcx>,
     pub span: Span,
-    pub value: ConstVal
+    pub value: ConstUsize,
 }
 
 impl<'tcx> Debug for TypedConstVal<'tcx> {
     fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
-        try!(write!(fmt, "const "));
-        fmt_const_val(fmt, &self.value)
+        write!(fmt, "const {}", ConstInt::Usize(self.value))
     }
 }
 
@@ -897,8 +897,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
     use middle::const_eval::ConstVal::*;
     match *const_val {
         Float(f) => write!(fmt, "{:?}", f),
-        Int(n) => write!(fmt, "{:?}", n),
-        Uint(n) => write!(fmt, "{:?}", n),
+        Integral(n) => write!(fmt, "{}", n),
         Str(ref s) => write!(fmt, "{:?}", s),
         ByteStr(ref bytes) => {
             let escaped: String = bytes
@@ -911,6 +910,8 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
         Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
         Struct(node_id) | Tuple(node_id) | Array(node_id, _) | Repeat(node_id, _) =>
             write!(fmt, "{}", node_to_string(node_id)),
+        Char(c) => write!(fmt, "{:?}", c),
+        Dummy => unreachable!(),
     }
 }
 
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 26f6db4aa4f..b6b2694a7cb 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -14,7 +14,6 @@
  */
 
 use mir::repr::*;
-use middle::const_eval::ConstVal;
 use middle::subst::{Subst, Substs};
 use middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_front::hir;
@@ -144,12 +143,10 @@ impl<'tcx> Mir<'tcx> {
         match *rvalue {
             Rvalue::Use(ref operand) => Some(self.operand_ty(tcx, operand)),
             Rvalue::Repeat(ref operand, ref count) => {
-                if let ConstVal::Uint(u) = count.value {
-                    let op_ty = self.operand_ty(tcx, operand);
-                    Some(tcx.mk_array(op_ty, u as usize))
-                } else {
-                    None
-                }
+                let op_ty = self.operand_ty(tcx, operand);
+                let count = count.value.as_u64(tcx.sess.target.uint_type);
+                assert_eq!(count as usize as u64, count);
+                Some(tcx.mk_array(op_ty, count as usize))
             }
             Rvalue::Ref(reg, bk, ref lv) => {
                 let lv_ty = self.lvalue_ty(tcx, lv).to_ty(tcx);
diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml
new file mode 100644
index 00000000000..f885e9a94d5
--- /dev/null
+++ b/src/librustc_const_eval/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_const_eval"
+version = "0.0.0"
+
+[lib]
+name = "rustc_const_eval"
+path = "lib.rs"
+crate-type = ["dylib"]
+
+[dependencies]
+log = { path = "../liblog" }
+serialize = { path = "../libserialize" }
+syntax = { path = "../libsyntax" }
diff --git a/src/librustc_const_eval/err.rs b/src/librustc_const_eval/err.rs
new file mode 100644
index 00000000000..126b3824efe
--- /dev/null
+++ b/src/librustc_const_eval/err.rs
@@ -0,0 +1,85 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use syntax::ast;
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum ConstMathErr {
+    NotInRange,
+    CmpBetweenUnequalTypes,
+    UnequalTypes(Op),
+    Overflow(Op),
+    ShiftNegative,
+    DivisionByZero,
+    RemainderByZero,
+    UnsignedNegation,
+    ULitOutOfRange(ast::UintTy),
+    LitOutOfRange(ast::IntTy),
+}
+pub use self::ConstMathErr::*;
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum Op {
+    Add,
+    Sub,
+    Mul,
+    Div,
+    Rem,
+    Shr,
+    Shl,
+    Neg,
+    BitAnd,
+    BitOr,
+    BitXor,
+}
+
+impl ConstMathErr {
+    pub fn description(&self) -> &'static str {
+        use self::Op::*;
+        match *self {
+            NotInRange => "inferred value out of range",
+            CmpBetweenUnequalTypes => "compared two integrals of different types",
+            UnequalTypes(Add) => "tried to add two integrals of different types",
+            UnequalTypes(Sub) => "tried to subtract two integrals of different types",
+            UnequalTypes(Mul) => "tried to multiply two integrals of different types",
+            UnequalTypes(Div) => "tried to divide two integrals of different types",
+            UnequalTypes(Rem) => {
+                "tried to calculate the remainder of two integrals of different types"
+            },
+            UnequalTypes(BitAnd) => "tried to bitand two integrals of different types",
+            UnequalTypes(BitOr) => "tried to bitor two integrals of different types",
+            UnequalTypes(BitXor) => "tried to xor two integrals of different types",
+            UnequalTypes(_) => unreachable!(),
+            Overflow(Add) => "attempted to add with overflow",
+            Overflow(Sub) => "attempted to subtract with overflow",
+            Overflow(Mul) => "attempted to multiply with overflow",
+            Overflow(Div) => "attempted to divide with overflow",
+            Overflow(Rem) => "attempted to calculate the remainder with overflow",
+            Overflow(Neg) => "attempted to negate with overflow",
+            Overflow(Shr) => "attempted to shift right with overflow",
+            Overflow(Shl) => "attempted to shift left with overflow",
+            Overflow(_) => unreachable!(),
+            ShiftNegative => "attempted to shift by a negative amount",
+            DivisionByZero => "attempted to divide by zero",
+            RemainderByZero => "attempted to calculate the remainder with a divisor of zero",
+            UnsignedNegation => "unary negation of unsigned integer",
+            ULitOutOfRange(ast::UintTy::U8) => "literal out of range for u8",
+            ULitOutOfRange(ast::UintTy::U16) => "literal out of range for u16",
+            ULitOutOfRange(ast::UintTy::U32) => "literal out of range for u32",
+            ULitOutOfRange(ast::UintTy::U64) => "literal out of range for u64",
+            ULitOutOfRange(ast::UintTy::Us) => "literal out of range for usize",
+            LitOutOfRange(ast::IntTy::I8) => "literal out of range for i8",
+            LitOutOfRange(ast::IntTy::I16) => "literal out of range for i16",
+            LitOutOfRange(ast::IntTy::I32) => "literal out of range for i32",
+            LitOutOfRange(ast::IntTy::I64) => "literal out of range for i64",
+            LitOutOfRange(ast::IntTy::Is) => "literal out of range for isize",
+        }
+    }
+}
diff --git a/src/librustc_const_eval/int.rs b/src/librustc_const_eval/int.rs
new file mode 100644
index 00000000000..15253987bf2
--- /dev/null
+++ b/src/librustc_const_eval/int.rs
@@ -0,0 +1,569 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cmp::Ordering;
+use syntax::attr::IntType;
+use syntax::ast::{IntTy, UintTy};
+
+use super::is::*;
+use super::us::*;
+use super::err::*;
+
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
+pub enum ConstInt {
+    I8(i8),
+    I16(i16),
+    I32(i32),
+    I64(i64),
+    Isize(ConstIsize),
+    U8(u8),
+    U16(u16),
+    U32(u32),
+    U64(u64),
+    Usize(ConstUsize),
+    Infer(u64),
+    InferSigned(i64),
+}
+pub use self::ConstInt::*;
+
+
+macro_rules! bounds {
+    ($($t:ident $min:ident $max:ident)*) => {
+        mod as_u64 {
+            $(
+                #[allow(dead_code)]
+                pub const $min: u64 = ::std::$t::MIN as u64;
+                #[allow(dead_code)]
+                pub const $max: u64 = ::std::$t::MAX as u64;
+            )*
+        }
+        mod as_i64 {
+            $(
+                #[allow(dead_code)]
+                pub const $min: i64 = ::std::$t::MIN as i64;
+                #[allow(dead_code)]
+                pub const $max: i64 = ::std::$t::MAX as i64;
+            )*
+        }
+    }
+}
+
+bounds!{
+    i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX isize IMIN IMAX
+    u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX usize UMIN UMAX
+}
+
+impl ConstInt {
+    /// If either value is `Infer` or `InferSigned`, try to turn the value into the type of
+    /// the other value. If both values have no type, don't do anything
+    pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> {
+        let inferred = match (self, other) {
+            (InferSigned(_), InferSigned(_))
+            | (Infer(_), Infer(_)) => self, // no inference possible
+            // kindof wrong, you could have had values > I64MAX during computation of a
+            (Infer(a @ 0...as_u64::I64MAX), InferSigned(_)) => InferSigned(a as i64),
+            (Infer(_), InferSigned(_)) => return Err(ConstMathErr::NotInRange),
+            (_, InferSigned(_))
+            | (_, Infer(_)) => return other.infer(self).map(|(b, a)| (a, b)),
+
+            (Infer(a @ 0...as_u64::I8MAX), I8(_)) => I8(a as i64 as i8),
+            (Infer(a @ 0...as_u64::I16MAX), I16(_)) => I16(a as i64 as i16),
+            (Infer(a @ 0...as_u64::I32MAX), I32(_)) => I32(a as i64 as i32),
+            (Infer(a @ 0...as_u64::I64MAX), I64(_)) => I64(a as i64),
+            (Infer(a @ 0...as_u64::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)),
+            (Infer(a @ 0...as_u64::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)),
+            (Infer(a @ 0...as_u64::U8MAX), U8(_)) => U8(a as u8),
+            (Infer(a @ 0...as_u64::U16MAX), U16(_)) => U16(a as u16),
+            (Infer(a @ 0...as_u64::U32MAX), U32(_)) => U32(a as u32),
+            (Infer(a), U64(_)) => U64(a),
+            (Infer(a @ 0...as_u64::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
+            (Infer(a), Usize(Us64(_))) => Usize(Us64(a)),
+
+            (Infer(_), _) => return Err(ConstMathErr::NotInRange),
+
+            (InferSigned(a @ as_i64::I8MIN...as_i64::I8MAX), I8(_)) => I8(a as i8),
+            (InferSigned(a @ as_i64::I16MIN...as_i64::I16MAX), I16(_)) => I16(a as i16),
+            (InferSigned(a @ as_i64::I32MIN...as_i64::I32MAX), I32(_)) => I32(a as i32),
+            (InferSigned(a), I64(_)) => I64(a),
+            (InferSigned(a @ as_i64::I32MIN...as_i64::I32MAX), Isize(Is32(_))) => {
+                Isize(Is32(a as i32))
+            },
+            (InferSigned(a), Isize(Is64(_))) => Isize(Is64(a)),
+            (InferSigned(a @ 0...as_i64::U8MAX), U8(_)) => U8(a as u8),
+            (InferSigned(a @ 0...as_i64::U16MAX), U16(_)) => U16(a as u16),
+            (InferSigned(a @ 0...as_i64::U32MAX), U32(_)) => U32(a as u32),
+            (InferSigned(a @ 0...as_i64::I64MAX), U64(_)) => U64(a as u64),
+            (InferSigned(a @ 0...as_i64::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
+            (InferSigned(a @ 0...as_i64::I64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
+            (InferSigned(_), _) => return Err(ConstMathErr::NotInRange),
+            _ => self, // already known types
+        };
+        Ok((inferred, other))
+    }
+
+    /// Turn this value into an `Infer` or an `InferSigned`
+    pub fn erase_type(self) -> Self {
+        match self {
+            Infer(i) => Infer(i),
+            InferSigned(i) if i < 0 => InferSigned(i),
+            I8(i) if i < 0 => InferSigned(i as i64),
+            I16(i) if i < 0 => InferSigned(i as i64),
+            I32(i) if i < 0 => InferSigned(i as i64),
+            I64(i) if i < 0 => InferSigned(i as i64),
+            Isize(Is32(i)) if i < 0 => InferSigned(i as i64),
+            Isize(Is64(i)) if i < 0 => InferSigned(i as i64),
+            InferSigned(i) => Infer(i as u64),
+            I8(i) => Infer(i as u64),
+            I16(i) => Infer(i as u64),
+            I32(i) => Infer(i as u64),
+            I64(i) => Infer(i as u64),
+            Isize(Is32(i)) => Infer(i as u64),
+            Isize(Is64(i)) => Infer(i as u64),
+            U8(i) => Infer(i as u64),
+            U16(i) => Infer(i as u64),
+            U32(i) => Infer(i as u64),
+            U64(i) => Infer(i as u64),
+            Usize(Us32(i)) => Infer(i as u64),
+            Usize(Us64(i)) => Infer(i),
+        }
+    }
+
+    /// Description of the type, not the value
+    pub fn description(&self) -> &'static str {
+        match *self {
+            Infer(_) => "not yet inferred integral",
+            InferSigned(_) => "not yet inferred signed integral",
+            I8(_) => "i8",
+            I16(_) => "i16",
+            I32(_) => "i32",
+            I64(_) => "i64",
+            Isize(_) => "isize",
+            U8(_) => "u8",
+            U16(_) => "u16",
+            U32(_) => "u32",
+            U64(_) => "u64",
+            Usize(_) => "usize",
+        }
+    }
+
+    /// Erases the type and returns a u64.
+    /// This is not the same as `-5i8 as u64` but as `-5i8 as i64 as u64`
+    pub fn to_u64_unchecked(self) -> u64 {
+        match self.erase_type() {
+            ConstInt::Infer(i) => i,
+            ConstInt::InferSigned(i) => i as u64,
+            _ => unreachable!(),
+        }
+    }
+
+    /// Converts the value to a `u32` if it's in the range 0...std::u32::MAX
+    pub fn to_u32(&self) -> Option<u32> {
+        match *self {
+            I8(v) if v >= 0 => Some(v as u32),
+            I16(v) if v >= 0 => Some(v as u32),
+            I32(v) if v >= 0 => Some(v as u32),
+            InferSigned(v)
+            | Isize(Is64(v))
+            | I64(v) if v >= 0 && v <= ::std::u32::MAX as i64 => Some(v as u32),
+            Isize(Is32(v)) if v >= 0 => Some(v as u32),
+            U8(v) => Some(v as u32),
+            U16(v) => Some(v as u32),
+            U32(v) => Some(v),
+            Infer(v)
+            | Usize(Us64(v))
+            | U64(v) if v <= ::std::u32::MAX as u64 => Some(v as u32),
+            Usize(Us32(v)) => Some(v),
+            _ => None,
+        }
+    }
+
+    /// Converts the value to a `u64` if it's >= 0
+    pub fn to_u64(&self) -> Option<u64> {
+        match *self {
+            Infer(v) => Some(v),
+            InferSigned(v) if v >= 0 => Some(v as u64),
+            I8(v) if v >= 0 => Some(v as u64),
+            I16(v) if v >= 0 => Some(v as u64),
+            I32(v) if v >= 0 => Some(v as u64),
+            I64(v) if v >= 0 => Some(v as u64),
+            Isize(Is32(v)) if v >= 0 => Some(v as u64),
+            Isize(Is64(v)) if v >= 0 => Some(v as u64),
+            U8(v) => Some(v as u64),
+            U16(v) => Some(v as u64),
+            U32(v) => Some(v as u64),
+            U64(v) => Some(v),
+            Usize(Us32(v)) => Some(v as u64),
+            Usize(Us64(v)) => Some(v),
+            _ => None,
+        }
+    }
+
+    pub fn is_negative(&self) -> bool {
+        match *self {
+            I8(v) => v < 0,
+            I16(v) => v < 0,
+            I32(v) => v < 0,
+            I64(v) => v < 0,
+            Isize(Is32(v)) => v < 0,
+            Isize(Is64(v)) => v < 0,
+            InferSigned(v) => v < 0,
+            _ => false,
+        }
+    }
+
+    /// Compares the values if they are of the same type
+    pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
+        match try!(self.infer(rhs)) {
+            (I8(a), I8(b)) => Ok(a.cmp(&b)),
+            (I16(a), I16(b)) => Ok(a.cmp(&b)),
+            (I32(a), I32(b)) => Ok(a.cmp(&b)),
+            (I64(a), I64(b)) => Ok(a.cmp(&b)),
+            (Isize(Is32(a)), Isize(Is32(b))) => Ok(a.cmp(&b)),
+            (Isize(Is64(a)), Isize(Is64(b))) => Ok(a.cmp(&b)),
+            (U8(a), U8(b)) => Ok(a.cmp(&b)),
+            (U16(a), U16(b)) => Ok(a.cmp(&b)),
+            (U32(a), U32(b)) => Ok(a.cmp(&b)),
+            (U64(a), U64(b)) => Ok(a.cmp(&b)),
+            (Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)),
+            (Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)),
+            (Infer(a), Infer(b)) => Ok(a.cmp(&b)),
+            (InferSigned(a), InferSigned(b)) => Ok(a.cmp(&b)),
+            _ => Err(CmpBetweenUnequalTypes),
+        }
+    }
+
+    /// Adds 1 to the value and wraps around if the maximum for the type is reached
+    pub fn wrap_incr(self) -> Self {
+        macro_rules! add1 {
+            ($e:expr) => { ($e).wrapping_add(1) }
+        }
+        match self {
+            ConstInt::I8(i) => ConstInt::I8(add1!(i)),
+            ConstInt::I16(i) => ConstInt::I16(add1!(i)),
+            ConstInt::I32(i) => ConstInt::I32(add1!(i)),
+            ConstInt::I64(i) => ConstInt::I64(add1!(i)),
+            ConstInt::Isize(ConstIsize::Is32(i)) => ConstInt::Isize(ConstIsize::Is32(add1!(i))),
+            ConstInt::Isize(ConstIsize::Is64(i)) => ConstInt::Isize(ConstIsize::Is64(add1!(i))),
+            ConstInt::U8(i) => ConstInt::U8(add1!(i)),
+            ConstInt::U16(i) => ConstInt::U16(add1!(i)),
+            ConstInt::U32(i) => ConstInt::U32(add1!(i)),
+            ConstInt::U64(i) => ConstInt::U64(add1!(i)),
+            ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))),
+            ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))),
+            ConstInt::Infer(_) | ConstInt::InferSigned(_) => panic!("no type info for const int"),
+        }
+    }
+
+    pub fn int_type(self) -> Option<IntType> {
+        match self {
+            ConstInt::I8(_) => Some(IntType::SignedInt(IntTy::I8)),
+            ConstInt::I16(_) => Some(IntType::SignedInt(IntTy::I16)),
+            ConstInt::I32(_) => Some(IntType::SignedInt(IntTy::I32)),
+            ConstInt::I64(_) => Some(IntType::SignedInt(IntTy::I64)),
+            ConstInt::Isize(_) => Some(IntType::SignedInt(IntTy::Is)),
+            ConstInt::U8(_) => Some(IntType::UnsignedInt(UintTy::U8)),
+            ConstInt::U16(_) => Some(IntType::UnsignedInt(UintTy::U16)),
+            ConstInt::U32(_) => Some(IntType::UnsignedInt(UintTy::U32)),
+            ConstInt::U64(_) => Some(IntType::UnsignedInt(UintTy::U64)),
+            ConstInt::Usize(_) => Some(IntType::UnsignedInt(UintTy::Us)),
+            _ => None,
+        }
+    }
+}
+
+impl ::std::cmp::PartialOrd for ConstInt {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.try_cmp(*other).ok()
+    }
+}
+
+impl ::std::cmp::Ord for ConstInt {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.try_cmp(*other).unwrap()
+    }
+}
+
+impl ::std::fmt::Display for ConstInt {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
+        match *self {
+            Infer(i) => write!(fmt, "{}", i),
+            InferSigned(i) => write!(fmt, "{}", i),
+            I8(i) => write!(fmt, "{}i8", i),
+            I16(i) => write!(fmt, "{}i16", i),
+            I32(i) => write!(fmt, "{}i32", i),
+            I64(i) => write!(fmt, "{}i64", i),
+            Isize(ConstIsize::Is64(i)) => write!(fmt, "{}isize", i),
+            Isize(ConstIsize::Is32(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),
+            Usize(ConstUsize::Us64(i)) => write!(fmt, "{}usize", i),
+            Usize(ConstUsize::Us32(i)) => write!(fmt, "{}usize", i),
+        }
+    }
+}
+
+macro_rules! overflowing {
+    ($e:expr, $err:expr) => {{
+        if $e.1 {
+            return Err(Overflow($err));
+        } else {
+            $e.0
+        }
+    }}
+}
+
+macro_rules! impl_binop {
+    ($op:ident, $func:ident, $checked_func:ident) => {
+        impl ::std::ops::$op for ConstInt {
+            type Output = Result<Self, ConstMathErr>;
+            fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
+                match try!(self.infer(rhs)) {
+                    (I8(a), I8(b)) => a.$checked_func(b).map(I8),
+                    (I16(a), I16(b)) => a.$checked_func(b).map(I16),
+                    (I32(a), I32(b)) => a.$checked_func(b).map(I32),
+                    (I64(a), I64(b)) => a.$checked_func(b).map(I64),
+                    (Isize(Is32(a)), Isize(Is32(b))) => a.$checked_func(b).map(Is32).map(Isize),
+                    (Isize(Is64(a)), Isize(Is64(b))) => a.$checked_func(b).map(Is64).map(Isize),
+                    (U8(a), U8(b)) => a.$checked_func(b).map(U8),
+                    (U16(a), U16(b)) => a.$checked_func(b).map(U16),
+                    (U32(a), U32(b)) => a.$checked_func(b).map(U32),
+                    (U64(a), U64(b)) => a.$checked_func(b).map(U64),
+                    (Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize),
+                    (Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize),
+                    (Infer(a), Infer(b)) => a.$checked_func(b).map(Infer),
+                    (InferSigned(a), InferSigned(b)) => a.$checked_func(b).map(InferSigned),
+                    _ => return Err(UnequalTypes(Op::$op)),
+                }.ok_or(Overflow(Op::$op))
+            }
+        }
+    }
+}
+
+macro_rules! derive_binop {
+    ($op:ident, $func:ident) => {
+        impl ::std::ops::$op for ConstInt {
+            type Output = Result<Self, ConstMathErr>;
+            fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
+                match try!(self.infer(rhs)) {
+                    (I8(a), I8(b)) => Ok(I8(a.$func(b))),
+                    (I16(a), I16(b)) => Ok(I16(a.$func(b))),
+                    (I32(a), I32(b)) => Ok(I32(a.$func(b))),
+                    (I64(a), I64(b)) => Ok(I64(a.$func(b))),
+                    (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a.$func(b)))),
+                    (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a.$func(b)))),
+                    (U8(a), U8(b)) => Ok(U8(a.$func(b))),
+                    (U16(a), U16(b)) => Ok(U16(a.$func(b))),
+                    (U32(a), U32(b)) => Ok(U32(a.$func(b))),
+                    (U64(a), U64(b)) => Ok(U64(a.$func(b))),
+                    (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))),
+                    (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))),
+                    (Infer(a), Infer(b)) => Ok(Infer(a.$func(b))),
+                    (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a.$func(b))),
+                    _ => Err(UnequalTypes(Op::$op)),
+                }
+            }
+        }
+    }
+}
+
+impl_binop!(Add, add, checked_add);
+impl_binop!(Sub, sub, checked_sub);
+impl_binop!(Mul, mul, checked_mul);
+derive_binop!(BitAnd, bitand);
+derive_binop!(BitOr, bitor);
+derive_binop!(BitXor, bitxor);
+
+fn check_division(
+    lhs: ConstInt,
+    rhs: ConstInt,
+    op: Op,
+    zerr: ConstMathErr,
+) -> Result<(), ConstMathErr> {
+    match (lhs, rhs) {
+        (I8(_), I8(0)) => Err(zerr),
+        (I16(_), I16(0)) => Err(zerr),
+        (I32(_), I32(0)) => Err(zerr),
+        (I64(_), I64(0)) => Err(zerr),
+        (Isize(_), Isize(Is32(0))) => Err(zerr),
+        (Isize(_), Isize(Is64(0))) => Err(zerr),
+        (InferSigned(_), InferSigned(0)) => Err(zerr),
+
+        (U8(_), U8(0)) => Err(zerr),
+        (U16(_), U16(0)) => Err(zerr),
+        (U32(_), U32(0)) => Err(zerr),
+        (U64(_), U64(0)) => Err(zerr),
+        (Usize(_), Usize(Us32(0))) => Err(zerr),
+        (Usize(_), Usize(Us64(0))) => Err(zerr),
+        (Infer(_), Infer(0)) => Err(zerr),
+
+        (I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)),
+        (I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)),
+        (I32(::std::i32::MIN), I32(-1)) => Err(Overflow(op)),
+        (I64(::std::i64::MIN), I64(-1)) => Err(Overflow(op)),
+        (Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)),
+        (Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)),
+        (InferSigned(::std::i64::MIN), InferSigned(-1)) => Err(Overflow(op)),
+
+        _ => Ok(()),
+    }
+}
+
+impl ::std::ops::Div for ConstInt {
+    type Output = Result<Self, ConstMathErr>;
+    fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
+        let (lhs, rhs) = try!(self.infer(rhs));
+        try!(check_division(lhs, rhs, Op::Div, DivisionByZero));
+        match (lhs, rhs) {
+            (I8(a), I8(b)) => Ok(I8(a/b)),
+            (I16(a), I16(b)) => Ok(I16(a/b)),
+            (I32(a), I32(b)) => Ok(I32(a/b)),
+            (I64(a), I64(b)) => Ok(I64(a/b)),
+            (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))),
+            (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))),
+            (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a/b)),
+
+            (U8(a), U8(b)) => Ok(U8(a/b)),
+            (U16(a), U16(b)) => Ok(U16(a/b)),
+            (U32(a), U32(b)) => Ok(U32(a/b)),
+            (U64(a), U64(b)) => Ok(U64(a/b)),
+            (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))),
+            (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))),
+            (Infer(a), Infer(b)) => Ok(Infer(a/b)),
+
+            _ => Err(UnequalTypes(Op::Div)),
+        }
+    }
+}
+
+impl ::std::ops::Rem for ConstInt {
+    type Output = Result<Self, ConstMathErr>;
+    fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
+        let (lhs, rhs) = try!(self.infer(rhs));
+        // should INT_MIN%-1 be zero or an error?
+        try!(check_division(lhs, rhs, Op::Rem, RemainderByZero));
+        match (lhs, rhs) {
+            (I8(a), I8(b)) => Ok(I8(a%b)),
+            (I16(a), I16(b)) => Ok(I16(a%b)),
+            (I32(a), I32(b)) => Ok(I32(a%b)),
+            (I64(a), I64(b)) => Ok(I64(a%b)),
+            (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))),
+            (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))),
+            (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a%b)),
+
+            (U8(a), U8(b)) => Ok(U8(a%b)),
+            (U16(a), U16(b)) => Ok(U16(a%b)),
+            (U32(a), U32(b)) => Ok(U32(a%b)),
+            (U64(a), U64(b)) => Ok(U64(a%b)),
+            (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))),
+            (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))),
+            (Infer(a), Infer(b)) => Ok(Infer(a%b)),
+
+            _ => Err(UnequalTypes(Op::Rem)),
+        }
+    }
+}
+
+impl ::std::ops::Shl<ConstInt> for ConstInt {
+    type Output = Result<Self, ConstMathErr>;
+    fn shl(self, rhs: Self) -> Result<Self, ConstMathErr> {
+        let b = try!(rhs.to_u32().ok_or(ShiftNegative));
+        match self {
+            I8(a) => Ok(I8(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            I16(a) => Ok(I16(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            I32(a) => Ok(I32(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            I64(a) => Ok(I64(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
+            Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
+            U8(a) => Ok(U8(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            U16(a) => Ok(U16(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            U32(a) => Ok(U32(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            U64(a) => Ok(U64(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
+            Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
+            Infer(a) => Ok(Infer(overflowing!(a.overflowing_shl(b), Op::Shl))),
+            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shl(b), Op::Shl))),
+        }
+    }
+}
+
+impl ::std::ops::Shr<ConstInt> for ConstInt {
+    type Output = Result<Self, ConstMathErr>;
+    fn shr(self, rhs: Self) -> Result<Self, ConstMathErr> {
+        let b = try!(rhs.to_u32().ok_or(ShiftNegative));
+        match self {
+            I8(a) => Ok(I8(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            I16(a) => Ok(I16(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            I32(a) => Ok(I32(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            I64(a) => Ok(I64(overflowing!(a.overflowing_shr(b), Op::Shl))),
+            Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
+            Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
+            U8(a) => Ok(U8(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            U16(a) => Ok(U16(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            U32(a) => Ok(U32(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            U64(a) => Ok(U64(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
+            Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
+            Infer(a) => Ok(Infer(overflowing!(a.overflowing_shr(b), Op::Shr))),
+            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shr(b), Op::Shr))),
+        }
+    }
+}
+
+impl ::std::ops::Neg for ConstInt {
+    type Output = Result<Self, ConstMathErr>;
+    fn neg(self) -> Result<Self, ConstMathErr> {
+        match self {
+            I8(a) => Ok(I8(overflowing!(a.overflowing_neg(), Op::Neg))),
+            I16(a) => Ok(I16(overflowing!(a.overflowing_neg(), Op::Neg))),
+            I32(a) => Ok(I32(overflowing!(a.overflowing_neg(), Op::Neg))),
+            I64(a) => Ok(I64(overflowing!(a.overflowing_neg(), Op::Neg))),
+            Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_neg(), Op::Neg)))),
+            Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_neg(), Op::Neg)))),
+            U8(0) => Ok(U8(0)),
+            U16(0) => Ok(U16(0)),
+            U32(0) => Ok(U32(0)),
+            U64(0) => Ok(U64(0)),
+            Usize(Us32(0)) => Ok(Usize(Us32(0))),
+            Usize(Us64(0)) => Ok(Usize(Us64(0))),
+            U8(_) => Err(UnsignedNegation),
+            U16(_) => Err(UnsignedNegation),
+            U32(_) => Err(UnsignedNegation),
+            U64(_) => Err(UnsignedNegation),
+            Usize(_) => Err(UnsignedNegation),
+            Infer(a @ 0...as_u64::I64MAX) => Ok(InferSigned(-(a as i64))),
+            Infer(_) => Err(Overflow(Op::Neg)),
+            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))),
+        }
+    }
+}
+
+impl ::std::ops::Not for ConstInt {
+    type Output = Result<Self, ConstMathErr>;
+    fn not(self) -> Result<Self, ConstMathErr> {
+        match self {
+            I8(a) => Ok(I8(!a)),
+            I16(a) => Ok(I16(!a)),
+            I32(a) => Ok(I32(!a)),
+            I64(a) => Ok(I64(!a)),
+            Isize(Is32(a)) => Ok(Isize(Is32(!a))),
+            Isize(Is64(a)) => Ok(Isize(Is64(!a))),
+            U8(a) => Ok(U8(!a)),
+            U16(a) => Ok(U16(!a)),
+            U32(a) => Ok(U32(!a)),
+            U64(a) => Ok(U64(!a)),
+            Usize(Us32(a)) => Ok(Usize(Us32(!a))),
+            Usize(Us64(a)) => Ok(Usize(Us64(!a))),
+            Infer(a) => Ok(Infer(!a)),
+            InferSigned(a) => Ok(InferSigned(!a)),
+        }
+    }
+}
diff --git a/src/librustc_const_eval/is.rs b/src/librustc_const_eval/is.rs
new file mode 100644
index 00000000000..082c6510f8b
--- /dev/null
+++ b/src/librustc_const_eval/is.rs
@@ -0,0 +1,39 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use syntax::ast;
+use super::err::*;
+
+/// Depending on the target only one variant is ever used in a compilation.
+/// Anything else is an error. This invariant is checked at several locations
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
+pub enum ConstIsize {
+    Is32(i32),
+    Is64(i64),
+}
+pub use self::ConstIsize::*;
+
+impl ConstIsize {
+    pub fn as_i64(self, target_int_ty: ast::IntTy) -> i64 {
+        match (self, target_int_ty) {
+            (Is32(i), ast::IntTy::I32) => i as i64,
+            (Is64(i), ast::IntTy::I64) => i,
+            _ => panic!("got invalid isize size for target"),
+        }
+    }
+    pub fn new(i: i64, target_int_ty: ast::IntTy) -> Result<Self, ConstMathErr> {
+        match target_int_ty {
+            ast::IntTy::I32 if i as i32 as i64 == i => Ok(Is32(i as i32)),
+            ast::IntTy::I32 => Err(LitOutOfRange(ast::IntTy::Is)),
+            ast::IntTy::I64 => Ok(Is64(i)),
+            _ => unreachable!(),
+        }
+    }
+}
diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs
new file mode 100644
index 00000000000..e4c702f643b
--- /dev/null
+++ b/src/librustc_const_eval/lib.rs
@@ -0,0 +1,42 @@
+// Copyright 2012-2013 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.
+
+//! Rusty Mathematics
+//!
+//! # Note
+//!
+//! This API is completely unstable and subject to change.
+
+#![crate_name = "rustc_const_eval"]
+#![unstable(feature = "rustc_private", issue = "27812")]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+      html_root_url = "https://doc.rust-lang.org/nightly/")]
+
+
+#![feature(rustc_private)]
+#![feature(staged_api)]
+
+#[macro_use] extern crate log;
+#[macro_use] extern crate syntax;
+
+extern crate serialize as rustc_serialize; // used by deriving
+
+mod int;
+mod us;
+mod is;
+mod err;
+
+pub use int::*;
+pub use us::*;
+pub use is::*;
+pub use err::ConstMathErr;
diff --git a/src/librustc_const_eval/us.rs b/src/librustc_const_eval/us.rs
new file mode 100644
index 00000000000..e5a7086d436
--- /dev/null
+++ b/src/librustc_const_eval/us.rs
@@ -0,0 +1,39 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use syntax::ast;
+use super::err::*;
+
+/// Depending on the target only one variant is ever used in a compilation.
+/// Anything else is an error. This invariant is checked at several locations
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
+pub enum ConstUsize {
+    Us32(u32),
+    Us64(u64),
+}
+pub use self::ConstUsize::*;
+
+impl ConstUsize {
+    pub fn as_u64(self, target_uint_ty: ast::UintTy) -> u64 {
+        match (self, target_uint_ty) {
+            (Us32(i), ast::UintTy::U32) => i as u64,
+            (Us64(i), ast::UintTy::U64) => i,
+            _ => panic!("got invalid usize size for target"),
+        }
+    }
+    pub fn new(i: u64, target_uint_ty: ast::UintTy) -> Result<Self, ConstMathErr> {
+        match target_uint_ty {
+            ast::UintTy::U32 if i as u32 as u64 == i => Ok(Us32(i as u32)),
+            ast::UintTy::U32 => Err(ULitOutOfRange(ast::UintTy::Us)),
+            ast::UintTy::U64 => Ok(Us64(i)),
+            _ => unreachable!(),
+        }
+    }
+}
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 10535549ceb..4d844bbf032 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -143,8 +143,11 @@ impl LateLintPass for TypeLimits {
                             else { false }
                         } else {
                             match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
-                                Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
-                                Ok(ConstVal::Uint(shift)) => { shift >= bits },
+                                Ok(ConstVal::Integral(i)) => {
+                                    i.is_negative() || i.to_u64()
+                                                        .map(|i| i >= bits)
+                                                        .unwrap_or(true)
+                                },
                                 _ => { false }
                             }
                         };
diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml
index d6bb4b157a6..e8b5a7efdd9 100644
--- a/src/librustc_metadata/Cargo.toml
+++ b/src/librustc_metadata/Cargo.toml
@@ -15,6 +15,7 @@ rbml = { path = "../librbml" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
 rustc_bitflags = { path = "../librustc_bitflags" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_front = { path = "../librustc_front" }
 rustc_llvm = { path = "../librustc_llvm" }
 serialize = { path = "../libserialize" }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 06f81a17a06..dfc794dc5b8 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -35,6 +35,8 @@ use middle::subst;
 use middle::ty::{ImplContainer, TraitContainer};
 use middle::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind};
 
+use rustc_const_eval::ConstInt;
+
 use rustc::mir;
 use rustc::mir::visit::MutVisitor;
 
@@ -198,7 +200,7 @@ fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> {
     reader::tagged_docs(d, tag_items_data_item_reexport)
 }
 
-fn variant_disr_val(d: rbml::Doc) -> Option<ty::Disr> {
+fn variant_disr_val(d: rbml::Doc) -> Option<u64> {
     reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| {
         reader::with_doc_data(val_doc, |data| {
             str::from_utf8(data).ok().and_then(|s| s.parse().ok())
@@ -396,7 +398,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
                 did: did,
                 name: item_name(intr, item),
                 fields: get_variant_fields(intr, cdata, item, tcx),
-                disr_val: disr,
+                disr_val: ConstInt::Infer(disr),
                 kind: expect_variant_kind(item_family(item), tcx),
             }
         }).collect()
@@ -432,7 +434,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
             did: did,
             name: item_name(intr, doc),
             fields: get_variant_fields(intr, cdata, doc, tcx),
-            disr_val: 0,
+            disr_val: ConstInt::Infer(0),
             kind: expect_variant_kind(item_family(doc), tcx),
         }
     }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 1d1cd382255..3dc0e53b254 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -26,6 +26,7 @@ use middle::dependency_format::Linkage;
 use middle::stability;
 use middle::subst;
 use middle::ty::{self, Ty, TyCtxt};
+use middle::ty::util::IntTypeExt;
 
 use rustc::back::svh::Svh;
 use rustc::front::map::{LinkedPath, PathElem, PathElems};
@@ -238,7 +239,8 @@ fn encode_symbol(ecx: &EncodeContext,
 fn encode_disr_val(_: &EncodeContext,
                    rbml_w: &mut Encoder,
                    disr_val: ty::Disr) {
-    rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_string());
+    // convert to u64 so just the number is printed, without any type info
+    rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string());
 }
 
 fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) {
@@ -262,13 +264,14 @@ fn encode_struct_fields(rbml_w: &mut Encoder,
 
 fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                       rbml_w: &mut Encoder,
-                                      id: NodeId,
+                                      did: DefId,
                                       vis: hir::Visibility,
                                       index: &mut CrateIndex<'tcx>) {
-    debug!("encode_enum_variant_info(id={})", id);
-
-    let mut disr_val = 0;
-    let def = ecx.tcx.lookup_adt_def(ecx.tcx.map.local_def_id(id));
+    debug!("encode_enum_variant_info(did={:?})", did);
+    let repr_hints = ecx.tcx.lookup_repr_hints(did);
+    let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0));
+    let mut disr_val = repr_type.initial_discriminant(&ecx.tcx);
+    let def = ecx.tcx.lookup_adt_def(did);
     for variant in &def.variants {
         let vid = variant.did;
         let variant_node_id = ecx.local_id(vid);
@@ -290,7 +293,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             ty::VariantKind::Unit => 'w',
         });
         encode_name(rbml_w, variant.name);
-        encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id));
+        encode_parent_item(rbml_w, did);
         encode_visibility(rbml_w, vis);
 
         let attrs = ecx.tcx.get_attrs(vid);
@@ -313,7 +316,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
         ecx.tcx.map.with_path(variant_node_id, |path| encode_path(rbml_w, path));
         rbml_w.end_tag();
-        disr_val = disr_val.wrapping_add(1);
+        disr_val = disr_val.wrap_incr();
     }
 }
 
@@ -1035,7 +1038,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
         encode_enum_variant_info(ecx,
                                  rbml_w,
-                                 item.id,
+                                 def_id,
                                  vis,
                                  index);
       }
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 5386c5b77c2..f0f0fb84754 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -36,6 +36,7 @@ extern crate rustc;
 extern crate rustc_back;
 extern crate rustc_front;
 extern crate rustc_llvm;
+extern crate rustc_const_eval;
 
 pub use rustc::middle;
 
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml
index 93817ab0db6..99237c9fa5f 100644
--- a/src/librustc_mir/Cargo.toml
+++ b/src/librustc_mir/Cargo.toml
@@ -13,6 +13,7 @@ graphviz = { path = "../libgraphviz" }
 log = { path = "../liblog" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_front = { path = "../librustc_front" }
 syntax = { path = "../libsyntax" }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index e6430b7d634..9ecbf748d7c 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -269,7 +269,7 @@ enum TestKind<'tcx> {
 
     // test length of the slice is equal to len
     Len {
-        len: usize,
+        len: u64,
         op: BinOp,
     },
 }
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 02f32da2b83..d42c8ff7bd7 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -84,7 +84,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                 };
                 Test {
                     span: match_pair.pattern.span,
-                    kind: TestKind::Len { len: len, op: op },
+                    kind: TestKind::Len { len: len as u64, op: op },
                 }
             }
 
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index 8c435b45dae..13ab26c358d 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -46,7 +46,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
         Operand::Constant(constant)
     }
 
-    pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: usize) -> Lvalue<'tcx> {
+    pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: u64) -> Lvalue<'tcx> {
         let usize_ty = self.hir.usize_ty();
         let temp = self.temp(usize_ty);
         self.cfg.push_assign_constant(
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 3d14ad2374b..6d411b9c07b 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -94,6 +94,8 @@ use rustc::middle::ty::{self, Ty, TyCtxt};
 use rustc::mir::repr::*;
 use syntax::codemap::{Span, DUMMY_SP};
 use syntax::parse::token::intern_and_get_ident;
+use rustc::middle::const_eval::ConstVal;
+use rustc_const_eval::ConstInt;
 
 pub struct Scope<'tcx> {
     extent: CodeExtent,
@@ -517,7 +519,9 @@ impl<'a,'tcx> Builder<'a,'tcx> {
         }, Constant {
             span: span,
             ty: self.hir.tcx().types.u32,
-            literal: self.hir.usize_literal(span_lines.line)
+            literal: Literal::Value {
+                value: ConstVal::Integral(ConstInt::U32(span_lines.line as u32)),
+            },
         })
     }
 
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index cbd6bed81a6..1f8a5da9c1b 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -10,12 +10,13 @@
 
 use hair::*;
 use rustc_data_structures::fnv::FnvHashMap;
+use rustc_const_eval::ConstInt;
 use hair::cx::Cx;
 use hair::cx::block;
 use hair::cx::to_ref::ToRef;
 use rustc::front::map;
 use rustc::middle::def::Def;
-use rustc::middle::const_eval;
+use rustc::middle::const_eval::{self, ConstVal};
 use rustc::middle::region::CodeExtent;
 use rustc::middle::pat_util;
 use rustc::middle::ty::{self, VariantDef, Ty};
@@ -227,28 +228,37 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                 }
             }
 
-            hir::ExprUnary(op, ref arg) => {
+            hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
                 if cx.tcx.is_method_call(self.id) {
                     overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
                                         PassArgs::ByValue, arg.to_ref(), vec![])
                 } else {
-                    // FIXME overflow
-                    let op = match op {
-                        hir::UnOp::UnNot => UnOp::Not,
-                        hir::UnOp::UnNeg => UnOp::Neg,
-                        hir::UnOp::UnDeref => {
-                            cx.tcx.sess.span_bug(
-                                self.span,
-                                "UnDeref should have been handled elsewhere");
-                        }
-                    };
                     ExprKind::Unary {
-                        op: op,
+                        op: UnOp::Not,
                         arg: arg.to_ref(),
                     }
                 }
             }
 
+            hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
+                if cx.tcx.is_method_call(self.id) {
+                    overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
+                                        PassArgs::ByValue, arg.to_ref(), vec![])
+                } else {
+                    // FIXME runtime-overflow
+                    if let hir::ExprLit(_) = arg.node {
+                        ExprKind::Literal {
+                            literal: cx.const_eval_literal(self),
+                        }
+                    } else {
+                        ExprKind::Unary {
+                            op: UnOp::Neg,
+                            arg: arg.to_ref(),
+                        }
+                    }
+                }
+            }
+
             hir::ExprStruct(_, ref fields, ref base) => {
                 match expr_ty.sty {
                     ty::TyStruct(adt, substs) => {
@@ -338,7 +348,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                 count: TypedConstVal {
                     ty: cx.tcx.expr_ty(c),
                     span: c.span,
-                    value: const_eval::eval_const_expr(cx.tcx, c)
+                    value: match const_eval::eval_const_expr(cx.tcx, c) {
+                        ConstVal::Integral(ConstInt::Usize(u)) => u,
+                        other => panic!("constant evaluation of repeat count yielded {:?}", other),
+                    },
                 }
             },
             hir::ExprRet(ref v) =>
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index f1b74ca1288..fd4cf7c0473 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -24,6 +24,7 @@ use rustc::middle::ty::{self, Ty, TyCtxt};
 use syntax::codemap::Span;
 use syntax::parse::token;
 use rustc_front::hir;
+use rustc_const_eval::{ConstInt, ConstUsize};
 
 #[derive(Copy, Clone)]
 pub struct Cx<'a, 'tcx: 'a> {
@@ -50,8 +51,11 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
         self.tcx.types.usize
     }
 
-    pub fn usize_literal(&mut self, value: usize) -> Literal<'tcx> {
-        Literal::Value { value: ConstVal::Uint(value as u64) }
+    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))},
+            Err(_) => panic!("usize literal out of range for target"),
+        }
     }
 
     pub fn bool_ty(&mut self) -> Ty<'tcx> {
diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs
index 6f4375d53ec..d1e3f08aff8 100644
--- a/src/librustc_mir/hair/cx/pattern.rs
+++ b/src/librustc_mir/hair/cx/pattern.rs
@@ -87,7 +87,7 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
                     Def::Const(def_id) | Def::AssociatedConst(def_id) =>
                         match const_eval::lookup_const_by_id(self.cx.tcx, def_id,
                                                              Some(pat.id), None) {
-                            Some(const_expr) => {
+                            Some((const_expr, _const_ty)) => {
                                 let pat = const_eval::const_expr_to_pat(self.cx.tcx, const_expr,
                                                                         pat.span);
                                 return self.to_pattern(&pat);
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 5d915f37f6e..7c8c8945bbc 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -31,6 +31,7 @@ extern crate rustc_data_structures;
 extern crate rustc_front;
 extern crate rustc_back;
 extern crate syntax;
+extern crate rustc_const_eval;
 
 pub mod build;
 pub mod graphviz;
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 3a39a3c6dd1..a9e03bba7db 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -604,7 +604,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                 }
                 Some(Def::Const(did)) |
                 Some(Def::AssociatedConst(did)) => {
-                    if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
+                    if let Some((expr, _ty)) = const_eval::lookup_const_by_id(v.tcx, did,
                                                                        Some(e.id),
                                                                        None) {
                         let inner = v.global_expr(Mode::Const, expr);
diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml
index 24320c4d563..b7faafeba9a 100644
--- a/src/librustc_trans/Cargo.toml
+++ b/src/librustc_trans/Cargo.toml
@@ -16,6 +16,7 @@ graphviz = { path = "../libgraphviz" }
 log = { path = "../liblog" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_front = { path = "../librustc_front" }
 rustc_llvm = { path = "../librustc_llvm" }
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 6f596b15b92..d7e79e46720 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -50,6 +50,7 @@ pub extern crate rustc_llvm as llvm;
 extern crate rustc_mir;
 extern crate rustc_platform_intrinsics as intrinsics;
 extern crate serialize;
+extern crate rustc_const_eval;
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs
index c5508a8268f..320bb1eab3c 100644
--- a/src/librustc_trans/trans/adt.rs
+++ b/src/librustc_trans/trans/adt.rs
@@ -1035,7 +1035,7 @@ fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) {
     match ity {
         attr::UnsignedInt(_) => {
             assert!(min <= discr);
-            assert!(discr <= max)
+            assert!(discr <= max);
         },
         attr::SignedInt(_) => {
             assert!(min.0 as i64 <= discr.0 as i64);
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 6c47cab64ef..7d37627ad0e 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -15,15 +15,7 @@ use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
 use llvm::{InternalLinkage, ValueRef, Bool, True};
 use middle::const_qualif::ConstQualif;
 use middle::cstore::LOCAL_CRATE;
-use middle::const_eval::{self, ConstVal, ConstEvalErr};
-use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg};
-use middle::const_eval::{const_int_checked_add, const_uint_checked_add};
-use middle::const_eval::{const_int_checked_sub, const_uint_checked_sub};
-use middle::const_eval::{const_int_checked_mul, const_uint_checked_mul};
-use middle::const_eval::{const_int_checked_div, const_uint_checked_div};
-use middle::const_eval::{const_int_checked_rem, const_uint_checked_rem};
-use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl};
-use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
+use middle::const_eval::{self, ConstEvalErr};
 use middle::def::Def;
 use middle::def_id::DefId;
 use trans::{adt, closure, debuginfo, expr, inline, machine};
@@ -42,9 +34,10 @@ use trans::Disr;
 use middle::subst::Substs;
 use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
 use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
-use middle::ty::{self, Ty};
+use middle::ty::{self, Ty, TyCtxt};
 use middle::ty::cast::{CastTy,IntTy};
 use util::nodemap::NodeMap;
+use rustc_const_eval::{ConstInt, ConstMathErr, ConstUsize, ConstIsize};
 
 use rustc_front::hir;
 
@@ -234,7 +227,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 
     match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id), Some(param_substs)) {
-        Some(ref expr) => expr,
+        Some((ref expr, _ty)) => expr,
         None => {
             ccx.sess().span_bug(ref_expr.span, "constant item not found")
         }
@@ -469,35 +462,70 @@ fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
         // Catch this up front by looking for ExprLit directly,
         // and just accepting it.
         if let hir::ExprLit(_) = inner_e.node { return Ok(()); }
-
-        let result = match t.sty {
-            ty::TyInt(int_type) => {
-                let input = match const_to_opt_int(te) {
-                    Some(v) => v,
-                    None => return Ok(()),
-                };
-                const_int_checked_neg(
-                    input, e, Some(const_eval::IntTy::from(cx.tcx(), int_type)))
-            }
-            ty::TyUint(uint_type) => {
-                let input = match const_to_opt_uint(te) {
-                    Some(v) => v,
-                    None => return Ok(()),
-                };
-                const_uint_checked_neg(
-                    input, e, Some(const_eval::UintTy::from(cx.tcx(), uint_type)))
-            }
-            _ => return Ok(()),
+        let cval = match to_const_int(te, t, cx.tcx()) {
+            Some(v) => v,
+            None => return Ok(()),
         };
-        const_err(cx, e, result, trueconst)
+        match -cval {
+            Ok(_) => return Ok(()),
+            Err(err) => const_err(cx, e, Err(err), trueconst),
+        }
     } else {
         Ok(())
     }
 }
 
+fn to_const_int(value: ValueRef, t: Ty, tcx: &TyCtxt) -> Option<ConstInt> {
+    match t.sty {
+        ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type {
+            ast::IntTy::I8 => {
+                assert_eq!(input as i8 as i64, input);
+                Some(ConstInt::I8(input as i8))
+            },
+            ast::IntTy::I16 => {
+                assert_eq!(input as i16 as i64, input);
+                Some(ConstInt::I16(input as i16))
+            },
+            ast::IntTy::I32 => {
+                assert_eq!(input as i32 as i64, input);
+                Some(ConstInt::I32(input as i32))
+            },
+            ast::IntTy::I64 => {
+                Some(ConstInt::I64(input))
+            },
+            ast::IntTy::Is => {
+                ConstIsize::new(input, tcx.sess.target.int_type)
+                    .ok().map(ConstInt::Isize)
+            },
+        }),
+        ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type {
+            ast::UintTy::U8 => {
+                assert_eq!(input as u8 as u64, input);
+                Some(ConstInt::U8(input as u8))
+            },
+            ast::UintTy::U16 => {
+                assert_eq!(input as u16 as u64, input);
+                Some(ConstInt::U16(input as u16))
+            },
+            ast::UintTy::U32 => {
+                assert_eq!(input as u32 as u64, input);
+                Some(ConstInt::U32(input as u32))
+            },
+            ast::UintTy::U64 => {
+                Some(ConstInt::U64(input))
+            },
+            ast::UintTy::Us => {
+                ConstUsize::new(input, tcx.sess.target.uint_type)
+                    .ok().map(ConstInt::Usize)
+            },
+        }),
+        _ => None,
+    }
+}
+
 fn const_err(cx: &CrateContext,
              e: &hir::Expr,
-             result: Result<ConstVal, ConstEvalErr>,
+             result: Result<ConstInt, ConstMathErr>,
              trueconst: TrueConst)
              -> Result<(), ConstEvalFailure> {
     match (result, trueconst) {
@@ -506,10 +534,12 @@ fn const_err(cx: &CrateContext,
             Ok(())
         },
         (Err(err), TrueConst::Yes) => {
+            let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) };
             cx.tcx().sess.span_err(e.span, &err.description());
             Err(Compiletime(err))
         },
         (Err(err), TrueConst::No) => {
+            let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) };
             cx.tcx().sess.span_warn(e.span, &err.description());
             Err(Runtime(err))
         },
@@ -520,46 +550,18 @@ fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
                               te1: ValueRef, te2: ValueRef,
                               trueconst: TrueConst) -> Result<(), ConstEvalFailure> {
     let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { unreachable!() };
-
-    let result = match t.sty {
-        ty::TyInt(int_type) => {
-            let (lhs, rhs) = match (const_to_opt_int(te1),
-                                    const_to_opt_int(te2)) {
-                (Some(v1), Some(v2)) => (v1, v2),
-                _ => return Ok(()),
-            };
-
-            let opt_ety = Some(const_eval::IntTy::from(cx.tcx(), int_type));
-            match b.node {
-                hir::BiAdd => const_int_checked_add(lhs, rhs, e, opt_ety),
-                hir::BiSub => const_int_checked_sub(lhs, rhs, e, opt_ety),
-                hir::BiMul => const_int_checked_mul(lhs, rhs, e, opt_ety),
-                hir::BiDiv => const_int_checked_div(lhs, rhs, e, opt_ety),
-                hir::BiRem => const_int_checked_rem(lhs, rhs, e, opt_ety),
-                hir::BiShl => const_int_checked_shl(lhs, rhs, e, opt_ety),
-                hir::BiShr => const_int_checked_shr(lhs, rhs, e, opt_ety),
-                _ => return Ok(()),
-            }
-        }
-        ty::TyUint(uint_type) => {
-            let (lhs, rhs) = match (const_to_opt_uint(te1),
-                                    const_to_opt_uint(te2)) {
-                (Some(v1), Some(v2)) => (v1, v2),
-                _ => return Ok(()),
-            };
-
-            let opt_ety = Some(const_eval::UintTy::from(cx.tcx(), uint_type));
-            match b.node {
-                hir::BiAdd => const_uint_checked_add(lhs, rhs, e, opt_ety),
-                hir::BiSub => const_uint_checked_sub(lhs, rhs, e, opt_ety),
-                hir::BiMul => const_uint_checked_mul(lhs, rhs, e, opt_ety),
-                hir::BiDiv => const_uint_checked_div(lhs, rhs, e, opt_ety),
-                hir::BiRem => const_uint_checked_rem(lhs, rhs, e, opt_ety),
-                hir::BiShl => const_uint_checked_shl(lhs, rhs, e, opt_ety),
-                hir::BiShr => const_uint_checked_shr(lhs, rhs, e, opt_ety),
-                _ => return Ok(()),
-            }
-        }
+    let (lhs, rhs) = match (to_const_int(te1, t, cx.tcx()), to_const_int(te2, t, cx.tcx())) {
+        (Some(v1), Some(v2)) => (v1, v2),
+        _ => return Ok(()),
+    };
+    let result = match b.node {
+        hir::BiAdd => lhs + rhs,
+        hir::BiSub => lhs - rhs,
+        hir::BiMul => lhs * rhs,
+        hir::BiDiv => lhs / rhs,
+        hir::BiRem => lhs % rhs,
+        hir::BiShl => lhs << rhs,
+        hir::BiShr => lhs >> rhs,
         _ => return Ok(()),
     };
     const_err(cx, e, result, trueconst)
diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs
index 0cd1f4e7fbf..e22d42e9d28 100644
--- a/src/librustc_trans/trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/trans/debuginfo/metadata.rs
@@ -1597,7 +1597,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 llvm::LLVMDIBuilderCreateEnumerator(
                     DIB(cx),
                     name.as_ptr(),
-                    v.disr_val as u64)
+                    v.disr_val.to_u64_unchecked())
             }
         })
         .collect();
diff --git a/src/librustc_trans/trans/disr.rs b/src/librustc_trans/trans/disr.rs
index 7cb10a8bc44..d74c1ac50ad 100644
--- a/src/librustc_trans/trans/disr.rs
+++ b/src/librustc_trans/trans/disr.rs
@@ -26,7 +26,7 @@ impl ::std::ops::BitAnd for Disr {
 
 impl From<::middle::ty::Disr> for Disr {
     fn from(i: ::middle::ty::Disr) -> Disr {
-        Disr(i)
+        Disr(i.to_u64_unchecked())
     }
 }
 
diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs
index a0615a6cf5b..c20d8b01eb7 100644
--- a/src/librustc_trans/trans/mir/constant.rs
+++ b/src/librustc_trans/trans/mir/constant.rs
@@ -12,6 +12,7 @@ use back::abi;
 use llvm::ValueRef;
 use middle::ty::{Ty, TypeFoldable};
 use rustc::middle::const_eval::{self, ConstVal};
+use rustc_const_eval::ConstInt::*;
 use rustc::mir::repr as mir;
 use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral,
                     C_str_slice, C_nil, C_undef};
@@ -19,6 +20,7 @@ use trans::consts;
 use trans::expr;
 use trans::inline;
 use trans::type_of;
+use trans::type_::Type;
 
 use super::operand::{OperandRef, OperandValue};
 use super::MirContext;
@@ -63,8 +65,24 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         match *cv {
             ConstVal::Float(v) => C_floating_f64(v, llty),
             ConstVal::Bool(v) => C_bool(ccx, v),
-            ConstVal::Int(v) => C_integral(llty, v as u64, true),
-            ConstVal::Uint(v) => C_integral(llty, v, false),
+            ConstVal::Integral(I8(v)) => C_integral(Type::i8(ccx), v as u64, true),
+            ConstVal::Integral(I16(v)) => C_integral(Type::i16(ccx), v as u64, true),
+            ConstVal::Integral(I32(v)) => C_integral(Type::i32(ccx), v as u64, true),
+            ConstVal::Integral(I64(v)) => C_integral(Type::i64(ccx), v as u64, true),
+            ConstVal::Integral(Isize(v)) => {
+                let i = v.as_i64(ccx.tcx().sess.target.int_type);
+                C_integral(Type::int(ccx), i as u64, true)
+            },
+            ConstVal::Integral(U8(v)) => C_integral(Type::i8(ccx), v as u64, false),
+            ConstVal::Integral(U16(v)) => C_integral(Type::i16(ccx), v as u64, false),
+            ConstVal::Integral(U32(v)) => C_integral(Type::i32(ccx), v as u64, false),
+            ConstVal::Integral(U64(v)) => C_integral(Type::i64(ccx), v, false),
+            ConstVal::Integral(Usize(v)) => {
+                let u = v.as_u64(ccx.tcx().sess.target.uint_type);
+                C_integral(Type::int(ccx), u, false)
+            },
+            ConstVal::Integral(Infer(v)) => C_integral(llty, v as u64, false),
+            ConstVal::Integral(InferSigned(v)) => C_integral(llty, v as u64, true),
             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::Struct(id) | ConstVal::Tuple(id) |
@@ -74,6 +92,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     expr::trans(bcx, expr).datum.val
                 })
             },
+            ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
+            ConstVal::Dummy => unreachable!(),
             ConstVal::Function(_) => C_nil(ccx)
         }
     }
@@ -99,7 +119,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs));
                 let def_id = inline::maybe_instantiate_inline(bcx.ccx(), def_id);
                 let expr = const_eval::lookup_const_by_id(bcx.tcx(), def_id, None, Some(substs))
-                            .expect("def was const, but lookup_const_by_id failed");
+                            .expect("def was const, but lookup_const_by_id failed").0;
                 // FIXME: this is falling back to translating from HIR. This is not easy to fix,
                 // because we would have somehow adapt const_eval to work on MIR rather than HIR.
                 let d = bcx.with_block(|bcx| {
diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs
index ce10ed425f6..ea80af14f1f 100644
--- a/src/librustc_trans/trans/mir/rvalue.rs
+++ b/src/librustc_trans/trans/mir/rvalue.rs
@@ -11,6 +11,8 @@
 use llvm::ValueRef;
 use rustc::middle::ty::{self, Ty};
 use middle::ty::cast::{CastTy, IntTy};
+use middle::const_eval::ConstVal;
+use rustc_const_eval::ConstInt;
 use rustc::mir::repr as mir;
 
 use trans::asm;
@@ -95,7 +97,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
             mir::Rvalue::Repeat(ref elem, ref count) => {
                 let tr_elem = self.trans_operand(&bcx, elem);
-                let size = self.trans_constval(&bcx, &count.value, count.ty).immediate();
+                let count = ConstVal::Integral(ConstInt::Usize(count.value));
+                let size = self.trans_constval(&bcx, &count, bcx.tcx().types.usize).immediate();
                 let bcx = bcx.map_block(|block| {
                     let base = expr::get_dataptr(block, dest.llval);
                     tvec::iter_vec_raw(block, base, tr_elem.ty, size, |block, llslot, _| {
diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml
index fd33e9da1f9..1c907972863 100644
--- a/src/librustc_typeck/Cargo.toml
+++ b/src/librustc_typeck/Cargo.toml
@@ -15,5 +15,6 @@ arena = { path = "../libarena" }
 fmt_macros = { path = "../libfmt_macros" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_front = { path = "../librustc_front" }
 rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 1938fa75829..ba56c5d24ab 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -65,6 +65,8 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
 use util::common::{ErrorReported, FN_OUTPUT_NAME};
 use util::nodemap::FnvHashSet;
 
+use rustc_const_eval::ConstInt;
+
 use syntax::{abi, ast};
 use syntax::codemap::{Span, Pos};
 use syntax::errors::DiagnosticBuilder;
@@ -1680,22 +1682,16 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
         hir::TyFixedLengthVec(ref ty, ref e) => {
             let hint = UncheckedExprHint(tcx.types.usize);
             match const_eval::eval_const_expr_partial(tcx, &e, hint, None) {
-                Ok(r) => {
-                    match r {
-                        ConstVal::Int(i) =>
-                            tcx.mk_array(ast_ty_to_ty(this, rscope, &ty),
-                                         i as usize),
-                        ConstVal::Uint(i) =>
-                            tcx.mk_array(ast_ty_to_ty(this, rscope, &ty),
-                                         i as usize),
-                        _ => {
-                            span_err!(tcx.sess, ast_ty.span, E0249,
-                                      "expected constant integer expression \
-                                       for array length");
-                            this.tcx().types.err
-                        }
-                    }
-                }
+                Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
+                    let i = i.as_u64(tcx.sess.target.uint_type);
+                    assert_eq!(i as usize as u64, i);
+                    tcx.mk_array(ast_ty_to_ty(this, rscope, &ty), i as usize)
+                },
+                Ok(val) => {
+                    span_err!(tcx.sess, ast_ty.span, E0249,
+                              "expected usize value for array length, got {}", val.description());
+                    this.tcx().types.err
+                },
                 Err(ref r) => {
                     let mut err = struct_span_err!(tcx.sess, r.span, E0250,
                                                    "array length constant evaluation error: {}",
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0743c0b9e18..19731407d9e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -94,7 +94,7 @@ use middle::pat_util::{self, pat_id_map};
 use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
 use middle::traits::{self, report_fulfillment_errors};
 use middle::ty::{GenericPredicates, TypeScheme};
-use middle::ty::{Disr, ParamTy, ParameterEnvironment};
+use middle::ty::{ParamTy, ParameterEnvironment};
 use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
 use middle::ty::{self, ToPolyTraitRef, Ty, TyCtxt};
 use middle::ty::{MethodCall, MethodCallee};
@@ -102,7 +102,7 @@ use middle::ty::adjustment;
 use middle::ty::error::TypeError;
 use middle::ty::fold::{TypeFolder, TypeFoldable};
 use middle::ty::relate::TypeRelation;
-use middle::ty::util::Representability;
+use middle::ty::util::{Representability, IntTypeExt};
 use require_c_abi_if_variadic;
 use rscope::{ElisionFailureInfo, RegionScope};
 use session::{Session, CompileResult};
@@ -4076,34 +4076,6 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                                     sp: Span,
                                     vs: &'tcx [hir::Variant],
                                     id: ast::NodeId) {
-    // disr_in_range should be removed once we have forced type hints for consts
-    fn disr_in_range(ccx: &CrateCtxt,
-                     ty: attr::IntType,
-                     disr: ty::Disr) -> bool {
-        fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
-            match ty {
-                ast::UintTy::U8 => disr as u8 as Disr == disr,
-                ast::UintTy::U16 => disr as u16 as Disr == disr,
-                ast::UintTy::U32 => disr as u32 as Disr == disr,
-                ast::UintTy::U64 => disr as u64 as Disr == disr,
-                ast::UintTy::Us => uint_in_range(ccx, ccx.tcx.sess.target.uint_type, disr)
-            }
-        }
-        fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
-            match ty {
-                ast::IntTy::I8 => disr as i8 as Disr == disr,
-                ast::IntTy::I16 => disr as i16 as Disr == disr,
-                ast::IntTy::I32 => disr as i32 as Disr == disr,
-                ast::IntTy::I64 => disr as i64 as Disr == disr,
-                ast::IntTy::Is => int_in_range(ccx, ccx.tcx.sess.target.int_type, disr)
-            }
-        }
-        match ty {
-            attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
-            attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
-        }
-    }
-
     fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                           vs: &'tcx [hir::Variant],
                           id: ast::NodeId,
@@ -4117,7 +4089,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         let inh = static_inherited_fields(ccx, &tables);
         let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id);
 
-        let (_, repr_type_ty) = ccx.tcx.enum_repr_type(Some(&hint));
+        let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(&ccx.tcx);
         for v in vs {
             if let Some(ref e) = v.node.disr_expr {
                 check_const_with_ty(&fcx, e.span, e, repr_type_ty);
@@ -4142,23 +4114,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                 }
                 None => {}
             }
-            // Check for unrepresentable discriminant values
-            match hint {
-                attr::ReprAny | attr::ReprExtern => {
-                    disr_vals.push(current_disr_val);
-                }
-                attr::ReprInt(sp, ity) => {
-                    if !disr_in_range(ccx, ity, current_disr_val) {
-                        let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0082,
-                            "discriminant value outside specified type");
-                        span_note!(&mut err, sp,
-                            "discriminant type specified here");
-                        err.emit();
-                    }
-                }
-                // Error reported elsewhere.
-                attr::ReprSimd | attr::ReprPacked => {}
-            }
+            disr_vals.push(current_disr_val);
         }
     }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index b493b64a45f..b97d3f4993a 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -81,6 +81,8 @@ use util::common::{ErrorReported, MemoizationMap};
 use util::nodemap::{FnvHashMap, FnvHashSet};
 use write_ty_to_tcx;
 
+use rustc_const_eval::ConstInt;
+
 use std::cell::RefCell;
 use std::collections::HashSet;
 use std::rc::Rc;
@@ -1012,7 +1014,7 @@ fn convert_struct_def<'tcx>(tcx: &TyCtxt<'tcx>,
     tcx.intern_adt_def(
         did,
         ty::AdtKind::Struct,
-        vec![convert_struct_variant(tcx, ctor_id, it.name, 0, def)]
+        vec![convert_struct_variant(tcx, ctor_id, it.name, ConstInt::Infer(0), def)]
     )
 }
 
@@ -1021,24 +1023,39 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
                           def: &hir::EnumDef)
                           -> ty::AdtDefMaster<'tcx>
 {
+    fn print_err(tcx: &TyCtxt, span: Span, ty: ty::Ty, cv: ConstVal) {
+        span_err!(tcx.sess, span, E0079, "mismatched types: expected `{}` got `{}`",
+                  ty, cv.description());
+    }
     fn evaluate_disr_expr<'tcx>(tcx: &TyCtxt<'tcx>,
-                                repr_ty: Ty<'tcx>,
+                                repr_ty: attr::IntType,
                                 e: &hir::Expr) -> Option<ty::Disr> {
         debug!("disr expr, checking {}", pprust::expr_to_string(e));
 
-        let hint = UncheckedExprHint(repr_ty);
+        let ty_hint = repr_ty.to_ty(tcx);
+        let hint = UncheckedExprHint(ty_hint);
         match const_eval::eval_const_expr_partial(tcx, e, hint, None) {
-            Ok(ConstVal::Int(val)) => Some(val as ty::Disr),
-            Ok(ConstVal::Uint(val)) => Some(val as ty::Disr),
-            Ok(_) => {
-                let sign_desc = if repr_ty.is_signed() {
-                    "signed"
-                } else {
-                    "unsigned"
-                };
-                span_err!(tcx.sess, e.span, E0079,
-                          "expected {} integer constant",
-                          sign_desc);
+            Ok(ConstVal::Integral(i)) => {
+                // FIXME: eval_const_expr_partial should return an error if the hint is wrong
+                match (repr_ty, i) {
+                    (attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => Some(i),
+                    (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => Some(i),
+                    (attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => Some(i),
+                    (attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => Some(i),
+                    (attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => Some(i),
+                    (attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => Some(i),
+                    (attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => Some(i),
+                    (attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => Some(i),
+                    (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => Some(i),
+                    (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Some(i),
+                    (_, i) => {
+                        print_err(tcx, e.span, ty_hint, ConstVal::Integral(i));
+                        None
+                    },
+                }
+            },
+            Ok(cv) => {
+                print_err(tcx, e.span, ty_hint, cv);
                 None
             },
             Err(err) => {
@@ -1057,16 +1074,11 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
     fn report_discrim_overflow(tcx: &TyCtxt,
                                variant_span: Span,
                                variant_name: &str,
-                               repr_type: attr::IntType,
                                prev_val: ty::Disr) {
-        let computed_value = repr_type.disr_wrap_incr(Some(prev_val));
-        let computed_value = repr_type.disr_string(computed_value);
-        let prev_val = repr_type.disr_string(prev_val);
-        let repr_type = repr_type.to_ty(tcx);
         span_err!(tcx.sess, variant_span, E0370,
-                  "enum discriminant overflowed on value after {}: {}; \
+                  "enum discriminant overflowed on value after {}; \
                    set explicitly via {} = {} if that is desired outcome",
-                  prev_val, repr_type, variant_name, computed_value);
+                  prev_val, variant_name, prev_val.wrap_incr());
     }
 
     fn next_disr(tcx: &TyCtxt,
@@ -1076,12 +1088,11 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
         if let Some(prev_disr_val) = prev_disr_val {
             let result = repr_type.disr_incr(prev_disr_val);
             if let None = result {
-                report_discrim_overflow(tcx, v.span, &v.node.name.as_str(),
-                                             repr_type, prev_disr_val);
+                report_discrim_overflow(tcx, v.span, &v.node.name.as_str(), prev_disr_val);
             }
             result
         } else {
-            Some(ty::INITIAL_DISCRIMINANT_VALUE)
+            Some(repr_type.initial_discriminant(tcx))
         }
     }
     fn convert_enum_variant<'tcx>(tcx: &TyCtxt<'tcx>,
@@ -1095,17 +1106,19 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
     }
     let did = tcx.map.local_def_id(it.id);
     let repr_hints = tcx.lookup_repr_hints(did);
-    let (repr_type, repr_type_ty) = tcx.enum_repr_type(repr_hints.get(0));
+    let repr_type = tcx.enum_repr_type(repr_hints.get(0));
     let mut prev_disr = None;
     let variants = def.variants.iter().map(|v| {
         let disr = match v.node.disr_expr {
-            Some(ref e) => evaluate_disr_expr(tcx, repr_type_ty, e),
+            Some(ref e) => evaluate_disr_expr(tcx, repr_type, e),
             None => next_disr(tcx, v, repr_type, prev_disr)
-        }.unwrap_or(repr_type.disr_wrap_incr(prev_disr));
+        }.unwrap_or_else(|| {
+            prev_disr.map(ty::Disr::wrap_incr)
+                     .unwrap_or(repr_type.initial_discriminant(tcx))
+        });
 
-        let v = convert_enum_variant(tcx, v, disr);
         prev_disr = Some(disr);
-        v
+        convert_enum_variant(tcx, v, disr)
     }).collect();
     tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants)
 }
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 035f8c60500..125c3d426a8 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -91,6 +91,7 @@ extern crate rustc;
 extern crate rustc_platform_intrinsics as intrinsics;
 extern crate rustc_front;
 extern crate rustc_back;
+extern crate rustc_const_eval;
 
 pub use rustc::dep_graph;
 pub use rustc::front;
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 061047cbd2f..ef54be72037 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -337,7 +337,7 @@ pub fn build_impl(cx: &DocContext,
                 let type_scheme = tcx.lookup_item_type(did);
                 let default = if assoc_const.has_value {
                     Some(const_eval::lookup_const_by_id(tcx, did, None, None)
-                         .unwrap().span.to_src(cx))
+                         .unwrap().0.span.to_src(cx))
                 } else {
                     None
                 };
@@ -479,7 +479,7 @@ fn build_const(cx: &DocContext, tcx: &TyCtxt,
     use rustc::middle::const_eval;
     use rustc_front::print::pprust;
 
-    let expr = const_eval::lookup_const_by_id(tcx, did, None, None).unwrap_or_else(|| {
+    let (expr, ty) = const_eval::lookup_const_by_id(tcx, did, None, None).unwrap_or_else(|| {
         panic!("expected lookup_const_by_id to succeed for {:?}", did);
     });
     debug!("converting constant expr {:?} to snippet", expr);
@@ -487,7 +487,7 @@ fn build_const(cx: &DocContext, tcx: &TyCtxt,
     debug!("got snippet {}", sn);
 
     clean::Constant {
-        type_: tcx.lookup_item_type(did).ty.clean(cx),
+        type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| tcx.lookup_item_type(did).ty.clean(cx)),
         expr: sn
     }
 }
diff --git a/src/test/auxiliary/dummy_mir_pass.rs b/src/test/auxiliary/dummy_mir_pass.rs
index 89101fe709d..fdfbc98b007 100644
--- a/src/test/auxiliary/dummy_mir_pass.rs
+++ b/src/test/auxiliary/dummy_mir_pass.rs
@@ -16,6 +16,7 @@
 #[macro_use] extern crate rustc;
 extern crate rustc_front;
 extern crate rustc_plugin;
+extern crate rustc_const_eval;
 extern crate syntax;
 
 use rustc::mir::transform::{self, MirPass};
@@ -23,6 +24,7 @@ use rustc::mir::repr::{Mir, Literal};
 use rustc::mir::visit::MutVisitor;
 use rustc::middle::ty;
 use rustc::middle::const_eval::ConstVal;
+use rustc_const_eval::ConstInt;
 use rustc_plugin::Registry;
 
 use syntax::ast::NodeId;
@@ -40,8 +42,10 @@ struct Visitor;
 
 impl<'tcx> MutVisitor<'tcx> for Visitor {
     fn visit_literal(&mut self, literal: &mut Literal<'tcx>) {
-        if let Literal::Value { value: ConstVal::Int(ref mut i @ 11) } = *literal {
-            *i = 42;
+        if let Literal::Value { ref mut value } = *literal {
+            if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value {
+                *i = 42;
+            }
         }
     }
 }
diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs
index be67e06d99f..4d156a49192 100644
--- a/src/test/compile-fail/const-err.rs
+++ b/src/test/compile-fail/const-err.rs
@@ -25,9 +25,9 @@ fn main() {
     //~^ WARN attempted to add with overflow
     //~^^ WARN attempted to add with overflow
     let c = 200u8 * 4;
-    //~^ WARN attempted to mul with overflow
+    //~^ WARN attempted to multiply with overflow
     let d = 42u8 - (42u8 + 1);
-    //~^ WARN attempted to sub with overflow
+    //~^ WARN attempted to subtract with overflow
     let _e = BLA;
     black_box(a);
     black_box(b);
diff --git a/src/test/compile-fail/const-eval-overflow-2.rs b/src/test/compile-fail/const-eval-overflow-2.rs
index be04bc9bd3b..07e27a7dc9a 100644
--- a/src/test/compile-fail/const-eval-overflow-2.rs
+++ b/src/test/compile-fail/const-eval-overflow-2.rs
@@ -21,10 +21,11 @@ const NEG_128: i8 = -128;
 const NEG_NEG_128: i8 = -NEG_128;
 //~^ ERROR constant evaluation error: attempted to negate with overflow
 //~| ERROR attempted to negate with overflow
+//~| ERROR attempted to negate with overflow
 
 fn main() {
     match -128i8 {
-        NEG_NEG_128 => println!("A"),
+        NEG_NEG_128 => println!("A"), //~ NOTE in pattern here
         _ => println!("B"),
     }
 }
diff --git a/src/test/compile-fail/const-eval-overflow-3.rs b/src/test/compile-fail/const-eval-overflow-3.rs
index c2bc5b2648a..c90ae045f96 100644
--- a/src/test/compile-fail/const-eval-overflow-3.rs
+++ b/src/test/compile-fail/const-eval-overflow-3.rs
@@ -36,4 +36,3 @@ fn main() {
 fn foo<T:fmt::Debug>(x: T) {
     println!("{:?}", x);
 }
-
diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs
index 253285d3919..5aa93cf6383 100644
--- a/src/test/compile-fail/const-eval-overflow-4b.rs
+++ b/src/test/compile-fail/const-eval-overflow-4b.rs
@@ -21,8 +21,9 @@ use std::{u8, u16, u32, u64, usize};
 
 const A_I8_T
     : [u32; (i8::MAX as i8 + 1u8) as usize]
-    //~^ ERROR mismatched types
-    //~| ERROR the trait `core::ops::Add<u8>` is not implemented for the type `i8`
+    //~^ ERROR mismatched types:
+    //~| expected `i8`,
+    //~| found `u8` [E0250]
     = [0; (i8::MAX as usize) + 1];
 
 fn main() {
diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs
index 2a2fc2ef080..3dfcb5bb29a 100644
--- a/src/test/compile-fail/const-eval-overflow.rs
+++ b/src/test/compile-fail/const-eval-overflow.rs
@@ -23,84 +23,84 @@ const VALS_I8: (i8, i8, i8, i8) =
     (-i8::MIN,
      //~^ ERROR attempted to negate with overflow
      i8::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      i8::MAX + 1,
      //~^ ERROR attempted to add with overflow
      i8::MIN * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_I16: (i16, i16, i16, i16) =
     (-i16::MIN,
      //~^ ERROR attempted to negate with overflow
      i16::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      i16::MAX + 1,
      //~^ ERROR attempted to add with overflow
      i16::MIN * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_I32: (i32, i32, i32, i32) =
     (-i32::MIN,
      //~^ ERROR attempted to negate with overflow
      i32::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      i32::MAX + 1,
      //~^ ERROR attempted to add with overflow
      i32::MIN * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_I64: (i64, i64, i64, i64) =
     (-i64::MIN,
      //~^ ERROR attempted to negate with overflow
      i64::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      i64::MAX + 1,
      //~^ ERROR attempted to add with overflow
      i64::MAX * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_U8: (u8, u8, u8, u8) =
     (-(u8::MIN as i8) as u8,
      u8::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      u8::MAX + 1,
      //~^ ERROR attempted to add with overflow
      u8::MAX * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_U16: (u16, u16, u16, u16) =
     (-(u16::MIN as i16) as u16,
      u16::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      u16::MAX + 1,
      //~^ ERROR attempted to add with overflow
      u16::MAX * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_U32: (u32, u32, u32, u32) =
     (-(u32::MIN as i32) as u32,
      u32::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      u32::MAX + 1,
      //~^ ERROR attempted to add with overflow
      u32::MAX * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 const VALS_U64: (u64, u64, u64, u64) =
     (-(u64::MIN as i64) as u64,
      u64::MIN - 1,
-     //~^ ERROR attempted to sub with overflow
+     //~^ ERROR attempted to subtract with overflow
      u64::MAX + 1,
      //~^ ERROR attempted to add with overflow
      u64::MAX * 2,
-     //~^ ERROR attempted to mul with overflow
+     //~^ ERROR attempted to multiply with overflow
      );
 
 fn main() {
diff --git a/src/test/compile-fail/const-integer-bool-ops.rs b/src/test/compile-fail/const-integer-bool-ops.rs
index 37a93ec954d..0d6cf3bab45 100644
--- a/src/test/compile-fail/const-integer-bool-ops.rs
+++ b/src/test/compile-fail/const-integer-bool-ops.rs
@@ -8,32 +8,30 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-const X: usize = 42 && 39; //~ ERROR: can't do this op on unsigned integrals
+const X: usize = 42 && 39; //~ ERROR: can't do this op on integrals
 const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here
 
-const X1: usize = 42 || 39; //~ ERROR: can't do this op on unsigned integrals
+const X1: usize = 42 || 39; //~ ERROR: can't do this op on integrals
 const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here
 
-// FIXME: the error should be `on signed integrals`
-const X2: usize = -42 || -39; //~ ERROR: can't do this op on unsigned integrals
+const X2: usize = -42 || -39; //~ ERROR: unary negation of unsigned integer
 const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
 
-// FIXME: the error should be `on signed integrals`
-const X3: usize = -42 && -39; //~ ERROR: can't do this op on unsigned integrals
+const X3: usize = -42 && -39; //~ ERROR: unary negation of unsigned integer
 const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
 
 const Y: usize = 42.0 == 42.0;
-const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected constant integer expression for array length
+const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
 const Y1: usize = 42.0 >= 42.0;
-const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected constant integer expression for array length
+const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
 const Y2: usize = 42.0 <= 42.0;
-const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected constant integer expression for array length
+const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
 const Y3: usize = 42.0 > 42.0;
-const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected constant integer expression for array length
+const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
 const Y4: usize = 42.0 < 42.0;
-const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected constant integer expression for array length
+const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
 const Y5: usize = 42.0 != 42.0;
-const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected constant integer expression for array length
+const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
 
 fn main() {
     let _ = ARR;
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 786c72b66f3..9c6b774b990 100644
--- a/src/test/compile-fail/const-len-underflow-separate-spans.rs
+++ b/src/test/compile-fail/const-len-underflow-separate-spans.rs
@@ -15,7 +15,7 @@
 const ONE: usize = 1;
 const TWO: usize = 2;
 const LEN: usize = ONE - TWO;
-//~^ ERROR array length constant evaluation error: attempted to sub with overflow [E0250]
+//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
 
 fn main() {
     let a: [i8; LEN] = unimplemented!();
diff --git a/src/test/compile-fail/const-len-underflow-subspans.rs b/src/test/compile-fail/const-len-underflow-subspans.rs
index 020717dc1e1..d51f31087d0 100644
--- a/src/test/compile-fail/const-len-underflow-subspans.rs
+++ b/src/test/compile-fail/const-len-underflow-subspans.rs
@@ -16,5 +16,5 @@ const TWO: usize = 2;
 
 fn main() {
     let a: [i8; ONE - TWO] = unimplemented!();
-    //~^ ERROR array length constant evaluation error: attempted to sub with overflow [E0250]
+    //~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
 }
diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs
index 8c607fc7e32..9d3c432d148 100644
--- a/src/test/compile-fail/const-tup-index-span.rs
+++ b/src/test/compile-fail/const-tup-index-span.rs
@@ -11,7 +11,7 @@
 // Test spans of errors
 
 const TUP: (usize,) = 5 << 64;
-//~^ ERROR: attempted left shift with overflow [E0250]
+//~^ ERROR: attempted to shift left with overflow [E0250]
 const ARR: [i32; TUP.0] = [];
 
 fn main() {
diff --git a/src/test/compile-fail/discrim-overflow-2.rs b/src/test/compile-fail/discrim-overflow-2.rs
index 76378d5c802..0ff740212e8 100644
--- a/src/test/compile-fail/discrim-overflow-2.rs
+++ b/src/test/compile-fail/discrim-overflow-2.rs
@@ -24,7 +24,7 @@ fn f_i8() {
     enum A {
         Ok = i8::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed on value after 127: i8; set explicitly via OhNo = -128 if that is desired outcome
+        OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome
     }
 }
 
@@ -33,7 +33,7 @@ fn f_u8() {
     enum A {
         Ok = u8::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed on value after 255: u8; set explicitly via OhNo = 0 if that is desired outcome
+        OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome
     }
 }
 
diff --git a/src/test/compile-fail/discrim-overflow.rs b/src/test/compile-fail/discrim-overflow.rs
index 5d7e61e9d1e..7316e737b6d 100644
--- a/src/test/compile-fail/discrim-overflow.rs
+++ b/src/test/compile-fail/discrim-overflow.rs
@@ -22,7 +22,7 @@ fn f_i8() {
     enum A {
         Ok = i8::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed on value after 127: i8; set explicitly via OhNo = -128 if that is desired outcome
+        OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome
     }
 
     let x = A::Ok;
@@ -33,7 +33,7 @@ fn f_u8() {
     enum A {
         Ok = u8::MAX - 1,
         Ok2,
-        OhNo, //~ ERROR enum discriminant overflowed on value after 255: u8; set explicitly via OhNo = 0 if that is desired outcome
+        OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome
     }
 
     let x = A::Ok;
diff --git a/src/test/compile-fail/enum-discrim-too-small.rs b/src/test/compile-fail/enum-discrim-too-small.rs
index 84a27a38200..d6ba09bb4c5 100644
--- a/src/test/compile-fail/enum-discrim-too-small.rs
+++ b/src/test/compile-fail/enum-discrim-too-small.rs
@@ -9,46 +9,32 @@
 // except according to those terms.
 
 
-#[repr(u8)] //~ NOTE discriminant type specified here
+#[repr(u8)]
 enum Eu8 {
     Au8 = 23,
     Bu8 = 223,
-    Cu8 = -23, //~ ERROR discriminant value outside specified type
+    Cu8 = -23, //~ ERROR unary negation of unsigned integer
 }
 
-#[repr(i8)] //~ NOTE discriminant type specified here
-enum Ei8 {
-    Ai8 = 23,
-    Bi8 = -23,
-    Ci8 = 223, //~ ERROR discriminant value outside specified type
-}
-
-#[repr(u16)] //~ NOTE discriminant type specified here
+#[repr(u16)]
 enum Eu16 {
     Au16 = 23,
     Bu16 = 55555,
-    Cu16 = -22333, //~ ERROR discriminant value outside specified type
-}
-
-#[repr(i16)] //~ NOTE discriminant type specified here
-enum Ei16 {
-    Ai16 = 23,
-    Bi16 = -22333,
-    Ci16 = 55555, //~ ERROR discriminant value outside specified type
+    Cu16 = -22333, //~ ERROR unary negation of unsigned integer
 }
 
-#[repr(u32)] //~ NOTE discriminant type specified here
+#[repr(u32)]
 enum Eu32 {
     Au32 = 23,
     Bu32 = 3_000_000_000,
-    Cu32 = -2_000_000_000, //~ ERROR discriminant value outside specified type
+    Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
 }
 
-#[repr(i32)] //~ NOTE discriminant type specified here
-enum Ei32 {
-    Ai32 = 23,
-    Bi32 = -2_000_000_000,
-    Ci32 = 3_000_000_000, //~ ERROR discriminant value outside specified type
+#[repr(u64)]
+enum Eu64 {
+    Au32 = 23,
+    Bu32 = 3_000_000_000,
+    Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
 }
 
 // u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`.  This is a
diff --git a/src/test/compile-fail/enum-discrim-too-small2.rs b/src/test/compile-fail/enum-discrim-too-small2.rs
new file mode 100644
index 00000000000..d66716c14c3
--- /dev/null
+++ b/src/test/compile-fail/enum-discrim-too-small2.rs
@@ -0,0 +1,47 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(overflowing_literals)]
+#![allow(dead_code)]
+
+#[repr(i8)]
+enum Ei8 {
+    Ai8 = 23,
+    Bi8 = -23,
+    Ci8 = 223, //~ ERROR literal out of range for i8
+}
+
+#[repr(i16)]
+enum Ei16 {
+    Ai16 = 23,
+    Bi16 = -22333,
+    Ci16 = 55555, //~ ERROR literal out of range for i16
+}
+
+#[repr(i32)]
+enum Ei32 {
+    Ai32 = 23,
+    Bi32 = -2_000_000_000,
+    Ci32 = 3_000_000_000, //~ ERROR literal out of range for i32
+}
+
+#[repr(i64)]
+enum Ei64 {
+    Ai64 = 23,
+    Bi64 = -9223372036854775808,
+    Ci64 = 9223372036854775809, //~ ERROR literal out of range for i64
+}
+
+// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`.  This is a
+// little counterintuitive, but since the discriminant can store all the bits, and extracting it
+// with a cast requires specifying the signedness, there is no loss of information in those cases.
+// This also applies to isize and usize on 64-bit targets.
+
+pub fn main() { }
diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs
index ed1327f3118..7ca274b81e5 100644
--- a/src/test/compile-fail/eval-enum.rs
+++ b/src/test/compile-fail/eval-enum.rs
@@ -10,7 +10,8 @@
 
 enum test {
     div_zero = 1/0, //~ERROR constant evaluation error: attempted to divide by zero
-    rem_zero = 1%0  //~ERROR constant evaluation error: attempted remainder with a divisor of zero
+    rem_zero = 1%0,
+//~^ ERROR constant evaluation error: attempted to calculate the remainder with a divisor of zero
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/feature-gate-negate-unsigned.rs b/src/test/compile-fail/feature-gate-negate-unsigned.rs
index 15cc17b19db..546fc5e3c60 100644
--- a/src/test/compile-fail/feature-gate-negate-unsigned.rs
+++ b/src/test/compile-fail/feature-gate-negate-unsigned.rs
@@ -21,22 +21,7 @@ const _MAX: usize = -1;
 //~| HELP use a cast or the `!` operator
 
 fn main() {
-    let a = -1;
-    //~^ ERROR unary negation of unsigned integer
-    //~| HELP use a cast or the `!` operator
-    let _b : u8 = a; // for infering variable a to u8.
-
-    -a;
-    //~^ ERROR unary negation of unsigned integer
-    //~| HELP use a cast or the `!` operator
-
-    let _d = -1u8;
-    //~^ ERROR unary negation of unsigned integer
-    //~| HELP use a cast or the `!` operator
-
-    for _ in -10..10u8 {}
-    //~^ ERROR unary negation of unsigned integer
-    //~| HELP use a cast or the `!` operator
-
+    let x = 5u8;
+    let _y = -x; //~ ERROR unary negation of unsigned integer
     -S; // should not trigger the gate; issue 26840
 }
diff --git a/src/test/compile-fail/feature-gate-negate-unsigned0.rs b/src/test/compile-fail/feature-gate-negate-unsigned0.rs
new file mode 100644
index 00000000000..05b194345d4
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-negate-unsigned0.rs
@@ -0,0 +1,31 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that negating unsigned integers doesn't compile
+
+struct S;
+impl std::ops::Neg for S {
+    type Output = u32;
+    fn neg(self) -> u32 { 0 }
+}
+
+fn main() {
+    let a = -1;
+    //~^ ERROR unary negation of unsigned integer
+    let _b : u8 = a; // for infering variable a to u8.
+
+    let _d = -1u8;
+    //~^ ERROR unary negation of unsigned integer
+
+    for _ in -10..10u8 {}
+    //~^ ERROR unary negation of unsigned integer
+
+    -S; // should not trigger the gate; issue 26840
+}
diff --git a/src/test/compile-fail/issue-15524.rs b/src/test/compile-fail/issue-15524.rs
index b378d2f885e..bdf344dcdfe 100644
--- a/src/test/compile-fail/issue-15524.rs
+++ b/src/test/compile-fail/issue-15524.rs
@@ -12,12 +12,12 @@ const N: isize = 1;
 
 enum Foo {
     A = 1,
-    B = 1, //~ ERROR discriminant value `1` already exists
+    B = 1, //~ ERROR discriminant value `1isize` already exists
     //~^^ NOTE conflicting
     C = 0,
-    D, //~ ERROR discriminant value `1` already exists
+    D, //~ ERROR discriminant value `1isize` already exists
     //~^^^^^ NOTE conflicting
-    E = N, //~ ERROR discriminant value `1` already exists
+    E = N, //~ ERROR discriminant value `1isize` already exists
     //~^^^^^^^ NOTE conflicting
 }
 
diff --git a/src/test/compile-fail/issue-8460-const.rs b/src/test/compile-fail/issue-8460-const.rs
index 95921556c7d..fe51d0b6998 100644
--- a/src/test/compile-fail/issue-8460-const.rs
+++ b/src/test/compile-fail/issue-8460-const.rs
@@ -35,23 +35,23 @@ fn main() {
     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
     //~^ ERROR attempted to divide by zero
     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow
+    //~^ ERROR attempted to calculate the remainder with overflow
     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow
+    //~^ ERROR attempted to calculate the remainder with overflow
     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow
+    //~^ ERROR attempted to calculate the remainder with overflow
     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow
+    //~^ ERROR attempted to calculate the remainder with overflow
     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow
+    //~^ ERROR attempted to calculate the remainder with overflow
     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero
+    //~^ ERROR attempted to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero
+    //~^ ERROR attempted to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero
+    //~^ ERROR attempted to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero
+    //~^ ERROR attempted to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero
+    //~^ ERROR attempted to calculate the remainder with a divisor of zero
 }
diff --git a/src/test/compile-fail/issue-8761.rs b/src/test/compile-fail/issue-8761.rs
index 35be01970cb..1c98abce030 100644
--- a/src/test/compile-fail/issue-8761.rs
+++ b/src/test/compile-fail/issue-8761.rs
@@ -10,13 +10,13 @@
 
 enum Foo {
     A = 1i64,
-    //~^ ERROR mismatched types
-    //~| expected `isize`
-    //~| found `i64`
+    //~^ ERROR mismatched types:
+    //~| expected `isize`,
+    //~| found `i64` [E0080]
     B = 2u8
-    //~^ ERROR mismatched types
-    //~| expected `isize`
-    //~| found `u8`
+    //~^ ERROR mismatched types:
+    //~| expected `isize`,
+    //~| found `u8` [E0080]
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/lint-type-limits.rs b/src/test/compile-fail/lint-type-limits.rs
index 0b414ad73db..29929c120c3 100644
--- a/src/test/compile-fail/lint-type-limits.rs
+++ b/src/test/compile-fail/lint-type-limits.rs
@@ -24,11 +24,6 @@ fn bar() -> i8 {
     return 123;
 }
 
-fn baz() -> bool {
-    128 > bar() //~ ERROR comparison is useless due to type limits
-                //~^ WARNING literal out of range for i8
-}
-
 fn bleh() {
     let u = 42u8;
     let _ = u > 255; //~ ERROR comparison is useless due to type limits
@@ -40,11 +35,3 @@ fn bleh() {
     let _ = u >= 0; //~ ERROR comparison is useless due to type limits
     let _ = 0 <= u; //~ ERROR comparison is useless due to type limits
 }
-
-fn qux() {
-    let mut i = 1i8;
-    while 200 != i { //~ ERROR comparison is useless due to type limits
-                     //~^ WARNING literal out of range for i8
-        i += 1;
-    }
-}
diff --git a/src/test/compile-fail/lint-type-limits2.rs b/src/test/compile-fail/lint-type-limits2.rs
new file mode 100644
index 00000000000..8fc18d16469
--- /dev/null
+++ b/src/test/compile-fail/lint-type-limits2.rs
@@ -0,0 +1,24 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+// compile-flags: -D unused-comparisons
+fn main() { }
+
+
+fn bar() -> i8 {
+    return 123;
+}
+
+fn baz() -> bool {
+    128 > bar() //~ ERROR comparison is useless due to type limits
+                //~| WARN literal out of range for i8
+}
diff --git a/src/test/compile-fail/lint-type-limits3.rs b/src/test/compile-fail/lint-type-limits3.rs
new file mode 100644
index 00000000000..b09dc0acdbf
--- /dev/null
+++ b/src/test/compile-fail/lint-type-limits3.rs
@@ -0,0 +1,22 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+// compile-flags: -D unused-comparisons
+fn main() { }
+
+fn qux() {
+    let mut i = 1i8;
+    while 200 != i { //~ ERROR comparison is useless due to type limits
+                     //~| WARN literal out of range for i8
+        i += 1;
+    }
+}
diff --git a/src/test/compile-fail/lint-type-overflow.rs b/src/test/compile-fail/lint-type-overflow.rs
index eb5b77f7a45..ce336905c01 100644
--- a/src/test/compile-fail/lint-type-overflow.rs
+++ b/src/test/compile-fail/lint-type-overflow.rs
@@ -25,7 +25,6 @@ fn main() {
 
     let x2: i8 = -128; // should be OK
     let x1: i8 = 128; //~ error: literal out of range for i8
-    let x2: i8 = --128; //~ error: literal out of range for i8
 
     let x3: i8 = -129; //~ error: literal out of range for i8
     let x3: i8 = -(129); //~ error: literal out of range for i8
@@ -54,9 +53,4 @@ fn main() {
     let x = 18446744073709551615_i64; //~ error: literal out of range for i64
     let x: i64 = -9223372036854775809; //~ error: literal out of range for i64
     let x = -9223372036854775809_i64; //~ error: literal out of range for i64
-
-    let x = -3.40282348e+38_f32; //~ error: literal out of range for f32
-    let x =  3.40282348e+38_f32; //~ error: literal out of range for f32
-    let x = -1.7976931348623159e+308_f64; //~ error: literal out of range for f64
-    let x =  1.7976931348623159e+308_f64; //~ error: literal out of range for f64
 }
diff --git a/src/test/compile-fail/lint-type-overflow2.rs b/src/test/compile-fail/lint-type-overflow2.rs
new file mode 100644
index 00000000000..83300f18c3e
--- /dev/null
+++ b/src/test/compile-fail/lint-type-overflow2.rs
@@ -0,0 +1,22 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+
+#![deny(overflowing_literals)]
+
+#[allow(unused_variables)]
+fn main() {
+    let x2: i8 = --128; //~ error: literal out of range for i8
+
+    let x = -3.40282348e+38_f32; //~ error: literal out of range for f32
+    let x =  3.40282348e+38_f32; //~ error: literal out of range for f32
+    let x = -1.7976931348623159e+308_f64; //~ error: literal out of range for f64
+    let x =  1.7976931348623159e+308_f64; //~ error: literal out of range for f64
+}
diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs
index 9aa61418d6d..10b722946a8 100644
--- a/src/test/compile-fail/repeat_count.rs
+++ b/src/test/compile-fail/repeat_count.rs
@@ -43,13 +43,17 @@ fn main() {
     let f = [0; -4_isize];
     //~^ ERROR mismatched types
     //~| expected `usize`
-    //~| found `isize`
-    //~| ERROR expected positive integer for repeat count, found negative integer [E0306]
+    //~| found `isize` [E0308]
+    //~| ERROR mismatched types:
+    //~| expected `usize`,
+    //~| found `isize` [E0307]
     let f = [0_usize; -1_isize];
     //~^ ERROR mismatched types
     //~| expected `usize`
-    //~| found `isize`
-    //~| ERROR expected positive integer for repeat count, found negative integer [E0306]
+    //~| found `isize` [E0308]
+    //~| ERROR mismatched types
+    //~| expected `usize`
+    //~| found `isize` [E0307]
     struct G {
         g: (),
     }
diff --git a/src/test/run-pass/const-fn.rs b/src/test/run-pass/const-fn.rs
index 5961ed8d339..562040dc562 100644
--- a/src/test/run-pass/const-fn.rs
+++ b/src/test/run-pass/const-fn.rs
@@ -10,7 +10,7 @@
 
 // A very basic test of const fn functionality.
 
-#![feature(const_fn)]
+#![feature(const_fn, const_indexing)]
 
 const fn add(x: u32, y: u32) -> u32 {
     x + y
@@ -24,6 +24,14 @@ const unsafe fn div(x: u32, y: u32) -> u32 {
     x / y
 }
 
+const fn generic<T>(t: T) -> T {
+    t
+}
+
+const fn generic_arr<T: Copy>(t: [T; 1]) -> T {
+    t[0]
+}
+
 const SUM: u32 = add(44, 22);
 const DIFF: u32 = sub(44, 22);
 const DIV: u32 = unsafe{div(44, 22)};
@@ -36,4 +44,6 @@ fn main() {
     assert_eq!(DIV, 2);
 
     let _: [&'static str; sub(100, 99) as usize] = ["hi"];
+    let _: [&'static str; generic(1)] = ["hi"];
+    let _: [&'static str; generic_arr([1])] = ["hi"];
 }
diff --git a/src/test/run-pass/const-negation.rs b/src/test/run-pass/const-negation.rs
new file mode 100644
index 00000000000..96f4217e4cb
--- /dev/null
+++ b/src/test/run-pass/const-negation.rs
@@ -0,0 +1,42 @@
+// 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.
+
+#![feature(stmt_expr_attributes)]
+
+#[deny(const_err)]
+
+fn main() {
+    #[cfg(target_pointer_width = "32")]
+    const I: isize = -2147483648isize;
+    #[cfg(target_pointer_width = "64")]
+    const I: isize = -9223372036854775808isize;
+    assert_eq!(::std::i32::MIN as u64, 0xffffffff80000000);
+    assert_eq!(-2147483648isize as u64, 0xffffffff80000000);
+    assert_eq!(::std::i64::MIN as u64, 0x8000000000000000);
+    #[cfg(target_pointer_width = "64")]
+    assert_eq!(-9223372036854775808isize as u64, 0x8000000000000000);
+    #[cfg(target_pointer_width = "32")]
+    assert_eq!(-9223372036854775808isize as u64, 0);
+    const J: usize = ::std::i32::MAX as usize;
+    const K: usize = -1i32 as u32 as usize;
+    const L: usize = ::std::i32::MIN as usize;
+    const M: usize = ::std::i64::MIN as usize;
+    match 5 {
+        J => {},
+        K => {},
+        L => {},
+        M => {},
+        _ => {}
+    }
+    match 5 {
+        I => {},
+        _ => {}
+    }
+}
diff --git a/src/test/run-pass/enum-discrim-autosizing.rs b/src/test/run-pass/enum-discrim-autosizing.rs
index 99e44735d0f..53c44f2bb24 100644
--- a/src/test/run-pass/enum-discrim-autosizing.rs
+++ b/src/test/run-pass/enum-discrim-autosizing.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(stmt_expr_attributes)]
 
 use std::mem::size_of;
 
@@ -46,11 +47,6 @@ enum Ei64 {
     Bi64 = 0x8000_0000
 }
 
-enum Eu64 {
-    Au64 = 0,
-    Bu64 = 0x8000_0000_0000_0000
-}
-
 pub fn main() {
     assert_eq!(size_of::<Ei8>(), 1);
     assert_eq!(size_of::<Eu8>(), 1);
@@ -58,6 +54,8 @@ pub fn main() {
     assert_eq!(size_of::<Eu16>(), 2);
     assert_eq!(size_of::<Ei32>(), 4);
     assert_eq!(size_of::<Eu32>(), 4);
+    #[cfg(target_pointer_width = "64")]
     assert_eq!(size_of::<Ei64>(), 8);
-    assert_eq!(size_of::<Eu64>(), 8);
+    #[cfg(target_pointer_width = "32")]
+    assert_eq!(size_of::<Ei64>(), 4);
 }
diff --git a/src/test/run-pass/issue-23833.rs b/src/test/run-pass/issue-23833.rs
new file mode 100644
index 00000000000..7d63c41eb26
--- /dev/null
+++ b/src/test/run-pass/issue-23833.rs
@@ -0,0 +1,25 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::fmt;
+use std::{i8, i16, i32, i64, isize};
+use std::{u8, u16, u32, u64, usize};
+
+const A_I8_T
+    : [u32; (i8::MAX as i8 - 1i8) as usize]
+    = [0; (i8::MAX as usize) - 1];
+
+fn main() {
+    foo(&A_I8_T[..]);
+}
+
+fn foo<T:fmt::Debug>(x: T) {
+    println!("{:?}", x);
+}