Skip to content

Commit 470d759

Browse files
committed
Fix missed same-sized member clash in ClashingExternDeclarations.
1 parent 9182910 commit 470d759

File tree

3 files changed

+73
-12
lines changed

3 files changed

+73
-12
lines changed

src/librustc_lint/builtin.rs

+32-5
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ use rustc_hir::def_id::DefId;
3636
use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind};
3737
use rustc_hir::{HirId, HirIdSet, Node};
3838
use rustc_middle::lint::LintDiagnosticBuilder;
39-
use rustc_middle::ty::subst::GenericArgKind;
39+
use rustc_middle::ty::subst::{GenericArgKind, Subst};
4040
use rustc_middle::ty::{self, Ty, TyCtxt};
4141
use rustc_session::lint::FutureIncompatibleInfo;
4242
use rustc_span::edition::Edition;
4343
use rustc_span::source_map::Spanned;
4444
use rustc_span::symbol::{kw, sym, Ident, Symbol};
4545
use rustc_span::{BytePos, Span};
46-
use rustc_target::abi::VariantIdx;
46+
use rustc_target::abi::{LayoutOf, VariantIdx};
4747
use rustc_trait_selection::traits::misc::can_type_implement_copy;
4848

4949
use crate::nonstandard_style::{method_context, MethodLateContext};
@@ -2131,6 +2131,7 @@ impl ClashingExternDeclarations {
21312131
/// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
21322132
/// with the same members (as the declarations shouldn't clash).
21332133
fn structurally_same_type<'tcx>(cx: &LateContext<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
2134+
debug!("structurally_same_type(cx, a = {:?}, b = {:?})", a, b);
21342135
let tcx = cx.tcx;
21352136
if a == b || rustc_middle::ty::TyS::same_type(a, b) {
21362137
// All nominally-same types are structurally same, too.
@@ -2141,17 +2142,43 @@ impl ClashingExternDeclarations {
21412142
let a_kind = &a.kind;
21422143
let b_kind = &b.kind;
21432144

2144-
use rustc_target::abi::LayoutOf;
21452145
let compare_layouts = |a, b| -> bool {
2146-
&cx.layout_of(a).unwrap().layout.abi == &cx.layout_of(b).unwrap().layout.abi
2146+
let a_layout = &cx.layout_of(a).unwrap().layout.abi;
2147+
let b_layout = &cx.layout_of(b).unwrap().layout.abi;
2148+
debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout);
2149+
a_layout == b_layout
21472150
};
21482151

21492152
#[allow(rustc::usage_of_ty_tykind)]
21502153
let is_primitive_or_pointer =
21512154
|kind: &ty::TyKind<'_>| kind.is_primitive() || matches!(kind, RawPtr(..));
21522155

21532156
match (a_kind, b_kind) {
2154-
(Adt(..), Adt(..)) => compare_layouts(a, b),
2157+
(Adt(_, a_substs), Adt(_, b_substs)) => {
2158+
let a = a.subst(cx.tcx, a_substs);
2159+
let b = b.subst(cx.tcx, b_substs);
2160+
debug!("Comparing {:?} and {:?}", a, b);
2161+
2162+
if let (Adt(a_def, ..), Adt(b_def, ..)) = (&a.kind, &b.kind) {
2163+
// Grab a flattened representation of all fields.
2164+
let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter());
2165+
let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter());
2166+
compare_layouts(a, b)
2167+
&& a_fields.eq_by(
2168+
b_fields,
2169+
|&ty::FieldDef { did: a_did, .. },
2170+
&ty::FieldDef { did: b_did, .. }| {
2171+
Self::structurally_same_type(
2172+
cx,
2173+
tcx.type_of(a_did),
2174+
tcx.type_of(b_did),
2175+
)
2176+
},
2177+
)
2178+
} else {
2179+
unreachable!()
2180+
}
2181+
}
21552182
(Array(a_ty, a_const), Array(b_ty, b_const)) => {
21562183
// For arrays, we also check the constness of the type.
21572184
a_const.val == b_const.val

src/test/ui/lint/clashing-extern-fn.rs

+22
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,28 @@ mod sameish_members {
174174
}
175175
}
176176

177+
mod same_sized_members_clash {
178+
mod a {
179+
#[repr(C)]
180+
struct Point3 {
181+
x: f32,
182+
y: f32,
183+
z: f32,
184+
}
185+
extern "C" { fn origin() -> Point3; }
186+
}
187+
mod b {
188+
#[repr(C)]
189+
struct Point3 {
190+
x: i32,
191+
y: i32,
192+
z: i32, // NOTE: Incorrectly redeclared as i32
193+
}
194+
extern "C" { fn origin() -> Point3; }
195+
//~^ WARN `origin` redeclared with a different signature
196+
}
197+
}
198+
177199
mod transparent {
178200
#[repr(transparent)]
179201
struct T(usize);

src/test/ui/lint/clashing-extern-fn.stderr

+19-7
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,20 @@ LL | fn draw_point(p: Point);
105105
= note: expected `unsafe extern "C" fn(sameish_members::a::Point)`
106106
found `unsafe extern "C" fn(sameish_members::b::Point)`
107107

108+
warning: `origin` redeclared with a different signature
109+
--> $DIR/clashing-extern-fn.rs:194:22
110+
|
111+
LL | extern "C" { fn origin() -> Point3; }
112+
| ---------------------- `origin` previously declared here
113+
...
114+
LL | extern "C" { fn origin() -> Point3; }
115+
| ^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
116+
|
117+
= note: expected `unsafe extern "C" fn() -> same_sized_members_clash::a::Point3`
118+
found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3`
119+
108120
warning: `transparent_incorrect` redeclared with a different signature
109-
--> $DIR/clashing-extern-fn.rs:195:13
121+
--> $DIR/clashing-extern-fn.rs:217:13
110122
|
111123
LL | fn transparent_incorrect() -> T;
112124
| -------------------------------- `transparent_incorrect` previously declared here
@@ -118,7 +130,7 @@ LL | fn transparent_incorrect() -> isize;
118130
found `unsafe extern "C" fn() -> isize`
119131

120132
warning: `missing_return_type` redeclared with a different signature
121-
--> $DIR/clashing-extern-fn.rs:213:13
133+
--> $DIR/clashing-extern-fn.rs:235:13
122134
|
123135
LL | fn missing_return_type() -> usize;
124136
| ---------------------------------- `missing_return_type` previously declared here
@@ -130,7 +142,7 @@ LL | fn missing_return_type();
130142
found `unsafe extern "C" fn()`
131143

132144
warning: `non_zero_usize` redeclared with a different signature
133-
--> $DIR/clashing-extern-fn.rs:231:13
145+
--> $DIR/clashing-extern-fn.rs:253:13
134146
|
135147
LL | fn non_zero_usize() -> core::num::NonZeroUsize;
136148
| ----------------------------------------------- `non_zero_usize` previously declared here
@@ -142,7 +154,7 @@ LL | fn non_zero_usize() -> usize;
142154
found `unsafe extern "C" fn() -> usize`
143155

144156
warning: `non_null_ptr` redeclared with a different signature
145-
--> $DIR/clashing-extern-fn.rs:233:13
157+
--> $DIR/clashing-extern-fn.rs:255:13
146158
|
147159
LL | fn non_null_ptr() -> core::ptr::NonNull<usize>;
148160
| ----------------------------------------------- `non_null_ptr` previously declared here
@@ -154,7 +166,7 @@ LL | fn non_null_ptr() -> *const usize;
154166
found `unsafe extern "C" fn() -> *const usize`
155167

156168
warning: `option_non_zero_usize_incorrect` redeclared with a different signature
157-
--> $DIR/clashing-extern-fn.rs:259:13
169+
--> $DIR/clashing-extern-fn.rs:281:13
158170
|
159171
LL | fn option_non_zero_usize_incorrect() -> usize;
160172
| ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
@@ -166,7 +178,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize;
166178
found `unsafe extern "C" fn() -> isize`
167179

168180
warning: `option_non_null_ptr_incorrect` redeclared with a different signature
169-
--> $DIR/clashing-extern-fn.rs:261:13
181+
--> $DIR/clashing-extern-fn.rs:283:13
170182
|
171183
LL | fn option_non_null_ptr_incorrect() -> *const usize;
172184
| --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
@@ -177,5 +189,5 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize;
177189
= note: expected `unsafe extern "C" fn() -> *const usize`
178190
found `unsafe extern "C" fn() -> *const isize`
179191

180-
warning: 14 warnings emitted
192+
warning: 15 warnings emitted
181193

0 commit comments

Comments
 (0)