about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>2015-12-16 18:44:15 +0100
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>2016-03-10 12:50:12 +0100
commit7bde56e14941924c17daeaa1996d61d0ffdb6bd1 (patch)
treee7690e75421bb80a98fe6f2e8968680f0fca8914
parent3ac4076ac0e4276dce59cd254dfa2c5cf848dca8 (diff)
downloadrust-7bde56e14941924c17daeaa1996d61d0ffdb6bd1.tar.gz
rust-7bde56e14941924c17daeaa1996d61d0ffdb6bd1.zip
typestrong constant integers
-rw-r--r--mk/crates.mk16
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/middle/const_eval.rs699
-rw-r--r--src/librustc/middle/ty/mod.rs5
-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/err.rs85
-rw-r--r--src/librustc_const_eval/int.rs551
-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/decoder.rs8
-rw-r--r--src/librustc_metadata/encoder.rs21
-rw-r--r--src/librustc_metadata/lib.rs1
-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/lib.rs1
-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.rs144
-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.rs25
-rw-r--r--src/librustc_trans/trans/mir/rvalue.rs5
-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/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.rs3
-rw-r--r--src/test/compile-fail/const-eval-overflow-4b.rs3
-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.rs44
-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.rs8
-rw-r--r--src/test/compile-fail/lint-type-limits.rs13
-rw-r--r--src/test/compile-fail/lint-type-limits2.rs23
-rw-r--r--src/test/compile-fail/lint-type-limits3.rs21
-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.rs4
-rw-r--r--src/test/run-pass/const-fn.rs12
-rw-r--r--src/test/run-pass/const-negation.rs37
-rw-r--r--src/test/run-pass/issue-23833.rs25
-rw-r--r--src/test/run-pass/packed-struct-generic-layout.rs4
-rw-r--r--src/test/run-pass/shift.rs6
65 files changed, 1614 insertions, 917 deletions
diff --git a/mk/crates.mk b/mk/crates.mk
index 1ecceb9280a..c4ab068f39b 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/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/const_eval.rs b/src/librustc/middle/const_eval.rs
index 06030c00211..c3f8d7bf959 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;
@@ -43,10 +42,20 @@ 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> {
@@ -248,8 +257,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 +266,14 @@ pub enum ConstVal {
     Function(DefId),
     Array(ast::NodeId, u64),
     Repeat(ast::NodeId, u64),
+    Char(char),
 }
 
 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 +282,7 @@ 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),
         }
     }
 }
@@ -286,8 +295,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 +304,7 @@ 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,
             _ => false,
         }
     }
@@ -307,9 +316,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 +325,7 @@ impl ConstVal {
             Function(_) => "function definition",
             Array(..) => "array",
             Repeat(..) => "repeat",
+            Char(..) => "char",
         }
     }
 }
@@ -402,7 +410,6 @@ pub enum ErrKind {
     CannotCast,
     CannotCastTo(&'static str),
     InvalidOpForInts(hir::BinOp_),
-    InvalidOpForUInts(hir::BinOp_),
     InvalidOpForBools(hir::BinOp_),
     InvalidOpForFloats(hir::BinOp_),
     InvalidOpForIntUint(hir::BinOp_),
@@ -442,6 +449,13 @@ pub enum ErrKind {
     MiscCatchAll,
 
     IndexOpFeatureGated,
+    Math(ConstMathErr),
+}
+
+impl From<ConstMathErr> for ErrKind {
+    fn from(err: ConstMathErr) -> ErrKind {
+        Math(err)
+    }
 }
 
 impl ConstEvalErr {
@@ -451,8 +465,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 +505,7 @@ 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(),
         }
     }
 }
@@ -536,276 +550,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 +583,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 +643,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 +665,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 +704,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,9 +713,6 @@ 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
@@ -1103,10 +842,28 @@ 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 = match ty_hint {
+                  ExprTypeChecked => ExprTypeChecked,
+                  UncheckedExprNoHint | UncheckedExprHint(_) => {
+                      if let Some(hint) = tcx.ast_ty_to_ty_cache.borrow().get(&arg.ty.id) {
+                          let mut new_ty_hint = UncheckedExprHint(hint);
+                          for t in hint.walk() {
+                              if let ty::TypeVariants::TyParam(_) = t.sty {
+                                  // found a generic argument, but we are in typeck
+                                  new_ty_hint = UncheckedExprNoHint;
+                                  break;
+                              }
+                          }
+                          new_ty_hint
+                      } else {
+                          UncheckedExprNoHint
+                      }
+                  },
+              };
               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 +873,10 @@ 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) => match lit_to_const(&lit.node, tcx, ety, lit.span) {
+          Ok(val) => val,
+          Err(err) => signal!(e, Math(err)),
+      },
       hir::ExprBlock(ref block) => {
         match block.expr {
             Some(ref expr) => try!(eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)),
@@ -1134,14 +894,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 +916,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 +932,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 +944,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)
+                    return eval_const_expr_partial(tcx, &fields[index.node], ty_hint, fn_args)
                 } else {
                     signal!(e, TupleIndexOutOfBounds);
                 }
@@ -1205,7 +965,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)
+                    return eval_const_expr_partial(tcx, &f.expr, ty_hint, fn_args)
                 } else {
                     signal!(e, MissingStructField);
                 }
@@ -1289,100 +1049,155 @@ 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 i8))),
+        ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i16))),
+        ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i32))),
+        ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i64))),
+        ty::TyInt(ast::IntTy::Is) => {
+            Ok(Integral(Isize(try!(ConstIsize::new(v as i64, tcx.sess.target.int_type)))))
+        },
+        ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
+        ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
+        ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
+        ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
+        ty::TyUint(ast::UintTy::Us) => {
+            Ok(Integral(Usize(try!(ConstUsize::new(v, tcx.sess.target.uint_type)))))
+        },
+        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: &ty::ctxt<'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: &ty::ctxt<'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: &ty::ctxt<'tcx>,
+                      ty_hint: Option<Ty<'tcx>>,
+                      span: Span,
+                      ) -> Result<ConstVal, ConstMathErr> {
+    use syntax::ast::*;
+    use syntax::ast::LitIntType::*;
+    const I8MAX: u64 = ::std::i8::MAX as u64;
+    const I16MAX: u64 = ::std::i16::MAX as u64;
+    const I32MAX: u64 = ::std::i32::MAX as u64;
+    const I64MAX: u64 = ::std::i64::MAX as u64;
+    const U8MAX: u64 = ::std::u8::MAX as u64;
+    const U16MAX: u64 = ::std::u16::MAX as u64;
+    const U32MAX: u64 = ::std::u32::MAX as u64;
+    const U64MAX: u64 = ::std::u64::MAX as u64;
+    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 @ 0...I8MAX, Signed(IntTy::I8)) => Ok(Integral(I8(n as i8))),
+        LitKind::Int(n @ 0...I16MAX, Signed(IntTy::I16)) => Ok(Integral(I16(n as i16))),
+        LitKind::Int(n @ 0...I32MAX, Signed(IntTy::I32)) => Ok(Integral(I32(n as i32))),
+        LitKind::Int(n @ 0...I64MAX, Signed(IntTy::I64)) => Ok(Integral(I64(n as i64))),
+        LitKind::Int(n, Signed(IntTy::Is)) => {
+            Ok(Integral(Isize(try!(ConstIsize::new(n as i64, tcx.sess.target.int_type)))))
+        },
+
+        LitKind::Int(_, Signed(ty)) => Err(ConstMathErr::LitOutOfRange(ty)),
+
+        LitKind::Int(n, Unsuffixed) => {
+            match ty_hint.map(|t| &t.sty) {
+                Some(&ty::TyInt(ity)) => {
+                    lit_to_const(&LitKind::Int(n, Signed(ity)), tcx, ty_hint, span)
+                },
+                Some(&ty::TyUint(uty)) => {
+                    lit_to_const(&LitKind::Int(n, Unsigned(uty)), tcx, ty_hint, span)
+                },
+                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());
+                    lit_to_const(lit, tcx, Some(int_ty.to_ty(tcx)), span)
+                },
+                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 @ 0...U8MAX, Unsigned(UintTy::U8)) => Ok(Integral(U8(n as u8))),
+        LitKind::Int(n @ 0...U16MAX, Unsigned(UintTy::U16)) => Ok(Integral(U16(n as u16))),
+        LitKind::Int(n @ 0...U32MAX, Unsigned(UintTy::U32)) => Ok(Integral(U32(n as u32))),
+        LitKind::Int(n @ 0...U64MAX, Unsigned(UintTy::U64)) => Ok(Integral(U64(n as u64))),
+
+        LitKind::Int(n, Unsigned(UintTy::Us)) => {
+            Ok(Integral(Usize(try!(ConstUsize::new(n as u64, tcx.sess.target.uint_type)))))
+        },
+        LitKind::Int(_, Unsigned(ty)) => Err(ConstMathErr::ULitOutOfRange(ty)),
+
+        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/mod.rs b/src/librustc/middle/ty/mod.rs
index 2e38080bfb0..c98ae2cceab 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
 
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 4556611df59..15f240755ad 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/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..896d4a9b7d5
--- /dev/null
+++ b/src/librustc_const_eval/int.rs
@@ -0,0 +1,551 @@
+// 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 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 i8),
+            (Infer(a @ 0...as_u64::I16MAX), I16(_)) => I16(a as i16),
+            (Infer(a @ 0...as_u64::I32MAX), I32(_)) => I32(a 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 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"),
+        }
+    }
+}
+
+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/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/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/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_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..ebe19aa972c 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;
 
@@ -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..2c251a4cd57 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,7 @@ 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::Function(_) => C_nil(ccx)
         }
     }
@@ -99,7 +118,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/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 3ce03e24578..e0d4e128cf5 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -80,6 +80,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;
@@ -1021,7 +1023,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)]
     )
 }
 
@@ -1030,24 +1032,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) => {
@@ -1066,16 +1083,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,
@@ -1085,12 +1097,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>,
@@ -1104,17 +1115,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/test/auxiliary/dummy_mir_pass.rs b/src/test/auxiliary/dummy_mir_pass.rs
index 16ef965e0db..5206f693372 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::MirPass;
@@ -23,6 +24,7 @@ use rustc::mir::repr::{Mir, Literal};
 use rustc::mir::visit::MutVisitor;
 use rustc::middle::infer::InferCtxt;
 use rustc::middle::const_eval::ConstVal;
+use rustc_const_eval::ConstInt;
 use rustc_plugin::Registry;
 
 struct Pass;
@@ -37,8 +39,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..33fa4aae611 100644
--- a/src/test/compile-fail/const-eval-overflow-3.rs
+++ b/src/test/compile-fail/const-eval-overflow-3.rs
@@ -17,7 +17,7 @@
 // self-hosted and a cross-compiled setup; therefore resorting to
 // error-pattern for now.
 
-// error-pattern: expected constant integer for repeat count, but attempted to add with overflow
+// error-pattern: expected constant integer for repeat count, but tried to add two integrals of
 
 #![allow(unused_imports)]
 
@@ -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..68ef1b47751 100644
--- a/src/test/compile-fail/const-eval-overflow-4b.rs
+++ b/src/test/compile-fail/const-eval-overflow-4b.rs
@@ -21,8 +21,7 @@ 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 tried to add two integrals of different types [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..a25d0a9e187
--- /dev/null
+++ b/src/test/compile-fail/enum-discrim-too-small2.rs
@@ -0,0 +1,44 @@
+// 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.
+
+#[repr(i8)]
+enum Ei8 {
+    Ai8 = 23,
+    Bi8 = -23,
+    Ci8 = 223, //~ ERROR literal out of range for i8 [E0080]
+}
+
+#[repr(i16)]
+enum Ei16 {
+    Ai16 = 23,
+    Bi16 = -22333,
+    Ci16 = 55555, //~ ERROR literal out of range for i16 [E0080]
+}
+
+#[repr(i32)]
+enum Ei32 {
+    Ai32 = 23,
+    Bi32 = -2_000_000_000,
+    Ci32 = 3_000_000_000, //~ ERROR literal out of range for i32 [E0080]
+}
+
+#[repr(i64)]
+enum Ei64 {
+    Ai64 = 23,
+    Bi64 = -9223372036854775808,
+    Ci64 = 9223372036854775809, //~ ERROR literal out of range for i64 [E0080]
+}
+
+// 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..da8bd1dc28d 100644
--- a/src/test/compile-fail/issue-8761.rs
+++ b/src/test/compile-fail/issue-8761.rs
@@ -10,13 +10,9 @@
 
 enum Foo {
     A = 1i64,
-    //~^ ERROR mismatched types
-    //~| expected `isize`
-    //~| found `i64`
+    //~^ ERROR mismatched types: expected `isize` got `i64`
     B = 2u8
-    //~^ ERROR mismatched types
-    //~| expected `isize`
-    //~| found `u8`
+    //~^ ERROR mismatched types: expected `isize` got `u8`
 }
 
 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..20e756c803a
--- /dev/null
+++ b/src/test/compile-fail/lint-type-limits2.rs
@@ -0,0 +1,23 @@
+// 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 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..fed4143a6d7
--- /dev/null
+++ b/src/test/compile-fail/lint-type-limits3.rs
@@ -0,0 +1,21 @@
+// 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 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..c0913be1354 100644
--- a/src/test/compile-fail/repeat_count.rs
+++ b/src/test/compile-fail/repeat_count.rs
@@ -44,12 +44,12 @@ fn main() {
     //~^ ERROR mismatched types
     //~| expected `usize`
     //~| found `isize`
-    //~| ERROR expected positive integer for repeat count, found negative integer [E0306]
+    //~| ERROR expected positive integer for repeat count, found isize [E0306]
     let f = [0_usize; -1_isize];
     //~^ ERROR mismatched types
     //~| expected `usize`
     //~| found `isize`
-    //~| ERROR expected positive integer for repeat count, found negative integer [E0306]
+    //~| ERROR expected positive integer for repeat count, found isize [E0306]
     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..afd82e7d8ac
--- /dev/null
+++ b/src/test/run-pass/const-negation.rs
@@ -0,0 +1,37 @@
+// 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.
+
+#[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);
+    assert_eq!(-9223372036854775808isize as u64, 0x8000000000000000);
+    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/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);
+}
diff --git a/src/test/run-pass/packed-struct-generic-layout.rs b/src/test/run-pass/packed-struct-generic-layout.rs
index b962a5c7933..1c8a1322ad2 100644
--- a/src/test/run-pass/packed-struct-generic-layout.rs
+++ b/src/test/run-pass/packed-struct-generic-layout.rs
@@ -20,7 +20,7 @@ struct S<T, S> {
 
 pub fn main() {
     unsafe {
-        let s = S { a: 0xff_ff_ff_ffu32, b: 1, c: 0xaa_aa_aa_aa as i32 };
+        let s = S { a: 0xff_ff_ff_ffu32, b: 1, c: 0xaa_aa_aa_aa as u32 };
         let transd : [u8; 9] = mem::transmute(s);
         // Don't worry about endianness, the numbers are palindromic.
         assert_eq!(transd,
@@ -29,7 +29,7 @@ pub fn main() {
                     0xaa, 0xaa, 0xaa, 0xaa]);
 
 
-        let s = S { a: 1u8, b: 2u8, c: 0b10000001_10000001 as i16};
+        let s = S { a: 1u8, b: 2u8, c: 0b10000001_10000001 as u16};
         let transd : [u8; 4] = mem::transmute(s);
         // Again, no endianness problems.
         assert_eq!(transd,
diff --git a/src/test/run-pass/shift.rs b/src/test/run-pass/shift.rs
index 2f417e0e2f4..5ca6a023099 100644
--- a/src/test/run-pass/shift.rs
+++ b/src/test/run-pass/shift.rs
@@ -45,7 +45,7 @@ fn test_expr() {
     let v4 = 4 as isize;
     let v2 = 2 as isize;
     assert_eq!(v10 >> v2 as usize, v2 as i8);
-    assert_eq!(v10 << v4 as usize, 160 as i8);
+    assert_eq!(v10 << v2 as usize, 40 as i8);
 
     let v10 = 10 as usize;
     let v4 = 4 as isize;
@@ -71,9 +71,9 @@ fn test_const() {
     assert_eq!(r2_3, 160 as isize);
 
     static r1_4: i8 = 10i8 >> 2_usize;
-    static r2_4: i8 = 10i8 << 4_usize;
+    static r2_4: i8 = 10i8 << 2_usize;
     assert_eq!(r1_4, 2 as i8);
-    assert_eq!(r2_4, 160 as i8);
+    assert_eq!(r2_4, 40 as i8);
 
     static r1_5: usize = 10_usize >> 2_usize;
     static r2_5: usize = 10_usize << 4_usize;