@@ -2153,123 +2153,208 @@ impl ClashingExternDeclarations {
2153
2153
b : Ty < ' tcx > ,
2154
2154
ckind : CItemKind ,
2155
2155
) -> bool {
2156
- debug ! ( "structurally_same_type(cx, a = {:?}, b = {:?})" , a, b) ;
2157
- let tcx = cx. tcx ;
2158
- if a == b || rustc_middle:: ty:: TyS :: same_type ( a, b) {
2159
- // All nominally-same types are structurally same, too.
2160
- true
2161
- } else {
2162
- // Do a full, depth-first comparison between the two.
2163
- use rustc_middle:: ty:: TyKind :: * ;
2164
- let a_kind = & a. kind ;
2165
- let b_kind = & b. kind ;
2166
-
2167
- let compare_layouts = |a, b| -> bool {
2168
- let a_layout = & cx. layout_of ( a) . unwrap ( ) . layout . abi ;
2169
- let b_layout = & cx. layout_of ( b) . unwrap ( ) . layout . abi ;
2170
- debug ! ( "{:?} == {:?} = {}" , a_layout, b_layout, a_layout == b_layout) ;
2171
- a_layout == b_layout
2172
- } ;
2156
+ // In order to avoid endlessly recursing on recursive types, we maintain a "seen" set.
2157
+ // We'll need to store every combination of types we encounter anyway, so we also memoize
2158
+ // the result.
2159
+ struct SeenSet < ' tcx > ( FxHashMap < ( Ty < ' tcx > , Ty < ' tcx > ) , Option < bool > > ) ;
2160
+
2161
+ enum SeenSetResult {
2162
+ /// We've never seen this combination of types.
2163
+ Unseen ,
2164
+ /// We've seen this combination of types, but are still computing the result.
2165
+ Computing ,
2166
+ /// We've seen this combination of types, and have already computed the result.
2167
+ Computed ( bool ) ,
2168
+ }
2169
+
2170
+ impl < ' tcx > SeenSet < ' tcx > {
2171
+ fn new ( ) -> Self {
2172
+ SeenSet ( FxHashMap :: default ( ) )
2173
+ }
2174
+ /// Mark (a, b) as `Computing`.
2175
+ fn mark_computing ( & mut self , a : Ty < ' tcx > , b : Ty < ' tcx > ) {
2176
+ self . 0 . insert ( ( a, b) , None ) ;
2177
+ }
2178
+ /// Mark (a, b) as `Computed(result)`.
2179
+ fn mark_computed ( & mut self , a : Ty < ' tcx > , b : Ty < ' tcx > , result : bool ) {
2180
+ * self . 0 . get_mut ( & ( a, b) ) . expect ( "Missing prior call to mark_computing" ) =
2181
+ Some ( result) ;
2182
+ }
2183
+ fn get ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> SeenSetResult {
2184
+ match self . 0 . get ( & ( a, b) ) {
2185
+ None => SeenSetResult :: Unseen ,
2186
+ Some ( None ) => SeenSetResult :: Computing ,
2187
+ Some ( Some ( b) ) => SeenSetResult :: Computed ( * b) ,
2188
+ }
2189
+ }
2190
+ }
2191
+ fn structurally_same_type_impl < ' tcx > (
2192
+ seen_types : & mut SeenSet < ' tcx > ,
2193
+ cx : & LateContext < ' tcx > ,
2194
+ a : Ty < ' tcx > ,
2195
+ b : Ty < ' tcx > ,
2196
+ ckind : CItemKind ,
2197
+ ) -> bool {
2198
+ debug ! ( "structurally_same_type_impl(cx, a = {:?}, b = {:?})" , a, b) ;
2199
+ match seen_types. get ( a, b) {
2200
+ // If we've already computed the result, just return the memoized result.
2201
+ SeenSetResult :: Computed ( result) => result,
2202
+ // We are already in the process of computing structural sameness for this type,
2203
+ // meaning we've found a cycle. The types are structurally same, then.
2204
+ SeenSetResult :: Computing => true ,
2205
+ // We haven't seen this combination of types at all -- compute their sameness.
2206
+ SeenSetResult :: Unseen => {
2207
+ seen_types. mark_computing ( a, b) ;
2208
+ let tcx = cx. tcx ;
2209
+ let result = if a == b || rustc_middle:: ty:: TyS :: same_type ( a, b) {
2210
+ // All nominally-same types are structurally same, too.
2211
+ true
2212
+ } else {
2213
+ // Do a full, depth-first comparison between the two.
2214
+ use rustc_middle:: ty:: TyKind :: * ;
2215
+ let a_kind = & a. kind ;
2216
+ let b_kind = & b. kind ;
2217
+
2218
+ let compare_layouts = |a, b| -> bool {
2219
+ let a_layout = & cx. layout_of ( a) . unwrap ( ) . layout . abi ;
2220
+ let b_layout = & cx. layout_of ( b) . unwrap ( ) . layout . abi ;
2221
+ debug ! ( "{:?} == {:?} = {}" , a_layout, b_layout, a_layout == b_layout) ;
2222
+ a_layout == b_layout
2223
+ } ;
2224
+
2225
+ #[ allow( rustc:: usage_of_ty_tykind) ]
2226
+ let is_primitive_or_pointer = |kind : & ty:: TyKind < ' _ > | {
2227
+ kind. is_primitive ( ) || matches ! ( kind, RawPtr ( ..) )
2228
+ } ;
2173
2229
2174
- #[ allow( rustc:: usage_of_ty_tykind) ]
2175
- let is_primitive_or_pointer =
2176
- |kind : & ty:: TyKind < ' _ > | kind. is_primitive ( ) || matches ! ( kind, RawPtr ( ..) ) ;
2177
-
2178
- match ( a_kind, b_kind) {
2179
- ( Adt ( _, a_substs) , Adt ( _, b_substs) ) => {
2180
- let a = a. subst ( cx. tcx , a_substs) ;
2181
- let b = b. subst ( cx. tcx , b_substs) ;
2182
- debug ! ( "Comparing {:?} and {:?}" , a, b) ;
2183
-
2184
- if let ( Adt ( a_def, ..) , Adt ( b_def, ..) ) = ( & a. kind , & b. kind ) {
2185
- // Grab a flattened representation of all fields.
2186
- let a_fields = a_def. variants . iter ( ) . flat_map ( |v| v. fields . iter ( ) ) ;
2187
- let b_fields = b_def. variants . iter ( ) . flat_map ( |v| v. fields . iter ( ) ) ;
2188
- compare_layouts ( a, b)
2230
+ match ( a_kind, b_kind) {
2231
+ ( Adt ( _, a_substs) , Adt ( _, b_substs) ) => {
2232
+ let a = a. subst ( cx. tcx , a_substs) ;
2233
+ let b = b. subst ( cx. tcx , b_substs) ;
2234
+ debug ! ( "Comparing {:?} and {:?}" , a, b) ;
2235
+
2236
+ if let ( Adt ( a_def, ..) , Adt ( b_def, ..) ) = ( & a. kind , & b. kind ) {
2237
+ // Grab a flattened representation of all fields.
2238
+ let a_fields =
2239
+ a_def. variants . iter ( ) . flat_map ( |v| v. fields . iter ( ) ) ;
2240
+ let b_fields =
2241
+ b_def. variants . iter ( ) . flat_map ( |v| v. fields . iter ( ) ) ;
2242
+ compare_layouts ( a, b)
2189
2243
&& a_fields. eq_by (
2190
2244
b_fields,
2191
2245
|& ty:: FieldDef { did : a_did, .. } ,
2192
2246
& ty:: FieldDef { did : b_did, .. } | {
2193
- Self :: structurally_same_type (
2247
+ structurally_same_type_impl (
2248
+ seen_types,
2194
2249
cx,
2195
2250
tcx. type_of ( a_did) ,
2196
2251
tcx. type_of ( b_did) ,
2197
2252
ckind,
2198
2253
)
2199
2254
} ,
2200
2255
)
2201
- } else {
2202
- unreachable ! ( )
2203
- }
2204
- }
2205
- ( Array ( a_ty, a_const) , Array ( b_ty, b_const) ) => {
2206
- // For arrays, we also check the constness of the type.
2207
- a_const. val == b_const. val
2208
- && Self :: structurally_same_type ( cx, a_const. ty , b_const. ty , ckind)
2209
- && Self :: structurally_same_type ( cx, a_ty, b_ty, ckind)
2210
- }
2211
- ( Slice ( a_ty) , Slice ( b_ty) ) => Self :: structurally_same_type ( cx, a_ty, b_ty, ckind) ,
2212
- ( RawPtr ( a_tymut) , RawPtr ( b_tymut) ) => {
2213
- a_tymut. mutbl == b_tymut. mutbl
2214
- && Self :: structurally_same_type ( cx, & a_tymut. ty , & b_tymut. ty , ckind)
2215
- }
2216
- ( Ref ( _a_region, a_ty, a_mut) , Ref ( _b_region, b_ty, b_mut) ) => {
2217
- // For structural sameness, we don't need the region to be same.
2218
- a_mut == b_mut && Self :: structurally_same_type ( cx, a_ty, b_ty, ckind)
2219
- }
2220
- ( FnDef ( ..) , FnDef ( ..) ) => {
2221
- let a_poly_sig = a. fn_sig ( tcx) ;
2222
- let b_poly_sig = b. fn_sig ( tcx) ;
2223
-
2224
- // As we don't compare regions, skip_binder is fine.
2225
- let a_sig = a_poly_sig. skip_binder ( ) ;
2226
- let b_sig = b_poly_sig. skip_binder ( ) ;
2227
-
2228
- ( a_sig. abi , a_sig. unsafety , a_sig. c_variadic )
2229
- == ( b_sig. abi , b_sig. unsafety , b_sig. c_variadic )
2230
- && a_sig. inputs ( ) . iter ( ) . eq_by ( b_sig. inputs ( ) . iter ( ) , |a, b| {
2231
- Self :: structurally_same_type ( cx, a, b, ckind)
2232
- } )
2233
- && Self :: structurally_same_type ( cx, a_sig. output ( ) , b_sig. output ( ) , ckind)
2234
- }
2235
- ( Tuple ( a_substs) , Tuple ( b_substs) ) => {
2236
- a_substs. types ( ) . eq_by ( b_substs. types ( ) , |a_ty, b_ty| {
2237
- Self :: structurally_same_type ( cx, a_ty, b_ty, ckind)
2238
- } )
2239
- }
2240
- // For these, it's not quite as easy to define structural-sameness quite so easily.
2241
- // For the purposes of this lint, take the conservative approach and mark them as
2242
- // not structurally same.
2243
- ( Dynamic ( ..) , Dynamic ( ..) )
2244
- | ( Error ( ..) , Error ( ..) )
2245
- | ( Closure ( ..) , Closure ( ..) )
2246
- | ( Generator ( ..) , Generator ( ..) )
2247
- | ( GeneratorWitness ( ..) , GeneratorWitness ( ..) )
2248
- | ( Projection ( ..) , Projection ( ..) )
2249
- | ( Opaque ( ..) , Opaque ( ..) ) => false ,
2250
-
2251
- // These definitely should have been caught above.
2252
- ( Bool , Bool ) | ( Char , Char ) | ( Never , Never ) | ( Str , Str ) => unreachable ! ( ) ,
2253
-
2254
- // An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a
2255
- // non-null field.
2256
- ( Adt ( ..) , other_kind) | ( other_kind, Adt ( ..) )
2257
- if is_primitive_or_pointer ( other_kind) =>
2258
- {
2259
- let ( primitive, adt) =
2260
- if is_primitive_or_pointer ( & a. kind ) { ( a, b) } else { ( b, a) } ;
2261
- if let Some ( ty) = crate :: types:: repr_nullable_ptr ( cx, adt, ckind) {
2262
- ty == primitive
2263
- } else {
2264
- compare_layouts ( a, b)
2265
- }
2256
+ } else {
2257
+ unreachable ! ( )
2258
+ }
2259
+ }
2260
+ ( Array ( a_ty, a_const) , Array ( b_ty, b_const) ) => {
2261
+ // For arrays, we also check the constness of the type.
2262
+ a_const. val == b_const. val
2263
+ && structurally_same_type_impl (
2264
+ seen_types, cx, a_const. ty , b_const. ty , ckind,
2265
+ )
2266
+ && structurally_same_type_impl (
2267
+ seen_types, cx, a_ty, b_ty, ckind,
2268
+ )
2269
+ }
2270
+ ( Slice ( a_ty) , Slice ( b_ty) ) => {
2271
+ structurally_same_type_impl ( seen_types, cx, a_ty, b_ty, ckind)
2272
+ }
2273
+ ( RawPtr ( a_tymut) , RawPtr ( b_tymut) ) => {
2274
+ a_tymut. mutbl == b_tymut. mutbl
2275
+ && structurally_same_type_impl (
2276
+ seen_types,
2277
+ cx,
2278
+ & a_tymut. ty ,
2279
+ & b_tymut. ty ,
2280
+ ckind,
2281
+ )
2282
+ }
2283
+ ( Ref ( _a_region, a_ty, a_mut) , Ref ( _b_region, b_ty, b_mut) ) => {
2284
+ // For structural sameness, we don't need the region to be same.
2285
+ a_mut == b_mut
2286
+ && structurally_same_type_impl (
2287
+ seen_types, cx, a_ty, b_ty, ckind,
2288
+ )
2289
+ }
2290
+ ( FnDef ( ..) , FnDef ( ..) ) => {
2291
+ let a_poly_sig = a. fn_sig ( tcx) ;
2292
+ let b_poly_sig = b. fn_sig ( tcx) ;
2293
+
2294
+ // As we don't compare regions, skip_binder is fine.
2295
+ let a_sig = a_poly_sig. skip_binder ( ) ;
2296
+ let b_sig = b_poly_sig. skip_binder ( ) ;
2297
+
2298
+ ( a_sig. abi , a_sig. unsafety , a_sig. c_variadic )
2299
+ == ( b_sig. abi , b_sig. unsafety , b_sig. c_variadic )
2300
+ && a_sig. inputs ( ) . iter ( ) . eq_by ( b_sig. inputs ( ) . iter ( ) , |a, b| {
2301
+ structurally_same_type_impl ( seen_types, cx, a, b, ckind)
2302
+ } )
2303
+ && structurally_same_type_impl (
2304
+ seen_types,
2305
+ cx,
2306
+ a_sig. output ( ) ,
2307
+ b_sig. output ( ) ,
2308
+ ckind,
2309
+ )
2310
+ }
2311
+ ( Tuple ( a_substs) , Tuple ( b_substs) ) => {
2312
+ a_substs. types ( ) . eq_by ( b_substs. types ( ) , |a_ty, b_ty| {
2313
+ structurally_same_type_impl ( seen_types, cx, a_ty, b_ty, ckind)
2314
+ } )
2315
+ }
2316
+ // For these, it's not quite as easy to define structural-sameness quite so easily.
2317
+ // For the purposes of this lint, take the conservative approach and mark them as
2318
+ // not structurally same.
2319
+ ( Dynamic ( ..) , Dynamic ( ..) )
2320
+ | ( Error ( ..) , Error ( ..) )
2321
+ | ( Closure ( ..) , Closure ( ..) )
2322
+ | ( Generator ( ..) , Generator ( ..) )
2323
+ | ( GeneratorWitness ( ..) , GeneratorWitness ( ..) )
2324
+ | ( Projection ( ..) , Projection ( ..) )
2325
+ | ( Opaque ( ..) , Opaque ( ..) ) => false ,
2326
+
2327
+ // These definitely should have been caught above.
2328
+ ( Bool , Bool ) | ( Char , Char ) | ( Never , Never ) | ( Str , Str ) => {
2329
+ unreachable ! ( )
2330
+ }
2331
+
2332
+ // An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a
2333
+ // non-null field.
2334
+ ( Adt ( ..) , other_kind) | ( other_kind, Adt ( ..) )
2335
+ if is_primitive_or_pointer ( other_kind) =>
2336
+ {
2337
+ let ( primitive, adt) =
2338
+ if is_primitive_or_pointer ( & a. kind ) { ( a, b) } else { ( b, a) } ;
2339
+ if let Some ( ty) = crate :: types:: repr_nullable_ptr ( cx, adt, ckind) {
2340
+ ty == primitive
2341
+ } else {
2342
+ compare_layouts ( a, b)
2343
+ }
2344
+ }
2345
+ // Otherwise, just compare the layouts. This may fail to lint for some
2346
+ // incompatible types, but at the very least, will stop reads into
2347
+ // uninitialised memory.
2348
+ _ => compare_layouts ( a, b) ,
2349
+ }
2350
+ } ;
2351
+ seen_types. mark_computed ( a, b, result) ;
2352
+ result
2266
2353
}
2267
- // Otherwise, just compare the layouts. This may fail to lint for some
2268
- // incompatible types, but at the very least, will stop reads into
2269
- // uninitialised memory.
2270
- _ => compare_layouts ( a, b) ,
2271
2354
}
2272
2355
}
2356
+ let mut seen_types = SeenSet :: new ( ) ;
2357
+ structurally_same_type_impl ( & mut seen_types, cx, a, b, ckind)
2273
2358
}
2274
2359
}
2275
2360
0 commit comments