Skip to content

Commit f38eb93

Browse files
committed
Fix clashing_extern_declarations false positive.
Fixes a false positive for transparent newtype with a non-zero member.
1 parent 0301700 commit f38eb93

File tree

4 files changed

+101
-9
lines changed

4 files changed

+101
-9
lines changed

src/librustc_lint/builtin.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2162,6 +2162,38 @@ impl ClashingExternDeclarations {
21622162
ckind: CItemKind,
21632163
) -> bool {
21642164
debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b);
2165+
let tcx = cx.tcx;
2166+
2167+
// Given a transparent newtype, reach through and grab the inner
2168+
// type unless the newtype makes the type non-null.
2169+
let non_transparent_ty = |ty: Ty<'tcx>| -> Ty<'tcx> {
2170+
let mut ty = ty;
2171+
loop {
2172+
if let ty::Adt(def, substs) = ty.kind {
2173+
let is_transparent = def.subst(tcx, substs).repr.transparent();
2174+
let is_enum = def.is_enum();
2175+
let is_non_null = crate::types::guaranteed_nonnull_optimization(tcx, &def);
2176+
debug!(
2177+
"non_transparent_ty({:?}) -- type is transparent? {}, type is enum? {}, type is non-null? {}",
2178+
ty, is_transparent, is_enum, is_non_null
2179+
);
2180+
if is_transparent && !is_enum && !is_non_null {
2181+
ty = def
2182+
.non_enum_variant()
2183+
.transparent_newtype_field(tcx)
2184+
.unwrap()
2185+
.ty(tcx, substs);
2186+
continue;
2187+
}
2188+
}
2189+
debug!("non_transparent_ty -> {:?}", ty);
2190+
return ty;
2191+
}
2192+
};
2193+
2194+
let a = non_transparent_ty(a);
2195+
let b = non_transparent_ty(b);
2196+
21652197
if !seen_types.insert((a, b)) {
21662198
// We've encountered a cycle. There's no point going any further -- the types are
21672199
// structurally the same.

src/librustc_lint/types.rs

Lines changed: 11 additions & 7 deletions
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 guaranteed_nonnull_optimization<'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 = guaranteed_nonnull_optimization(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) {

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

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,62 @@ mod non_zero_and_non_null {
258258
}
259259
}
260260

261+
// See #75739
262+
mod non_zero_transparent {
263+
mod a1 {
264+
use std::num::NonZeroUsize;
265+
extern "C" {
266+
fn f1() -> NonZeroUsize;
267+
}
268+
}
269+
270+
mod b1 {
271+
#[repr(transparent)]
272+
struct X(NonZeroUsize);
273+
use std::num::NonZeroUsize;
274+
extern "C" {
275+
fn f1() -> X;
276+
}
277+
}
278+
279+
mod a2 {
280+
use std::num::NonZeroUsize;
281+
extern "C" {
282+
fn f2() -> NonZeroUsize;
283+
}
284+
}
285+
286+
mod b2 {
287+
#[repr(transparent)]
288+
struct X1(NonZeroUsize);
289+
290+
#[repr(transparent)]
291+
struct X(X1);
292+
293+
use std::num::NonZeroUsize;
294+
extern "C" {
295+
// Same case as above, but with two layers of newtyping.
296+
fn f2() -> X;
297+
}
298+
}
299+
300+
mod a3 {
301+
#[repr(transparent)]
302+
struct X(core::ptr::NonNull<i32>);
303+
304+
use std::num::NonZeroUsize;
305+
extern "C" {
306+
fn f3() -> X;
307+
}
308+
}
309+
310+
mod b3 {
311+
extern "C" {
312+
fn f3() -> core::ptr::NonNull<i32>;
313+
}
314+
}
315+
}
316+
261317
mod null_optimised_enums {
262318
mod a {
263319
extern "C" {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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:337: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:339: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)