@@ -79,6 +79,8 @@ pub enum Repr<'tcx> {
79
79
CEnum ( IntType , Disr , Disr ) , // discriminant range (signedness based on the IntType)
80
80
/// Single-case variants, and structs/tuples/records.
81
81
Univariant ( Struct < ' tcx > ) ,
82
+ /// Untagged unions.
83
+ UntaggedUnion ( Union < ' tcx > ) ,
82
84
/// General-case enums: for each case there is a struct, and they
83
85
/// all start with a field for the discriminant.
84
86
General ( IntType , Vec < Struct < ' tcx > > ) ,
@@ -121,6 +123,15 @@ pub struct Struct<'tcx> {
121
123
pub fields : Vec < Ty < ' tcx > > ,
122
124
}
123
125
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
+
124
135
#[ derive( Copy , Clone ) ]
125
136
pub struct MaybeSizedValue {
126
137
pub value : ValueRef ,
@@ -176,8 +187,12 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
176
187
177
188
Univariant ( mk_struct ( cx, & ftys[ ..] , packed, t) )
178
189
}
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) )
181
196
}
182
197
ty:: TyClosure ( _, ref substs) => {
183
198
Univariant ( mk_struct ( cx, & substs. upvar_tys , false , t) )
@@ -482,6 +497,31 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
482
497
}
483
498
}
484
499
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
+
485
525
#[ derive( Debug ) ]
486
526
struct IntBounds {
487
527
slo : i64 ,
@@ -646,7 +686,7 @@ pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
646
686
pub fn finish_type_of < ' a , ' tcx > ( cx : & CrateContext < ' a , ' tcx > ,
647
687
r : & Repr < ' tcx > , llty : & mut Type ) {
648
688
match * r {
649
- CEnum ( ..) | General ( ..) | RawNullablePointer { .. } => { }
689
+ CEnum ( ..) | General ( ..) | UntaggedUnion ( .. ) | RawNullablePointer { .. } => { }
650
690
Univariant ( ref st) | StructWrappedNullablePointer { nonnull : ref st, .. } =>
651
691
llty. set_struct_body ( & struct_llfields ( cx, st, false , false ) ,
652
692
st. packed )
@@ -690,6 +730,34 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
690
730
}
691
731
}
692
732
}
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
+ }
693
761
General ( ity, ref sts) => {
694
762
// We need a representation that has:
695
763
// * The alignment of the most-aligned field
@@ -762,7 +830,7 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
762
830
RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
763
831
( BranchKind :: Switch , Some ( trans_get_discr ( bcx, r, scrutinee, None , range_assert) ) )
764
832
}
765
- Univariant ( ..) => {
833
+ Univariant ( ..) | UntaggedUnion ( .. ) => {
766
834
// N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
767
835
( BranchKind :: Single , None )
768
836
}
@@ -773,7 +841,7 @@ pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
773
841
match * r {
774
842
CEnum ( ity, _, _) => ity. is_signed ( ) ,
775
843
General ( ity, _) => ity. is_signed ( ) ,
776
- Univariant ( ..) => false ,
844
+ Univariant ( ..) | UntaggedUnion ( .. ) => false ,
777
845
RawNullablePointer { .. } => false ,
778
846
StructWrappedNullablePointer { .. } => false ,
779
847
}
@@ -794,7 +862,7 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
794
862
load_discr ( bcx, ity, ptr, Disr ( 0 ) , Disr ( cases. len ( ) as u64 - 1 ) ,
795
863
range_assert)
796
864
}
797
- Univariant ( ..) => C_u8 ( bcx. ccx ( ) , 0 ) ,
865
+ Univariant ( ..) | UntaggedUnion ( .. ) => C_u8 ( bcx. ccx ( ) , 0 ) ,
798
866
RawNullablePointer { nndiscr, nnty, .. } => {
799
867
let cmp = if nndiscr == Disr ( 0 ) { IntEQ } else { IntNE } ;
800
868
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)
856
924
General ( ity, _) => {
857
925
C_integral ( ll_inttype ( bcx. ccx ( ) , ity) , discr. 0 , true )
858
926
}
859
- Univariant ( ..) => {
860
- bug ! ( "no cases for univariants or structs " )
927
+ Univariant ( ..) | UntaggedUnion ( .. ) => {
928
+ bug ! ( "no cases for univariants, structs or unions " )
861
929
}
862
930
RawNullablePointer { .. } |
863
931
StructWrappedNullablePointer { .. } => {
@@ -884,6 +952,9 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
884
952
Univariant ( _) => {
885
953
assert_eq ! ( discr, Disr ( 0 ) ) ;
886
954
}
955
+ UntaggedUnion ( ..) => {
956
+ assert_eq ! ( discr, Disr ( 0 ) ) ;
957
+ }
887
958
RawNullablePointer { nndiscr, nnty, ..} => {
888
959
if discr != nndiscr {
889
960
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>,
939
1010
General ( _, ref cases) => {
940
1011
struct_field_ptr ( bcx, & cases[ discr. 0 as usize ] , val, ix + 1 , true )
941
1012
}
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
+ }
942
1018
RawNullablePointer { nndiscr, ref nullfields, .. } |
943
1019
StructWrappedNullablePointer { nndiscr, ref nullfields, .. } if discr != nndiscr => {
944
1020
// 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
1100
1176
contents. extend_from_slice ( & [ padding ( ccx, max_sz - case. size ) ] ) ;
1101
1177
C_struct ( ccx, & contents[ ..] , false )
1102
1178
}
1179
+ UntaggedUnion ( ..) => {
1180
+ unimplemented_unions ! ( ) ;
1181
+ }
1103
1182
Univariant ( ref st) => {
1104
1183
assert_eq ! ( discr, Disr ( 0 ) ) ;
1105
1184
let contents = build_const_struct ( ccx, st, vals) ;
@@ -1211,6 +1290,7 @@ pub fn const_get_field(r: &Repr, val: ValueRef, _discr: Disr,
1211
1290
match * r {
1212
1291
CEnum ( ..) => bug ! ( "element access in C-like enum const" ) ,
1213
1292
Univariant ( ..) => const_struct_field ( val, ix) ,
1293
+ UntaggedUnion ( ..) => const_struct_field ( val, 0 ) ,
1214
1294
General ( ..) => const_struct_field ( val, ix + 1 ) ,
1215
1295
RawNullablePointer { .. } => {
1216
1296
assert_eq ! ( ix, 0 ) ;
0 commit comments