@@ -29,6 +29,7 @@ use rustc_ast::visit::{FnCtxt, FnKind};
29
29
use rustc_ast::{self as ast, *};
30
30
use rustc_ast_pretty::pprust::{self, expr_to_string};
31
31
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
32
+ use rustc_data_structures::stack::ensure_sufficient_stack;
32
33
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
33
34
use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
34
35
use rustc_feature::{GateIssue, Stability};
@@ -2153,123 +2154,152 @@ impl ClashingExternDeclarations {
2153
2154
b: Ty<'tcx>,
2154
2155
ckind: CItemKind,
2155
2156
) -> 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
- };
2157
+ fn structurally_same_type_impl<'tcx>(
2158
+ seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>,
2159
+ cx: &LateContext<'tcx>,
2160
+ a: Ty<'tcx>,
2161
+ b: Ty<'tcx>,
2162
+ ckind: CItemKind,
2163
+ ) -> bool {
2164
+ debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b);
2165
+ if !seen_types.insert((a, b)) {
2166
+ // We've encountered a cycle. There's no point going any further -- the types are
2167
+ // structurally the same.
2168
+ return true;
2169
+ }
2170
+ let tcx = cx.tcx;
2171
+ if a == b || rustc_middle::ty::TyS::same_type(a, b) {
2172
+ // All nominally-same types are structurally same, too.
2173
+ true
2174
+ } else {
2175
+ // Do a full, depth-first comparison between the two.
2176
+ use rustc_middle::ty::TyKind::*;
2177
+ let a_kind = &a.kind;
2178
+ let b_kind = &b.kind;
2179
+
2180
+ let compare_layouts = |a, b| -> bool {
2181
+ let a_layout = &cx.layout_of(a).unwrap().layout.abi;
2182
+ let b_layout = &cx.layout_of(b).unwrap().layout.abi;
2183
+ debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout);
2184
+ a_layout == b_layout
2185
+ };
2186
+
2187
+ #[allow(rustc::usage_of_ty_tykind)]
2188
+ let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| {
2189
+ kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..))
2190
+ };
2173
2191
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)
2192
+ ensure_sufficient_stack(|| {
2193
+ match (a_kind, b_kind) {
2194
+ (Adt(a_def, a_substs), Adt(b_def, b_substs)) => {
2195
+ let a = a.subst(cx.tcx, a_substs);
2196
+ let b = b.subst(cx.tcx, b_substs);
2197
+ debug!("Comparing {:?} and {:?}", a, b);
2198
+
2199
+ // Grab a flattened representation of all fields.
2200
+ let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter());
2201
+ let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter());
2202
+ compare_layouts(a, b)
2189
2203
&& a_fields.eq_by(
2190
2204
b_fields,
2191
2205
|&ty::FieldDef { did: a_did, .. },
2192
2206
&ty::FieldDef { did: b_did, .. }| {
2193
- Self::structurally_same_type(
2207
+ structurally_same_type_impl(
2208
+ seen_types,
2194
2209
cx,
2195
2210
tcx.type_of(a_did),
2196
2211
tcx.type_of(b_did),
2197
2212
ckind,
2198
2213
)
2199
2214
},
2200
2215
)
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)
2216
+ }
2217
+ (Array(a_ty, a_const), Array(b_ty, b_const)) => {
2218
+ // For arrays, we also check the constness of the type.
2219
+ a_const.val == b_const.val
2220
+ && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
2221
+ }
2222
+ (Slice(a_ty), Slice(b_ty)) => {
2223
+ structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
2224
+ }
2225
+ (RawPtr(a_tymut), RawPtr(b_tymut)) => {
2226
+ a_tymut.mutbl == b_tymut.mutbl
2227
+ && structurally_same_type_impl(
2228
+ seen_types,
2229
+ cx,
2230
+ &a_tymut.ty,
2231
+ &b_tymut.ty,
2232
+ ckind,
2233
+ )
2234
+ }
2235
+ (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
2236
+ // For structural sameness, we don't need the region to be same.
2237
+ a_mut == b_mut
2238
+ && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
2239
+ }
2240
+ (FnDef(..), FnDef(..)) => {
2241
+ let a_poly_sig = a.fn_sig(tcx);
2242
+ let b_poly_sig = b.fn_sig(tcx);
2243
+
2244
+ // As we don't compare regions, skip_binder is fine.
2245
+ let a_sig = a_poly_sig.skip_binder();
2246
+ let b_sig = b_poly_sig.skip_binder();
2247
+
2248
+ (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
2249
+ == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
2250
+ && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
2251
+ structurally_same_type_impl(seen_types, cx, a, b, ckind)
2252
+ })
2253
+ && structurally_same_type_impl(
2254
+ seen_types,
2255
+ cx,
2256
+ a_sig.output(),
2257
+ b_sig.output(),
2258
+ ckind,
2259
+ )
2260
+ }
2261
+ (Tuple(a_substs), Tuple(b_substs)) => {
2262
+ a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| {
2263
+ structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
2264
+ })
2265
+ }
2266
+ // For these, it's not quite as easy to define structural-sameness quite so easily.
2267
+ // For the purposes of this lint, take the conservative approach and mark them as
2268
+ // not structurally same.
2269
+ (Dynamic(..), Dynamic(..))
2270
+ | (Error(..), Error(..))
2271
+ | (Closure(..), Closure(..))
2272
+ | (Generator(..), Generator(..))
2273
+ | (GeneratorWitness(..), GeneratorWitness(..))
2274
+ | (Projection(..), Projection(..))
2275
+ | (Opaque(..), Opaque(..)) => false,
2276
+
2277
+ // These definitely should have been caught above.
2278
+ (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
2279
+
2280
+ // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
2281
+ // enum layout optimisation is being applied.
2282
+ (Adt(..), other_kind) | (other_kind, Adt(..))
2283
+ if is_primitive_or_pointer(other_kind) =>
2284
+ {
2285
+ let (primitive, adt) =
2286
+ if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) };
2287
+ if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
2288
+ ty == primitive
2289
+ } else {
2290
+ compare_layouts(a, b)
2291
+ }
2292
+ }
2293
+ // Otherwise, just compare the layouts. This may fail to lint for some
2294
+ // incompatible types, but at the very least, will stop reads into
2295
+ // uninitialised memory.
2296
+ _ => compare_layouts(a, b),
2265
2297
}
2266
- }
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),
2298
+ })
2271
2299
}
2272
2300
}
2301
+ let mut seen_types = FxHashSet::default();
2302
+ structurally_same_type_impl(&mut seen_types, cx, a, b, ckind)
2273
2303
}
2274
2304
}
2275
2305
0 commit comments