diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index bcf796caa7a4a..d86d4c97c3bed 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -407,6 +407,10 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { // 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); @@ -418,6 +422,7 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { let padding = C_null(T_array(T_i8(), size)); C_struct(~[lldiscrim, padding]) } + } Some(ast::def_struct(_)) => { let ety = ty::expr_ty(cx.tcx, e); let llty = type_of::type_of(cx, ety); @@ -442,14 +447,14 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { } Some(ast::def_variant(tid, vid)) => { let ety = ty::expr_ty(cx.tcx, e); - let degen = ty::enum_is_univariant(cx.tcx, tid); + 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 !degen { + 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 @@ -464,8 +469,6 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { // without affecting its internal alignment or // changing the alignment of the enum. C_struct(~[discrim, C_packed_struct(~[c_args]), padding]) - } else if size == 0 { - C_struct(~[discrim]) } else { C_struct(~[c_args]) } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index cab2adc43faa6..30ba0e7feeec8 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -674,12 +674,15 @@ fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr, // N-ary variant. let fn_data = callee::trans_fn_ref(bcx, vid, ref_expr.id); return fn_data_to_datum(bcx, vid, fn_data, lldest); - } else { + } else if !ty::enum_is_univariant(ccx.tcx, tid) { // Nullary variant. let lldiscrimptr = GEPi(bcx, lldest, [0u, 0u]); let lldiscrim = C_int(bcx.ccx(), variant_info.disr_val); Store(bcx, lldiscrim, lldiscrimptr); return bcx; + } else { + // Nullary univariant. + return bcx; } } ast::def_struct(*) => { @@ -1591,10 +1594,22 @@ fn trans_imm_cast(bcx: block, expr: @ast::expr, {in: cast_enum, out: cast_integral} | {in: cast_enum, out: cast_float} => { let bcx = bcx; - let llenumty = T_opaque_enum_ptr(ccx); - let av_enum = PointerCast(bcx, llexpr, llenumty); - let lldiscrim_a_ptr = GEPi(bcx, av_enum, [0u, 0u]); - let lldiscrim_a = Load(bcx, lldiscrim_a_ptr); + let in_tid = match ty::get(t_in).sty { + ty::ty_enum(did, _) => did, + _ => ccx.sess.bug(~"enum cast source is not enum") + }; + let variants = ty::enum_variants(ccx.tcx, in_tid); + let lldiscrim_a = if variants.len() == 1 { + // Univariants don't have a discriminant field, + // because there's only one value it could have: + C_integral(T_enum_discrim(ccx), + variants[0].disr_val as u64, True) + } else { + let llenumty = T_opaque_enum_ptr(ccx); + let av_enum = PointerCast(bcx, llexpr, llenumty); + let lldiscrim_a_ptr = GEPi(bcx, av_enum, [0u, 0u]); + Load(bcx, lldiscrim_a_ptr) + }; match k_out { cast_integral => int_cast(bcx, ll_t_out, val_ty(lldiscrim_a), diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 84a19cd4c0477..972f702c18a81 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -242,14 +242,11 @@ pub fn fill_type_of_enum(cx: @crate_ctxt, did: ast::def_id, t: ty::t, debug!("type_of_enum %?: %?", t, ty::get(t)); let lltys = { - let degen = ty::enum_is_univariant(cx.tcx, did); + let univar = ty::enum_is_univariant(cx.tcx, did); let size = machine::static_size_of_enum(cx, t); - if !degen { + if !univar { ~[T_enum_discrim(cx), T_array(T_i8(), size)] } - else if size == 0u { - ~[T_enum_discrim(cx)] - } else { ~[T_array(T_i8(), size)] }