about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-07-22 12:49:06 +0000
committerbors <bors@rust-lang.org>2015-07-22 12:49:06 +0000
commitd4d4206e5604b86fc4a9b28a8b51d99121cc3a5d (patch)
tree2b46c7caa8b19a1e5c6393c8648f11644260f246
parent25281b121ff809f35a6abd7d2d115995436c3319 (diff)
parent6bdfb0534737b371e3b3e4abdec2f5dffd629916 (diff)
downloadrust-d4d4206e5604b86fc4a9b28a8b51d99121cc3a5d.tar.gz
rust-d4d4206e5604b86fc4a9b28a8b51d99121cc3a5d.zip
Auto merge of #26683 - eefriedman:const-eval-hint, r=pnkfelix
The "hint" mechanism is essentially used as a workaround to compute
types for expressions which have not yet been type-checked. This
commit clarifies that usage, and limits the effects to the places
where it is currently necessary.

Fixes #26210.
-rw-r--r--src/librustc/diagnostics.rs18
-rw-r--r--src/librustc/middle/check_const.rs18
-rw-r--r--src/librustc/middle/check_match.rs3
-rw-r--r--src/librustc/middle/const_eval.rs171
-rw-r--r--src/librustc/middle/ty.rs20
-rw-r--r--src/librustc_lint/builtin.rs3
-rw-r--r--src/librustc_trans/trans/_match.rs3
-rw-r--r--src/librustc_trans/trans/consts.rs4
-rw-r--r--src/librustc_typeck/astconv.rs4
-rw-r--r--src/librustc_typeck/check/_match.rs15
-rw-r--r--src/librustc_typeck/diagnostics.rs18
-rw-r--r--src/test/compile-fail/lint-exceeding-bitshifts.rs6
-rw-r--r--src/test/compile-fail/match-range-fail-2.rs23
-rw-r--r--src/test/compile-fail/match-range-fail.rs6
14 files changed, 194 insertions, 118 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 4b77c211df9..4e21efcf9eb 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -335,6 +335,24 @@ This error indicates that an attempt was made to divide by zero (or take the
 remainder of a zero divisor) in a static or constant expression.
 "##,
 
+E0030: r##"
+When matching against a range, the compiler verifies that the range is
+non-empty.  Range patterns include both end-points, so this is equivalent to
+requiring the start of the range to be less than or equal to the end of the
+range.
+
+For example:
+
+```
+match 5u32 {
+    // This range is ok, albeit pointless.
+    1 ... 1 => ...
+    // This range is empty, and the compiler can tell.
+    1000 ... 5 => ...
+}
+```
+"##,
+
 E0079: r##"
 Enum variants which contain no data can be given a custom integer
 representation. This error indicates that the value provided is not an
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 59f91a50f74..baaf6b6a040 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -26,6 +26,7 @@
 
 use middle::cast::{CastKind};
 use middle::const_eval;
+use middle::const_eval::EvalHint::ExprTypeChecked;
 use middle::def;
 use middle::expr_use_visitor as euv;
 use middle::infer;
@@ -39,6 +40,7 @@ use syntax::codemap::Span;
 use syntax::visit::{self, Visitor};
 
 use std::collections::hash_map::Entry;
+use std::cmp::Ordering;
 
 // Const qualification, from partial to completely promotable.
 bitflags! {
@@ -365,6 +367,19 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
             ast::PatRange(ref start, ref end) => {
                 self.global_expr(Mode::Const, &**start);
                 self.global_expr(Mode::Const, &**end);
+
+                match const_eval::compare_lit_exprs(self.tcx, start, end) {
+                    Some(Ordering::Less) |
+                    Some(Ordering::Equal) => {}
+                    Some(Ordering::Greater) => {
+                        span_err!(self.tcx.sess, start.span, E0030,
+                            "lower range bound must be less than or equal to upper");
+                    }
+                    None => {
+                        self.tcx.sess.span_bug(
+                            start.span, "literals of different types in range pat");
+                    }
+                }
             }
             _ => visit::walk_pat(self, p)
         }
@@ -457,7 +472,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                 match node_ty.sty {
                     ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
                         if !self.qualif.intersects(ConstQualif::NOT_CONST) {
-                            match const_eval::eval_const_expr_partial(self.tcx, ex, None) {
+                            match const_eval::eval_const_expr_partial(
+                                    self.tcx, ex, ExprTypeChecked) {
                                 Ok(_) => {}
                                 Err(msg) => {
                                     span_err!(self.tcx.sess, msg.span, E0020,
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index fc2444ed5b4..d8c2341df2d 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -15,6 +15,7 @@ use self::WitnessPreference::*;
 use middle::const_eval::{compare_const_vals, ConstVal};
 use middle::const_eval::{eval_const_expr, eval_const_expr_partial};
 use middle::const_eval::{const_expr_to_pat, lookup_const_by_id};
+use middle::const_eval::EvalHint::ExprTypeChecked;
 use middle::def::*;
 use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init};
 use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode};
@@ -263,7 +264,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat)
 fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
     ast_util::walk_pat(pat, |p| {
         if let ast::PatLit(ref expr) = p.node {
-            match eval_const_expr_partial(cx.tcx, &**expr, None) {
+            match eval_const_expr_partial(cx.tcx, &**expr, ExprTypeChecked) {
                 Ok(ConstVal::Float(f)) if f.is_nan() => {
                     span_warn!(cx.tcx.sess, p.span, E0003,
                                "unmatchable NaN in pattern, \
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 58053fbb189..9e2bcbaec8a 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -11,8 +11,8 @@
 #![allow(non_camel_case_types)]
 
 use self::ConstVal::*;
-
 use self::ErrKind::*;
+use self::EvalHint::*;
 
 use ast_map;
 use ast_map::blocks::FnLikeNode;
@@ -345,7 +345,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat>
 }
 
 pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> ConstVal {
-    match eval_const_expr_partial(tcx, e, None) {
+    match eval_const_expr_partial(tcx, e, ExprTypeChecked) {
         Ok(r) => r,
         Err(s) => tcx.sess.span_fatal(s.span, &s.description())
     }
@@ -434,6 +434,28 @@ impl ConstEvalErr {
 pub type EvalResult = Result<ConstVal, ConstEvalErr>;
 pub type CastResult = Result<ConstVal, ErrKind>;
 
+// FIXME: Long-term, this enum should go away: trying to evaluate
+// an expression which hasn't been type-checked is a recipe for
+// disaster.  That said, it's not clear how to fix ast_ty_to_ty
+// to avoid the ordering issue.
+
+/// Hint to determine how to evaluate constant expressions which
+/// might not be type-checked.
+#[derive(Copy, Clone, Debug)]
+pub enum EvalHint<'tcx> {
+    /// We have a type-checked expression.
+    ExprTypeChecked,
+    /// We have an expression which hasn't been type-checked, but we have
+    /// an idea of what the type will be because of the context. For example,
+    /// the length of an array is always `usize`. (This is referred to as
+    /// a hint because it isn't guaranteed to be consistent with what
+    /// type-checking would compute.)
+    UncheckedExprHint(Ty<'tcx>),
+    /// We have an expression which has not yet been type-checked, and
+    /// and we have no clue what the type will be.
+    UncheckedExprNoHint,
+}
+
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum IntTy { I8, I16, I32, I64 }
 #[derive(Copy, Clone, PartialEq, Debug)]
@@ -704,26 +726,34 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
            uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
 }}
 
-// After type checking, `eval_const_expr_partial` should always suffice. The
-// reason for providing `eval_const_expr_with_substs` is to allow
-// trait-associated consts to be evaluated *during* type checking, when the
-// substs for each expression have not been written into `tcx` yet.
+/// 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
+/// computing the length of an array. (See also the FIXME above EvalHint.)
 pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
                                      e: &Expr,
-                                     ty_hint: Option<Ty<'tcx>>) -> EvalResult {
-    eval_const_expr_with_substs(tcx, e, ty_hint, |id| {
-        tcx.node_id_item_substs(id).substs
-    })
-}
-
-pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
-                                            e: &Expr,
-                                            ty_hint: Option<Ty<'tcx>>,
-                                            get_substs: S) -> EvalResult
-        where S: Fn(ast::NodeId) -> subst::Substs<'tcx> {
+                                     ty_hint: EvalHint<'tcx>) -> EvalResult {
     fn fromb(b: bool) -> ConstVal { Int(b as i64) }
 
-    let ety = ty_hint.or_else(|| tcx.expr_ty_opt(e));
+    // Try to compute the type of the expression based on the EvalHint.
+    // (See also the definition of EvalHint, and the FIXME above EvalHint.)
+    let ety = match ty_hint {
+        ExprTypeChecked => {
+            // After type-checking, expr_ty is guaranteed to succeed.
+            Some(tcx.expr_ty(e))
+        }
+        UncheckedExprHint(ty) => {
+            // Use the type hint; it's not guaranteed to be right, but it's
+            // usually good enough.
+            Some(ty)
+        }
+        UncheckedExprNoHint => {
+            // This expression might not be type-checked, and we have no hint.
+            // Try to query the context for a type anyway; we might get lucky
+            // (for example, if the expression was imported from another crate).
+            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
@@ -739,7 +769,7 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
 
     let result = match e.node {
       ast::ExprUnary(ast::UnNeg, ref inner) => {
-        match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
+        match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) {
           Float(f) => Float(-f),
           Int(n) =>  try!(const_int_checked_neg(n, e, expr_int_type)),
           Uint(i) => {
@@ -749,7 +779,7 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
         }
       }
       ast::ExprUnary(ast::UnNot, ref inner) => {
-        match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
+        match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) {
           Int(i) => Int(!i),
           Uint(i) => const_uint_not(i, expr_uint_type),
           Bool(b) => Bool(!b),
@@ -758,10 +788,16 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
       }
       ast::ExprBinary(op, ref a, ref b) => {
         let b_ty = match op.node {
-            ast::BiShl | ast::BiShr => Some(tcx.types.usize),
-            _ => ety
+            ast::BiShl | ast::BiShr => {
+                if let ExprTypeChecked = ty_hint {
+                    ExprTypeChecked
+                } else {
+                    UncheckedExprHint(tcx.types.usize)
+                }
+            }
+            _ => ty_hint
         };
-        match (try!(eval_const_expr_partial(tcx, &**a, ety)),
+        match (try!(eval_const_expr_partial(tcx, &**a, ty_hint)),
                try!(eval_const_expr_partial(tcx, &**b, b_ty))) {
           (Float(a), Float(b)) => {
             match op.node {
@@ -851,22 +887,25 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
         }
       }
       ast::ExprCast(ref base, ref target_ty) => {
-        // This tends to get called w/o the type actually having been
-        // populated in the ctxt, which was causing things to blow up
-        // (#5900). Fall back to doing a limited lookup to get past it.
         let ety = ety.or_else(|| ast_ty_to_prim_ty(tcx, &**target_ty))
                 .unwrap_or_else(|| {
                     tcx.sess.span_fatal(target_ty.span,
                                         "target type not found for const cast")
                 });
 
-        // Prefer known type to noop, but always have a type hint.
-        //
-        // 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.
-        let base_hint = tcx.expr_ty_opt(&**base).unwrap_or(ety);
-        let val = try!(eval_const_expr_partial(tcx, &**base, Some(base_hint)));
+        let base_hint = if let ExprTypeChecked = ty_hint {
+            ExprTypeChecked
+        } else {
+            // FIXME (#23833): the type-hint can cause problems,
+            // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
+            // type to the sum, and thus no overflow is signaled.
+            match tcx.expr_ty_opt(&base) {
+                Some(t) => UncheckedExprHint(t),
+                None => ty_hint
+            }
+        };
+
+        let val = try!(eval_const_expr_partial(tcx, &**base, base_hint));
         match cast_const(tcx, val, ety) {
             Ok(val) => val,
             Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
@@ -896,12 +935,16 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
                           def::FromTrait(trait_id) => match tcx.map.find(def_id.node) {
                               Some(ast_map::NodeTraitItem(ti)) => match ti.node {
                                   ast::ConstTraitItem(ref ty, _) => {
-                                      let substs = get_substs(e.id);
-                                      (resolve_trait_associated_const(tcx,
-                                                                      ti,
-                                                                      trait_id,
-                                                                      substs),
-                                       Some(&**ty))
+                                      if let ExprTypeChecked = ty_hint {
+                                          let substs = tcx.node_id_item_substs(e.id).substs;
+                                          (resolve_trait_associated_const(tcx,
+                                                                          ti,
+                                                                          trait_id,
+                                                                          substs),
+                                           Some(&**ty))
+                                       } else {
+                                           (None, None)
+                                       }
                                   }
                                   _ => (None, None)
                               },
@@ -930,27 +973,42 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
               Some(actual_e) => actual_e,
               None => signal!(e, NonConstPath)
           };
-          let ety = ety.or_else(|| const_ty.and_then(|ty| ast_ty_to_prim_ty(tcx, ty)));
-          try!(eval_const_expr_partial(tcx, const_expr, ety))
+          let item_hint = if let UncheckedExprNoHint = ty_hint {
+              match const_ty {
+                  Some(ty) => match ast_ty_to_prim_ty(tcx, ty) {
+                      Some(ty) => UncheckedExprHint(ty),
+                      None => UncheckedExprNoHint
+                  },
+                  None => UncheckedExprNoHint
+              }
+          } else {
+              ty_hint
+          };
+          try!(eval_const_expr_partial(tcx, const_expr, item_hint))
       }
       ast::ExprLit(ref lit) => {
           lit_to_const(&**lit, ety)
       }
-      ast::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ety)),
+      ast::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ty_hint)),
       ast::ExprBlock(ref block) => {
         match block.expr {
-            Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ety)),
+            Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint)),
             None => Int(0)
         }
       }
       ast::ExprTup(_) => Tuple(e.id),
       ast::ExprStruct(..) => Struct(e.id),
       ast::ExprTupField(ref base, index) => {
-        if let Ok(c) = eval_const_expr_partial(tcx, base, None) {
+        let base_hint = if let ExprTypeChecked = ty_hint {
+            ExprTypeChecked
+        } else {
+            UncheckedExprNoHint
+        };
+        if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) {
             if let Tuple(tup_id) = c {
                 if let ast::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
                     if index.node < fields.len() {
-                        return eval_const_expr_partial(tcx, &fields[index.node], None)
+                        return eval_const_expr_partial(tcx, &fields[index.node], base_hint)
                     } else {
                         signal!(e, TupleIndexOutOfBounds);
                     }
@@ -966,13 +1024,18 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
       }
       ast::ExprField(ref base, field_name) => {
         // Get the base expression if it is a struct and it is constant
-        if let Ok(c) = eval_const_expr_partial(tcx, base, None) {
+        let base_hint = if let ExprTypeChecked = ty_hint {
+            ExprTypeChecked
+        } else {
+            UncheckedExprNoHint
+        };
+        if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) {
             if let Struct(struct_id) = c {
                 if let ast::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
                     // Check that the given field exists and evaluate it
                     if let Some(f) = fields.iter().find(|f| f.ident.node.as_str()
                                                          == field_name.node.as_str()) {
-                        return eval_const_expr_partial(tcx, &*f.expr, None)
+                        return eval_const_expr_partial(tcx, &*f.expr, base_hint)
                     } else {
                         signal!(e, MissingStructField);
                     }
@@ -1148,21 +1211,17 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
     })
 }
 
-pub fn compare_lit_exprs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
-                                  a: &Expr,
-                                  b: &Expr,
-                                  ty_hint: Option<Ty<'tcx>>,
-                                  get_substs: S) -> Option<Ordering>
-        where S: Fn(ast::NodeId) -> subst::Substs<'tcx> {
-    let a = match eval_const_expr_with_substs(tcx, a, ty_hint,
-                                              |id| {get_substs(id)}) {
+pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
+                               a: &Expr,
+                               b: &Expr) -> Option<Ordering> {
+    let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked) {
         Ok(a) => a,
         Err(e) => {
             tcx.sess.span_err(a.span, &e.description());
             return None;
         }
     };
-    let b = match eval_const_expr_with_substs(tcx, b, ty_hint, get_substs) {
+    let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked) {
         Ok(b) => b,
         Err(e) => {
             tcx.sess.span_err(b.span, &e.description());
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 7d79cc4df3d..17a76f6eed9 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -45,6 +45,7 @@ use middle;
 use middle::cast;
 use middle::check_const;
 use middle::const_eval::{self, ConstVal};
+use middle::const_eval::EvalHint::UncheckedExprHint;
 use middle::def::{self, DefMap, ExportMap};
 use middle::dependency_format;
 use middle::fast_reject;
@@ -5758,20 +5759,8 @@ impl<'tcx> ctxt<'tcx> {
                 Some(ref e) => {
                     debug!("disr expr, checking {}", pprust::expr_to_string(&**e));
 
-                    // check_expr (from check_const pass) doesn't guarantee
-                    // that the expression is in a form that eval_const_expr can
-                    // handle, so we may still get an internal compiler error
-                    //
-                    // pnkfelix: The above comment was transcribed from
-                    // the version of this code taken from rustc_typeck.
-                    // Presumably the implication is that we need to deal
-                    // with such ICE's as they arise.
-                    //
-                    // Since this can be called from `ty::enum_variants`
-                    // anyway, best thing is to make `eval_const_expr`
-                    // more robust (on case-by-case basis).
-
-                    match const_eval::eval_const_expr_partial(self, &**e, Some(repr_type_ty)) {
+                    let hint = UncheckedExprHint(repr_type_ty);
+                    match const_eval::eval_const_expr_partial(self, &**e, hint) {
                         Ok(ConstVal::Int(val)) => current_disr_val = val as Disr,
                         Ok(ConstVal::Uint(val)) => current_disr_val = val as Disr,
                         Ok(_) => {
@@ -6086,7 +6075,8 @@ impl<'tcx> ctxt<'tcx> {
 
     // Returns the repeat count for a repeating vector expression.
     pub fn eval_repeat_count(&self, count_expr: &ast::Expr) -> usize {
-        match const_eval::eval_const_expr_partial(self, count_expr, Some(self.types.usize)) {
+        let hint = UncheckedExprHint(self.types.usize);
+        match const_eval::eval_const_expr_partial(self, count_expr, hint) {
             Ok(val) => {
                 let found = match val {
                     ConstVal::Uint(count) => return count as usize,
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 1f4014bc692..ae95466e6e6 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -39,6 +39,7 @@ use middle::ty::{self, Ty};
 use middle::traits;
 use middle::{def, pat_util, stability};
 use middle::const_eval::{eval_const_expr_partial, ConstVal};
+use middle::const_eval::EvalHint::ExprTypeChecked;
 use middle::cfg;
 use rustc::ast_map;
 use util::nodemap::{FnvHashMap, NodeSet};
@@ -178,7 +179,7 @@ impl LintPass for TypeLimits {
                             if let ast::LitInt(shift, _) = lit.node { shift >= bits }
                             else { false }
                         } else {
-                            match eval_const_expr_partial(cx.tcx, &**r, Some(cx.tcx.types.usize)) {
+                            match eval_const_expr_partial(cx.tcx, &**r, ExprTypeChecked) {
                                 Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
                                 Ok(ConstVal::Uint(shift)) => { shift >= bits },
                                 _ => { false }
diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs
index 9a9b9c617a8..925da81d77e 100644
--- a/src/librustc_trans/trans/_match.rs
+++ b/src/librustc_trans/trans/_match.rs
@@ -235,8 +235,7 @@ struct ConstantExpr<'a>(&'a ast::Expr);
 
 impl<'a> ConstantExpr<'a> {
     fn eq(self, other: ConstantExpr<'a>, tcx: &ty::ctxt) -> bool {
-        match const_eval::compare_lit_exprs(tcx, self.0, other.0, None,
-                                            |id| {tcx.node_id_item_substs(id).substs}) {
+        match const_eval::compare_lit_exprs(tcx, self.0, other.0) {
             Some(result) => result == Ordering::Equal,
             None => panic!("compare_list_exprs: type mismatch"),
         }
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 242eceb8335..302ef68bddc 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -23,6 +23,8 @@ 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::EvalHint::ExprTypeChecked;
+use middle::const_eval::eval_const_expr_partial;
 use trans::{adt, closure, debuginfo, expr, inline, machine};
 use trans::base::{self, push_ctxt};
 use trans::common::*;
@@ -591,7 +593,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
         ast::ExprIndex(ref base, ref index) => {
             let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
-            let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) {
+            let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked) {
                 Ok(ConstVal::Int(i)) => i as u64,
                 Ok(ConstVal::Uint(u)) => u,
                 _ => cx.sess().span_bug(index.span,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 07af1aa64ae..8f0eef8ba0b 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -50,6 +50,7 @@
 
 use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS};
 use middle::const_eval::{self, ConstVal};
+use middle::const_eval::EvalHint::UncheckedExprHint;
 use middle::def;
 use middle::implicator::object_region_bounds;
 use middle::resolve_lifetime as rl;
@@ -1623,7 +1624,8 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
             ty
         }
         ast::TyFixedLengthVec(ref ty, ref e) => {
-            match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.usize)) {
+            let hint = UncheckedExprHint(tcx.types.usize);
+            match const_eval::eval_const_expr_partial(tcx, &e, hint) {
                 Ok(r) => {
                     match r {
                         ConstVal::Int(i) =>
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index a995401cf5c..c4b31d578db 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::const_eval;
 use middle::def;
 use middle::infer;
 use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
@@ -23,7 +22,7 @@ use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_typ
 use require_same_types;
 use util::nodemap::FnvHashMap;
 
-use std::cmp::{self, Ordering};
+use std::cmp;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use syntax::ast;
 use syntax::ast_util;
@@ -130,18 +129,6 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
 
             fcx.write_ty(pat.id, common_type);
 
-            // Finally we evaluate the constants and check that the range is non-empty.
-            let get_substs = |id| fcx.item_substs()[&id].substs.clone();
-            match const_eval::compare_lit_exprs(tcx, begin, end, Some(&common_type), get_substs) {
-                Some(Ordering::Less) |
-                Some(Ordering::Equal) => {}
-                Some(Ordering::Greater) => {
-                    span_err!(tcx.sess, begin.span, E0030,
-                        "lower range bound must be less than or equal to upper");
-                }
-                None => tcx.sess.span_bug(begin.span, "literals of different types in range pat")
-            }
-
             // subtyping doesn't matter here, as the value is some kind of scalar
             demand::eqtype(fcx, pat.span, expected, lhs_ty);
         }
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index a002ed311e8..f22da25c010 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -169,24 +169,6 @@ match string {
 ```
 "##,
 
-E0030: r##"
-When matching against a range, the compiler verifies that the range is
-non-empty.  Range patterns include both end-points, so this is equivalent to
-requiring the start of the range to be less than or equal to the end of the
-range.
-
-For example:
-
-```
-match 5u32 {
-    // This range is ok, albeit pointless.
-    1 ... 1 => ...
-    // This range is empty, and the compiler can tell.
-    1000 ... 5 => ...
-}
-```
-"##,
-
 E0033: r##"
 This error indicates that a pointer to a trait type cannot be implicitly
 dereferenced by a pattern. Every trait defines a type, but because the
diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs
index 5867bc2f09d..160551b81cb 100644
--- a/src/test/compile-fail/lint-exceeding-bitshifts.rs
+++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs
@@ -8,11 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(negate_unsigned)]
 #![deny(exceeding_bitshifts)]
 #![allow(unused_variables)]
 #![allow(dead_code)]
-#![feature(num_bits_bytes, negate_unsigned)]
+#![feature(num_bits_bytes)]
 
 fn main() {
       let n = 1u8 << 7;
@@ -60,4 +59,7 @@ fn main() {
 
       let n = 1_isize << std::isize::BITS; //~ ERROR: bitshift exceeds the type's number of bits
       let n = 1_usize << std::usize::BITS; //~ ERROR: bitshift exceeds the type's number of bits
+
+
+      let n = 1i8<<(1isize+-1);
 }
diff --git a/src/test/compile-fail/match-range-fail-2.rs b/src/test/compile-fail/match-range-fail-2.rs
new file mode 100644
index 00000000000..e30f783ce36
--- /dev/null
+++ b/src/test/compile-fail/match-range-fail-2.rs
@@ -0,0 +1,23 @@
+// 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.
+
+fn main() {
+    match 5 {
+        6 ... 1 => { }
+        _ => { }
+    };
+    //~^^^ ERROR lower range bound must be less than or equal to upper
+
+    match 5u64 {
+        0xFFFF_FFFF_FFFF_FFFF ... 1 => { }
+        _ => { }
+    };
+    //~^^^ ERROR lower range bound must be less than or equal to upper
+}
diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs
index 234b74f76d1..05b870b8f41 100644
--- a/src/test/compile-fail/match-range-fail.rs
+++ b/src/test/compile-fail/match-range-fail.rs
@@ -9,12 +9,6 @@
 // except according to those terms.
 
 fn main() {
-    match 5 {
-        6 ... 1 => { }
-        _ => { }
-    };
-    //~^^^ ERROR lower range bound must be less than or equal to upper
-
     match "wow" {
         "bar" ... "foo" => { }
     };