Skip to content

Commit 68c15be

Browse files
committed
Auto merge of #30084 - oli-obk:const_fn, r=pnkfelix
2 parents ac0e845 + 8e64e22 commit 68c15be

File tree

5 files changed

+56
-29
lines changed

5 files changed

+56
-29
lines changed

src/librustc/middle/const_eval.rs

+51-27
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ pub enum ErrKind {
403403
InvalidOpForUintInt(hir::BinOp_),
404404
NegateOn(ConstVal),
405405
NotOn(ConstVal),
406+
CallOn(ConstVal),
406407

407408
NegateWithOverflow(i64),
408409
AddiWithOverflow(i64, i64),
@@ -419,6 +420,7 @@ pub enum ErrKind {
419420
ShiftRightWithOverflow,
420421
MissingStructField,
421422
NonConstPath,
423+
UnimplementedConstVal(&'static str),
422424
UnresolvedPath,
423425
ExpectedConstTuple,
424426
ExpectedConstStruct,
@@ -449,6 +451,7 @@ impl ConstEvalErr {
449451
InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
450452
NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(),
451453
NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(),
454+
CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(),
452455

453456
NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
454457
AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
@@ -465,6 +468,8 @@ impl ConstEvalErr {
465468
ShiftRightWithOverflow => "attempted right shift with overflow".into_cow(),
466469
MissingStructField => "nonexistent struct field".into_cow(),
467470
NonConstPath => "non-constant path in constant expression".into_cow(),
471+
UnimplementedConstVal(what) =>
472+
format!("unimplemented constant expression: {}", what).into_cow(),
468473
UnresolvedPath => "unresolved path in constant expression".into_cow(),
469474
ExpectedConstTuple => "expected constant tuple".into_cow(),
470475
ExpectedConstStruct => "expected constant struct".into_cow(),
@@ -1043,8 +1048,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10431048
(None, None)
10441049
}
10451050
},
1046-
Some(def::DefFn(id, _)) => return Ok(Function(id)),
1047-
// FIXME: implement const methods?
1051+
Some(def::DefMethod(id)) | Some(def::DefFn(id, _)) => return Ok(Function(id)),
10481052
_ => (None, None)
10491053
};
10501054
let const_expr = match const_expr {
@@ -1070,31 +1074,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
10701074
} else {
10711075
UncheckedExprNoHint // we cannot reason about UncheckedExprHint here
10721076
};
1073-
let (
1074-
decl,
1075-
block,
1076-
constness,
1077-
) = match try!(eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)) {
1078-
Function(did) => if did.is_local() {
1079-
match tcx.map.find(did.index.as_u32()) {
1080-
Some(ast_map::NodeItem(it)) => match it.node {
1081-
hir::ItemFn(
1082-
ref decl,
1083-
hir::Unsafety::Normal,
1084-
constness,
1085-
abi::Abi::Rust,
1086-
_, // ducktype generics? types are funky in const_eval
1087-
ref block,
1088-
) => (decl, block, constness),
1089-
_ => signal!(e, NonConstPath),
1090-
},
1091-
_ => signal!(e, NonConstPath),
1092-
}
1093-
} else {
1094-
signal!(e, NonConstPath)
1095-
},
1096-
_ => signal!(e, NonConstPath),
1097-
};
1077+
let callee_val = try!(eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args));
1078+
let (decl, block, constness) = try!(get_fn_def(tcx, e, callee_val));
10981079
match (ty_hint, constness) {
10991080
(ExprTypeChecked, _) => {
11001081
// no need to check for constness... either check_const
@@ -1441,3 +1422,46 @@ pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
14411422
};
14421423
compare_const_vals(&a, &b)
14431424
}
1425+
1426+
1427+
// returns Err if callee is not `Function`
1428+
// `e` is only used for error reporting/spans
1429+
fn get_fn_def<'a>(tcx: &'a ty::ctxt,
1430+
e: &hir::Expr,
1431+
callee: ConstVal)
1432+
-> Result<(&'a hir::FnDecl, &'a hir::Block, hir::Constness), ConstEvalErr> {
1433+
let did = match callee {
1434+
Function(did) => did,
1435+
callee => signal!(e, CallOn(callee)),
1436+
};
1437+
debug!("fn call: {:?}", tcx.map.get_if_local(did));
1438+
match tcx.map.get_if_local(did) {
1439+
None => signal!(e, UnimplementedConstVal("calling non-local const fn")), // non-local
1440+
Some(ast_map::NodeItem(it)) => match it.node {
1441+
hir::ItemFn(
1442+
ref decl,
1443+
hir::Unsafety::Normal,
1444+
constness,
1445+
abi::Abi::Rust,
1446+
_, // ducktype generics? types are funky in const_eval
1447+
ref block,
1448+
) => Ok((&**decl, &**block, constness)),
1449+
_ => signal!(e, NonConstPath),
1450+
},
1451+
Some(ast_map::NodeImplItem(it)) => match it.node {
1452+
hir::ImplItemKind::Method(
1453+
hir::MethodSig {
1454+
ref decl,
1455+
unsafety: hir::Unsafety::Normal,
1456+
constness,
1457+
abi: abi::Abi::Rust,
1458+
.. // ducktype generics? types are funky in const_eval
1459+
},
1460+
ref block,
1461+
) => Ok((decl, block, constness)),
1462+
_ => signal!(e, NonConstPath),
1463+
},
1464+
Some(ast_map::NodeTraitItem(..)) => signal!(e, NonConstPath),
1465+
Some(_) => unimplemented!(),
1466+
}
1467+
}

src/test/compile-fail/const-eval-span.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
struct S(i32);
1515

1616
const CONSTANT: S = S(0);
17-
//~^ ERROR: constant evaluation error: non-constant path in constant expression [E0080]
17+
//~^ ERROR: constant evaluation error: call on struct [E0080]
1818

1919
enum E {
2020
V = CONSTANT,

src/test/compile-fail/const-fn-stability-calls-2.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ extern crate const_fn_lib;
1717
use const_fn_lib::foo;
1818

1919
fn main() {
20-
let x: [usize; foo()] = []; //~ ERROR non-constant path in constant expr
20+
let x: [usize; foo()] = [];
21+
//~^ ERROR unimplemented constant expression: calling non-local const fn [E0250]
2122
}

src/test/run-pass/const-fn-method.rs

+1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ const FOO: Foo = Foo::new();
2222

2323
pub fn main() {
2424
assert_eq!(FOO.value, 22);
25+
let _: [&'static str; Foo::new().value as usize] = ["hey"; 22];
2526
}

src/test/run-pass/const-fn.rs

+1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ fn main() {
2929

3030
assert_eq!(DIFF, 22);
3131

32+
let _: [&'static str; sub(100, 99) as usize] = ["hi"];
3233
}

0 commit comments

Comments
 (0)