Convert const ADT construction to trans::adt.
Also converts const cast-from-enum, because it used the same routine to get the discriminant as what's renovated to construct the enums. Also fixes ICE on struct-like variants as consts, and provides a slightly less bad ICE for functional-update-like struct expressions in consts.
This commit is contained in:
parent
2a028c5ab8
commit
bb689c09f5
@ -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; }
|
||||
|
@ -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)))])
|
||||
}
|
||||
ast::expr_struct(_, ref fs, _) => {
|
||||
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);
|
||||
adt::trans_const(cx, &repr, 0,
|
||||
fs.map(|f| const_expr(cx, f.node.expr)))
|
||||
}
|
||||
ast::expr_struct(_, ref fs, None) => {
|
||||
let ety = ty::expr_ty(cx.tcx, e);
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user