Skip to content

Commit 6b09c37

Browse files
committed
Auto merge of #73990 - jumbatm:clashing-extern-decl, r=nagisa
Fix incorrect clashing_extern_declarations warnings. Fixes #73735, fixes #73872. Fix clashing_extern_declarations warning for `#[repr(transparent)]` structs and safely-FFI-convertible enums, and not warning for clashes of struct members of different types, but the same size. r? @nagisa
2 parents 2186722 + 0bd292d commit 6b09c37

File tree

6 files changed

+456
-161
lines changed

6 files changed

+456
-161
lines changed

src/librustc_lint/builtin.rs

+82-21
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
//! If you define a new `LateLintPass`, you will also need to add it to the
2121
//! `late_lint_methods!` invocation in `lib.rs`.
2222
23-
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
23+
use crate::{
24+
types::CItemKind, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
25+
};
2426
use rustc_ast::ast::{self, Expr};
2527
use rustc_ast::attr::{self, HasAttrs};
2628
use rustc_ast::tokenstream::{TokenStream, TokenTree};
@@ -36,14 +38,14 @@ use rustc_hir::def_id::DefId;
3638
use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind};
3739
use rustc_hir::{HirId, HirIdSet, Node};
3840
use rustc_middle::lint::LintDiagnosticBuilder;
39-
use rustc_middle::ty::subst::GenericArgKind;
41+
use rustc_middle::ty::subst::{GenericArgKind, Subst};
4042
use rustc_middle::ty::{self, Ty, TyCtxt};
4143
use rustc_session::lint::FutureIncompatibleInfo;
4244
use rustc_span::edition::Edition;
4345
use rustc_span::source_map::Spanned;
4446
use rustc_span::symbol::{kw, sym, Ident, Symbol};
4547
use rustc_span::{BytePos, Span};
46-
use rustc_target::abi::VariantIdx;
48+
use rustc_target::abi::{LayoutOf, VariantIdx};
4749
use rustc_trait_selection::traits::misc::can_type_implement_copy;
4850

4951
use crate::nonstandard_style::{method_context, MethodLateContext};
@@ -2144,7 +2146,13 @@ impl ClashingExternDeclarations {
21442146
/// Checks whether two types are structurally the same enough that the declarations shouldn't
21452147
/// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
21462148
/// with the same members (as the declarations shouldn't clash).
2147-
fn structurally_same_type<'tcx>(cx: &LateContext<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
2149+
fn structurally_same_type<'tcx>(
2150+
cx: &LateContext<'tcx>,
2151+
a: Ty<'tcx>,
2152+
b: Ty<'tcx>,
2153+
ckind: CItemKind,
2154+
) -> bool {
2155+
debug!("structurally_same_type(cx, a = {:?}, b = {:?})", a, b);
21482156
let tcx = cx.tcx;
21492157
if a == b || rustc_middle::ty::TyS::same_type(a, b) {
21502158
// All nominally-same types are structurally same, too.
@@ -2155,47 +2163,77 @@ impl ClashingExternDeclarations {
21552163
let a_kind = &a.kind;
21562164
let b_kind = &b.kind;
21572165

2166+
let compare_layouts = |a, b| -> bool {
2167+
let a_layout = &cx.layout_of(a).unwrap().layout.abi;
2168+
let b_layout = &cx.layout_of(b).unwrap().layout.abi;
2169+
debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout);
2170+
a_layout == b_layout
2171+
};
2172+
2173+
#[allow(rustc::usage_of_ty_tykind)]
2174+
let is_primitive_or_pointer =
2175+
|kind: &ty::TyKind<'_>| kind.is_primitive() || matches!(kind, RawPtr(..));
2176+
21582177
match (a_kind, b_kind) {
2159-
(Adt(..), Adt(..)) => {
2160-
// Adts are pretty straightforward: just compare the layouts.
2161-
use rustc_target::abi::LayoutOf;
2162-
let a_layout = cx.layout_of(a).unwrap().layout;
2163-
let b_layout = cx.layout_of(b).unwrap().layout;
2164-
a_layout == b_layout
2178+
(Adt(_, a_substs), Adt(_, b_substs)) => {
2179+
let a = a.subst(cx.tcx, a_substs);
2180+
let b = b.subst(cx.tcx, b_substs);
2181+
debug!("Comparing {:?} and {:?}", a, b);
2182+
2183+
if let (Adt(a_def, ..), Adt(b_def, ..)) = (&a.kind, &b.kind) {
2184+
// Grab a flattened representation of all fields.
2185+
let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter());
2186+
let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter());
2187+
compare_layouts(a, b)
2188+
&& a_fields.eq_by(
2189+
b_fields,
2190+
|&ty::FieldDef { did: a_did, .. },
2191+
&ty::FieldDef { did: b_did, .. }| {
2192+
Self::structurally_same_type(
2193+
cx,
2194+
tcx.type_of(a_did),
2195+
tcx.type_of(b_did),
2196+
ckind,
2197+
)
2198+
},
2199+
)
2200+
} else {
2201+
unreachable!()
2202+
}
21652203
}
21662204
(Array(a_ty, a_const), Array(b_ty, b_const)) => {
21672205
// For arrays, we also check the constness of the type.
21682206
a_const.val == b_const.val
2169-
&& Self::structurally_same_type(cx, a_const.ty, b_const.ty)
2170-
&& Self::structurally_same_type(cx, a_ty, b_ty)
2207+
&& Self::structurally_same_type(cx, a_const.ty, b_const.ty, ckind)
2208+
&& Self::structurally_same_type(cx, a_ty, b_ty, ckind)
21712209
}
2172-
(Slice(a_ty), Slice(b_ty)) => Self::structurally_same_type(cx, a_ty, b_ty),
2210+
(Slice(a_ty), Slice(b_ty)) => Self::structurally_same_type(cx, a_ty, b_ty, ckind),
21732211
(RawPtr(a_tymut), RawPtr(b_tymut)) => {
21742212
a_tymut.mutbl == a_tymut.mutbl
2175-
&& Self::structurally_same_type(cx, &a_tymut.ty, &b_tymut.ty)
2213+
&& Self::structurally_same_type(cx, &a_tymut.ty, &b_tymut.ty, ckind)
21762214
}
21772215
(Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
21782216
// For structural sameness, we don't need the region to be same.
2179-
a_mut == b_mut && Self::structurally_same_type(cx, a_ty, b_ty)
2217+
a_mut == b_mut && Self::structurally_same_type(cx, a_ty, b_ty, ckind)
21802218
}
21812219
(FnDef(..), FnDef(..)) => {
2182-
// As we don't compare regions, skip_binder is fine.
21832220
let a_poly_sig = a.fn_sig(tcx);
21842221
let b_poly_sig = b.fn_sig(tcx);
21852222

2223+
// As we don't compare regions, skip_binder is fine.
21862224
let a_sig = a_poly_sig.skip_binder();
21872225
let b_sig = b_poly_sig.skip_binder();
21882226

21892227
(a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
21902228
== (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
21912229
&& a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
2192-
Self::structurally_same_type(cx, a, b)
2230+
Self::structurally_same_type(cx, a, b, ckind)
21932231
})
2194-
&& Self::structurally_same_type(cx, a_sig.output(), b_sig.output())
2232+
&& Self::structurally_same_type(cx, a_sig.output(), b_sig.output(), ckind)
21952233
}
21962234
(Tuple(a_substs), Tuple(b_substs)) => {
21972235
a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| {
2198-
Self::structurally_same_type(cx, a_ty, b_ty)
2236+
Self::structurally_same_type(cx, a_ty, b_ty, ckind)
21992237
})
22002238
}
22012239
// For these, it's not quite as easy to define structural-sameness quite so easily.
@@ -2208,9 +2246,27 @@ impl ClashingExternDeclarations {
22082246
| (GeneratorWitness(..), GeneratorWitness(..))
22092247
| (Projection(..), Projection(..))
22102248
| (Opaque(..), Opaque(..)) => false,
2249+
22112250
// These definitely should have been caught above.
22122251
(Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
2213-
_ => false,
2252+
2253+
// An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a
2254+
// non-null field.
2255+
(Adt(..), other_kind) | (other_kind, Adt(..))
2256+
if is_primitive_or_pointer(other_kind) =>
2257+
{
2258+
let (primitive, adt) =
2259+
if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) };
2260+
if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
2261+
ty == primitive
2262+
} else {
2263+
compare_layouts(a, b)
2264+
}
2265+
}
2266+
// Otherwise, just compare the layouts. This may fail to lint for some
2267+
// incompatible types, but at the very least, will stop reads into
2268+
// uninitialised memory.
2269+
_ => compare_layouts(a, b),
22142270
}
22152271
}
22162272
}
@@ -2231,7 +2287,12 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
22312287
existing_hid, existing_decl_ty, this_fi.hir_id, this_decl_ty
22322288
);
22332289
// Check that the declarations match.
2234-
if !Self::structurally_same_type(cx, existing_decl_ty, this_decl_ty) {
2290+
if !Self::structurally_same_type(
2291+
cx,
2292+
existing_decl_ty,
2293+
this_decl_ty,
2294+
CItemKind::Declaration,
2295+
) {
22352296
let orig_fi = tcx.hir().expect_foreign_item(existing_hid);
22362297
let orig = Self::name_of_extern_decl(tcx, orig_fi);
22372298

0 commit comments

Comments
 (0)