Skip to content

Commit 5b5a0df

Browse files
committed
librustc: Implement C-like enum constants. r=tjc
1 parent f34833a commit 5b5a0df

File tree

6 files changed

+88
-24
lines changed

6 files changed

+88
-24
lines changed

src/librustc/lib/llvm.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ extern mod llvm {
312312
fn LLVMStructType(ElementTypes: *TypeRef, ElementCount: c_uint,
313313
Packed: Bool) -> TypeRef;
314314
fn LLVMCountStructElementTypes(StructTy: TypeRef) -> c_uint;
315-
fn LLVMGetStructElementTypes(StructTy: TypeRef, Dest: *TypeRef);
315+
fn LLVMGetStructElementTypes(StructTy: TypeRef, Dest: *mut TypeRef);
316316
fn LLVMIsPackedStruct(StructTy: TypeRef) -> Bool;
317317

318318
/* Operations on array, pointer, and vector types (sequence types) */
@@ -1123,10 +1123,9 @@ fn type_to_str_inner(names: type_names, outer0: ~[TypeRef], ty: TypeRef) ->
11231123
Struct => {
11241124
let mut s: ~str = ~"{";
11251125
let n_elts = llvm::LLVMCountStructElementTypes(ty) as uint;
1126-
let elts = vec::from_elem(n_elts, 0 as TypeRef);
1127-
unsafe {
1128-
llvm::LLVMGetStructElementTypes(ty, vec::raw::to_ptr(elts));
1129-
}
1126+
let mut elts = vec::from_elem(n_elts, 0 as TypeRef);
1127+
llvm::LLVMGetStructElementTypes(ty,
1128+
ptr::to_mut_unsafe_ptr(&mut elts[0]));
11301129
s += tys_str(names, outer, elts);
11311130
s += ~"}";
11321131
return s;
@@ -1179,6 +1178,18 @@ fn fn_ty_param_tys(fn_ty: TypeRef) -> ~[TypeRef] unsafe {
11791178
return args;
11801179
}
11811180

1181+
fn struct_element_types(struct_ty: TypeRef) -> ~[TypeRef] {
1182+
unsafe {
1183+
let count = llvm::LLVMCountStructElementTypes(struct_ty);
1184+
let mut buf: ~[TypeRef] =
1185+
vec::from_elem(count as uint,
1186+
cast::transmute::<uint,TypeRef>(0));
1187+
llvm::LLVMGetStructElementTypes(struct_ty,
1188+
ptr::to_mut_unsafe_ptr(&mut buf[0]));
1189+
return move buf;
1190+
}
1191+
}
1192+
11821193

11831194
/* Memory-managed interface to target data. */
11841195

src/librustc/middle/check_const.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ fn check_expr(sess: Session, def_map: resolve::DefMap,
9494
}
9595
match def_map.find(e.id) {
9696
Some(def_const(def_id)) |
97-
Some(def_fn(def_id, _)) => {
97+
Some(def_fn(def_id, _)) |
98+
Some(def_variant(_, def_id)) => {
9899
if !ast_util::is_local(def_id) {
99100
sess.span_err(
100101
e.span, ~"paths in constants may only refer to \

src/librustc/middle/trans/common.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -581,8 +581,9 @@ fn val_str(tn: type_names, v: ValueRef) -> ~str {
581581
fn struct_elt(llstructty: TypeRef, n: uint) -> TypeRef unsafe {
582582
let elt_count = llvm::LLVMCountStructElementTypes(llstructty) as uint;
583583
assert (n < elt_count);
584-
let elt_tys = vec::from_elem(elt_count, T_nil());
585-
llvm::LLVMGetStructElementTypes(llstructty, to_ptr(elt_tys));
584+
let mut elt_tys = vec::from_elem(elt_count, T_nil());
585+
llvm::LLVMGetStructElementTypes(llstructty,
586+
ptr::to_mut_unsafe_ptr(&mut elt_tys[0]));
586587
return llvm::LLVMGetElementType(elt_tys[n]);
587588
}
588589

@@ -822,11 +823,12 @@ fn T_task(targ_cfg: @session::config) -> TypeRef {
822823
fn T_tydesc_field(cx: @crate_ctxt, field: uint) -> TypeRef unsafe {
823824
// Bit of a kludge: pick the fn typeref out of the tydesc..
824825

825-
let tydesc_elts: ~[TypeRef] =
826+
let mut tydesc_elts: ~[TypeRef] =
826827
vec::from_elem::<TypeRef>(abi::n_tydesc_fields,
827828
T_nil());
828-
llvm::LLVMGetStructElementTypes(cx.tydesc_type,
829-
to_ptr::<TypeRef>(tydesc_elts));
829+
llvm::LLVMGetStructElementTypes(
830+
cx.tydesc_type,
831+
ptr::to_mut_unsafe_ptr(&mut tydesc_elts[0]));
830832
let t = llvm::LLVMGetElementType(tydesc_elts[field]);
831833
return t;
832834
}

src/librustc/middle/trans/consts.rs

+45-9
Original file line numberDiff line numberDiff line change
@@ -369,15 +369,51 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
369369
ast::expr_path(pth) => {
370370
assert pth.types.len() == 0;
371371
match cx.tcx.def_map.find(e.id) {
372-
Some(ast::def_fn(def_id, _)) => {
373-
assert ast_util::is_local(def_id);
374-
let f = base::get_item_val(cx, def_id.node);
375-
C_struct(~[f, C_null(T_opaque_box_ptr(cx))])
376-
}
377-
Some(ast::def_const(def_id)) => {
378-
get_const_val(cx, def_id)
379-
}
380-
_ => cx.sess.span_bug(e.span, ~"expected a const or fn def")
372+
Some(ast::def_fn(def_id, _)) => {
373+
assert ast_util::is_local(def_id);
374+
let f = base::get_item_val(cx, def_id.node);
375+
C_struct(~[f, C_null(T_opaque_box_ptr(cx))])
376+
}
377+
Some(ast::def_const(def_id)) => {
378+
get_const_val(cx, def_id)
379+
}
380+
Some(ast::def_variant(enum_did, variant_did)) => {
381+
// Note that we know this is a C-like (nullary) enum variant,
382+
// or we wouldn't have gotten here -- the constant checker
383+
// forbids paths that don't map to C-like enum variants.
384+
let ety = ty::expr_ty(cx.tcx, e);
385+
let llty = type_of::type_of(cx, ety);
386+
let llstructtys = lib::llvm::struct_element_types(llty);
387+
388+
// Can't use `discrims` from the crate context here because
389+
// those discriminants have an extra level of indirection,
390+
// and there's no LLVM constant load instruction.
391+
let mut lldiscrim_opt = None;
392+
for ty::enum_variants(cx.tcx, enum_did).each |variant_info| {
393+
if variant_info.id == variant_did {
394+
lldiscrim_opt = Some(C_int(cx,
395+
variant_info.disr_val));
396+
break;
397+
}
398+
}
399+
400+
let lldiscrim;
401+
match lldiscrim_opt {
402+
None => {
403+
cx.tcx.sess.span_bug(e.span,
404+
~"didn't find discriminant?!");
405+
}
406+
Some(found_lldiscrim) => {
407+
lldiscrim = found_lldiscrim;
408+
}
409+
}
410+
411+
C_named_struct(llty, ~[ lldiscrim, C_null(llstructtys[1]) ])
412+
}
413+
_ => {
414+
cx.sess.span_bug(e.span,
415+
~"expected a const, fn, or variant def")
416+
}
381417
}
382418
}
383419
ast::expr_paren(e) => { return const_expr(cx, e); }

src/librustc/middle/trans/foreign.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,9 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] {
7575

7676
fn struct_tys(ty: TypeRef) -> ~[TypeRef] {
7777
let n = llvm::LLVMCountStructElementTypes(ty);
78-
let elts = vec::from_elem(n as uint, ptr::null());
79-
do vec::as_imm_buf(elts) |buf, _len| {
80-
llvm::LLVMGetStructElementTypes(ty, buf);
81-
}
78+
let mut elts = vec::from_elem(n as uint, ptr::null());
79+
llvm::LLVMGetStructElementTypes(ty,
80+
ptr::to_mut_unsafe_ptr(&mut elts[0]));
8281
return elts;
8382
}
8483

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
enum Foo {
2+
Bar,
3+
Baz,
4+
Boo,
5+
}
6+
7+
const X: Foo = Bar;
8+
9+
fn main() {
10+
match X {
11+
Bar => {}
12+
Baz | Boo => fail
13+
}
14+
}
15+

0 commit comments

Comments
 (0)