@@ -178,6 +178,8 @@ enum Value<'tcx> {
178178 /// An aggregate value, either tuple/closure/struct/enum.
179179 /// This does not contain unions, as we cannot reason with the value.
180180 Aggregate ( VariantIdx , Vec < VnIndex > ) ,
181+ /// A union aggregate value.
182+ Union ( FieldIdx , VnIndex ) ,
181183 /// A raw pointer aggregate built from a thin pointer and metadata.
182184 RawPtr {
183185 /// Thin pointer component. This is field 0 in MIR.
@@ -431,6 +433,21 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
431433 return None ;
432434 }
433435 }
436+ Union ( active_field, field) => {
437+ let field = self . evaluated [ field] . as_ref ( ) ?;
438+ if matches ! ( ty. backend_repr, BackendRepr :: Scalar ( ..) | BackendRepr :: ScalarPair ( ..) )
439+ {
440+ let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . discard_err ( ) ?;
441+ let field_dest = self . ecx . project_field ( & dest, active_field) . discard_err ( ) ?;
442+ self . ecx . copy_op ( field, & field_dest) . discard_err ( ) ?;
443+ self . ecx
444+ . alloc_mark_immutable ( dest. ptr ( ) . provenance . unwrap ( ) . alloc_id ( ) )
445+ . discard_err ( ) ?;
446+ dest. into ( )
447+ } else {
448+ return None ;
449+ }
450+ }
434451 RawPtr { pointer, metadata } => {
435452 let pointer = self . evaluated [ pointer] . as_ref ( ) ?;
436453 let metadata = self . evaluated [ metadata] . as_ref ( ) ?;
@@ -608,6 +625,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
608625 ProjectionElem :: Field ( f, _) => {
609626 if let Value :: Aggregate ( _, fields) = self . get ( value) {
610627 return Some ( ( projection_ty, fields[ f. as_usize ( ) ] ) ) ;
628+ } else if let Value :: Union ( active, field) = * self . get ( value)
629+ && active == f
630+ {
631+ return Some ( ( projection_ty, field) ) ;
611632 } else if let Value :: Projection ( outer_value, ProjectionElem :: Downcast ( _, read_variant) ) = self . get ( value)
612633 && let Value :: Aggregate ( written_variant, fields) = self . get ( * outer_value)
613634 // This pass is not aware of control-flow, so we do not know whether the
@@ -980,7 +1001,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
9801001 | AggregateKind :: Coroutine ( ..) => FIRST_VARIANT ,
9811002 AggregateKind :: Adt ( _, variant_index, _, _, None ) => variant_index,
9821003 // Do not track unions.
983- AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return None ,
1004+ AggregateKind :: Adt ( _, _, _, _, Some ( active_field) ) => {
1005+ let field = * fields. first ( ) ?;
1006+ return Some ( self . insert ( ty, Value :: Union ( active_field, field) ) ) ;
1007+ }
9841008 AggregateKind :: RawPtr ( ..) => {
9851009 assert_eq ! ( field_ops. len( ) , 2 ) ;
9861010 let [ mut pointer, metadata] = fields. try_into ( ) . unwrap ( ) ;
0 commit comments