Skip to content

Commit

Permalink
Auto merge of #30084 - oli-obk:const_fn, r=pnkfelix
Browse files Browse the repository at this point in the history
  • Loading branch information
bors committed Dec 4, 2015
2 parents ac0e845 + 8e64e22 commit 68c15be
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 29 deletions.
78 changes: 51 additions & 27 deletions src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ pub enum ErrKind {
InvalidOpForUintInt(hir::BinOp_),
NegateOn(ConstVal),
NotOn(ConstVal),
CallOn(ConstVal),

NegateWithOverflow(i64),
AddiWithOverflow(i64, i64),
Expand All @@ -419,6 +420,7 @@ pub enum ErrKind {
ShiftRightWithOverflow,
MissingStructField,
NonConstPath,
UnimplementedConstVal(&'static str),
UnresolvedPath,
ExpectedConstTuple,
ExpectedConstStruct,
Expand Down Expand Up @@ -449,6 +451,7 @@ impl ConstEvalErr {
InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(),
NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(),
CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(),

NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
Expand All @@ -465,6 +468,8 @@ impl ConstEvalErr {
ShiftRightWithOverflow => "attempted right shift with overflow".into_cow(),
MissingStructField => "nonexistent struct field".into_cow(),
NonConstPath => "non-constant path in constant expression".into_cow(),
UnimplementedConstVal(what) =>
format!("unimplemented constant expression: {}", what).into_cow(),
UnresolvedPath => "unresolved path in constant expression".into_cow(),
ExpectedConstTuple => "expected constant tuple".into_cow(),
ExpectedConstStruct => "expected constant struct".into_cow(),
Expand Down Expand Up @@ -1043,8 +1048,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
(None, None)
}
},
Some(def::DefFn(id, _)) => return Ok(Function(id)),
// FIXME: implement const methods?
Some(def::DefMethod(id)) | Some(def::DefFn(id, _)) => return Ok(Function(id)),
_ => (None, None)
};
let const_expr = match const_expr {
Expand All @@ -1070,31 +1074,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
} else {
UncheckedExprNoHint // we cannot reason about UncheckedExprHint here
};
let (
decl,
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()) {
Some(ast_map::NodeItem(it)) => match it.node {
hir::ItemFn(
ref decl,
hir::Unsafety::Normal,
constness,
abi::Abi::Rust,
_, // ducktype generics? types are funky in const_eval
ref block,
) => (decl, block, constness),
_ => signal!(e, NonConstPath),
},
_ => signal!(e, NonConstPath),
}
} else {
signal!(e, NonConstPath)
},
_ => signal!(e, NonConstPath),
};
let callee_val = try!(eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args));
let (decl, block, constness) = try!(get_fn_def(tcx, e, callee_val));
match (ty_hint, constness) {
(ExprTypeChecked, _) => {
// no need to check for constness... either check_const
Expand Down Expand Up @@ -1441,3 +1422,46 @@ pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
};
compare_const_vals(&a, &b)
}


// returns Err if callee is not `Function`
// `e` is only used for error reporting/spans
fn get_fn_def<'a>(tcx: &'a ty::ctxt,
e: &hir::Expr,
callee: ConstVal)
-> Result<(&'a hir::FnDecl, &'a hir::Block, hir::Constness), ConstEvalErr> {
let did = match callee {
Function(did) => did,
callee => signal!(e, CallOn(callee)),
};
debug!("fn call: {:?}", tcx.map.get_if_local(did));
match tcx.map.get_if_local(did) {
None => signal!(e, UnimplementedConstVal("calling non-local const fn")), // non-local
Some(ast_map::NodeItem(it)) => match it.node {
hir::ItemFn(
ref decl,
hir::Unsafety::Normal,
constness,
abi::Abi::Rust,
_, // ducktype generics? types are funky in const_eval
ref block,
) => Ok((&**decl, &**block, constness)),
_ => signal!(e, NonConstPath),
},
Some(ast_map::NodeImplItem(it)) => match it.node {
hir::ImplItemKind::Method(
hir::MethodSig {
ref decl,
unsafety: hir::Unsafety::Normal,
constness,
abi: abi::Abi::Rust,
.. // ducktype generics? types are funky in const_eval
},
ref block,
) => Ok((decl, block, constness)),
_ => signal!(e, NonConstPath),
},
Some(ast_map::NodeTraitItem(..)) => signal!(e, NonConstPath),
Some(_) => unimplemented!(),
}
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/const-eval-span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
struct S(i32);

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

enum E {
V = CONSTANT,
Expand Down
3 changes: 2 additions & 1 deletion src/test/compile-fail/const-fn-stability-calls-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ extern crate const_fn_lib;
use const_fn_lib::foo;

fn main() {
let x: [usize; foo()] = []; //~ ERROR non-constant path in constant expr
let x: [usize; foo()] = [];
//~^ ERROR unimplemented constant expression: calling non-local const fn [E0250]
}
1 change: 1 addition & 0 deletions src/test/run-pass/const-fn-method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ const FOO: Foo = Foo::new();

pub fn main() {
assert_eq!(FOO.value, 22);
let _: [&'static str; Foo::new().value as usize] = ["hey"; 22];
}
1 change: 1 addition & 0 deletions src/test/run-pass/const-fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ fn main() {

assert_eq!(DIFF, 22);

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

0 comments on commit 68c15be

Please sign in to comment.