rustc: reuse const vals, translate fn paths as consts. Close #2530.
This commit is contained in:
parent
b0ed151539
commit
92e3a8c17e
@ -96,18 +96,16 @@ struct Guard<T, U:Copy> {
|
||||
mod test {
|
||||
|
||||
fn sadness_key(_x: @Handler<int,int>) { }
|
||||
const sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
fn trouble(i: int) {
|
||||
// Condition should work as a const, just limitations in consts.
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
debug!("trouble: raising conition");
|
||||
let j = sadness_condition.raise(&i);
|
||||
debug!("trouble: handler recovered with %d", j);
|
||||
}
|
||||
|
||||
fn nested_trap_test_inner() {
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut inner_trapped = false;
|
||||
|
||||
@ -126,9 +124,6 @@ fn nested_trap_test_inner() {
|
||||
#[test]
|
||||
fn nested_trap_test_outer() {
|
||||
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut outer_trapped = false;
|
||||
|
||||
do sadness_condition.trap(|_j| {
|
||||
@ -144,8 +139,6 @@ fn nested_trap_test_outer() {
|
||||
}
|
||||
|
||||
fn nested_reraise_trap_test_inner() {
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut inner_trapped = false;
|
||||
|
||||
@ -166,9 +159,6 @@ fn nested_reraise_trap_test_inner() {
|
||||
#[test]
|
||||
fn nested_reraise_trap_test_outer() {
|
||||
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut outer_trapped = false;
|
||||
|
||||
do sadness_condition.trap(|_j| {
|
||||
@ -184,8 +174,6 @@ fn nested_reraise_trap_test_outer() {
|
||||
|
||||
#[test]
|
||||
fn test_default() {
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut trapped = false;
|
||||
|
||||
|
@ -82,19 +82,30 @@ fn check_expr(sess: Session, def_map: resolve::DefMap,
|
||||
~"` in a constant expression");
|
||||
}
|
||||
}
|
||||
expr_path(_) => {
|
||||
expr_path(pth) => {
|
||||
// NB: In the future you might wish to relax this slightly
|
||||
// to handle on-demand instantiation of functions via
|
||||
// foo::<bar> in a const. Currently that is only done on
|
||||
// a path in trans::callee that only works in block contexts.
|
||||
if pth.types.len() != 0 {
|
||||
sess.span_err(
|
||||
e.span, ~"paths in constants may only refer to \
|
||||
items without type parameters");
|
||||
}
|
||||
match def_map.find(e.id) {
|
||||
Some(def_const(def_id)) => {
|
||||
Some(def_const(def_id)) |
|
||||
Some(def_fn(def_id, _)) => {
|
||||
if !ast_util::is_local(def_id) {
|
||||
sess.span_err(
|
||||
e.span, ~"paths in constants may only refer to \
|
||||
crate-local constants");
|
||||
crate-local constants or functions");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
sess.span_err(
|
||||
e.span,
|
||||
~"paths in constants may only refer to constants");
|
||||
~"paths in constants may only refer to \
|
||||
constants or functions");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2688,6 +2688,7 @@ fn trans_crate(sess: session::Session,
|
||||
vtables: map::HashMap(),
|
||||
const_cstr_cache: HashMap(),
|
||||
const_globals: HashMap(),
|
||||
const_values: HashMap(),
|
||||
module_data: HashMap(),
|
||||
lltypes: ty::new_ty_hash(),
|
||||
names: new_namegen(sess.parse_sess.interner),
|
||||
|
@ -140,10 +140,19 @@ fn BuilderRef_res(B: BuilderRef) -> BuilderRef_res {
|
||||
vtables: HashMap<mono_id, ValueRef>,
|
||||
// Cache of constant strings,
|
||||
const_cstr_cache: HashMap<~str, ValueRef>,
|
||||
// Reverse-direction for const ptrs cast from globals,
|
||||
// since the ptr -> init association is lost any
|
||||
// time a GlobalValue is cast.
|
||||
|
||||
// Reverse-direction for const ptrs cast from globals.
|
||||
// Key is an int, cast from a ValueRef holding a *T,
|
||||
// Val is a ValueRef holding a *[T].
|
||||
//
|
||||
// Needed because LLVM loses pointer->pointee association
|
||||
// when we ptrcast, and we have to ptrcast during translation
|
||||
// of a [T] const because we form a slice, a [*T,int] pair, not
|
||||
// a pointer to an LLVM array type.
|
||||
const_globals: HashMap<int, ValueRef>,
|
||||
|
||||
// Cache of emitted const values
|
||||
const_values: HashMap<ast::node_id, ValueRef>,
|
||||
module_data: HashMap<~str, ValueRef>,
|
||||
lltypes: HashMap<ty::t, TypeRef>,
|
||||
names: namegen,
|
||||
|
@ -28,10 +28,6 @@ fn const_lit(cx: @crate_ctxt, e: @ast::expr, lit: ast::lit)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME (#2530): this should do some structural hash-consing to avoid
|
||||
// duplicate constants. I think. Maybe LLVM has a magical mode that does so
|
||||
// later on?
|
||||
|
||||
fn const_ptrcast(cx: @crate_ctxt, a: ValueRef, t: TypeRef) -> ValueRef {
|
||||
let b = llvm::LLVMConstPointerCast(a, T_ptr(t));
|
||||
assert cx.const_globals.insert(b as int, a);
|
||||
@ -341,24 +337,29 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
|
||||
~"bad const-slice expr")
|
||||
}
|
||||
}
|
||||
ast::expr_path(_) => {
|
||||
ast::expr_path(pth) => {
|
||||
assert pth.types.len() == 0;
|
||||
match cx.tcx.def_map.find(e.id) {
|
||||
Some(ast::def_const(def_id)) => {
|
||||
// Don't know how to handle external consts
|
||||
assert ast_util::is_local(def_id);
|
||||
match cx.tcx.items.get(def_id.node) {
|
||||
ast_map::node_item(@{
|
||||
node: ast::item_const(_, subexpr), _
|
||||
}, _) => {
|
||||
// FIXME (#2530): Instead of recursing here to regenerate
|
||||
// the values for other constants, we should just look up
|
||||
// the already-defined value.
|
||||
const_expr(cx, subexpr)
|
||||
}
|
||||
_ => cx.sess.span_bug(e.span, ~"expected item")
|
||||
}
|
||||
Some(ast::def_fn(def_id, _)) => {
|
||||
assert ast_util::is_local(def_id);
|
||||
let f = base::get_item_val(cx, def_id.node);
|
||||
C_struct(~[f, C_null(T_opaque_box_ptr(cx))])
|
||||
}
|
||||
_ => cx.sess.span_bug(e.span, ~"expected to find a const def")
|
||||
Some(ast::def_const(def_id)) => {
|
||||
assert ast_util::is_local(def_id);
|
||||
if ! cx.const_values.contains_key(def_id.node) {
|
||||
match cx.tcx.items.get(def_id.node) {
|
||||
ast_map::node_item(@{
|
||||
node: ast::item_const(_, subexpr), _
|
||||
}, _) => {
|
||||
trans_const(cx, subexpr, def_id.node);
|
||||
}
|
||||
_ => cx.sess.span_bug(e.span, ~"expected item")
|
||||
}
|
||||
}
|
||||
cx.const_values.get(def_id.node)
|
||||
}
|
||||
_ => cx.sess.span_bug(e.span, ~"expected a const or fn def")
|
||||
}
|
||||
}
|
||||
ast::expr_paren(e) => { return const_expr(cx, e); }
|
||||
@ -369,11 +370,9 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
|
||||
|
||||
fn trans_const(ccx: @crate_ctxt, e: @ast::expr, id: ast::node_id) {
|
||||
let _icx = ccx.insn_ctxt("trans_const");
|
||||
let v = const_expr(ccx, e);
|
||||
|
||||
// The scalars come back as 1st class LLVM vals
|
||||
// which we have to stick into global constants.
|
||||
let g = base::get_item_val(ccx, id);
|
||||
let v = const_expr(ccx, e);
|
||||
ccx.const_values.insert(id, v);
|
||||
llvm::LLVMSetInitializer(g, v);
|
||||
llvm::LLVMSetGlobalConstant(g, True);
|
||||
}
|
||||
|
11
src/test/run-pass/const-fn-val.rs
Normal file
11
src/test/run-pass/const-fn-val.rs
Normal file
@ -0,0 +1,11 @@
|
||||
fn foo() -> int {
|
||||
return 0xca7f000d;
|
||||
}
|
||||
|
||||
struct Bar { f: &fn() -> int }
|
||||
|
||||
const b : Bar = Bar { f: foo };
|
||||
|
||||
fn main() {
|
||||
assert (b.f)() == 0xca7f000d;
|
||||
}
|
Loading…
Reference in New Issue
Block a user