@@ -213,6 +213,8 @@ enum Value<'a, 'tcx> {
213213/// An aggregate value, either tuple/closure/struct/enum.
214214/// This does not contain unions, as we cannot reason with the value.
215215Aggregate ( VariantIdx , & ' a [ VnIndex ] ) ,
216+ /// A union aggregate value.
217+ Union ( FieldIdx , VnIndex ) ,
216218/// A raw pointer aggregate built from a thin pointer and metadata.
217219RawPtr {
218220/// Thin pointer component. This is field 0 in MIR.
@@ -600,6 +602,21 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
600602return None ;
601603}
602604}
605+ Union ( active_field, field) => {
606+ let field = self . evaluated [ field] . as_ref ( ) ?;
607+ if matches ! ( ty. backend_repr, BackendRepr :: Scalar ( ..) | BackendRepr :: ScalarPair ( ..) )
608+ {
609+ let dest = self . ecx . allocate ( ty, MemoryKind :: Stack ) . discard_err ( ) ?;
610+ let field_dest = self . ecx . project_field ( & dest, active_field) . discard_err ( ) ?;
611+ self . ecx . copy_op ( field, & field_dest) . discard_err ( ) ?;
612+ self . ecx
613+ . alloc_mark_immutable ( dest. ptr ( ) . provenance . unwrap ( ) . alloc_id ( ) )
614+ . discard_err ( ) ?;
615+ dest. into ( )
616+ } else {
617+ return None ;
618+ }
619+ }
603620RawPtr { pointer, metadata } => {
604621let pointer = self . evaluated [ pointer] . as_ref ( ) ?;
605622let metadata = self . evaluated [ metadata] . as_ref ( ) ?;
@@ -802,11 +819,11 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
802819}
803820}
804821ProjectionElem :: Downcast ( name, index) => ProjectionElem :: Downcast ( name, index) ,
805- ProjectionElem :: Field ( f, _) => {
806- if let Value :: Aggregate ( _, fields) =self . get ( value ) {
807- return Some ( ( projection_ty, fields [ f . as_usize ( ) ] ) ) ;
808- } else if let Value :: Projection ( outer_value, ProjectionElem :: Downcast ( _, read_variant) ) = self . get ( value )
809- && let Value :: Aggregate ( written_variant, fields) = self . get ( outer_value)
822+ ProjectionElem :: Field ( f, _) => match self . get ( value ) {
823+ Value :: Aggregate ( _, fields) => return Some ( ( projection_ty , fields [ f . as_usize ( ) ] ) ) ,
824+ Value :: Union ( active , field ) if active == f => return Some ( ( projection_ty, field ) ) ,
825+ Value :: Projection ( outer_value, ProjectionElem :: Downcast ( _, read_variant) )
826+ if let Value :: Aggregate ( written_variant, fields) = self . get ( outer_value)
810827// This pass is not aware of control-flow, so we do not know whether the
811828// replacement we are doing is actually reachable. We could be in any arm of
812829// ```
@@ -822,12 +839,12 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
822839// accessing the wrong variant is not UB if the enum has repr.
823840// So it's not impossible for a series of MIR opts to generate
824841// a downcast to an inactive variant.
825- && written_variant == read_variant
842+ && written_variant == read_variant =>
826843{
827844return Some ( ( projection_ty, fields[ f. as_usize ( ) ] ) ) ;
828845}
829- ProjectionElem :: Field ( f, ( ) )
830- }
846+ _ => ProjectionElem :: Field ( f, ( ) ) ,
847+ } ,
831848ProjectionElem :: Index ( idx) => {
832849if let Value :: Repeat ( inner, _) = self . get ( value) {
833850return Some ( ( projection_ty, inner) ) ;
@@ -1167,7 +1184,10 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
11671184 | AggregateKind :: Coroutine ( ..) => FIRST_VARIANT ,
11681185AggregateKind :: Adt ( _, variant_index, _, _, None ) => variant_index,
11691186// Do not track unions.
1170- AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return None ,
1187+ AggregateKind :: Adt ( _, _, _, _, Some ( active_field) ) => {
1188+ let field = * fields. first ( ) ?;
1189+ return Some ( self . insert ( ty, Value :: Union ( active_field, field) ) ) ;
1190+ }
11711191AggregateKind :: RawPtr ( ..) => {
11721192assert_eq ! ( field_ops. len( ) , 2 ) ;
11731193let [ mut pointer, metadata] = fields. try_into ( ) . unwrap ( ) ;
0 commit comments