From 5b5a0df7ee46f4c465eb479a4ceb4a61d621bf5d Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 30 Nov 2012 13:25:43 -0800 Subject: [PATCH] librustc: Implement C-like enum constants. r=tjc --- src/librustc/lib/llvm.rs | 21 +++++++--- src/librustc/middle/check_const.rs | 3 +- src/librustc/middle/trans/common.rs | 12 +++--- src/librustc/middle/trans/consts.rs | 54 ++++++++++++++++++++----- src/librustc/middle/trans/foreign.rs | 7 ++-- src/test/run-pass/const-nullary-enum.rs | 15 +++++++ 6 files changed, 88 insertions(+), 24 deletions(-) create mode 100644 src/test/run-pass/const-nullary-enum.rs diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index fa364700b74d..ea86db77c3f4 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -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::(0)); + llvm::LLVMGetStructElementTypes(struct_ty, + ptr::to_mut_unsafe_ptr(&mut buf[0])); + return move buf; + } +} + /* Memory-managed interface to target data. */ diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index e900b13b7c5e..2348c79ce66b 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -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 \ diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 99241efe9d10..450ab0495c69 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -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::(abi::n_tydesc_fields, T_nil()); - llvm::LLVMGetStructElementTypes(cx.tydesc_type, - to_ptr::(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; } diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index dcf5cee952f2..17282e91d160 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -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); } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 4fe7c307d597..6ff11b091463 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -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; } diff --git a/src/test/run-pass/const-nullary-enum.rs b/src/test/run-pass/const-nullary-enum.rs new file mode 100644 index 000000000000..644517deca88 --- /dev/null +++ b/src/test/run-pass/const-nullary-enum.rs @@ -0,0 +1,15 @@ +enum Foo { + Bar, + Baz, + Boo, +} + +const X: Foo = Bar; + +fn main() { + match X { + Bar => {} + Baz | Boo => fail + } +} +