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) => {
|
expr_call(callee, _, false) => {
|
||||||
match def_map.find(callee.id) {
|
match def_map.find(callee.id) {
|
||||||
Some(def_struct(*)) => {} // OK.
|
Some(def_struct(*)) => {} // OK.
|
||||||
|
Some(def_variant(*)) => {} // OK.
|
||||||
_ => {
|
_ => {
|
||||||
sess.span_err(
|
sess.span_err(
|
||||||
e.span,
|
e.span,
|
||||||
~"function calls in constants are limited to \
|
~"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 {
|
fn lookup_discriminant(ccx: @crate_ctxt, vid: ast::def_id) -> ValueRef {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _icx = ccx.insn_ctxt("lookup_discriminant");
|
let _icx = ccx.insn_ctxt("lookup_discriminant");
|
||||||
@ -2284,17 +2308,22 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
|
|||||||
let my_path = vec::append(/*bad*/copy *pth,
|
let my_path = vec::append(/*bad*/copy *pth,
|
||||||
~[path_name(i.ident)]);
|
~[path_name(i.ident)]);
|
||||||
match i.node {
|
match i.node {
|
||||||
ast::item_const(_, _) => {
|
ast::item_const(_, expr) => {
|
||||||
let typ = ty::node_id_to_type(ccx.tcx, i.id);
|
let typ = ty::node_id_to_type(ccx.tcx, i.id);
|
||||||
let s = mangle_exported_name(ccx, my_path, typ);
|
let s = mangle_exported_name(ccx, my_path, typ);
|
||||||
let g = str::as_c_str(s, |buf| {
|
// 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 {
|
unsafe {
|
||||||
llvm::LLVMAddGlobal(ccx.llmod, type_of(ccx, typ), buf)
|
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);
|
ccx.item_symbols.insert(i.id, s);
|
||||||
g
|
g
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ast::item_fn(_, purity, _, _) => {
|
ast::item_fn(_, purity, _, _) => {
|
||||||
let llfn = if purity != ast::extern_fn {
|
let llfn = if purity != ast::extern_fn {
|
||||||
register_fn(ccx, i.span, my_path, i.id, i.attrs)
|
register_fn(ccx, i.span, my_path, i.id, i.attrs)
|
||||||
|
@ -414,42 +414,10 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
|
|||||||
// variant or we wouldn't have gotten here -- the constant
|
// variant or we wouldn't have gotten here -- the constant
|
||||||
// checker forbids paths that don't map to C-like enum
|
// checker forbids paths that don't map to C-like enum
|
||||||
// variants.
|
// variants.
|
||||||
let ety = ty::expr_ty(cx.tcx, e);
|
let lldiscrim = base::get_discrim_val(cx, e.span,
|
||||||
let llty = type_of::type_of(cx, ety);
|
enum_did,
|
||||||
|
variant_did);
|
||||||
// Can't use `discrims` from the crate context here
|
C_struct(~[lldiscrim])
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
Some(ast::def_struct(_)) => {
|
Some(ast::def_struct(_)) => {
|
||||||
let ety = ty::expr_ty(cx.tcx, e);
|
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 ])
|
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")
|
_ => 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 {
|
unsafe {
|
||||||
let _icx = ccx.insn_ctxt("trans_const");
|
let _icx = ccx.insn_ctxt("trans_const");
|
||||||
let g = base::get_item_val(ccx, id);
|
let g = base::get_item_val(ccx, id);
|
||||||
let v = const_expr(ccx, e);
|
// At this point, get_item_val has already translated the
|
||||||
ccx.const_values.insert(id, v);
|
// constant's initializer to determine its LLVM type.
|
||||||
|
let v = ccx.const_values.get(id);
|
||||||
llvm::LLVMSetInitializer(g, v);
|
llvm::LLVMSetInitializer(g, v);
|
||||||
llvm::LLVMSetGlobalConstant(g, True);
|
llvm::LLVMSetGlobalConstant(g, True);
|
||||||
}
|
}
|
||||||
|
@ -801,7 +801,11 @@ fn trans_def_lvalue(bcx: block,
|
|||||||
ast::def_const(did) => {
|
ast::def_const(did) => {
|
||||||
let const_ty = expr_ty(bcx, ref_expr);
|
let const_ty = expr_ty(bcx, ref_expr);
|
||||||
let val = if did.crate == ast::local_crate {
|
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 {
|
} else {
|
||||||
base::trans_external_path(ccx, did, const_ty)
|
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
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
@ -21,5 +21,10 @@ fn main() {
|
|||||||
Bar => {}
|
Bar => {}
|
||||||
Baz | Boo => fail
|
Baz | Boo => fail
|
||||||
}
|
}
|
||||||
|
match Y {
|
||||||
|
Baz => {}
|
||||||
|
Bar | Boo => fail
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Y: Foo = Baz;
|
||||||
|
@ -16,4 +16,7 @@ const X: Foo = Bar;
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
assert((X as uint) == 0xDEADBEE);
|
assert((X as uint) == 0xDEADBEE);
|
||||||
|
assert((Y as uint) == 0xDEADBEE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Y: Foo = Bar;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user