@@ -2153,123 +2153,208 @@ impl ClashingExternDeclarations {
21532153 b : Ty < ' tcx > ,
21542154 ckind : CItemKind ,
21552155 ) -> 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+ } ;
21732229
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)
21892243 && a_fields. eq_by (
21902244 b_fields,
21912245 |& ty:: FieldDef { did : a_did, .. } ,
21922246 & ty:: FieldDef { did : b_did, .. } | {
2193- Self :: structurally_same_type (
2247+ structurally_same_type_impl (
2248+ seen_types,
21942249 cx,
21952250 tcx. type_of ( a_did) ,
21962251 tcx. type_of ( b_did) ,
21972252 ckind,
21982253 )
21992254 } ,
22002255 )
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
22662353 }
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) ,
22712354 }
22722355 }
2356+ let mut seen_types = SeenSet :: new ( ) ;
2357+ structurally_same_type_impl ( & mut seen_types, cx, a, b, ckind)
22732358 }
22742359}
22752360
0 commit comments