rustc: reuse const vals, translate fn paths as consts. Close #2530.

This commit is contained in:
Graydon Hoare 2012-11-06 17:13:52 -08:00
parent b0ed151539
commit 92e3a8c17e
6 changed files with 65 additions and 46 deletions

View File

@ -96,18 +96,16 @@ struct Guard<T, U:Copy> {
mod test {
fn sadness_key(_x: @Handler<int,int>) { }
fn trouble(i: int) {
// Condition should work as a const, just limitations in consts.
let sadness_condition : Condition<int,int> =
const sadness_condition : Condition<int,int> =
Condition { key: sadness_key };
fn trouble(i: int) {
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;

View File

@ -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");
}
}
}

View File

@ -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),

View File

@ -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,

View File

@ -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
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))])
}
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), _
}, _) => {
// 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)
trans_const(cx, subexpr, def_id.node);
}
_ => cx.sess.span_bug(e.span, ~"expected item")
}
}
_ => cx.sess.span_bug(e.span, ~"expected to find a const def")
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);
}

View 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;
}