From b4e30bd2a3946c1f0a24ef52a130e0b8fddc00a8 Mon Sep 17 00:00:00 2001
From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 14 Oct 2015 12:30:10 +0200
Subject: [PATCH 1/3] allow constant evaluation of function calls

---
 src/librustc/middle/check_const.rs            |   2 +-
 src/librustc/middle/check_match.rs            |   2 +-
 src/librustc/middle/const_eval.rs             | 104 +++++++++++++++---
 src/librustc/middle/ty/util.rs                |   2 +-
 src/librustc_lint/types.rs                    |   3 +-
 src/librustc_mir/tcx/pattern.rs               |   3 +-
 src/librustc_trans/trans/consts.rs            |   3 +-
 src/librustc_typeck/astconv.rs                |   2 +-
 src/librustc_typeck/collect.rs                |   2 +-
 src/test/compile-fail/const-eval-span.rs      |   2 +-
 .../const-fn-destructuring-arg.rs             |  18 +++
 .../const-fn-stability-calls-2.rs             |   2 +-
 src/test/run-pass/const-fn-const-eval.rs      |  19 ++++
 src/test/run-pass/shift-near-oflo.rs          |  43 ++++----
 14 files changed, 155 insertions(+), 52 deletions(-)
 create mode 100644 src/test/compile-fail/const-fn-destructuring-arg.rs
 create mode 100644 src/test/run-pass/const-fn-const-eval.rs

diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 433d2468a0973..263c9bd15774d 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -473,7 +473,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                     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, ExprTypeChecked) {
+                                    self.tcx, ex, ExprTypeChecked, None) {
                                 Ok(_) => {}
                                 Err(msg) => {
                                     self.tcx.sess.add_lint(::lint::builtin::CONST_ERR, ex.id,
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 4d7dd60a27156..0ba2ee5c69489 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -272,7 +272,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat)
 fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
     front_util::walk_pat(pat, |p| {
         if let hir::PatLit(ref expr) = p.node {
-            match eval_const_expr_partial(cx.tcx, &**expr, ExprTypeChecked) {
+            match eval_const_expr_partial(cx.tcx, &**expr, ExprTypeChecked, None) {
                 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 3c68fb62e2445..2066c821749c7 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -19,13 +19,14 @@ use front::map::blocks::FnLikeNode;
 use metadata::csearch;
 use metadata::inline::InlinedItem;
 use middle::{astencode, def, infer, subst, traits};
-use middle::def_id::{DefId};
+use middle::def_id::DefId;
 use middle::pat_util::def_to_path;
 use middle::ty::{self, Ty};
 use middle::astconv_util::ast_ty_to_prim_ty;
 use util::num::ToPrimitive;
+use util::nodemap::NodeMap;
 
-use syntax::ast;
+use syntax::{ast, abi};
 use rustc_front::hir::Expr;
 use rustc_front::hir;
 use rustc_front::visit::FnKind;
@@ -253,6 +254,7 @@ pub enum ConstVal {
     Bool(bool),
     Struct(ast::NodeId),
     Tuple(ast::NodeId),
+    Function(DefId),
 }
 
 /// Note that equality for `ConstVal` means that the it is the same
@@ -271,6 +273,7 @@ impl PartialEq for ConstVal {
             (&Bool(a), &Bool(b)) => a == b,
             (&Struct(a), &Struct(b)) => a == b,
             (&Tuple(a), &Tuple(b)) => a == b,
+            (&Function(a), &Function(b)) => a == b,
             _ => false,
         }
     }
@@ -288,6 +291,7 @@ impl ConstVal {
             Bool(_) => "boolean",
             Struct(_) => "struct",
             Tuple(_) => "tuple",
+            Function(_) => "function definition",
         }
     }
 }
@@ -350,12 +354,13 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<hir::Pat>
 }
 
 pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> ConstVal {
-    match eval_const_expr_partial(tcx, e, ExprTypeChecked) {
+    match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
         Ok(r) => r,
         Err(s) => tcx.sess.span_fatal(s.span, &s.description())
     }
 }
 
+pub type FnArgMap<'a> = Option<&'a NodeMap<ConstVal>>;
 
 #[derive(Clone)]
 pub struct ConstEvalErr {
@@ -739,7 +744,8 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
 /// 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: EvalHint<'tcx>) -> EvalResult {
+                                     ty_hint: EvalHint<'tcx>,
+                                     fn_args: FnArgMap) -> EvalResult {
     fn fromb(b: bool) -> ConstVal { Int(b as i64) }
 
     // Try to compute the type of the expression based on the EvalHint.
@@ -776,7 +782,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
 
     let result = match e.node {
       hir::ExprUnary(hir::UnNeg, ref inner) => {
-        match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) {
+        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) => {
@@ -786,7 +792,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
         }
       }
       hir::ExprUnary(hir::UnNot, ref inner) => {
-        match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) {
+        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),
           Bool(b) => Bool(!b),
@@ -804,8 +810,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
             }
             _ => ty_hint
         };
-        match (try!(eval_const_expr_partial(tcx, &**a, ty_hint)),
-               try!(eval_const_expr_partial(tcx, &**b, b_ty))) {
+        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)) => {
             match op.node {
               hir::BiAdd => Float(a + b),
@@ -912,7 +918,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
             }
         };
 
-        let val = try!(eval_const_expr_partial(tcx, &**base, base_hint));
+        let val = try!(eval_const_expr_partial(tcx, &**base, base_hint, fn_args));
         match cast_const(tcx, val, ety) {
             Ok(val) => val,
             Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
@@ -990,6 +996,16 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
               Some(def::DefStruct(_)) => {
                   return Ok(ConstVal::Struct(e.id))
               }
+              Some(def::DefLocal(_, id)) => {
+                  debug!("DefLocal({:?}): {:?}", id, fn_args);
+                  if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
+                      return Ok(val.clone());
+                  } else {
+                      (None, None)
+                  }
+              },
+              Some(def::DefFn(id, _)) => return Ok(Function(id)),
+              // FIXME: implement const methods?
               _ => (None, None)
           };
           let const_expr = match const_expr {
@@ -1007,14 +1023,68 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
           } else {
               ty_hint
           };
-          try!(eval_const_expr_partial(tcx, const_expr, item_hint))
+          try!(eval_const_expr_partial(tcx, const_expr, item_hint, fn_args))
       }
+      hir::ExprCall(ref callee, ref args) => {
+          let sub_ty_hint = if let ExprTypeChecked = ty_hint {
+              ExprTypeChecked
+          } else {
+              UncheckedExprNoHint // we cannot reason about UncheckedExprHint here
+          };
+          let (
+            decl,
+            unsafety,
+            abi,
+            block,
+          ) = match try!(eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)) {
+              Function(did) => if did.is_local() {
+                  match tcx.map.find(did.index.as_u32()) {
+                      Some(ast_map::NodeItem(it)) => match it.node {
+                          hir::ItemFn(
+                              ref decl,
+                              unsafety,
+                              _, // no need to check for constness... either check_const
+                                 // already forbids this or we const eval over whatever
+                                 // we want
+                              abi,
+                              _, // ducktype generics? types are funky in const_eval
+                              ref block,
+                          ) => (decl, unsafety, abi, block),
+                          _ => signal!(e, NonConstPath),
+                      },
+                      _ => signal!(e, NonConstPath),
+                  }
+              } else {
+                  signal!(e, NonConstPath)
+              },
+              _ => signal!(e, NonConstPath),
+          };
+          assert_eq!(decl.inputs.len(), args.len());
+          assert_eq!(unsafety, hir::Unsafety::Normal);
+          assert_eq!(abi, abi::Abi::Rust);
+
+          let mut call_args = NodeMap();
+          for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) {
+              let arg_val = try!(eval_const_expr_partial(
+                  tcx,
+                  arg_expr,
+                  sub_ty_hint,
+                  fn_args
+              ));
+              debug!("const call arg: {:?}", arg);
+              let old = call_args.insert(arg.pat.id, arg_val);
+              assert!(old.is_none());
+          }
+          let result = block.expr.as_ref().unwrap();
+          debug!("const call({:?})", call_args);
+          try!(eval_const_expr_partial(tcx, &**result, ty_hint, Some(&call_args)))
+      },
       hir::ExprLit(ref lit) => {
           lit_to_const(&**lit, ety)
       }
       hir::ExprBlock(ref block) => {
         match block.expr {
-            Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint)),
+            Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint, fn_args)),
             None => Int(0)
         }
       }
@@ -1026,11 +1096,11 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
         } else {
             UncheckedExprNoHint
         };
-        if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) {
+        if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint, fn_args) {
             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)
+                        return eval_const_expr_partial(tcx, &fields[index.node], base_hint, fn_args)
                     } else {
                         signal!(e, TupleIndexOutOfBounds);
                     }
@@ -1051,14 +1121,14 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
         } else {
             UncheckedExprNoHint
         };
-        if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) {
+        if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint, fn_args) {
             if let Struct(struct_id) = c {
                 if let hir::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
                     // Check that the given field exists and evaluate it
                     // 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)
+                        return eval_const_expr_partial(tcx, &*f.expr, base_hint, fn_args)
                     } else {
                         signal!(e, MissingStructField);
                     }
@@ -1237,14 +1307,14 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
 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) {
+    let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) {
         Ok(a) => a,
         Err(e) => {
             tcx.sess.span_err(a.span, &e.description());
             return None;
         }
     };
-    let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked) {
+    let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) {
         Ok(b) => b,
         Err(e) => {
             tcx.sess.span_err(b.span, &e.description());
diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs
index a8f7a4db1338d..2142755d4a59e 100644
--- a/src/librustc/middle/ty/util.rs
+++ b/src/librustc/middle/ty/util.rs
@@ -335,7 +335,7 @@ impl<'tcx> ty::ctxt<'tcx> {
     /// Returns the repeat count for a repeating vector expression.
     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) {
+        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,
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index c95d8b7bf3e88..264228a7052a6 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -120,7 +120,7 @@ impl LateLintPass for TypeLimits {
                             if let ast::LitInt(shift, _) = lit.node { shift >= bits }
                             else { false }
                         } else {
-                            match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked) {
+                            match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
                                 Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
                                 Ok(ConstVal::Uint(shift)) => { shift >= bits },
                                 _ => { false }
@@ -674,4 +674,3 @@ impl LateLintPass for ImproperCTypes {
         }
     }
 }
-
diff --git a/src/librustc_mir/tcx/pattern.rs b/src/librustc_mir/tcx/pattern.rs
index 87ca87a103e19..e69f563edbac3 100644
--- a/src/librustc_mir/tcx/pattern.rs
+++ b/src/librustc_mir/tcx/pattern.rs
@@ -166,7 +166,8 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> {
                                 let opt_value =
                                     const_eval::eval_const_expr_partial(
                                         cx.tcx, const_expr,
-                                        const_eval::EvalHint::ExprTypeChecked);
+                                        const_eval::EvalHint::ExprTypeChecked,
+                                        None);
                                 let literal = if let Ok(value) = opt_value {
                                     Literal::Value { value: value }
                                 } else {
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 5986236c27f0e..90faef51c2c6c 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -664,10 +664,9 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             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) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst));
-            let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked) {
+            let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked, None) {
                 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 299b6be9951fc..425b04f822673 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1674,7 +1674,7 @@ 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) {
+            match const_eval::eval_const_expr_partial(tcx, &e, hint, None) {
                 Ok(r) => {
                     match r {
                         ConstVal::Int(i) =>
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 194710a46fbce..ca2bc59e8f4d8 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1148,7 +1148,7 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>,
         debug!("disr expr, checking {}", pprust::expr_to_string(e));
 
         let hint = UncheckedExprHint(repr_ty);
-        match const_eval::eval_const_expr_partial(tcx, e, 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(_) => {
diff --git a/src/test/compile-fail/const-eval-span.rs b/src/test/compile-fail/const-eval-span.rs
index 8e9209916f35b..3e75afcda6d71 100644
--- a/src/test/compile-fail/const-eval-span.rs
+++ b/src/test/compile-fail/const-eval-span.rs
@@ -14,7 +14,7 @@
 struct S(i32);
 
 const CONSTANT: S = S(0);
-//~^ ERROR: constant evaluation error: unsupported constant expr
+//~^ ERROR: constant evaluation error: non-constant path in constant expression [E0080]
 
 enum E {
     V = CONSTANT,
diff --git a/src/test/compile-fail/const-fn-destructuring-arg.rs b/src/test/compile-fail/const-fn-destructuring-arg.rs
new file mode 100644
index 0000000000000..1642c04106723
--- /dev/null
+++ b/src/test/compile-fail/const-fn-destructuring-arg.rs
@@ -0,0 +1,18 @@
+// 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 certain things are disallowed in const fn signatures
+
+#![feature(const_fn)]
+
+// no destructuring
+const fn i((a, b): (u32, u32)) -> u32 { a + b } //~ ERROR: E0022
+
+fn main() {}
diff --git a/src/test/compile-fail/const-fn-stability-calls-2.rs b/src/test/compile-fail/const-fn-stability-calls-2.rs
index dd9a415311e53..59e0db7b35508 100644
--- a/src/test/compile-fail/const-fn-stability-calls-2.rs
+++ b/src/test/compile-fail/const-fn-stability-calls-2.rs
@@ -17,5 +17,5 @@ extern crate const_fn_lib;
 use const_fn_lib::foo;
 
 fn main() {
-    let x: [usize; foo()] = []; //~ ERROR unsupported constant expr
+    let x: [usize; foo()] = []; //~ ERROR non-constant path in constant expr
 }
diff --git a/src/test/run-pass/const-fn-const-eval.rs b/src/test/run-pass/const-fn-const-eval.rs
new file mode 100644
index 0000000000000..77c70fe7f6354
--- /dev/null
+++ b/src/test/run-pass/const-fn-const-eval.rs
@@ -0,0 +1,19 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_fn)]
+
+const fn add(x: usize, y: usize) -> usize {
+    x + y
+}
+
+const ARR: [i32; add(1, 2)] = [5, 6, 7];
+
+pub fn main() {}
diff --git a/src/test/run-pass/shift-near-oflo.rs b/src/test/run-pass/shift-near-oflo.rs
index 4ff058f336661..542e8de9e53ca 100644
--- a/src/test/run-pass/shift-near-oflo.rs
+++ b/src/test/run-pass/shift-near-oflo.rs
@@ -13,9 +13,6 @@
 // Check that we do *not* overflow on a number of edge cases.
 // (compare with test/run-fail/overflowing-{lsh,rsh}*.rs)
 
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
-
 fn main() {
     test_left_shift();
     test_right_shift();
@@ -26,34 +23,34 @@ fn test_left_shift() {
 
     macro_rules! tests {
         ($iN:ty, $uN:ty, $max_rhs:expr, $expect_i:expr, $expect_u:expr) => { {
-            let x = (1 as $iN) << id(0);
+            let x = (1 as $iN) << 0;
             assert_eq!(x, 1);
-            let x = (1 as $uN) << id(0);
+            let x = (1 as $uN) << 0;
             assert_eq!(x, 1);
-            let x = (1 as $iN) << id($max_rhs);
+            let x = (1 as $iN) << $max_rhs;
             assert_eq!(x, $expect_i);
-            let x = (1 as $uN) << id($max_rhs);
+            let x = (1 as $uN) << $max_rhs;
             assert_eq!(x, $expect_u);
             // high-order bits on LHS are silently discarded without panic.
-            let x = (3 as $iN) << id($max_rhs);
+            let x = (3 as $iN) << $max_rhs;
             assert_eq!(x, $expect_i);
-            let x = (3 as $uN) << id($max_rhs);
+            let x = (3 as $uN) << $max_rhs;
             assert_eq!(x, $expect_u);
         } }
     }
 
-    let x = 1_i8 << id(0);
+    let x = 1_i8 << 0;
     assert_eq!(x, 1);
-    let x = 1_u8 << id(0);
+    let x = 1_u8 << 0;
     assert_eq!(x, 1);
-    let x = 1_i8 << id(7);
+    let x = 1_i8 << 7;
     assert_eq!(x, std::i8::MIN);
-    let x = 1_u8 << id(7);
+    let x = 1_u8 << 7;
     assert_eq!(x, 0x80);
     // high-order bits on LHS are silently discarded without panic.
-    let x = 3_i8 << id(7);
+    let x = 3_i8 << 7;
     assert_eq!(x, std::i8::MIN);
-    let x = 3_u8 << id(7);
+    let x = 3_u8 << 7;
     assert_eq!(x, 0x80);
 
     // above is (approximately) expanded from:
@@ -71,23 +68,23 @@ fn test_right_shift() {
         ($iN:ty, $uN:ty, $max_rhs:expr,
          $signbit_i:expr, $highbit_i:expr, $highbit_u:expr) =>
         { {
-            let x = (1 as $iN) >> id(0);
+            let x = (1 as $iN) >> 0;
             assert_eq!(x, 1);
-            let x = (1 as $uN) >> id(0);
+            let x = (1 as $uN) >> 0;
             assert_eq!(x, 1);
-            let x = ($highbit_i) >> id($max_rhs-1);
+            let x = ($highbit_i) >> $max_rhs-1;
             assert_eq!(x, 1);
-            let x = ($highbit_u) >> id($max_rhs);
+            let x = ($highbit_u) >> $max_rhs;
             assert_eq!(x, 1);
             // sign-bit is carried by arithmetic right shift
-            let x = ($signbit_i) >> id($max_rhs);
+            let x = ($signbit_i) >> $max_rhs;
             assert_eq!(x, -1);
             // low-order bits on LHS are silently discarded without panic.
-            let x = ($highbit_i + 1) >> id($max_rhs-1);
+            let x = ($highbit_i + 1) >> $max_rhs-1;
             assert_eq!(x, 1);
-            let x = ($highbit_u + 1) >> id($max_rhs);
+            let x = ($highbit_u + 1) >> $max_rhs;
             assert_eq!(x, 1);
-            let x = ($signbit_i + 1) >> id($max_rhs);
+            let x = ($signbit_i + 1) >> $max_rhs;
             assert_eq!(x, -1);
         } }
     }

From 72f42f1174e80fe627c4a49524107f15e134ddca Mon Sep 17 00:00:00 2001
From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 14 Oct 2015 12:30:33 +0200
Subject: [PATCH 2/3] copy paste error of stable attribute

---
 src/librustc/middle/const_eval.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 2066c821749c7..00b4e34c18fa5 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -262,7 +262,6 @@ pub enum ConstVal {
 /// == NaN` (at least if it's the same NaN; distinct encodings for NaN
 /// are considering unequal).
 impl PartialEq for ConstVal {
-    #[stable(feature = "rust1", since = "1.0.0")]
     fn eq(&self, other: &ConstVal) -> bool {
         match (self, other) {
             (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},

From 2b000feba57a324534008356909e02394784cfcc Mon Sep 17 00:00:00 2001
From: Oliver Schneider <git1984941651981@oli-obk.de>
Date: Tue, 27 Oct 2015 09:39:07 +0100
Subject: [PATCH 3/3] the const evaluator might run before check_const

So we cannot assume that the function call was marked NOT_CONST by check_const.
---
 src/librustc/middle/const_eval.rs | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 00b4e34c18fa5..1651e71c49a2a 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -1031,10 +1031,11 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
               UncheckedExprNoHint // we cannot reason about UncheckedExprHint here
           };
           let (
-            decl,
-            unsafety,
-            abi,
-            block,
+              decl,
+              unsafety,
+              abi,
+              block,
+              constness,
           ) = match try!(eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)) {
               Function(did) => if did.is_local() {
                   match tcx.map.find(did.index.as_u32()) {
@@ -1042,13 +1043,11 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
                           hir::ItemFn(
                               ref decl,
                               unsafety,
-                              _, // no need to check for constness... either check_const
-                                 // already forbids this or we const eval over whatever
-                                 // we want
+                              constness,
                               abi,
                               _, // ducktype generics? types are funky in const_eval
                               ref block,
-                          ) => (decl, unsafety, abi, block),
+                          ) => (decl, unsafety, abi, block, constness),
                           _ => signal!(e, NonConstPath),
                       },
                       _ => signal!(e, NonConstPath),
@@ -1058,6 +1057,15 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
               },
               _ => signal!(e, NonConstPath),
           };
+          if let ExprTypeChecked = ty_hint {
+              // no need to check for constness... either check_const
+              // already forbids this or we const eval over whatever
+              // we want
+          } else {
+              // we don't know much about the function, so we force it to be a const fn
+              // so compilation will fail later in case the const fn's body is not const
+              assert_eq!(constness, hir::Constness::Const)
+          }
           assert_eq!(decl.inputs.len(), args.len());
           assert_eq!(unsafety, hir::Unsafety::Normal);
           assert_eq!(abi, abi::Abi::Rust);