Fixes a false positive for transparent newtype with a non-zero member.
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.
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};
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) {
}
}
+// 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" {
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
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