@@ -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 ) ]
125136pub 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 ) ]
486526struct IntBounds {
487527 slo : i64 ,
@@ -646,7 +686,7 @@ pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
646686pub 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 ) ;
0 commit comments