Skip to content

Commit 957971b

Browse files
committed
Implement layout calculation and add more trans stubs
1 parent c2ca153 commit 957971b

File tree

5 files changed

+205
-20
lines changed

5 files changed

+205
-20
lines changed

src/librustc/ty/layout.rs

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ impl<'a, 'gcx, 'tcx> Struct {
488488

489489
for field in fields {
490490
if !self.sized {
491-
bug!("Struct::compute: field #{} of `{}` comes after unsized field",
491+
bug!("Struct::extend: field #{} of `{}` comes after unsized field",
492492
self.offset_after_field.len(), scapegoat);
493493
}
494494

@@ -623,6 +623,54 @@ impl<'a, 'gcx, 'tcx> Struct {
623623
}
624624
}
625625

626+
/// An untagged union.
627+
#[derive(PartialEq, Eq, Hash, Debug)]
628+
pub struct Union {
629+
pub align: Align,
630+
631+
pub min_size: Size,
632+
633+
/// If true, no alignment padding is used.
634+
pub packed: bool,
635+
}
636+
637+
impl<'a, 'gcx, 'tcx> Union {
638+
pub fn new(dl: &TargetDataLayout, packed: bool) -> Union {
639+
Union {
640+
align: if packed { dl.i8_align } else { dl.aggregate_align },
641+
min_size: Size::from_bytes(0),
642+
packed: packed,
643+
}
644+
}
645+
646+
/// Extend the Struct with more fields.
647+
pub fn extend<I>(&mut self, dl: &TargetDataLayout,
648+
fields: I,
649+
scapegoat: Ty<'gcx>)
650+
-> Result<(), LayoutError<'gcx>>
651+
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
652+
for (index, field) in fields.enumerate() {
653+
let field = field?;
654+
if field.is_unsized() {
655+
bug!("Union::extend: field #{} of `{}` is unsized",
656+
index, scapegoat);
657+
}
658+
659+
if !self.packed {
660+
self.align = self.align.max(field.align(dl));
661+
}
662+
self.min_size = cmp::max(self.min_size, field.size(dl));
663+
}
664+
665+
Ok(())
666+
}
667+
668+
/// Get the size with trailing aligment padding.
669+
pub fn stride(&self) -> Size {
670+
self.min_size.abi_align(self.align)
671+
}
672+
}
673+
626674
/// The first half of a fat pointer.
627675
/// - For a trait object, this is the address of the box.
628676
/// - For a slice, this is the base address.
@@ -690,6 +738,11 @@ pub enum Layout {
690738
non_zero: bool
691739
},
692740

741+
/// Untagged unions.
742+
UntaggedUnion {
743+
variants: Union,
744+
},
745+
693746
/// General-case enums: for each case there is a struct, and they
694747
/// all start with a field for the discriminant.
695748
General {
@@ -896,8 +949,14 @@ impl<'a, 'gcx, 'tcx> Layout {
896949
non_zero: Some(def.did) == tcx.lang_items.non_zero()
897950
}
898951
}
899-
ty::TyUnion(..) => {
900-
unimplemented_unions!();
952+
ty::TyUnion(def, substs) => {
953+
let fields = def.struct_variant().fields.iter().map(|field| {
954+
field.ty(tcx, substs).layout(infcx)
955+
});
956+
let packed = tcx.lookup_packed(def.did);
957+
let mut un = Union::new(dl, packed);
958+
un.extend(dl, fields, ty)?;
959+
UntaggedUnion { variants: un }
901960
}
902961
ty::TyEnum(def, substs) => {
903962
let hint = *tcx.lookup_repr_hints(def.did).get(0)
@@ -1118,7 +1177,7 @@ impl<'a, 'gcx, 'tcx> Layout {
11181177
pub fn is_unsized(&self) -> bool {
11191178
match *self {
11201179
Scalar {..} | Vector {..} | FatPointer {..} |
1121-
CEnum {..} | General {..} |
1180+
CEnum {..} | UntaggedUnion {..} | General {..} |
11221181
RawNullablePointer {..} |
11231182
StructWrappedNullablePointer {..} => false,
11241183

@@ -1152,6 +1211,7 @@ impl<'a, 'gcx, 'tcx> Layout {
11521211

11531212
CEnum { discr, .. } => Int(discr).size(dl),
11541213
Array { size, .. } | General { size, .. } => size,
1214+
UntaggedUnion { ref variants } => variants.stride(),
11551215

11561216
Univariant { ref variant, .. } |
11571217
StructWrappedNullablePointer { nonnull: ref variant, .. } => {
@@ -1191,6 +1251,7 @@ impl<'a, 'gcx, 'tcx> Layout {
11911251

11921252
CEnum { discr, .. } => Int(discr).align(dl),
11931253
Array { align, .. } | General { align, .. } => align,
1254+
UntaggedUnion { ref variants } => variants.align,
11941255

11951256
Univariant { ref variant, .. } |
11961257
StructWrappedNullablePointer { nonnull: ref variant, .. } => {
@@ -1256,9 +1317,6 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
12561317
}
12571318
}
12581319

1259-
ty::TyUnion(..) => {
1260-
unimplemented_unions!();
1261-
}
12621320
ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
12631321
// Only newtypes and enums w/ nullable pointer optimization.
12641322
if def.variants.is_empty() || def.variants.len() > 2 {

src/librustc_mir/hair/cx/expr.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
459459

460460
hir::ExprStruct(_, ref fields, ref base) => {
461461
match expr_ty.sty {
462-
ty::TyStruct(adt, substs) => {
462+
ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) => {
463463
let field_refs = field_refs(&adt.variants[0], fields);
464464
ExprKind::Adt {
465465
adt_def: adt,
@@ -477,9 +477,6 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
477477
})
478478
}
479479
}
480-
ty::TyUnion(..) => {
481-
unimplemented_unions!();
482-
}
483480
ty::TyEnum(adt, substs) => {
484481
match cx.tcx.expect_def(expr.id) {
485482
Def::Variant(enum_id, variant_id) => {

src/librustc_trans/adt.rs

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ pub enum Repr<'tcx> {
7979
CEnum(IntType, Disr, Disr), // discriminant range (signedness based on the IntType)
8080
/// Single-case variants, and structs/tuples/records.
8181
Univariant(Struct<'tcx>),
82+
/// Untagged unions.
83+
UntaggedUnion(Union<'tcx>),
8284
/// General-case enums: for each case there is a struct, and they
8385
/// all start with a field for the discriminant.
8486
General(IntType, Vec<Struct<'tcx>>),
@@ -121,6 +123,15 @@ pub struct Struct<'tcx> {
121123
pub fields: Vec<Ty<'tcx>>,
122124
}
123125

126+
/// For untagged unions.
127+
#[derive(Eq, PartialEq, Debug)]
128+
pub struct Union<'tcx> {
129+
pub min_size: u64,
130+
pub align: u32,
131+
pub packed: bool,
132+
pub fields: Vec<Ty<'tcx>>,
133+
}
134+
124135
#[derive(Copy, Clone)]
125136
pub struct MaybeSizedValue {
126137
pub value: ValueRef,
@@ -176,8 +187,12 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
176187

177188
Univariant(mk_struct(cx, &ftys[..], packed, t))
178189
}
179-
ty::TyUnion(..) => {
180-
unimplemented_unions!();
190+
ty::TyUnion(def, substs) => {
191+
let ftys = def.struct_variant().fields.iter().map(|field| {
192+
monomorphize::field_ty(cx.tcx(), substs, field)
193+
}).collect::<Vec<_>>();
194+
let packed = cx.tcx().lookup_packed(def.did);
195+
UntaggedUnion(mk_union(cx, &ftys[..], packed, t))
181196
}
182197
ty::TyClosure(_, ref substs) => {
183198
Univariant(mk_struct(cx, &substs.upvar_tys, false, t))
@@ -482,6 +497,31 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
482497
}
483498
}
484499

500+
fn mk_union<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
501+
tys: &[Ty<'tcx>], packed: bool,
502+
_scapegoat: Ty<'tcx>)
503+
-> Union<'tcx> {
504+
let mut min_size = 0;
505+
let mut align = 0;
506+
for llty in tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)) {
507+
let field_size = machine::llsize_of_alloc(cx, llty);
508+
if min_size < field_size {
509+
min_size = field_size;
510+
}
511+
let field_align = machine::llalign_of_min(cx, llty);
512+
if align < field_align {
513+
align = field_align;
514+
}
515+
}
516+
517+
Union {
518+
min_size: min_size,
519+
align: align,
520+
packed: packed,
521+
fields: tys.to_vec(),
522+
}
523+
}
524+
485525
#[derive(Debug)]
486526
struct IntBounds {
487527
slo: i64,
@@ -646,7 +686,7 @@ pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
646686
pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
647687
r: &Repr<'tcx>, llty: &mut Type) {
648688
match *r {
649-
CEnum(..) | General(..) | RawNullablePointer { .. } => { }
689+
CEnum(..) | General(..) | UntaggedUnion(..) | RawNullablePointer { .. } => { }
650690
Univariant(ref st) | StructWrappedNullablePointer { nonnull: ref st, .. } =>
651691
llty.set_struct_body(&struct_llfields(cx, st, false, false),
652692
st.packed)
@@ -690,6 +730,34 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
690730
}
691731
}
692732
}
733+
UntaggedUnion(ref un) => {
734+
// Use alignment-sized ints to fill all the union storage.
735+
let (size, align) = (roundup(un.min_size, un.align), un.align);
736+
737+
let align_s = align as u64;
738+
assert_eq!(size % align_s, 0); // Ensure division in align_units comes out evenly
739+
let align_units = size / align_s;
740+
let fill_ty = match align_s {
741+
1 => Type::array(&Type::i8(cx), align_units),
742+
2 => Type::array(&Type::i16(cx), align_units),
743+
4 => Type::array(&Type::i32(cx), align_units),
744+
8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 =>
745+
Type::array(&Type::i64(cx), align_units),
746+
a if a.count_ones() == 1 => Type::array(&Type::vector(&Type::i32(cx), a / 4),
747+
align_units),
748+
_ => bug!("unsupported union alignment: {}", align)
749+
};
750+
match name {
751+
None => {
752+
TypeContext::direct(Type::struct_(cx, &[fill_ty], un.packed))
753+
}
754+
Some(name) => {
755+
let mut llty = Type::named_struct(cx, name);
756+
llty.set_struct_body(&[fill_ty], un.packed);
757+
TypeContext::direct(llty)
758+
}
759+
}
760+
}
693761
General(ity, ref sts) => {
694762
// We need a representation that has:
695763
// * The alignment of the most-aligned field
@@ -762,7 +830,7 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
762830
RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
763831
(BranchKind::Switch, Some(trans_get_discr(bcx, r, scrutinee, None, range_assert)))
764832
}
765-
Univariant(..) => {
833+
Univariant(..) | UntaggedUnion(..) => {
766834
// N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
767835
(BranchKind::Single, None)
768836
}
@@ -773,7 +841,7 @@ pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
773841
match *r {
774842
CEnum(ity, _, _) => ity.is_signed(),
775843
General(ity, _) => ity.is_signed(),
776-
Univariant(..) => false,
844+
Univariant(..) | UntaggedUnion(..) => false,
777845
RawNullablePointer { .. } => false,
778846
StructWrappedNullablePointer { .. } => false,
779847
}
@@ -794,7 +862,7 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
794862
load_discr(bcx, ity, ptr, Disr(0), Disr(cases.len() as u64 - 1),
795863
range_assert)
796864
}
797-
Univariant(..) => C_u8(bcx.ccx(), 0),
865+
Univariant(..) | UntaggedUnion(..) => C_u8(bcx.ccx(), 0),
798866
RawNullablePointer { nndiscr, nnty, .. } => {
799867
let cmp = if nndiscr == Disr(0) { IntEQ } else { IntNE };
800868
let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
@@ -856,8 +924,8 @@ pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr)
856924
General(ity, _) => {
857925
C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true)
858926
}
859-
Univariant(..) => {
860-
bug!("no cases for univariants or structs")
927+
Univariant(..) | UntaggedUnion(..) => {
928+
bug!("no cases for univariants, structs or unions")
861929
}
862930
RawNullablePointer { .. } |
863931
StructWrappedNullablePointer { .. } => {
@@ -884,6 +952,9 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
884952
Univariant(_) => {
885953
assert_eq!(discr, Disr(0));
886954
}
955+
UntaggedUnion(..) => {
956+
assert_eq!(discr, Disr(0));
957+
}
887958
RawNullablePointer { nndiscr, nnty, ..} => {
888959
if discr != nndiscr {
889960
let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
@@ -939,6 +1010,11 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
9391010
General(_, ref cases) => {
9401011
struct_field_ptr(bcx, &cases[discr.0 as usize], val, ix + 1, true)
9411012
}
1013+
UntaggedUnion(ref un) => {
1014+
let ty = type_of::in_memory_type_of(bcx.ccx(), un.fields[ix]);
1015+
if bcx.is_unreachable() { return C_undef(ty.ptr_to()); }
1016+
bcx.pointercast(val.value, ty.ptr_to())
1017+
}
9421018
RawNullablePointer { nndiscr, ref nullfields, .. } |
9431019
StructWrappedNullablePointer { nndiscr, ref nullfields, .. } if discr != nndiscr => {
9441020
// The unit-like case might have a nonzero number of unit-like fields.
@@ -1100,6 +1176,9 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
11001176
contents.extend_from_slice(&[padding(ccx, max_sz - case.size)]);
11011177
C_struct(ccx, &contents[..], false)
11021178
}
1179+
UntaggedUnion(..) => {
1180+
unimplemented_unions!();
1181+
}
11031182
Univariant(ref st) => {
11041183
assert_eq!(discr, Disr(0));
11051184
let contents = build_const_struct(ccx, st, vals);
@@ -1211,6 +1290,7 @@ pub fn const_get_field(r: &Repr, val: ValueRef, _discr: Disr,
12111290
match *r {
12121291
CEnum(..) => bug!("element access in C-like enum const"),
12131292
Univariant(..) => const_struct_field(val, ix),
1293+
UntaggedUnion(..) => const_struct_field(val, 0),
12141294
General(..) => const_struct_field(val, ix + 1),
12151295
RawNullablePointer { .. } => {
12161296
assert_eq!(ix, 0);

src/librustc_trans/debuginfo/metadata.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,9 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
13021302
]
13031303
}
13041304
}
1305+
adt::UntaggedUnion(..) => {
1306+
unimplemented_unions!();
1307+
}
13051308
adt::RawNullablePointer { nndiscr: non_null_variant_index, nnty, .. } => {
13061309
// As far as debuginfo is concerned, the pointer this enum
13071310
// represents is still wrapped in a struct. This is to make the
@@ -1616,7 +1619,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
16161619
},
16171620
adt::RawNullablePointer { .. } |
16181621
adt::StructWrappedNullablePointer { .. } |
1619-
adt::Univariant(..) => None,
1622+
adt::Univariant(..) | adt::UntaggedUnion(..) => None,
16201623
adt::General(inttype, _) => Some(discriminant_type_metadata(inttype)),
16211624
};
16221625

0 commit comments

Comments
 (0)