about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/trans/base.rs24
-rw-r--r--src/librustc/middle/trans/consts.rs133
2 files changed, 44 insertions, 113 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index b6701c6c3df..d5656b9002b 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -828,30 +828,6 @@ pub fn trans_external_path(ccx: @CrateContext, did: ast::def_id, t: ty::t)
     };
 }
 
-pub fn get_discrim_val(cx: @CrateContext, span: span, enum_did: ast::def_id,
-                       variant_did: ast::def_id) -> ValueRef {
-    // 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;
-        }
-    }
-
-    match lldiscrim_opt {
-        None => {
-            cx.tcx.sess.span_bug(span, ~"didn't find discriminant?!");
-        }
-        Some(found_lldiscrim) => {
-            found_lldiscrim
-        }
-    }
-}
-
 pub fn invoke(bcx: block, llfn: ValueRef, +llargs: ~[ValueRef]) -> block {
     let _icx = bcx.insn_ctxt("invoke_");
     if bcx.unreachable { return bcx; }
diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs
index 6d37c4393ab..19d5bb4dbf5 100644
--- a/src/librustc/middle/trans/consts.rs
+++ b/src/librustc/middle/trans/consts.rs
@@ -12,6 +12,7 @@ use core::prelude::*;
 
 use lib::llvm::{llvm, ValueRef, TypeRef, Bool, True, False};
 use middle::const_eval;
+use middle::trans::adt;
 use middle::trans::base;
 use middle::trans::base::get_insn_ctxt;
 use middle::trans::common::*;
@@ -328,24 +329,8 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef {
               }
               (expr::cast_enum, expr::cast_integral) |
               (expr::cast_enum, expr::cast_float)  => {
-                let def = ty::resolve_expr(cx.tcx, base);
-                let (enum_did, variant_did) = match def {
-                    ast::def_variant(enum_did, variant_did) => {
-                        (enum_did, variant_did)
-                    }
-                    _ => cx.sess.bug(~"enum cast source is not enum")
-                };
-                // Note that we know this is a C-like (nullary) enum
-                // variant or we wouldn't have gotten here
-                let variants = ty::enum_variants(cx.tcx, enum_did);
-                let iv = if variants.len() == 1 {
-                    // Univariants don't have a discriminant field,
-                    // because there's only one value it could have:
-                    C_integral(T_i64(),
-                               variants[0].disr_val as u64, True)
-                } else {
-                    base::get_discrim_val(cx, e.span, enum_did, variant_did)
-                };
+                let repr = adt::represent_type(cx, basety);
+                let iv = C_int(cx, adt::const_get_discrim(cx, &repr, v));
                 let ety_cast = expr::cast_type_kind(ety);
                 match ety_cast {
                     expr::cast_integral => {
@@ -373,18 +358,22 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef {
             gv
           }
           ast::expr_tup(es) => {
-            C_struct(es.map(|e| const_expr(cx, *e)))
+              let ety = ty::expr_ty(cx.tcx, e);
+              let repr = adt::represent_type(cx, ety);
+              adt::trans_const(cx, &repr, 0, es.map(|e| const_expr(cx, *e)))
           }
           ast::expr_rec(ref fs, None) => {
-              C_struct([C_struct(
-                  (*fs).map(|f| const_expr(cx, f.node.expr)))])
+              let ety = ty::expr_ty(cx.tcx, e);
+              let repr = adt::represent_type(cx, ety);
+              adt::trans_const(cx, &repr, 0,
+                               fs.map(|f| const_expr(cx, f.node.expr)))
           }
-          ast::expr_struct(_, ref fs, _) => {
+          ast::expr_struct(_, ref fs, None) => {
               let ety = ty::expr_ty(cx.tcx, e);
-              let cs = do expr::with_field_tys(cx.tcx,
-                                               ety,
-                                               None) |_hd, field_tys| {
-                  field_tys.map(|field_ty| {
+              let repr = adt::represent_type(cx, ety);
+              do expr::with_field_tys(cx.tcx, ety, Some(e.id))
+                  |discr, field_tys| {
+                  let cs = field_tys.map(|field_ty| {
                       match fs.find(|f| field_ty.ident == f.node.ident) {
                           Some(ref f) => const_expr(cx, (*f).node.expr),
                           None => {
@@ -392,9 +381,9 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef {
                                   e.span, ~"missing struct field");
                           }
                       }
-                  })
-              };
-              C_struct([C_struct(cs)])
+                  });
+                  adt::trans_const(cx, &repr, discr, cs)
+              }
           }
           ast::expr_vec(es, ast::m_imm) => {
             let (v, _, _) = const_vec(cx, e, es);
@@ -452,25 +441,12 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef {
                     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.
-                    if ty::enum_is_univariant(cx.tcx, enum_did) {
-                        // Univariants have no discriminant field.
-                        C_struct(~[])
-                    } else {
-                    let lldiscrim = base::get_discrim_val(cx, e.span,
-                                                          enum_did,
-                                                          variant_did);
-                    // However, we still have to pad it out to the
-                    // size of the full enum; see the expr_call case,
-                    // below.
                     let ety = ty::expr_ty(cx.tcx, e);
-                    let size = machine::static_size_of_enum(cx, ety);
-                    let padding = C_null(T_array(T_i8(), size));
-                    C_struct(~[lldiscrim, padding])
-                }
+                    let repr = adt::represent_type(cx, ety);
+                    let vinfo = ty::enum_variant_with_id(cx.tcx,
+                                                         enum_did,
+                                                         variant_did);
+                    adt::trans_const(cx, &repr, vinfo.disr_val, [])
                 }
                 Some(ast::def_struct(_)) => {
                     let ety = ty::expr_ty(cx.tcx, e);
@@ -478,52 +454,31 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef {
                     C_null(llty)
                 }
                 _ => {
-                    cx.sess.span_bug(e.span,
-                                     ~"expected a const, fn, or variant def")
+                    cx.sess.span_bug(e.span, ~"expected a const, fn, \
+                                               struct, or variant def")
                 }
             }
           }
           ast::expr_call(callee, args, _) => {
-            match cx.tcx.def_map.find(&callee.id) {
-                Some(ast::def_struct(def_id)) => {
-                    let llstructbody =
-                        C_struct(args.map(|a| const_expr(cx, *a)));
-                    if ty::ty_dtor(cx.tcx, def_id).is_present() {
-                        C_struct(~[ llstructbody, C_u8(0) ])
-                    } else {
-                        C_struct(~[ llstructbody ])
-                    }
-                }
-            Some(ast::def_variant(tid, vid)) => {
-                let ety = ty::expr_ty(cx.tcx, e);
-                let univar = ty::enum_is_univariant(cx.tcx, tid);
-                let size = machine::static_size_of_enum(cx, ety);
-
-                let discrim = base::get_discrim_val(cx, e.span, tid, vid);
-                let c_args = C_struct(args.map(|a| const_expr(cx, *a)));
-
-                // FIXME (#1645): enum body alignment is generaly wrong.
-                if !univar {
-                    // Pad out the data to the size of its type_of;
-                    // this is necessary if the enum is contained
-                    // within an aggregate (tuple, struct, vector) so
-                    // that the next element is at the right offset.
-                    let actual_size =
-                        machine::llsize_of_real(cx, llvm::LLVMTypeOf(c_args));
-                    let padding =
-                        C_null(T_array(T_i8(), size - actual_size));
-                    // A packed_struct has an alignment of 1; thus,
-                    // wrapping one around c_args will misalign it the
-                    // same way we normally misalign enum bodies
-                    // without affecting its internal alignment or
-                    // changing the alignment of the enum.
-                    C_struct(~[discrim, C_packed_struct(~[c_args]), padding])
-                } else {
-                    C_struct(~[c_args])
-                }
-            }
-                _ => cx.sess.span_bug(e.span, ~"expected a struct def")
-            }
+              match cx.tcx.def_map.find(&callee.id) {
+                  Some(ast::def_struct(_)) => {
+                      let ety = ty::expr_ty(cx.tcx, e);
+                      let repr = adt::represent_type(cx, ety);
+                      adt::trans_const(cx, &repr, 0,
+                                       args.map(|a| const_expr(cx, *a)))
+                  }
+                  Some(ast::def_variant(enum_did, variant_did)) => {
+                      let ety = ty::expr_ty(cx.tcx, e);
+                      let repr = adt::represent_type(cx, ety);
+                      let vinfo = ty::enum_variant_with_id(cx.tcx,
+                                                           enum_did,
+                                                           variant_did);
+                      adt::trans_const(cx, &repr, vinfo.disr_val,
+                                       args.map(|a| const_expr(cx, *a)))
+                  }
+                  _ => cx.sess.span_bug(e.span, ~"expected a struct or \
+                                                  variant def")
+              }
           }
           ast::expr_paren(e) => { return const_expr(cx, e); }
           _ => cx.sess.span_bug(e.span,