librustc: Implement C-like enum constants. r=tjc

This commit is contained in:
Patrick Walton 2012-11-30 13:25:43 -08:00
parent f34833abfc
commit 5b5a0df7ee
6 changed files with 88 additions and 24 deletions

View File

@ -312,7 +312,7 @@ extern mod llvm {
fn LLVMStructType(ElementTypes: *TypeRef, ElementCount: c_uint,
Packed: Bool) -> TypeRef;
fn LLVMCountStructElementTypes(StructTy: TypeRef) -> c_uint;
fn LLVMGetStructElementTypes(StructTy: TypeRef, Dest: *TypeRef);
fn LLVMGetStructElementTypes(StructTy: TypeRef, Dest: *mut TypeRef);
fn LLVMIsPackedStruct(StructTy: TypeRef) -> Bool;
/* 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) ->
Struct => {
let mut s: ~str = ~"{";
let n_elts = llvm::LLVMCountStructElementTypes(ty) as uint;
let elts = vec::from_elem(n_elts, 0 as TypeRef);
unsafe {
llvm::LLVMGetStructElementTypes(ty, vec::raw::to_ptr(elts));
}
let mut elts = vec::from_elem(n_elts, 0 as TypeRef);
llvm::LLVMGetStructElementTypes(ty,
ptr::to_mut_unsafe_ptr(&mut elts[0]));
s += tys_str(names, outer, elts);
s += ~"}";
return s;
@ -1179,6 +1178,18 @@ fn fn_ty_param_tys(fn_ty: TypeRef) -> ~[TypeRef] unsafe {
return args;
}
fn struct_element_types(struct_ty: TypeRef) -> ~[TypeRef] {
unsafe {
let count = llvm::LLVMCountStructElementTypes(struct_ty);
let mut buf: ~[TypeRef] =
vec::from_elem(count as uint,
cast::transmute::<uint,TypeRef>(0));
llvm::LLVMGetStructElementTypes(struct_ty,
ptr::to_mut_unsafe_ptr(&mut buf[0]));
return move buf;
}
}
/* Memory-managed interface to target data. */

View File

@ -94,7 +94,8 @@ fn check_expr(sess: Session, def_map: resolve::DefMap,
}
match def_map.find(e.id) {
Some(def_const(def_id)) |
Some(def_fn(def_id, _)) => {
Some(def_fn(def_id, _)) |
Some(def_variant(_, def_id)) => {
if !ast_util::is_local(def_id) {
sess.span_err(
e.span, ~"paths in constants may only refer to \

View File

@ -581,8 +581,9 @@ fn val_str(tn: type_names, v: ValueRef) -> ~str {
fn struct_elt(llstructty: TypeRef, n: uint) -> TypeRef unsafe {
let elt_count = llvm::LLVMCountStructElementTypes(llstructty) as uint;
assert (n < elt_count);
let elt_tys = vec::from_elem(elt_count, T_nil());
llvm::LLVMGetStructElementTypes(llstructty, to_ptr(elt_tys));
let mut elt_tys = vec::from_elem(elt_count, T_nil());
llvm::LLVMGetStructElementTypes(llstructty,
ptr::to_mut_unsafe_ptr(&mut elt_tys[0]));
return llvm::LLVMGetElementType(elt_tys[n]);
}
@ -822,11 +823,12 @@ fn T_task(targ_cfg: @session::config) -> TypeRef {
fn T_tydesc_field(cx: @crate_ctxt, field: uint) -> TypeRef unsafe {
// Bit of a kludge: pick the fn typeref out of the tydesc..
let tydesc_elts: ~[TypeRef] =
let mut tydesc_elts: ~[TypeRef] =
vec::from_elem::<TypeRef>(abi::n_tydesc_fields,
T_nil());
llvm::LLVMGetStructElementTypes(cx.tydesc_type,
to_ptr::<TypeRef>(tydesc_elts));
llvm::LLVMGetStructElementTypes(
cx.tydesc_type,
ptr::to_mut_unsafe_ptr(&mut tydesc_elts[0]));
let t = llvm::LLVMGetElementType(tydesc_elts[field]);
return t;
}

View File

@ -369,15 +369,51 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
ast::expr_path(pth) => {
assert pth.types.len() == 0;
match cx.tcx.def_map.find(e.id) {
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)) => {
get_const_val(cx, def_id)
}
_ => cx.sess.span_bug(e.span, ~"expected a const or fn def")
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)) => {
get_const_val(cx, def_id)
}
Some(ast::def_variant(enum_did, variant_did)) => {
// Note that we know this is a C-like (nullary) enum 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);
let llstructtys = lib::llvm::struct_element_types(llty);
// 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;
}
}
C_named_struct(llty, ~[ lldiscrim, C_null(llstructtys[1]) ])
}
_ => {
cx.sess.span_bug(e.span,
~"expected a const, fn, or variant def")
}
}
}
ast::expr_paren(e) => { return const_expr(cx, e); }

View File

@ -75,10 +75,9 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] {
fn struct_tys(ty: TypeRef) -> ~[TypeRef] {
let n = llvm::LLVMCountStructElementTypes(ty);
let elts = vec::from_elem(n as uint, ptr::null());
do vec::as_imm_buf(elts) |buf, _len| {
llvm::LLVMGetStructElementTypes(ty, buf);
}
let mut elts = vec::from_elem(n as uint, ptr::null());
llvm::LLVMGetStructElementTypes(ty,
ptr::to_mut_unsafe_ptr(&mut elts[0]));
return elts;
}

View File

@ -0,0 +1,15 @@
enum Foo {
Bar,
Baz,
Boo,
}
const X: Foo = Bar;
fn main() {
match X {
Bar => {}
Baz | Boo => fail
}
}