about summary refs log tree commit diff
path: root/src/comp/middle
diff options
context:
space:
mode:
authorKevin Atkinson <kevina@cs.utah.edu>2012-01-10 14:50:40 -0700
committerGraydon Hoare <graydon@mozilla.com>2012-01-10 15:59:57 -0800
commit08abf8d37fa549ebc67f80d80530f4aa43d716e4 (patch)
treef6c9bce62c494a37d989d07be4661f57c0c7eba3 /src/comp/middle
parentd0fe6723fc2f431205092bda9ec399d932081bd0 (diff)
downloadrust-08abf8d37fa549ebc67f80d80530f4aa43d716e4.tar.gz
rust-08abf8d37fa549ebc67f80d80530f4aa43d716e4.zip
Support explicit discriminant numbers on tag variants.
Addresses issue #1393.

For now disallow disr. values unless all variants use nullary
contractors (i.e. "enum-like").

Disr. values are now encoded in the crate metadata, but only when it
will differ from the inferred value based on the order.
Diffstat (limited to 'src/comp/middle')
-rw-r--r--src/comp/middle/trans.rs28
-rw-r--r--src/comp/middle/trans_alt.rs8
-rw-r--r--src/comp/middle/ty.rs7
3 files changed, 18 insertions, 25 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 6534c7d9b62..998c944b6e0 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -1726,17 +1726,15 @@ fn iter_structural_ty(cx: @block_ctxt, av: ValueRef, t: ty::t,
         Unreachable(unr_cx);
         let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb, n_variants);
         let next_cx = new_sub_block_ctxt(cx, "tag-iter-next");
-        let i = 0u;
         for variant: ty::variant_info in *variants {
             let variant_cx =
                 new_sub_block_ctxt(cx,
                                    "tag-iter-variant-" +
-                                       uint::to_str(i, 10u));
-            AddCase(llswitch, C_int(ccx, i as int), variant_cx.llbb);
+                                       int::to_str(variant.disr_val, 10u));
+            AddCase(llswitch, C_int(ccx, variant.disr_val), variant_cx.llbb);
             variant_cx =
                 iter_variant(variant_cx, llunion_a_ptr, variant, tps, tid, f);
             Br(variant_cx, next_cx.llbb);
-            i += 1u;
         }
         ret next_cx;
       }
@@ -2745,12 +2743,9 @@ fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id)
             let bcx = alloc_result.bcx;
             let lltagptr = PointerCast(bcx, lltagblob, T_ptr(lltagty));
             let lldiscrimptr = GEPi(bcx, lltagptr, [0, 0]);
-            let d = if vec::len(*ty::tag_variants(ccx.tcx, tid)) != 1u {
-                let lldiscrim_gv = lookup_discriminant(bcx.fcx.lcx, vid);
-                let lldiscrim = Load(bcx, lldiscrim_gv);
-                lldiscrim
-            } else { C_int(ccx, 0) };
-            Store(bcx, d, lldiscrimptr);
+            let lldiscrim_gv = lookup_discriminant(bcx.fcx.lcx, vid);
+            let lldiscrim = Load(bcx, lldiscrim_gv);
+            Store(bcx, lldiscrim, lldiscrimptr);
             ret lval_no_env(bcx, lltagptr, temporary);
         }
       }
@@ -4685,7 +4680,7 @@ fn trans_res_ctor(cx: @local_ctxt, sp: span, dtor: ast::fn_decl,
 
 
 fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
-                     variant: ast::variant, index: int, is_degen: bool,
+                     variant: ast::variant, is_degen: bool,
                      ty_params: [ast::ty_param]) {
     let ccx = cx.ccx;
 
@@ -4735,7 +4730,7 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
             let lltagptr =
                 PointerCast(bcx, fcx.llretptr, T_opaque_tag_ptr(ccx));
             let lldiscrimptr = GEPi(bcx, lltagptr, [0, 0]);
-            Store(bcx, C_int(ccx, index), lldiscrimptr);
+            Store(bcx, C_int(ccx, variant.node.disr_val), lldiscrimptr);
             GEPi(bcx, lltagptr, [0, 1])
         };
     i = 0u;
@@ -5086,10 +5081,8 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
       ast::item_tag(variants, tps) {
         let sub_cx = extend_path(cx, item.ident);
         let degen = vec::len(variants) == 1u;
-        let i = 0;
         for variant: ast::variant in variants {
-            trans_tag_variant(sub_cx, item.id, variant, i, degen, tps);
-            i += 1;
+            trans_tag_variant(sub_cx, item.id, variant, degen, tps);
         }
       }
       ast::item_const(_, expr) { trans_const(cx.ccx, expr, item.id); }
@@ -5421,19 +5414,18 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str],
     visit::visit_item(it, new_pt, v);
     alt it.node {
       ast::item_tag(variants, _) {
-        let i = 0u;
         for variant in variants {
             let p = new_pt + [variant.node.name, "discrim"];
             let s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
+            let disr_val = variant.node.disr_val;
             let discrim_gvar = str::as_buf(s, {|buf|
                 llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
             });
-            llvm::LLVMSetInitializer(discrim_gvar, C_int(ccx, i as int));
+            llvm::LLVMSetInitializer(discrim_gvar, C_int(ccx, disr_val));
             llvm::LLVMSetGlobalConstant(discrim_gvar, True);
             ccx.discrims.insert(
                 ast_util::local_def(variant.node.id), discrim_gvar);
             ccx.discrim_symbols.insert(variant.node.id, s);
-            i += 1u;
         }
       }
       ast::item_impl(tps, some(@{node: ast::ty_path(_, id), _}), _, ms) {
diff --git a/src/comp/middle/trans_alt.rs b/src/comp/middle/trans_alt.rs
index 6e00521ef3b..a7eb94b9288 100644
--- a/src/comp/middle/trans_alt.rs
+++ b/src/comp/middle/trans_alt.rs
@@ -16,7 +16,7 @@ import trans_common::*;
 // An option identifying a branch (either a literal, a tag variant or a range)
 tag opt {
     lit(@ast::expr);
-    var(/* variant id */uint, /* variant dids */{tg: def_id, var: def_id});
+    var(/* disr val */int, /* variant dids */{tg: def_id, var: def_id});
     range(@ast::expr, @ast::expr);
 }
 fn opt_eq(a: opt, b: opt) -> bool {
@@ -53,7 +53,7 @@ fn trans_opt(bcx: @block_ctxt, o: opt) -> opt_result {
           }
         }
       }
-      var(id, _) { ret single_result(rslt(bcx, C_int(ccx, id as int))); }
+      var(disr_val, _) { ret single_result(rslt(bcx, C_int(ccx, disr_val))); }
       range(l1, l2) {
         ret range_result(rslt(bcx, trans::trans_const_expr(ccx, l1)),
                          rslt(bcx, trans::trans_const_expr(ccx, l2)));
@@ -64,10 +64,8 @@ fn trans_opt(bcx: @block_ctxt, o: opt) -> opt_result {
 fn variant_opt(ccx: @crate_ctxt, pat_id: ast::node_id) -> opt {
     let vdef = ast_util::variant_def_ids(ccx.tcx.def_map.get(pat_id));
     let variants = ty::tag_variants(ccx.tcx, vdef.tg);
-    let i = 0u;
     for v: ty::variant_info in *variants {
-        if vdef.var == v.id { ret var(i, vdef); }
-        i += 1u;
+        if vdef.var == v.id { ret var(v.disr_val, vdef); }
     }
     fail;
 }
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 76a9b4c69c7..dbd688de402 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -2686,7 +2686,8 @@ fn impl_iface(cx: ctxt, id: ast::def_id) -> option::t<t> {
 }
 
 // Tag information
-type variant_info = @{args: [ty::t], ctor_ty: ty::t, id: ast::def_id};
+type variant_info = @{args: [ty::t], ctor_ty: ty::t, id: ast::def_id,
+                      disr_val: int};
 
 fn tag_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] {
     alt cx.tag_var_cache.find(id) {
@@ -2705,7 +2706,9 @@ fn tag_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] {
                 } else { [] };
                 @{args: arg_tys,
                   ctor_ty: ctor_ty,
-                  id: ast_util::local_def(variant.node.id)}
+                  id: ast_util::local_def(variant.node.id),
+                  disr_val: variant.node.disr_val
+                 }
             })
           }
         }