Skip to content

Commit a94bff8

Browse files
authored
Rollup merge of rust-lang#75885 - jumbatm:issue75739-clashing-extern-declarations-transparent-nonzero, r=lcnr
Fix another clashing_extern_declarations false positive. Fixes rust-lang#75739. Fix another clashing_extern_declarations false positive, this time for transparent newtype with a non-zero member. r? @lcnr
2 parents 230b10b + 352df40 commit a94bff8

File tree

4 files changed

+135
-21
lines changed

4 files changed

+135
-21
lines changed

Diff for: src/librustc_lint/builtin.rs

+35
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use rustc_hir::def::{DefKind, Res};
3838
use rustc_hir::def_id::DefId;
3939
use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind};
4040
use rustc_hir::{HirId, HirIdSet, Node};
41+
use rustc_index::vec::Idx;
4142
use rustc_middle::lint::LintDiagnosticBuilder;
4243
use rustc_middle::ty::subst::{GenericArgKind, Subst};
4344
use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
@@ -2162,6 +2163,40 @@ impl ClashingExternDeclarations {
21622163
ckind: CItemKind,
21632164
) -> bool {
21642165
debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b);
2166+
let tcx = cx.tcx;
2167+
2168+
// Given a transparent newtype, reach through and grab the inner
2169+
// type unless the newtype makes the type non-null.
2170+
let non_transparent_ty = |ty: Ty<'tcx>| -> Ty<'tcx> {
2171+
let mut ty = ty;
2172+
loop {
2173+
if let ty::Adt(def, substs) = ty.kind {
2174+
let is_transparent = def.subst(tcx, substs).repr.transparent();
2175+
let is_non_null = crate::types::nonnull_optimization_guaranteed(tcx, &def);
2176+
debug!(
2177+
"non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}",
2178+
ty, is_transparent, is_non_null
2179+
);
2180+
if is_transparent && !is_non_null {
2181+
debug_assert!(def.variants.len() == 1);
2182+
let v = &def.variants[VariantIdx::new(0)];
2183+
ty = v
2184+
.transparent_newtype_field(tcx)
2185+
.expect(
2186+
"single-variant transparent structure with zero-sized field",
2187+
)
2188+
.ty(tcx, substs);
2189+
continue;
2190+
}
2191+
}
2192+
debug!("non_transparent_ty -> {:?}", ty);
2193+
return ty;
2194+
}
2195+
};
2196+
2197+
let a = non_transparent_ty(a);
2198+
let b = non_transparent_ty(b);
2199+
21652200
if !seen_types.insert((a, b)) {
21662201
// We've encountered a cycle. There's no point going any further -- the types are
21672202
// structurally the same.

Diff for: src/librustc_lint/types.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_index::vec::Idx;
1111
use rustc_middle::mir::interpret::{sign_extend, truncate};
1212
use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
1313
use rustc_middle::ty::subst::SubstsRef;
14-
use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
14+
use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
1515
use rustc_span::source_map;
1616
use rustc_span::symbol::sym;
1717
use rustc_span::{Span, DUMMY_SP};
@@ -527,22 +527,26 @@ enum FfiResult<'tcx> {
527527
FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> },
528528
}
529529

530+
crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: &ty::AdtDef) -> bool {
531+
tcx.get_attrs(def.did)
532+
.iter()
533+
.any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed))
534+
}
535+
530536
/// Is type known to be non-null?
531-
fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
537+
crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
532538
let tcx = cx.tcx;
533539
match ty.kind {
534540
ty::FnPtr(_) => true,
535541
ty::Ref(..) => true,
536542
ty::Adt(def, _) if def.is_box() && matches!(mode, CItemKind::Definition) => true,
537543
ty::Adt(def, substs) if def.repr.transparent() && !def.is_union() => {
538-
let guaranteed_nonnull_optimization = tcx
539-
.get_attrs(def.did)
540-
.iter()
541-
.any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed));
544+
let marked_non_null = nonnull_optimization_guaranteed(tcx, &def);
542545

543-
if guaranteed_nonnull_optimization {
546+
if marked_non_null {
544547
return true;
545548
}
549+
546550
for variant in &def.variants {
547551
if let Some(field) = variant.transparent_newtype_field(tcx) {
548552
if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) {

Diff for: src/test/ui/lint/clashing-extern-fn.rs

+78-3
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,9 @@ mod same_sized_members_clash {
182182
y: f32,
183183
z: f32,
184184
}
185-
extern "C" { fn origin() -> Point3; }
185+
extern "C" {
186+
fn origin() -> Point3;
187+
}
186188
}
187189
mod b {
188190
#[repr(C)]
@@ -191,8 +193,9 @@ mod same_sized_members_clash {
191193
y: i32,
192194
z: i32, // NOTE: Incorrectly redeclared as i32
193195
}
194-
extern "C" { fn origin() -> Point3; }
195-
//~^ WARN `origin` redeclared with a different signature
196+
extern "C" {
197+
fn origin() -> Point3; //~ WARN `origin` redeclared with a different signature
198+
}
196199
}
197200
}
198201

@@ -258,6 +261,78 @@ mod non_zero_and_non_null {
258261
}
259262
}
260263

264+
// See #75739
265+
mod non_zero_transparent {
266+
mod a1 {
267+
use std::num::NonZeroUsize;
268+
extern "C" {
269+
fn f1() -> NonZeroUsize;
270+
}
271+
}
272+
273+
mod b1 {
274+
#[repr(transparent)]
275+
struct X(NonZeroUsize);
276+
use std::num::NonZeroUsize;
277+
extern "C" {
278+
fn f1() -> X;
279+
}
280+
}
281+
282+
mod a2 {
283+
use std::num::NonZeroUsize;
284+
extern "C" {
285+
fn f2() -> NonZeroUsize;
286+
}
287+
}
288+
289+
mod b2 {
290+
#[repr(transparent)]
291+
struct X1(NonZeroUsize);
292+
293+
#[repr(transparent)]
294+
struct X(X1);
295+
296+
use std::num::NonZeroUsize;
297+
extern "C" {
298+
// Same case as above, but with two layers of newtyping.
299+
fn f2() -> X;
300+
}
301+
}
302+
303+
mod a3 {
304+
#[repr(transparent)]
305+
struct X(core::ptr::NonNull<i32>);
306+
307+
use std::num::NonZeroUsize;
308+
extern "C" {
309+
fn f3() -> X;
310+
}
311+
}
312+
313+
mod b3 {
314+
extern "C" {
315+
fn f3() -> core::ptr::NonNull<i32>;
316+
}
317+
}
318+
319+
mod a4 {
320+
#[repr(transparent)]
321+
enum E {
322+
X(std::num::NonZeroUsize),
323+
}
324+
extern "C" {
325+
fn f4() -> E;
326+
}
327+
}
328+
329+
mod b4 {
330+
extern "C" {
331+
fn f4() -> std::num::NonZeroUsize;
332+
}
333+
}
334+
}
335+
261336
mod null_optimised_enums {
262337
mod a {
263338
extern "C" {

Diff for: src/test/ui/lint/clashing-extern-fn.stderr

+11-11
Original file line numberDiff line numberDiff line change
@@ -106,19 +106,19 @@ LL | fn draw_point(p: Point);
106106
found `unsafe extern "C" fn(sameish_members::b::Point)`
107107

108108
warning: `origin` redeclared with a different signature
109-
--> $DIR/clashing-extern-fn.rs:194:22
109+
--> $DIR/clashing-extern-fn.rs:197:13
110110
|
111-
LL | extern "C" { fn origin() -> Point3; }
112-
| ---------------------- `origin` previously declared here
111+
LL | fn origin() -> Point3;
112+
| ---------------------- `origin` previously declared here
113113
...
114-
LL | extern "C" { fn origin() -> Point3; }
115-
| ^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
114+
LL | fn origin() -> Point3;
115+
| ^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
116116
|
117117
= note: expected `unsafe extern "C" fn() -> same_sized_members_clash::a::Point3`
118118
found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3`
119119

120120
warning: `transparent_incorrect` redeclared with a different signature
121-
--> $DIR/clashing-extern-fn.rs:217:13
121+
--> $DIR/clashing-extern-fn.rs:220:13
122122
|
123123
LL | fn transparent_incorrect() -> T;
124124
| -------------------------------- `transparent_incorrect` previously declared here
@@ -130,7 +130,7 @@ LL | fn transparent_incorrect() -> isize;
130130
found `unsafe extern "C" fn() -> isize`
131131

132132
warning: `missing_return_type` redeclared with a different signature
133-
--> $DIR/clashing-extern-fn.rs:235:13
133+
--> $DIR/clashing-extern-fn.rs:238:13
134134
|
135135
LL | fn missing_return_type() -> usize;
136136
| ---------------------------------- `missing_return_type` previously declared here
@@ -142,7 +142,7 @@ LL | fn missing_return_type();
142142
found `unsafe extern "C" fn()`
143143

144144
warning: `non_zero_usize` redeclared with a different signature
145-
--> $DIR/clashing-extern-fn.rs:253:13
145+
--> $DIR/clashing-extern-fn.rs:256:13
146146
|
147147
LL | fn non_zero_usize() -> core::num::NonZeroUsize;
148148
| ----------------------------------------------- `non_zero_usize` previously declared here
@@ -154,7 +154,7 @@ LL | fn non_zero_usize() -> usize;
154154
found `unsafe extern "C" fn() -> usize`
155155

156156
warning: `non_null_ptr` redeclared with a different signature
157-
--> $DIR/clashing-extern-fn.rs:255:13
157+
--> $DIR/clashing-extern-fn.rs:258:13
158158
|
159159
LL | fn non_null_ptr() -> core::ptr::NonNull<usize>;
160160
| ----------------------------------------------- `non_null_ptr` previously declared here
@@ -166,7 +166,7 @@ LL | fn non_null_ptr() -> *const usize;
166166
found `unsafe extern "C" fn() -> *const usize`
167167

168168
warning: `option_non_zero_usize_incorrect` redeclared with a different signature
169-
--> $DIR/clashing-extern-fn.rs:281:13
169+
--> $DIR/clashing-extern-fn.rs:356:13
170170
|
171171
LL | fn option_non_zero_usize_incorrect() -> usize;
172172
| ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
@@ -178,7 +178,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize;
178178
found `unsafe extern "C" fn() -> isize`
179179

180180
warning: `option_non_null_ptr_incorrect` redeclared with a different signature
181-
--> $DIR/clashing-extern-fn.rs:283:13
181+
--> $DIR/clashing-extern-fn.rs:358:13
182182
|
183183
LL | fn option_non_null_ptr_incorrect() -> *const usize;
184184
| --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here

0 commit comments

Comments
 (0)