Fix clashing_extern_declarations false positive.
Fixes a false positive for transparent newtype with a non-zero member.
This commit is contained in:
parent
03017003c7
commit
f38eb93634
4 changed files with 101 additions and 9 deletions
|
|
@ -2162,6 +2162,38 @@ impl ClashingExternDeclarations {
|
|||
ckind: CItemKind,
|
||||
) -> bool {
|
||||
debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b);
|
||||
let tcx = cx.tcx;
|
||||
|
||||
// Given a transparent newtype, reach through and grab the inner
|
||||
// type unless the newtype makes the type non-null.
|
||||
let non_transparent_ty = |ty: Ty<'tcx>| -> Ty<'tcx> {
|
||||
let mut ty = ty;
|
||||
loop {
|
||||
if let ty::Adt(def, substs) = ty.kind {
|
||||
let is_transparent = def.subst(tcx, substs).repr.transparent();
|
||||
let is_enum = def.is_enum();
|
||||
let is_non_null = crate::types::guaranteed_nonnull_optimization(tcx, &def);
|
||||
debug!(
|
||||
"non_transparent_ty({:?}) -- type is transparent? {}, type is enum? {}, type is non-null? {}",
|
||||
ty, is_transparent, is_enum, is_non_null
|
||||
);
|
||||
if is_transparent && !is_enum && !is_non_null {
|
||||
ty = def
|
||||
.non_enum_variant()
|
||||
.transparent_newtype_field(tcx)
|
||||
.unwrap()
|
||||
.ty(tcx, substs);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
debug!("non_transparent_ty -> {:?}", ty);
|
||||
return ty;
|
||||
}
|
||||
};
|
||||
|
||||
let a = non_transparent_ty(a);
|
||||
let b = non_transparent_ty(b);
|
||||
|
||||
if !seen_types.insert((a, b)) {
|
||||
// We've encountered a cycle. There's no point going any further -- the types are
|
||||
// structurally the same.
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_index::vec::Idx;
|
|||
use rustc_middle::mir::interpret::{sign_extend, truncate};
|
||||
use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
|
||||
use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_span::source_map;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
|
@ -527,22 +527,26 @@ enum FfiResult<'tcx> {
|
|||
FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> },
|
||||
}
|
||||
|
||||
crate fn guaranteed_nonnull_optimization<'tcx>(tcx: TyCtxt<'tcx>, def: &ty::AdtDef) -> bool {
|
||||
tcx.get_attrs(def.did)
|
||||
.iter()
|
||||
.any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed))
|
||||
}
|
||||
|
||||
/// Is type known to be non-null?
|
||||
fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
|
||||
crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
|
||||
let tcx = cx.tcx;
|
||||
match ty.kind {
|
||||
ty::FnPtr(_) => true,
|
||||
ty::Ref(..) => true,
|
||||
ty::Adt(def, _) if def.is_box() && matches!(mode, CItemKind::Definition) => true,
|
||||
ty::Adt(def, substs) if def.repr.transparent() && !def.is_union() => {
|
||||
let guaranteed_nonnull_optimization = tcx
|
||||
.get_attrs(def.did)
|
||||
.iter()
|
||||
.any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed));
|
||||
let marked_non_null = guaranteed_nonnull_optimization(tcx, &def);
|
||||
|
||||
if guaranteed_nonnull_optimization {
|
||||
if marked_non_null {
|
||||
return true;
|
||||
}
|
||||
|
||||
for variant in &def.variants {
|
||||
if let Some(field) = variant.transparent_newtype_field(tcx) {
|
||||
if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) {
|
||||
|
|
|
|||
|
|
@ -258,6 +258,62 @@ mod non_zero_and_non_null {
|
|||
}
|
||||
}
|
||||
|
||||
// See #75739
|
||||
mod non_zero_transparent {
|
||||
mod a1 {
|
||||
use std::num::NonZeroUsize;
|
||||
extern "C" {
|
||||
fn f1() -> NonZeroUsize;
|
||||
}
|
||||
}
|
||||
|
||||
mod b1 {
|
||||
#[repr(transparent)]
|
||||
struct X(NonZeroUsize);
|
||||
use std::num::NonZeroUsize;
|
||||
extern "C" {
|
||||
fn f1() -> X;
|
||||
}
|
||||
}
|
||||
|
||||
mod a2 {
|
||||
use std::num::NonZeroUsize;
|
||||
extern "C" {
|
||||
fn f2() -> NonZeroUsize;
|
||||
}
|
||||
}
|
||||
|
||||
mod b2 {
|
||||
#[repr(transparent)]
|
||||
struct X1(NonZeroUsize);
|
||||
|
||||
#[repr(transparent)]
|
||||
struct X(X1);
|
||||
|
||||
use std::num::NonZeroUsize;
|
||||
extern "C" {
|
||||
// Same case as above, but with two layers of newtyping.
|
||||
fn f2() -> X;
|
||||
}
|
||||
}
|
||||
|
||||
mod a3 {
|
||||
#[repr(transparent)]
|
||||
struct X(core::ptr::NonNull<i32>);
|
||||
|
||||
use std::num::NonZeroUsize;
|
||||
extern "C" {
|
||||
fn f3() -> X;
|
||||
}
|
||||
}
|
||||
|
||||
mod b3 {
|
||||
extern "C" {
|
||||
fn f3() -> core::ptr::NonNull<i32>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod null_optimised_enums {
|
||||
mod a {
|
||||
extern "C" {
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ LL | fn non_null_ptr() -> *const usize;
|
|||
found `unsafe extern "C" fn() -> *const usize`
|
||||
|
||||
warning: `option_non_zero_usize_incorrect` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:281:13
|
||||
--> $DIR/clashing-extern-fn.rs:337:13
|
||||
|
|
||||
LL | fn option_non_zero_usize_incorrect() -> usize;
|
||||
| ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
|
||||
|
|
@ -178,7 +178,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize;
|
|||
found `unsafe extern "C" fn() -> isize`
|
||||
|
||||
warning: `option_non_null_ptr_incorrect` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:283:13
|
||||
--> $DIR/clashing-extern-fn.rs:339:13
|
||||
|
|
||||
LL | fn option_non_null_ptr_incorrect() -> *const usize;
|
||||
| --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue