Merge pull request #4459 from jld/constenum
Allow consts to be initialized by non-nullary enum constructors
This commit is contained in:
commit
fbc33e0247
@ -138,11 +138,12 @@ fn check_expr(sess: Session, def_map: resolve::DefMap,
|
||||
expr_call(callee, _, false) => {
|
||||
match def_map.find(callee.id) {
|
||||
Some(def_struct(*)) => {} // OK.
|
||||
Some(def_variant(*)) => {} // OK.
|
||||
_ => {
|
||||
sess.span_err(
|
||||
e.span,
|
||||
~"function calls in constants are limited to \
|
||||
structure constructors");
|
||||
struct and enum constructors");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -779,6 +779,30 @@ fn trans_external_path(ccx: @crate_ctxt, did: ast::def_id, t: ty::t)
|
||||
};
|
||||
}
|
||||
|
||||
fn get_discrim_val(cx: @crate_ctxt, span: span, enum_did: ast::def_id,
|
||||
variant_did: ast::def_id) -> ValueRef {
|
||||
// Can't use `discrims` from the crate context here because
|
||||
// those discriminants have an extra level of indirection,
|
||||
// and there's no LLVM constant load instruction.
|
||||
let mut lldiscrim_opt = None;
|
||||
for ty::enum_variants(cx.tcx, enum_did).each |variant_info| {
|
||||
if variant_info.id == variant_did {
|
||||
lldiscrim_opt = Some(C_int(cx,
|
||||
variant_info.disr_val));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
match lldiscrim_opt {
|
||||
None => {
|
||||
cx.tcx.sess.span_bug(span, ~"didn't find discriminant?!");
|
||||
}
|
||||
Some(found_lldiscrim) => {
|
||||
found_lldiscrim
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_discriminant(ccx: @crate_ctxt, vid: ast::def_id) -> ValueRef {
|
||||
unsafe {
|
||||
let _icx = ccx.insn_ctxt("lookup_discriminant");
|
||||
@ -2284,16 +2308,21 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
|
||||
let my_path = vec::append(/*bad*/copy *pth,
|
||||
~[path_name(i.ident)]);
|
||||
match i.node {
|
||||
ast::item_const(_, _) => {
|
||||
ast::item_const(_, expr) => {
|
||||
let typ = ty::node_id_to_type(ccx.tcx, i.id);
|
||||
let s = mangle_exported_name(ccx, my_path, typ);
|
||||
let g = str::as_c_str(s, |buf| {
|
||||
unsafe {
|
||||
llvm::LLVMAddGlobal(ccx.llmod, type_of(ccx, typ), buf)
|
||||
}
|
||||
});
|
||||
ccx.item_symbols.insert(i.id, s);
|
||||
g
|
||||
// We need the translated value here, because for enums the
|
||||
// LLVM type is not fully determined by the Rust type.
|
||||
let v = consts::const_expr(ccx, expr);
|
||||
ccx.const_values.insert(id, v);
|
||||
unsafe {
|
||||
let llty = llvm::LLVMTypeOf(v);
|
||||
let g = str::as_c_str(s, |buf| {
|
||||
llvm::LLVMAddGlobal(ccx.llmod, llty, buf)
|
||||
});
|
||||
ccx.item_symbols.insert(i.id, s);
|
||||
g
|
||||
}
|
||||
}
|
||||
ast::item_fn(_, purity, _, _) => {
|
||||
let llfn = if purity != ast::extern_fn {
|
||||
|
@ -414,42 +414,10 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
|
||||
// variant or we wouldn't have gotten here -- the constant
|
||||
// checker forbids paths that don't map to C-like enum
|
||||
// variants.
|
||||
let ety = ty::expr_ty(cx.tcx, e);
|
||||
let llty = type_of::type_of(cx, ety);
|
||||
|
||||
// Can't use `discrims` from the crate context here
|
||||
// because those discriminants have an extra level of
|
||||
// indirection, and there's no LLVM constant load
|
||||
// instruction.
|
||||
let mut lldiscrim_opt = None;
|
||||
for ty::enum_variants(cx.tcx, enum_did).each
|
||||
|variant_info| {
|
||||
if variant_info.id == variant_did {
|
||||
lldiscrim_opt = Some(C_int(cx,
|
||||
variant_info.disr_val));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let lldiscrim;
|
||||
match lldiscrim_opt {
|
||||
None => {
|
||||
cx.tcx.sess.span_bug(e.span,
|
||||
~"didn't find discriminant?!");
|
||||
}
|
||||
Some(found_lldiscrim) => {
|
||||
lldiscrim = found_lldiscrim;
|
||||
}
|
||||
}
|
||||
let fields = if ty::enum_is_univariant(cx.tcx, enum_did) {
|
||||
~[lldiscrim]
|
||||
} else {
|
||||
let llstructtys =
|
||||
lib::llvm::struct_element_types(llty);
|
||||
~[lldiscrim, C_null(llstructtys[1])]
|
||||
};
|
||||
|
||||
C_named_struct(llty, fields)
|
||||
let lldiscrim = base::get_discrim_val(cx, e.span,
|
||||
enum_did,
|
||||
variant_did);
|
||||
C_struct(~[lldiscrim])
|
||||
}
|
||||
Some(ast::def_struct(_)) => {
|
||||
let ety = ty::expr_ty(cx.tcx, e);
|
||||
@ -475,6 +443,24 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
|
||||
C_named_struct(llty, ~[ llstructbody ])
|
||||
}
|
||||
}
|
||||
Some(ast::def_variant(tid, vid)) => {
|
||||
let ety = ty::expr_ty(cx.tcx, e);
|
||||
let degen = ty::enum_is_univariant(cx.tcx, tid);
|
||||
let size = shape::static_size_of_enum(cx, ety);
|
||||
|
||||
let discrim = base::get_discrim_val(cx, e.span, tid, vid);
|
||||
let c_args = C_struct(args.map(|a| const_expr(cx, *a)));
|
||||
|
||||
let fields = if !degen {
|
||||
~[discrim, c_args]
|
||||
} else if size == 0 {
|
||||
~[discrim]
|
||||
} else {
|
||||
~[c_args]
|
||||
};
|
||||
|
||||
C_struct(fields)
|
||||
}
|
||||
_ => cx.sess.span_bug(e.span, ~"expected a struct def")
|
||||
}
|
||||
}
|
||||
@ -485,12 +471,13 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_const(ccx: @crate_ctxt, e: @ast::expr, id: ast::node_id) {
|
||||
fn trans_const(ccx: @crate_ctxt, _e: @ast::expr, id: ast::node_id) {
|
||||
unsafe {
|
||||
let _icx = ccx.insn_ctxt("trans_const");
|
||||
let g = base::get_item_val(ccx, id);
|
||||
let v = const_expr(ccx, e);
|
||||
ccx.const_values.insert(id, v);
|
||||
// At this point, get_item_val has already translated the
|
||||
// constant's initializer to determine its LLVM type.
|
||||
let v = ccx.const_values.get(id);
|
||||
llvm::LLVMSetInitializer(g, v);
|
||||
llvm::LLVMSetGlobalConstant(g, True);
|
||||
}
|
||||
|
@ -801,7 +801,11 @@ fn trans_def_lvalue(bcx: block,
|
||||
ast::def_const(did) => {
|
||||
let const_ty = expr_ty(bcx, ref_expr);
|
||||
let val = if did.crate == ast::local_crate {
|
||||
base::get_item_val(ccx, did.node)
|
||||
// The LLVM global has the type of its initializer,
|
||||
// which may not be equal to the enum's type for
|
||||
// non-C-like enums.
|
||||
PointerCast(bcx, base::get_item_val(ccx, did.node),
|
||||
T_ptr(type_of(bcx.ccx(), const_ty)))
|
||||
} else {
|
||||
base::trans_external_path(ccx, did, const_ty)
|
||||
};
|
||||
|
38
src/test/run-pass/const-big-enum.rs
Normal file
38
src/test/run-pass/const-big-enum.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2013 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
enum Foo {
|
||||
Bar(u32),
|
||||
Baz,
|
||||
Quux(u64, u16)
|
||||
}
|
||||
|
||||
const X: Foo = Baz;
|
||||
|
||||
fn main() {
|
||||
match X {
|
||||
Baz => {}
|
||||
_ => fail
|
||||
}
|
||||
match Y {
|
||||
Bar(s) => assert(s == 2654435769),
|
||||
_ => fail
|
||||
}
|
||||
match Z {
|
||||
Quux(d,h) => {
|
||||
assert(d == 0x123456789abcdef0);
|
||||
assert(h == 0x1234);
|
||||
}
|
||||
_ => fail
|
||||
}
|
||||
}
|
||||
|
||||
const Y: Foo = Bar(2654435769);
|
||||
const Z: Foo = Quux(0x123456789abcdef0, 0x1234);
|
25
src/test/run-pass/const-enum-byref-self.rs
Normal file
25
src/test/run-pass/const-enum-byref-self.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2013 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
enum E { V, VV(int) }
|
||||
const C: E = V;
|
||||
|
||||
impl E {
|
||||
fn method(&self) {
|
||||
match *self {
|
||||
V => {}
|
||||
VV(*) => fail
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
C.method()
|
||||
}
|
23
src/test/run-pass/const-enum-byref.rs
Normal file
23
src/test/run-pass/const-enum-byref.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2013 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
enum E { V, VV(int) }
|
||||
const C: E = V;
|
||||
|
||||
fn f(a: &E) {
|
||||
match *a {
|
||||
V => {}
|
||||
VV(*) => fail
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
f(&C)
|
||||
}
|
20
src/test/run-pass/const-newtype-enum.rs
Normal file
20
src/test/run-pass/const-newtype-enum.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2013 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
enum Foo = u32;
|
||||
|
||||
const X: Foo = Foo(17);
|
||||
|
||||
fn main() {
|
||||
assert(*X == 17);
|
||||
assert(*Y == 23);
|
||||
}
|
||||
|
||||
const Y: Foo = Foo(23);
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -21,5 +21,10 @@ fn main() {
|
||||
Bar => {}
|
||||
Baz | Boo => fail
|
||||
}
|
||||
match Y {
|
||||
Baz => {}
|
||||
Bar | Boo => fail
|
||||
}
|
||||
}
|
||||
|
||||
const Y: Foo = Baz;
|
||||
|
@ -16,4 +16,7 @@ const X: Foo = Bar;
|
||||
|
||||
fn main() {
|
||||
assert((X as uint) == 0xDEADBEE);
|
||||
assert((Y as uint) == 0xDEADBEE);
|
||||
}
|
||||
|
||||
const Y: Foo = Bar;
|
||||
|
Loading…
Reference in New Issue
Block a user