use rustc_ast::visit::{FnCtxt, FnKind};
use rustc_ast_pretty::pprust::{self, expr_to_string};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
use rustc_feature::{GateIssue, Stability};
kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..))
};
- match (a_kind, b_kind) {
- (Adt(a_def, a_substs), Adt(b_def, b_substs)) => {
- let a = a.subst(cx.tcx, a_substs);
- let b = b.subst(cx.tcx, b_substs);
- debug!("Comparing {:?} and {:?}", a, b);
+ ensure_sufficient_stack(|| {
+ match (a_kind, b_kind) {
+ (Adt(a_def, a_substs), Adt(b_def, b_substs)) => {
+ let a = a.subst(cx.tcx, a_substs);
+ let b = b.subst(cx.tcx, b_substs);
+ debug!("Comparing {:?} and {:?}", a, b);
- // Grab a flattened representation of all fields.
- let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter());
- let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter());
- compare_layouts(a, b)
+ // Grab a flattened representation of all fields.
+ let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter());
+ let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter());
+ compare_layouts(a, b)
&& a_fields.eq_by(
b_fields,
|&ty::FieldDef { did: a_did, .. },
)
},
)
- }
- (Array(a_ty, a_const), Array(b_ty, b_const)) => {
- // For arrays, we also check the constness of the type.
- a_const.val == b_const.val
- && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
- }
- (Slice(a_ty), Slice(b_ty)) => {
- structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
- }
- (RawPtr(a_tymut), RawPtr(b_tymut)) => {
- a_tymut.mutbl == b_tymut.mutbl
- && structurally_same_type_impl(
- seen_types,
- cx,
- &a_tymut.ty,
- &b_tymut.ty,
- ckind,
- )
- }
- (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
- // For structural sameness, we don't need the region to be same.
- a_mut == b_mut
- && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
- }
- (FnDef(..), FnDef(..)) => {
- let a_poly_sig = a.fn_sig(tcx);
- let b_poly_sig = b.fn_sig(tcx);
-
- // As we don't compare regions, skip_binder is fine.
- let a_sig = a_poly_sig.skip_binder();
- let b_sig = b_poly_sig.skip_binder();
-
- (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
- == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
- && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
- structurally_same_type_impl(seen_types, cx, a, b, ckind)
- })
- && structurally_same_type_impl(
- seen_types,
- cx,
- a_sig.output(),
- b_sig.output(),
- ckind,
- )
- }
- (Tuple(a_substs), Tuple(b_substs)) => {
- a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| {
+ }
+ (Array(a_ty, a_const), Array(b_ty, b_const)) => {
+ // For arrays, we also check the constness of the type.
+ a_const.val == b_const.val
+ && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+ }
+ (Slice(a_ty), Slice(b_ty)) => {
structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
- })
- }
- // For these, it's not quite as easy to define structural-sameness quite so easily.
- // For the purposes of this lint, take the conservative approach and mark them as
- // not structurally same.
- (Dynamic(..), Dynamic(..))
- | (Error(..), Error(..))
- | (Closure(..), Closure(..))
- | (Generator(..), Generator(..))
- | (GeneratorWitness(..), GeneratorWitness(..))
- | (Projection(..), Projection(..))
- | (Opaque(..), Opaque(..)) => false,
-
- // These definitely should have been caught above.
- (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
-
- // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
- // enum layout optimisation is being applied.
- (Adt(..), other_kind) | (other_kind, Adt(..))
- if is_primitive_or_pointer(other_kind) =>
- {
- let (primitive, adt) =
- if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) };
- if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
- ty == primitive
- } else {
- compare_layouts(a, b)
}
+ (RawPtr(a_tymut), RawPtr(b_tymut)) => {
+ a_tymut.mutbl == b_tymut.mutbl
+ && structurally_same_type_impl(
+ seen_types,
+ cx,
+ &a_tymut.ty,
+ &b_tymut.ty,
+ ckind,
+ )
+ }
+ (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
+ // For structural sameness, we don't need the region to be same.
+ a_mut == b_mut
+ && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+ }
+ (FnDef(..), FnDef(..)) => {
+ let a_poly_sig = a.fn_sig(tcx);
+ let b_poly_sig = b.fn_sig(tcx);
+
+ // As we don't compare regions, skip_binder is fine.
+ let a_sig = a_poly_sig.skip_binder();
+ let b_sig = b_poly_sig.skip_binder();
+
+ (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
+ == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
+ && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
+ structurally_same_type_impl(seen_types, cx, a, b, ckind)
+ })
+ && structurally_same_type_impl(
+ seen_types,
+ cx,
+ a_sig.output(),
+ b_sig.output(),
+ ckind,
+ )
+ }
+ (Tuple(a_substs), Tuple(b_substs)) => {
+ a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| {
+ structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+ })
+ }
+ // For these, it's not quite as easy to define structural-sameness quite so easily.
+ // For the purposes of this lint, take the conservative approach and mark them as
+ // not structurally same.
+ (Dynamic(..), Dynamic(..))
+ | (Error(..), Error(..))
+ | (Closure(..), Closure(..))
+ | (Generator(..), Generator(..))
+ | (GeneratorWitness(..), GeneratorWitness(..))
+ | (Projection(..), Projection(..))
+ | (Opaque(..), Opaque(..)) => false,
+
+ // These definitely should have been caught above.
+ (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
+
+ // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
+ // enum layout optimisation is being applied.
+ (Adt(..), other_kind) | (other_kind, Adt(..))
+ if is_primitive_or_pointer(other_kind) =>
+ {
+ let (primitive, adt) =
+ if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) };
+ if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
+ ty == primitive
+ } else {
+ compare_layouts(a, b)
+ }
+ }
+ // Otherwise, just compare the layouts. This may fail to lint for some
+ // incompatible types, but at the very least, will stop reads into
+ // uninitialised memory.
+ _ => compare_layouts(a, b),
}
- // Otherwise, just compare the layouts. This may fail to lint for some
- // incompatible types, but at the very least, will stop reads into
- // uninitialised memory.
- _ => compare_layouts(a, b),
- }
+ })
}
}
let mut seen_types = FxHashSet::default();