@@ -70,27 +70,75 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
7070 } )
7171 }
7272
73- /// Find the wrapped inner type of a transparent wrapper.
74- /// Must not be called on 1-ZST (as they don't have a uniquely defined "wrapped field").
73+ /// Returns whether the given type has trivial ABI.
74+ fn has_trivial_abi ( & self , layout : TyAndLayout < ' tcx > ) -> InterpResult < ' tcx , bool > {
75+ if !layout. is_1zst ( ) {
76+ return interp_ok ( false ) ;
77+ }
78+ match * layout. ty . kind ( ) {
79+ ty:: Array ( elem, _len) => self . has_trivial_abi ( self . layout_of ( elem) ?) ,
80+ ty:: Tuple ( ..)
81+ | ty:: Never
82+ | ty:: FnDef ( ..)
83+ | ty:: Closure ( ..)
84+ | ty:: Coroutine ( ..)
85+ | ty:: CoroutineClosure ( ..) => interp_ok ( true ) ,
86+ ty:: Adt ( adt_def, _args) => {
87+ if adt_def. repr ( ) . transparent ( ) {
88+ // All fields must have trivial ABI.
89+ ( 0 ..layout. fields . count ( ) ) . try_fold ( true , |acc, idx| {
90+ interp_ok ( acc && self . has_trivial_abi ( layout. field ( self , idx) ) ?)
91+ } )
92+ } else if adt_def. repr ( ) . c ( ) {
93+ interp_ok ( false )
94+ } else {
95+ // Must be repr(Rust).
96+ interp_ok ( true )
97+ }
98+ }
99+ ty:: Alias ( ..) => panic ! ( "non-normalized type" ) ,
100+ _ => interp_ok ( false ) ,
101+ }
102+ }
103+
104+ /// Find the wrapped inner type of a transparent wrapper by going for the unique
105+ /// non-trivial-ABI field.
75106 ///
76107 /// We work with `TyAndLayout` here since that makes it much easier to iterate over all fields.
77108 fn unfold_transparent (
78109 & self ,
79110 layout : TyAndLayout < ' tcx > ,
80111 may_unfold : impl Fn ( AdtDef < ' tcx > ) -> bool ,
81- ) -> TyAndLayout < ' tcx > {
112+ ) -> InterpResult < ' tcx , TyAndLayout < ' tcx > > {
82113 match layout. ty . kind ( ) {
83114 ty:: Adt ( adt_def, _) if adt_def. repr ( ) . transparent ( ) && may_unfold ( * adt_def) => {
84115 assert_matches ! ( layout. variants, rustc_abi:: Variants :: Single { .. } ) ;
85- // Find the non-1-ZST field, and recurse.
86- let ( _, field) = layout. non_1zst_field ( self ) . unwrap ( ) ;
116+ // Look for non-trivial-ABI field(s).
117+ let mut found = None ;
118+ for idx in 0 ..layout. fields . count ( ) {
119+ let field = layout. field ( self , idx) ;
120+ if self . has_trivial_abi ( field) ? {
121+ continue ;
122+ }
123+ // Found a non-trivial ABI field!
124+ if found. is_some ( ) {
125+ // There is more than one such field.
126+ // FIXME: we should just panic here. But currently such repr(transparent)
127+ // types are still accepted. We just don't treat them as transparent.
128+ return interp_ok ( layout) ;
129+ }
130+ found = Some ( field) ;
131+ }
132+ let Some ( field) = found else {
133+ // All fields have trivial ABI. That means this type is effectively `()`.
134+ return interp_ok ( self . layout_of ( self . tcx . types . unit ) ?) ;
135+ } ;
136+ // Recurse.
87137 self . unfold_transparent ( field, may_unfold)
88138 }
89- ty:: Pat ( base, _) => self . layout_of ( * base) . expect (
90- "if the layout of a pattern type could be computed, so can the layout of its base" ,
91- ) ,
139+ ty:: Pat ( base, _) => interp_ok ( self . layout_of ( * base) ?) ,
92140 // Not a transparent type, no further unfolding.
93- _ => layout,
141+ _ => interp_ok ( layout) ,
94142 }
95143 }
96144
@@ -145,7 +193,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
145193 let inner = self . unfold_transparent ( inner, /* may_unfold */ |def| {
146194 // Stop at NPO types so that we don't miss that attribute in the check below!
147195 def. is_struct ( ) && !is_npo ( def)
148- } ) ;
196+ } ) ? ;
149197 interp_ok ( match inner. ty . kind ( ) {
150198 ty:: Ref ( ..) | ty:: FnPtr ( ..) => {
151199 // Option<&T> behaves like &T, and same for fn()
@@ -154,7 +202,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
154202 ty:: Adt ( def, _) if is_npo ( * def) => {
155203 // Once we found a `nonnull_optimization_guaranteed` type, further strip off
156204 // newtype structs from it to find the underlying ABI type.
157- self . unfold_transparent ( inner, /* may_unfold */ |def| def. is_struct ( ) )
205+ self . unfold_transparent ( inner, /* may_unfold */ |def| def. is_struct ( ) ) ?
158206 }
159207 _ => {
160208 // Everything else we do not unfold.
@@ -175,16 +223,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
175223 if caller. ty == callee. ty {
176224 return interp_ok ( true ) ;
177225 }
178- // 1-ZST are compatible with all 1-ZST (and with nothing else) .
179- if caller . is_1zst ( ) || callee . is_1zst ( ) {
180- return interp_ok ( caller . is_1zst ( ) && callee . is_1zst ( ) ) ;
226+ // Handle trivial-ABI types .
227+ if self . has_trivial_abi ( caller ) ? && self . has_trivial_abi ( callee ) ? {
228+ return interp_ok ( true ) ;
181229 }
182230 // Unfold newtypes and NPO optimizations.
183231 let unfold = |layout : TyAndLayout < ' tcx > | {
184- self . unfold_npo ( self . unfold_transparent ( layout, /* may_unfold */ |_def| true ) )
232+ self . unfold_transparent ( layout, /* may_unfold */ |_def| true )
233+ . and_then ( |f| self . unfold_npo ( f) )
185234 } ;
186235 let caller = unfold ( caller) ?;
187236 let callee = unfold ( callee) ?;
237+ // Not-quite-so-fast path: if the types are equal now, they are compatible.
238+ if caller. ty == callee. ty {
239+ return interp_ok ( true ) ;
240+ }
188241 // Now see if these inner types are compatible.
189242
190243 // Compatible pointer types. For thin pointers, we have to accept even non-`repr(transparent)`
@@ -240,8 +293,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
240293 return interp_ok ( caller == callee) ;
241294 }
242295
243- // Fall back to exact equality .
244- interp_ok ( caller == callee )
296+ // The rest is incompatible .
297+ interp_ok ( false )
245298 }
246299
247300 /// Returns a `bool` saying whether the two arguments are ABI-compatible.
0 commit comments