about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJed Davis <jld@panix.com>2012-12-30 20:30:23 -0800
committerJed Davis <jld@panix.com>2013-01-11 23:42:51 -0800
commitf76e28aa1c093c59671749006e1a7ae203d66b7c (patch)
treec731df0c8bba4ce50f16d412e9e9f9f67f635dbd
parent452642422dda045b89cbcb2b7d011c85c5202d5d (diff)
Allow consts' LLVM types to depend on their initializers.
Loosening the connection between the LLVM type and the Rust type
is necessary to use non-nullary enum constructors as const initializers,
because the const needs to be initialized with data of the actual type of
the variant in question, which is (generally) not the same as the u8
array in the `type_of` type.

Thus, referring to a const now requires casting the LLVM global to the
expected pointer type instead of using it as-is.
-rw-r--r--src/librustc/middle/trans/base.rs21
-rw-r--r--src/librustc/middle/trans/consts.rs7
-rw-r--r--src/librustc/middle/trans/expr.rs6
3 files changed, 22 insertions, 12 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index a02b8314ff3..a8b0da47e9a 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2308,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 {
diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs
index 421d1981c41..baa77472404 100644
--- a/src/librustc/middle/trans/consts.rs
+++ b/src/librustc/middle/trans/consts.rs
@@ -464,12 +464,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);
     }
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index a13aa73f330..6b6db717269 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -798,7 +798,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)
             };