about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Schneider <git-spam9815368754983@oli-obk.de>2015-10-02 10:36:45 +0200
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>2015-10-13 17:01:03 +0200
commit09d3adf52eaf6e411b49d26af7d347406f563557 (patch)
tree900941d16c00c6e90521d4122cbc851d72cb0953
parent81b3b27cf533e50424f749d1c1db23e5d8db952f (diff)
downloadrust-09d3adf52eaf6e411b49d26af7d347406f563557.tar.gz
rust-09d3adf52eaf6e411b49d26af7d347406f563557.zip
implement RFC 1229
const eval errors outside of true constant enviroments are not reported anymore, but instead forwarded to a lint.
-rw-r--r--src/librustc/lint/builtin.rs9
-rw-r--r--src/librustc/middle/check_const.rs8
-rw-r--r--src/librustc_trans/trans/_match.rs17
-rw-r--r--src/librustc_trans/trans/base.rs5
-rw-r--r--src/librustc_trans/trans/consts.rs259
-rw-r--r--src/librustc_trans/trans/expr.rs120
-rw-r--r--src/librustc_trans/trans/intrinsic.rs11
-rw-r--r--src/test/compile-fail/const-err.rs36
-rw-r--r--src/test/compile-fail/const-eval-overflow.rs2
-rw-r--r--src/test/compile-fail/issue-8460-const.rs42
-rw-r--r--src/test/run-fail/overflowing-add.rs4
-rw-r--r--src/test/run-fail/overflowing-lsh-1.rs5
-rw-r--r--src/test/run-fail/overflowing-lsh-2.rs5
-rw-r--r--src/test/run-fail/overflowing-lsh-3.rs5
-rw-r--r--src/test/run-fail/overflowing-lsh-4.rs5
-rw-r--r--src/test/run-fail/overflowing-mul.rs5
-rw-r--r--src/test/run-fail/overflowing-neg.rs5
-rw-r--r--src/test/run-fail/overflowing-rsh-1.rs5
-rw-r--r--src/test/run-fail/overflowing-rsh-2.rs5
-rw-r--r--src/test/run-fail/overflowing-rsh-3.rs5
-rw-r--r--src/test/run-fail/overflowing-rsh-4.rs5
-rw-r--r--src/test/run-fail/overflowing-sub.rs5
-rw-r--r--src/test/run-pass/wrapping-int-api.rs2
23 files changed, 376 insertions, 194 deletions
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index d9b05d80400..26f663b1c9d 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -17,6 +17,12 @@
 use lint::{LintPass, LateLintPass, LintArray};
 
 declare_lint! {
+    pub CONST_ERR,
+    Warn,
+    "constant evaluation detected erroneous expression"
+}
+
+declare_lint! {
     pub UNUSED_IMPORTS,
     Warn,
     "imports that are never used"
@@ -134,7 +140,8 @@ impl LintPass for HardwiredLints {
             VARIANT_SIZE_DIFFERENCES,
             FAT_PTR_TRANSMUTES,
             TRIVIAL_CASTS,
-            TRIVIAL_NUMERIC_CASTS
+            TRIVIAL_NUMERIC_CASTS,
+            CONST_ERR
         )
     }
 }
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 662dfdfd4e7..433d2468a09 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -176,8 +176,8 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
         if mode == Mode::ConstFn {
             for arg in &fd.inputs {
                 match arg.pat.node {
-                    hir::PatIdent(hir::BindByValue(hir::MutImmutable), _, None) => {}
                     hir::PatWild(_) => {}
+                    hir::PatIdent(hir::BindByValue(hir::MutImmutable), _, None) => {}
                     _ => {
                         span_err!(self.tcx.sess, arg.pat.span, E0022,
                                   "arguments of constant functions can only \
@@ -476,9 +476,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                                     self.tcx, ex, ExprTypeChecked) {
                                 Ok(_) => {}
                                 Err(msg) => {
-                                    span_err!(self.tcx.sess, msg.span, E0020,
-                                              "{} in a constant expression",
-                                              msg.description())
+                                    self.tcx.sess.add_lint(::lint::builtin::CONST_ERR, ex.id,
+                                                           msg.span,
+                                                           msg.description().into_owned())
                                 }
                             }
                         }
diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs
index dbb0e120805..f0e4c20be05 100644
--- a/src/librustc_trans/trans/_match.rs
+++ b/src/librustc_trans/trans/_match.rs
@@ -275,19 +275,30 @@ impl<'a, 'tcx> Opt<'a, 'tcx> {
     }
 
     fn trans<'blk>(&self, mut bcx: Block<'blk, 'tcx>) -> OptResult<'blk, 'tcx> {
+        use trans::consts::TrueConst::Yes;
         let _icx = push_ctxt("match::trans_opt");
         let ccx = bcx.ccx();
         match *self {
             ConstantValue(ConstantExpr(lit_expr), _) => {
                 let lit_ty = bcx.tcx().node_id_to_type(lit_expr.id);
-                let (llval, _) = consts::const_expr(ccx, &*lit_expr, bcx.fcx.param_substs, None);
+                let expr = consts::const_expr(ccx, &*lit_expr, bcx.fcx.param_substs, None, Yes);
+                let llval = match expr {
+                    Ok((llval, _)) => llval,
+                    Err(err) => bcx.ccx().sess().span_fatal(lit_expr.span, &err.description()),
+                };
                 let lit_datum = immediate_rvalue(llval, lit_ty);
                 let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
                 SingleResult(Result::new(bcx, lit_datum.val))
             }
             ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => {
-                let (l1, _) = consts::const_expr(ccx, &**l1, bcx.fcx.param_substs, None);
-                let (l2, _) = consts::const_expr(ccx, &**l2, bcx.fcx.param_substs, None);
+                let l1 = match consts::const_expr(ccx, &**l1, bcx.fcx.param_substs, None, Yes) {
+                    Ok((l1, _)) => l1,
+                    Err(err) => bcx.ccx().sess().span_fatal(l1.span, &err.description()),
+                };
+                let l2 = match consts::const_expr(ccx, &**l2, bcx.fcx.param_substs, None, Yes) {
+                    Ok((l2, _)) => l2,
+                    Err(err) => bcx.ccx().sess().span_fatal(l2.span, &err.description()),
+                };
                 RangeResult(Result::new(bcx, l1), Result::new(bcx, l2))
             }
             Variant(disr_val, ref repr, _, _) => {
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index 05b20ac3fb7..3c8c5b2d907 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -2125,7 +2125,10 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
           let mut v = TransItemVisitor{ ccx: ccx };
           v.visit_expr(&**expr);
 
-          let g = consts::trans_static(ccx, m, expr, item.id, &item.attrs);
+          let g = match consts::trans_static(ccx, m, expr, item.id, &item.attrs) {
+              Ok(g) => g,
+              Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()),
+          };
           set_global_section(ccx, g, item);
           update_linkage(ccx, g, Some(item.id), OriginalTranslation);
       },
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index f509ed8dc5c..48f1e57a19c 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -15,7 +15,7 @@ use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
 use llvm::{InternalLinkage, ValueRef, Bool, True};
 use metadata::cstore::LOCAL_CRATE;
 use middle::{check_const, def};
-use middle::const_eval::{self, ConstVal};
+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};
@@ -29,7 +29,10 @@ use middle::const_eval::eval_const_expr_partial;
 use middle::def_id::DefId;
 use trans::{adt, closure, debuginfo, expr, inline, machine};
 use trans::base::{self, push_ctxt};
-use trans::common::*;
+use trans::common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty};
+use trans::common::{type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt};
+use trans::common::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint};
+use trans::common::{type_is_fat_ptr, Field, C_vector, C_array, C_null, ExprId, MethodCallKey};
 use trans::declare;
 use trans::monomorphize;
 use trans::type_::Type;
@@ -44,6 +47,7 @@ use util::nodemap::NodeMap;
 use rustc_front::hir;
 
 use std::ffi::{CStr, CString};
+use std::borrow::Cow;
 use libc::c_uint;
 use syntax::ast;
 use syntax::attr;
@@ -191,7 +195,8 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                            node: ExprOrMethodCall,
                            def_id: DefId,
                            arg_vals: &[ValueRef],
-                           param_substs: &'tcx Substs<'tcx>) -> ValueRef {
+                           param_substs: &'tcx Substs<'tcx>,
+                           trueconst: TrueConst) -> Result<ValueRef, ConstEvalFailure> {
     let fn_like = const_eval::lookup_const_fn_by_id(ccx.tcx(), def_id);
     let fn_like = fn_like.expect("lookup_const_fn_by_id failed in const_fn_call");
 
@@ -204,9 +209,9 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let substs = ccx.tcx().mk_substs(node_id_substs(ccx, node, param_substs));
     match fn_like.body().expr {
         Some(ref expr) => {
-            const_expr(ccx, &**expr, substs, Some(&fn_args)).0
-        }
-        None => C_nil(ccx)
+            const_expr(ccx, &**expr, substs, Some(&fn_args), trueconst).map(|(res, _)| res)
+        },
+        None => Ok(C_nil(ccx)),
     }
 }
 
@@ -229,19 +234,57 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 }
 
+pub enum ConstEvalFailure {
+    /// in case the const evaluator failed on something that panic at runtime
+    /// as defined in RFC 1229
+    Runtime(ConstEvalErr),
+    // in case we found a true constant
+    Compiletime(ConstEvalErr),
+}
+
+impl ConstEvalFailure {
+    fn into_inner(self) -> ConstEvalErr {
+        match self {
+            Runtime(e) => e,
+            Compiletime(e) => e,
+        }
+    }
+    pub fn description(&self) -> Cow<str> {
+        match self {
+            &Runtime(ref e) => e.description(),
+            &Compiletime(ref e) => e.description(),
+        }
+    }
+}
+
+#[derive(Copy, Clone)]
+pub enum TrueConst {
+    Yes, No
+}
+
+use self::ConstEvalFailure::*;
+
 fn get_const_val(ccx: &CrateContext,
                  def_id: DefId,
-                 ref_expr: &hir::Expr) -> ValueRef {
+                 ref_expr: &hir::Expr) -> Result<ValueRef, ConstEvalFailure> {
     let expr = get_const_expr(ccx, def_id, ref_expr);
     let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
-    get_const_expr_as_global(ccx, expr, check_const::ConstQualif::empty(), empty_substs)
+    match get_const_expr_as_global(ccx, expr, check_const::ConstQualif::empty(),
+                                   empty_substs, TrueConst::Yes) {
+        Err(Runtime(err)) => {
+            ccx.tcx().sess.span_err(expr.span, &err.description());
+            Err(Compiletime(err))
+        },
+        other => other,
+    }
 }
 
 pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                           expr: &hir::Expr,
                                           qualif: check_const::ConstQualif,
-                                          param_substs: &'tcx Substs<'tcx>)
-                                          -> ValueRef {
+                                          param_substs: &'tcx Substs<'tcx>,
+                                          trueconst: TrueConst)
+                                          -> Result<ValueRef, ConstEvalFailure> {
     debug!("get_const_expr_as_global: {:?}", expr.id);
     // Special-case constants to cache a common global for all uses.
     match expr.node {
@@ -263,7 +306,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     let key = (expr.id, param_substs);
     match ccx.const_values().borrow().get(&key) {
-        Some(&val) => return val,
+        Some(&val) => return Ok(val),
         None => {}
     }
     let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,
@@ -271,9 +314,12 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let val = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) {
         // Avoid autorefs as they would create global instead of stack
         // references, even when only the latter are correct.
-        const_expr_unadjusted(ccx, expr, ty, param_substs, None)
+        try!(const_expr_unadjusted(ccx, expr, ty, param_substs, None, trueconst))
     } else {
-        const_expr(ccx, expr, param_substs, None).0
+        match const_expr(ccx, expr, param_substs, None, trueconst) {
+            Err(err) => return Err(err),
+            Ok((ok, _)) => ok,
+        }
     };
 
     // boolean SSA values are i1, but they have to be stored in i8 slots,
@@ -288,17 +334,18 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     let lvalue = addr_of(ccx, val, type_of::align_of(ccx, ty), "const");
     ccx.const_values().borrow_mut().insert(key, lvalue);
-    lvalue
+    Ok(lvalue)
 }
 
 pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                             e: &hir::Expr,
                             param_substs: &'tcx Substs<'tcx>,
-                            fn_args: FnArgMap)
-                            -> (ValueRef, Ty<'tcx>) {
+                            fn_args: FnArgMap,
+                            trueconst: TrueConst)
+                            -> Result<(ValueRef, Ty<'tcx>), ConstEvalFailure> {
     let ety = monomorphize::apply_param_substs(cx.tcx(), param_substs,
                                                &cx.tcx().expr_ty(e));
-    let llconst = const_expr_unadjusted(cx, e, ety, param_substs, fn_args);
+    let llconst = try!(const_expr_unadjusted(cx, e, ety, param_substs, fn_args, trueconst));
     let mut llconst = llconst;
     let mut ety_adjusted = monomorphize::apply_param_substs(cx.tcx(), param_substs,
                                                             &cx.tcx().expr_ty_adjusted(e));
@@ -393,11 +440,11 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                          e, ety_adjusted,
                          csize, tsize));
     }
-    (llconst, ety_adjusted)
+    Ok((llconst, ety_adjusted))
 }
 
 fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
-                             te: ValueRef) {
+                             te: ValueRef, trueconst: TrueConst) -> Result<(), ConstEvalFailure> {
     // The only kind of unary expression that we check for validity
     // here is `-expr`, to check if it "overflows" (e.g. `-i32::MIN`).
     if let hir::ExprUnary(hir::UnNeg, ref inner_e) = e.node {
@@ -410,13 +457,13 @@ 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; }
+        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,
+                    None => return Ok(()),
                 };
                 const_int_checked_neg(
                     input, e, Some(const_eval::IntTy::from(cx.tcx(), int_type)))
@@ -424,31 +471,51 @@ fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
             ty::TyUint(uint_type) => {
                 let input = match const_to_opt_uint(te) {
                     Some(v) => v,
-                    None => return,
+                    None => return Ok(()),
                 };
                 const_uint_checked_neg(
                     input, e, Some(const_eval::UintTy::from(cx.tcx(), uint_type)))
             }
-            _ => return,
+            _ => return Ok(()),
         };
+        const_err(cx, e, result, trueconst)
+    } else {
+        Ok(())
+    }
+}
 
-        // We do not actually care about a successful result.
-        if let Err(err) = result {
+fn const_err(cx: &CrateContext,
+             e: &hir::Expr,
+             result: Result<ConstVal, ConstEvalErr>,
+             trueconst: TrueConst)
+             -> Result<(), ConstEvalFailure> {
+    match (result, trueconst) {
+        (Ok(_), _) => {
+            // We do not actually care about a successful result.
+            Ok(())
+        },
+        (Err(err), TrueConst::Yes) => {
             cx.tcx().sess.span_err(e.span, &err.description());
-        }
+            Err(Compiletime(err))
+        },
+        (Err(err), TrueConst::No) => {
+            cx.tcx().sess.span_warn(e.span, &err.description());
+            Err(Runtime(err))
+        },
     }
 }
 
 fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
-                              te1: ValueRef, te2: ValueRef) {
-    let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { return };
+                              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,
+                _ => return Ok(()),
             };
 
             let opt_ety = Some(const_eval::IntTy::from(cx.tcx(), int_type));
@@ -460,14 +527,14 @@ fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
                 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,
+                _ => 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,
+                _ => return Ok(()),
             };
 
             let opt_ety = Some(const_eval::UintTy::from(cx.tcx(), uint_type));
@@ -479,43 +546,44 @@ fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
                 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,
+                _ => return Ok(()),
             }
         }
-        _ => return,
+        _ => return Ok(()),
     };
-    // We do not actually care about a successful result.
-    if let Err(err) = result {
-        cx.tcx().sess.span_err(e.span, &err.description());
-    }
+    const_err(cx, e, result, trueconst)
 }
 
 fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                    e: &hir::Expr,
                                    ety: Ty<'tcx>,
                                    param_substs: &'tcx Substs<'tcx>,
-                                   fn_args: FnArgMap)
-                                   -> ValueRef
+                                   fn_args: FnArgMap,
+                                   trueconst: TrueConst)
+                                   -> Result<ValueRef, ConstEvalFailure>
 {
     debug!("const_expr_unadjusted(e={:?}, ety={:?}, param_substs={:?})",
            e,
            ety,
            param_substs);
 
-    let map_list = |exprs: &[P<hir::Expr>]| -> Vec<ValueRef> {
+    let map_list = |exprs: &[P<hir::Expr>]| -> Result<Vec<ValueRef>, ConstEvalFailure> {
         exprs.iter()
-             .map(|e| const_expr(cx, &**e, param_substs, fn_args).0)
+             .map(|e| const_expr(cx, &**e, param_substs, fn_args, trueconst).map(|(l, _)| l))
+             .collect::<Vec<Result<ValueRef, ConstEvalFailure>>>()
+             .into_iter()
              .collect()
+         // this dance is necessary to eagerly run const_expr so all errors are reported
     };
     let _icx = push_ctxt("const_expr");
-    match e.node {
+    Ok(match e.node {
         hir::ExprLit(ref lit) => {
             const_lit(cx, e, &**lit)
         },
         hir::ExprBinary(b, ref e1, ref e2) => {
             /* Neither type is bottom, and we expect them to be unified
              * already, so the following is safe. */
-            let (te1, ty) = const_expr(cx, &**e1, param_substs, fn_args);
+            let (te1, ty) = try!(const_expr(cx, &**e1, param_substs, fn_args, trueconst));
             debug!("const_expr_unadjusted: te1={}, ty={:?}",
                    cx.tn().val_to_string(te1),
                    ty);
@@ -523,9 +591,9 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let is_float = ty.is_fp();
             let signed = ty.is_signed();
 
-            let (te2, _) = const_expr(cx, &**e2, param_substs, fn_args);
+            let (te2, _) = try!(const_expr(cx, &**e2, param_substs, fn_args, trueconst));
 
-            check_binary_expr_validity(cx, e, ty, te1, te2);
+            try!(check_binary_expr_validity(cx, e, ty, te1, te2, trueconst));
 
             unsafe { match b.node {
                 hir::BiAdd if is_float => llvm::LLVMConstFAdd(te1, te2),
@@ -571,9 +639,9 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             } } // unsafe { match b.node {
         },
         hir::ExprUnary(u, ref inner_e) => {
-            let (te, ty) = const_expr(cx, &**inner_e, param_substs, fn_args);
+            let (te, ty) = try!(const_expr(cx, &**inner_e, param_substs, fn_args, trueconst));
 
-            check_unary_expr_validity(cx, e, ty, te);
+            try!(check_unary_expr_validity(cx, e, ty, te, trueconst));
 
             let is_float = ty.is_fp();
             unsafe { match u {
@@ -584,21 +652,21 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             } }
         },
         hir::ExprField(ref base, field) => {
-            let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
+            let (bv, bt) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst));
             let brepr = adt::represent_type(cx, bt);
             let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None);
             let ix = vinfo.field_index(field.node);
             adt::const_get_field(cx, &*brepr, bv, vinfo.discr, ix)
         },
         hir::ExprTupField(ref base, idx) => {
-            let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
+            let (bv, bt) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst));
             let brepr = adt::represent_type(cx, bt);
             let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None);
             adt::const_get_field(cx, &*brepr, bv, vinfo.discr, idx.node)
         },
 
         hir::ExprIndex(ref base, ref index) => {
-            let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
+            let (bv, bt) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst));
             let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked) {
                 Ok(ConstVal::Int(i)) => i as u64,
                 Ok(ConstVal::Uint(u)) => u,
@@ -650,10 +718,10 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         hir::ExprCast(ref base, _) => {
             let t_cast = ety;
             let llty = type_of::type_of(cx, t_cast);
-            let (v, t_expr) = const_expr(cx, &**base, param_substs, fn_args);
+            let (v, t_expr) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst));
             debug!("trans_const_cast({:?} as {:?})", t_expr, t_cast);
             if expr::cast_is_noop(cx.tcx(), base, t_expr, t_cast) {
-                return v;
+                return Ok(v);
             }
             if type_is_fat_ptr(cx.tcx(), t_expr) {
                 // Fat pointer casts.
@@ -664,9 +732,9 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                    ptr_ty);
                 if type_is_fat_ptr(cx.tcx(), t_cast) {
                     let info = const_get_elt(cx, v, &[abi::FAT_PTR_EXTRA as u32]);
-                    return C_struct(cx, &[addr, info], false)
+                    return Ok(C_struct(cx, &[addr, info], false))
                 } else {
-                    return addr;
+                    return Ok(addr);
                 }
             }
             unsafe { match (
@@ -732,35 +800,47 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             } else {
                 // If this isn't the address of a static, then keep going through
                 // normal constant evaluation.
-                let (v, ty) = const_expr(cx, &**sub, param_substs, fn_args);
+                let (v, ty) = try!(const_expr(cx, &**sub, param_substs, fn_args, trueconst));
                 addr_of(cx, v, type_of::align_of(cx, ty), "ref")
             }
         },
         hir::ExprAddrOf(hir::MutMutable, ref sub) => {
-            let (v, ty) = const_expr(cx, &**sub, param_substs, fn_args);
+            let (v, ty) = try!(const_expr(cx, &**sub, param_substs, fn_args, trueconst));
             addr_of_mut(cx, v, type_of::align_of(cx, ty), "ref_mut_slice")
         },
         hir::ExprTup(ref es) => {
             let repr = adt::represent_type(cx, ety);
-            let vals = map_list(&es[..]);
+            let vals = try!(map_list(&es[..]));
             adt::trans_const(cx, &*repr, 0, &vals[..])
         },
         hir::ExprStruct(_, ref fs, ref base_opt) => {
             let repr = adt::represent_type(cx, ety);
 
             let base_val = match *base_opt {
-                Some(ref base) => Some(const_expr(cx, &**base, param_substs, fn_args)),
+                Some(ref base) => Some(try!(const_expr(
+                    cx,
+                    &**base,
+                    param_substs,
+                    fn_args,
+                    trueconst,
+                ))),
                 None => None
             };
 
             let VariantInfo { discr, fields } = VariantInfo::of_node(cx.tcx(), ety, e.id);
             let cs = fields.iter().enumerate().map(|(ix, &Field(f_name, _))| {
                 match (fs.iter().find(|f| f_name == f.name.node), base_val) {
-                    (Some(ref f), _) => const_expr(cx, &*f.expr, param_substs, fn_args).0,
-                    (_, Some((bv, _))) => adt::const_get_field(cx, &*repr, bv, discr, ix),
+                    (Some(ref f), _) => {
+                        const_expr(cx, &*f.expr, param_substs, fn_args, trueconst).map(|(l, _)| l)
+                    },
+                    (_, Some((bv, _))) => Ok(adt::const_get_field(cx, &*repr, bv, discr, ix)),
                     (_, None) => cx.sess().span_bug(e.span, "missing struct field"),
                 }
-            }).collect::<Vec<_>>();
+            })
+            .collect::<Vec<Result<_, ConstEvalFailure>>>()
+            .into_iter()
+            .collect::<Result<Vec<_>,ConstEvalFailure>>();
+            let cs = try!(cs);
             if ety.is_simd() {
                 C_vector(&cs[..])
             } else {
@@ -771,8 +851,17 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let unit_ty = ety.sequence_element_type(cx.tcx());
             let llunitty = type_of::type_of(cx, unit_ty);
             let vs = es.iter()
-                       .map(|e| const_expr(cx, &**e, param_substs, fn_args).0)
-                       .collect::<Vec<_>>();
+                       .map(|e| const_expr(
+                           cx,
+                           &**e,
+                           param_substs,
+                           fn_args,
+                           trueconst,
+                       ).map(|(l, _)| l))
+                       .collect::<Vec<Result<_, ConstEvalFailure>>>()
+                       .into_iter()
+                       .collect::<Result<Vec<_>, ConstEvalFailure>>();
+            let vs = try!(vs);
             // If the vector contains enums, an LLVM array won't work.
             if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
                 C_struct(cx, &vs[..], false)
@@ -784,7 +873,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let unit_ty = ety.sequence_element_type(cx.tcx());
             let llunitty = type_of::type_of(cx, unit_ty);
             let n = cx.tcx().eval_repeat_count(count);
-            let unit_val = const_expr(cx, &**elem, param_substs, fn_args).0;
+            let unit_val = try!(const_expr(cx, &**elem, param_substs, fn_args, trueconst)).0;
             let vs = vec![unit_val; n];
             if val_ty(unit_val) != llunitty {
                 C_struct(cx, &vs[..], false)
@@ -806,7 +895,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                     expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
                 }
                 def::DefConst(def_id) | def::DefAssociatedConst(def_id) => {
-                    const_deref_ptr(cx, get_const_val(cx, def_id, e))
+                    const_deref_ptr(cx, try!(get_const_val(cx, def_id, e)))
                 }
                 def::DefVariant(enum_did, variant_did, _) => {
                     let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
@@ -850,10 +939,17 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 };
             }
             let def = cx.tcx().def_map.borrow()[&callee.id].full_def();
-            let arg_vals = map_list(args);
+            let arg_vals = try!(map_list(args));
             match def {
                 def::DefFn(did, _) | def::DefMethod(did) => {
-                    const_fn_call(cx, ExprId(callee.id), did, &arg_vals, param_substs)
+                    try!(const_fn_call(
+                        cx,
+                        ExprId(callee.id),
+                        did,
+                        &arg_vals,
+                        param_substs,
+                        trueconst,
+                    ))
                 }
                 def::DefStruct(_) => {
                     if ety.is_simd() {
@@ -875,15 +971,21 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             }
         },
         hir::ExprMethodCall(_, _, ref args) => {
-            let arg_vals = map_list(args);
+            let arg_vals = try!(map_list(args));
             let method_call = ty::MethodCall::expr(e.id);
             let method_did = cx.tcx().tables.borrow().method_map[&method_call].def_id;
-            const_fn_call(cx, MethodCallKey(method_call),
-                          method_did, &arg_vals, param_substs)
+            try!(const_fn_call(cx, MethodCallKey(method_call),
+                               method_did, &arg_vals, param_substs, trueconst))
         },
         hir::ExprBlock(ref block) => {
             match block.expr {
-                Some(ref expr) => const_expr(cx, &**expr, param_substs, fn_args).0,
+                Some(ref expr) => try!(const_expr(
+                    cx,
+                    &**expr,
+                    param_substs,
+                    fn_args,
+                    trueconst,
+                )).0,
                 None => C_nil(cx),
             }
         },
@@ -902,20 +1004,27 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         },
         _ => cx.sess().span_bug(e.span,
                                 "bad constant expression type in consts::const_expr"),
-    }
+    })
 }
+
 pub fn trans_static(ccx: &CrateContext,
                     m: hir::Mutability,
                     expr: &hir::Expr,
                     id: ast::NodeId,
                     attrs: &Vec<ast::Attribute>)
-                    -> ValueRef {
+                    -> Result<ValueRef, ConstEvalErr> {
     unsafe {
         let _icx = push_ctxt("trans_static");
         let g = base::get_item_val(ccx, id);
 
         let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
-        let (v, _) = const_expr(ccx, expr, empty_substs, None);
+        let (v, _) = try!(const_expr(
+            ccx,
+            expr,
+            empty_substs,
+            None,
+            TrueConst::Yes,
+        ).map_err(|e| e.into_inner()));
 
         // boolean SSA values are i1, but they have to be stored in i8 slots,
         // otherwise some LLVM optimization passes don't work as expected
@@ -964,7 +1073,7 @@ pub fn trans_static(ccx: &CrateContext,
                                "thread_local") {
             llvm::set_thread_local(g, true);
         }
-        g
+        Ok(g)
     }
 }
 
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 6b9cec5ad24..6144de7109f 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -133,13 +133,25 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     ) {
         if !qualif.intersects(check_const::ConstQualif::PREFER_IN_PLACE) {
             if let SaveIn(lldest) = dest {
-                let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
-                                                            bcx.fcx.param_substs);
-                // Cast pointer to destination, because constants
-                // have different types.
-                let lldest = PointerCast(bcx, lldest, val_ty(global));
-                memcpy_ty(bcx, lldest, global, expr_ty_adjusted(bcx, expr));
-                return bcx;
+                match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
+                                                       bcx.fcx.param_substs,
+                                                       consts::TrueConst::No) {
+                    Ok(global) => {
+                        // Cast pointer to destination, because constants
+                        // have different types.
+                        let lldest = PointerCast(bcx, lldest, val_ty(global));
+                        memcpy_ty(bcx, lldest, global, expr_ty_adjusted(bcx, expr));
+                        return bcx;
+                    },
+                    Err(consts::ConstEvalFailure::Runtime(_)) => {
+                        // in case const evaluation errors, translate normally
+                        // debug assertions catch the same errors
+                        // see RFC 1229
+                    },
+                    Err(consts::ConstEvalFailure::Compiletime(_)) => {
+                        return bcx;
+                    },
+                }
             }
             // Even if we don't have a value to emit, and the expression
             // doesn't have any side-effects, we still have to translate the
@@ -221,48 +233,64 @@ pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         check_const::ConstQualif::NOT_CONST |
         check_const::ConstQualif::NEEDS_DROP
     ) {
-        let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
-                                                      bcx.fcx.param_substs);
+        match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
+                                                            bcx.fcx.param_substs,
+                                                            consts::TrueConst::No) {
+            Ok(global) => {
+                if qualif.intersects(check_const::ConstQualif::HAS_STATIC_BORROWS) {
+                    // Is borrowed as 'static, must return lvalue.
+
+                    // Cast pointer to global, because constants have different types.
+                    let const_ty = expr_ty_adjusted(bcx, expr);
+                    let llty = type_of::type_of(bcx.ccx(), const_ty);
+                    let global = PointerCast(bcx, global, llty.ptr_to());
+                    let datum = Datum::new(global, const_ty, Lvalue::new("expr::trans"));
+                    return DatumBlock::new(bcx, datum.to_expr_datum());
+                }
 
-        if qualif.intersects(check_const::ConstQualif::HAS_STATIC_BORROWS) {
-            // Is borrowed as 'static, must return lvalue.
+                // Otherwise, keep around and perform adjustments, if needed.
+                let const_ty = if adjusted_global {
+                    expr_ty_adjusted(bcx, expr)
+                } else {
+                    expr_ty(bcx, expr)
+                };
 
-            // Cast pointer to global, because constants have different types.
-            let const_ty = expr_ty_adjusted(bcx, expr);
-            let llty = type_of::type_of(bcx.ccx(), const_ty);
-            let global = PointerCast(bcx, global, llty.ptr_to());
-            let datum = Datum::new(global, const_ty, Lvalue::new("expr::trans"));
-            return DatumBlock::new(bcx, datum.to_expr_datum());
+                // This could use a better heuristic.
+                Some(if type_is_immediate(bcx.ccx(), const_ty) {
+                    // Cast pointer to global, because constants have different types.
+                    let llty = type_of::type_of(bcx.ccx(), const_ty);
+                    let global = PointerCast(bcx, global, llty.ptr_to());
+                    // Maybe just get the value directly, instead of loading it?
+                    immediate_rvalue(load_ty(bcx, global, const_ty), const_ty)
+                } else {
+                    let scratch = alloc_ty(bcx, const_ty, "const");
+                    call_lifetime_start(bcx, scratch);
+                    let lldest = if !const_ty.is_structural() {
+                        // Cast pointer to slot, because constants have different types.
+                        PointerCast(bcx, scratch, val_ty(global))
+                    } else {
+                        // In this case, memcpy_ty calls llvm.memcpy after casting both
+                        // source and destination to i8*, so we don't need any casts.
+                        scratch
+                    };
+                    memcpy_ty(bcx, lldest, global, const_ty);
+                    Datum::new(scratch, const_ty, Rvalue::new(ByRef))
+                })
+            },
+            Err(consts::ConstEvalFailure::Runtime(_)) => {
+                // in case const evaluation errors, translate normally
+                // debug assertions catch the same errors
+                // see RFC 1229
+                None
+            },
+            Err(consts::ConstEvalFailure::Compiletime(_)) => {
+                // generate a dummy llvm value
+                let const_ty = expr_ty(bcx, expr);
+                let llty = type_of::type_of(bcx.ccx(), const_ty);
+                let dummy = C_undef(llty.ptr_to());
+                Some(Datum::new(dummy, const_ty, Rvalue::new(ByRef)))
+            },
         }
-
-        // Otherwise, keep around and perform adjustments, if needed.
-        let const_ty = if adjusted_global {
-            expr_ty_adjusted(bcx, expr)
-        } else {
-            expr_ty(bcx, expr)
-        };
-
-        // This could use a better heuristic.
-        Some(if type_is_immediate(bcx.ccx(), const_ty) {
-            // Cast pointer to global, because constants have different types.
-            let llty = type_of::type_of(bcx.ccx(), const_ty);
-            let global = PointerCast(bcx, global, llty.ptr_to());
-            // Maybe just get the value directly, instead of loading it?
-            immediate_rvalue(load_ty(bcx, global, const_ty), const_ty)
-        } else {
-            let scratch = alloc_ty(bcx, const_ty, "const");
-            call_lifetime_start(bcx, scratch);
-            let lldest = if !const_ty.is_structural() {
-                // Cast pointer to slot, because constants have different types.
-                PointerCast(bcx, scratch, val_ty(global))
-            } else {
-                // In this case, memcpy_ty calls llvm.memcpy after casting both
-                // source and destination to i8*, so we don't need any casts.
-                scratch
-            };
-            memcpy_ty(bcx, lldest, global, const_ty);
-            Datum::new(scratch, const_ty, Rvalue::new(ByRef))
-        })
     } else {
         None
     };
diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs
index 0573d6301c5..b80cb7d5ca1 100644
--- a/src/librustc_trans/trans/intrinsic.rs
+++ b/src/librustc_trans/trans/intrinsic.rs
@@ -1563,7 +1563,16 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
             None => bcx.sess().span_bug(call_info.span,
                                         "intrinsic call with unexpected argument shape"),
         };
-        let vector = consts::const_expr(bcx.ccx(), vector, tcx.mk_substs(substs), None).0;
+        let vector = match consts::const_expr(
+            bcx.ccx(),
+            vector,
+            tcx.mk_substs(substs),
+            None,
+            consts::TrueConst::Yes, // this should probably help simd error reporting
+        ) {
+            Ok((vector, _)) => vector,
+            Err(err) => bcx.sess().span_fatal(call_info.span, &err.description()),
+        };
 
         let indices: Option<Vec<_>> = (0..n)
             .map(|i| {
diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs
new file mode 100644
index 00000000000..be67e06d99f
--- /dev/null
+++ b/src/test/compile-fail/const-err.rs
@@ -0,0 +1,36 @@
+// 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(exceeding_bitshifts)]
+#[deny(const_err)]
+
+fn black_box<T>(_: T) {
+    unimplemented!()
+}
+
+const BLA: u8 = 200u8 + 200u8;
+//~^ ERROR attempted to add with overflow
+
+fn main() {
+    let a = -std::i8::MIN;
+    //~^ WARN attempted to negate with overflow
+    let b = 200u8 + 200u8 + 200u8;
+    //~^ WARN attempted to add with overflow
+    //~^^ WARN attempted to add with overflow
+    let c = 200u8 * 4;
+    //~^ WARN attempted to mul with overflow
+    let d = 42u8 - (42u8 + 1);
+    //~^ WARN attempted to sub with overflow
+    let _e = BLA;
+    black_box(a);
+    black_box(b);
+    black_box(c);
+    black_box(d);
+}
diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs
index f991e5328c1..daa60955ad8 100644
--- a/src/test/compile-fail/const-eval-overflow.rs
+++ b/src/test/compile-fail/const-eval-overflow.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(negate_unsigned)]
-
 #![allow(unused_imports)]
 #![feature(negate_unsigned)]
 
diff --git a/src/test/compile-fail/issue-8460-const.rs b/src/test/compile-fail/issue-8460-const.rs
index 9c2e8d278ab..95921556c7d 100644
--- a/src/test/compile-fail/issue-8460-const.rs
+++ b/src/test/compile-fail/issue-8460-const.rs
@@ -8,48 +8,50 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![deny(const_err)]
+
 use std::{isize, i8, i16, i32, i64};
 use std::thread;
 
 fn main() {
     assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
-    //~^ ERROR attempted to divide with overflow in a constant expression
+    //~^ ERROR attempted to divide with overflow
     assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
-    //~^ ERROR attempted to divide with overflow in a constant expression
+    //~^ ERROR attempted to divide with overflow
     assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
-    //~^ ERROR attempted to divide with overflow in a constant expression
+    //~^ ERROR attempted to divide with overflow
     assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
-    //~^ ERROR attempted to divide with overflow in a constant expression
+    //~^ ERROR attempted to divide with overflow
     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
-    //~^ ERROR attempted to divide with overflow in a constant expression
+    //~^ ERROR attempted to divide with overflow
     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
-    //~^ ERROR attempted to divide by zero in a constant expression
+    //~^ ERROR attempted to divide by zero
     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
-    //~^ ERROR attempted to divide by zero in a constant expression
+    //~^ ERROR attempted to divide by zero
     assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
-    //~^ ERROR attempted to divide by zero in a constant expression
+    //~^ ERROR attempted to divide by zero
     assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
-    //~^ ERROR attempted to divide by zero in a constant expression
+    //~^ ERROR attempted to divide by zero
     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
-    //~^ ERROR attempted to divide by zero in a constant expression
+    //~^ ERROR attempted to divide by zero
     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow in a constant expression
+    //~^ ERROR attempted remainder with overflow
     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow in a constant expression
+    //~^ ERROR attempted remainder with overflow
     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow in a constant expression
+    //~^ ERROR attempted remainder with overflow
     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow in a constant expression
+    //~^ ERROR attempted remainder with overflow
     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
-    //~^ ERROR attempted remainder with overflow in a constant expression
+    //~^ ERROR attempted remainder with overflow
     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero in a constant expression
+    //~^ ERROR attempted remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero in a constant expression
+    //~^ ERROR attempted remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero in a constant expression
+    //~^ ERROR attempted remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero in a constant expression
+    //~^ ERROR attempted remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
-    //~^ ERROR attempted remainder with a divisor of zero in a constant expression
+    //~^ ERROR attempted remainder with a divisor of zero
 }
diff --git a/src/test/run-fail/overflowing-add.rs b/src/test/run-fail/overflowing-add.rs
index cd13b817c2b..6c6a41fa6f2 100644
--- a/src/test/run-fail/overflowing-add.rs
+++ b/src/test/run-fail/overflowing-add.rs
@@ -11,9 +11,7 @@
 // error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
 // compile-flags: -C debug-assertions
 
-// (Work around constant-evaluation)
-fn value() -> u8 { 200 }
 
 fn main() {
-    let _x = value() + value() + value();
+    let _x = 200u8 + 200u8 + 200u8;
 }
diff --git a/src/test/run-fail/overflowing-lsh-1.rs b/src/test/run-fail/overflowing-lsh-1.rs
index 54159153382..62935bacce8 100644
--- a/src/test/run-fail/overflowing-lsh-1.rs
+++ b/src/test/run-fail/overflowing-lsh-1.rs
@@ -11,9 +11,8 @@
 // error-pattern:thread '<main>' panicked at 'shift operation overflowed'
 // compile-flags: -C debug-assertions
 
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
 
 fn main() {
-    let _x = 1_i32 << id(32);
+    let _x = 1_i32 << 32;
 }
diff --git a/src/test/run-fail/overflowing-lsh-2.rs b/src/test/run-fail/overflowing-lsh-2.rs
index fd3e801457c..f6e6cb105c5 100644
--- a/src/test/run-fail/overflowing-lsh-2.rs
+++ b/src/test/run-fail/overflowing-lsh-2.rs
@@ -11,9 +11,8 @@
 // error-pattern:thread '<main>' panicked at 'shift operation overflowed'
 // compile-flags: -C debug-assertions
 
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
 
 fn main() {
-    let _x = 1 << id(-1);
+    let _x = 1 << -1;
 }
diff --git a/src/test/run-fail/overflowing-lsh-3.rs b/src/test/run-fail/overflowing-lsh-3.rs
index 58914bab3fb..a70f31954c6 100644
--- a/src/test/run-fail/overflowing-lsh-3.rs
+++ b/src/test/run-fail/overflowing-lsh-3.rs
@@ -11,9 +11,8 @@
 // error-pattern:thread '<main>' panicked at 'shift operation overflowed'
 // compile-flags: -C debug-assertions
 
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
 
 fn main() {
-    let _x = 1_u64 << id(64);
+    let _x = 1_u64 << 64;
 }
diff --git a/src/test/run-fail/overflowing-lsh-4.rs b/src/test/run-fail/overflowing-lsh-4.rs
index ed25876cec4..571feaeb943 100644
--- a/src/test/run-fail/overflowing-lsh-4.rs
+++ b/src/test/run-fail/overflowing-lsh-4.rs
@@ -14,12 +14,11 @@
 // This function is checking that our automatic truncation does not
 // sidestep the overflow checking.
 
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
 
 fn main() {
     // this signals overflow when checking is on
-    let x = 1_i8 << id(17);
+    let x = 1_i8 << 17;
 
     // ... but when checking is off, the fallback will truncate the
     // input to its lower three bits (= 1). Note that this is *not*
diff --git a/src/test/run-fail/overflowing-mul.rs b/src/test/run-fail/overflowing-mul.rs
index 5d2f5396240..a413a6f0abf 100644
--- a/src/test/run-fail/overflowing-mul.rs
+++ b/src/test/run-fail/overflowing-mul.rs
@@ -11,9 +11,6 @@
 // error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
 // compile-flags: -C debug-assertions
 
-// (Work around constant-evaluation)
-fn value() -> u8 { 200 }
-
 fn main() {
-    let x = value() * 4;
+    let x = 200u8 * 4;
 }
diff --git a/src/test/run-fail/overflowing-neg.rs b/src/test/run-fail/overflowing-neg.rs
index cdb74c7d7e2..7891d1ce9be 100644
--- a/src/test/run-fail/overflowing-neg.rs
+++ b/src/test/run-fail/overflowing-neg.rs
@@ -11,9 +11,6 @@
 // error-pattern:thread '<main>' panicked at 'attempted to negate with overflow'
 // compile-flags: -C debug-assertions
 
-// (Work around constant-evaluation)
-fn value() -> i8 { std::i8::MIN }
-
 fn main() {
-    let _x = -value();
+    let _x = -std::i8::MIN;
 }
diff --git a/src/test/run-fail/overflowing-rsh-1.rs b/src/test/run-fail/overflowing-rsh-1.rs
index c36a16f18f8..b58eaf7f836 100644
--- a/src/test/run-fail/overflowing-rsh-1.rs
+++ b/src/test/run-fail/overflowing-rsh-1.rs
@@ -11,9 +11,8 @@
 // error-pattern:thread '<main>' panicked at 'shift operation overflowed'
 // compile-flags: -C debug-assertions
 
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
 
 fn main() {
-    let _x = -1_i32 >> id(32);
+    let _x = -1_i32 >> 32;
 }
diff --git a/src/test/run-fail/overflowing-rsh-2.rs b/src/test/run-fail/overflowing-rsh-2.rs
index f619ebe9fb4..40b468a6ad4 100644
--- a/src/test/run-fail/overflowing-rsh-2.rs
+++ b/src/test/run-fail/overflowing-rsh-2.rs
@@ -11,9 +11,8 @@
 // error-pattern:thread '<main>' panicked at 'shift operation overflowed'
 // compile-flags: -C debug-assertions
 
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
 
 fn main() {
-    let _x = -1_i32 >> id(-1);
+    let _x = -1_i32 >> -1;
 }
diff --git a/src/test/run-fail/overflowing-rsh-3.rs b/src/test/run-fail/overflowing-rsh-3.rs
index c261e195fd7..afe6a908cb5 100644
--- a/src/test/run-fail/overflowing-rsh-3.rs
+++ b/src/test/run-fail/overflowing-rsh-3.rs
@@ -11,9 +11,8 @@
 // error-pattern:thread '<main>' panicked at 'shift operation overflowed'
 // compile-flags: -C debug-assertions
 
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
 
 fn main() {
-    let _x = -1_i64 >> id(64);
+    let _x = -1_i64 >> 64;
 }
diff --git a/src/test/run-fail/overflowing-rsh-4.rs b/src/test/run-fail/overflowing-rsh-4.rs
index 6e79a13d4e1..585186575f6 100644
--- a/src/test/run-fail/overflowing-rsh-4.rs
+++ b/src/test/run-fail/overflowing-rsh-4.rs
@@ -14,12 +14,11 @@
 // This function is checking that our (type-based) automatic
 // truncation does not sidestep the overflow checking.
 
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
 
 fn main() {
     // this signals overflow when checking is on
-    let x = 2_i8 >> id(17);
+    let x = 2_i8 >> 17;
 
     // ... but when checking is off, the fallback will truncate the
     // input to its lower three bits (= 1). Note that this is *not*
diff --git a/src/test/run-fail/overflowing-sub.rs b/src/test/run-fail/overflowing-sub.rs
index b089dccbaa5..ece4d37c36e 100644
--- a/src/test/run-fail/overflowing-sub.rs
+++ b/src/test/run-fail/overflowing-sub.rs
@@ -11,9 +11,6 @@
 // error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
 // compile-flags: -C debug-assertions
 
-// (Work around constant-evaluation)
-fn value() -> u8 { 42 }
-
 fn main() {
-    let _x = value() - (value() + 1);
+    let _x = 42u8 - (42u8 + 1);
 }
diff --git a/src/test/run-pass/wrapping-int-api.rs b/src/test/run-pass/wrapping-int-api.rs
index 48eea120623..5470ad93e14 100644
--- a/src/test/run-pass/wrapping-int-api.rs
+++ b/src/test/run-pass/wrapping-int-api.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(num_wrapping)]
-
 // Test inherent wrapping_* methods for {i,u}{size,8,16,32,64}.
 
 use std::{i8, i16, i32, i64, isize};