From b4e30bd2a3946c1f0a24ef52a130e0b8fddc00a8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider 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 } 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>; #[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 { pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>, a: &Expr, b: &Expr) -> Option { - 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 or the MIT license +// , 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 or the MIT license +// , 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(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 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 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);