diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 5d36a8b3d0e..500efefbb11 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -984,7 +984,14 @@ pub fn transparent_newtype_field<'a, 'tcx>( } /// Is type known to be non-null? -fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool { +fn ty_is_known_nonnull<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + mode: CItemKind, +) -> bool { + let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty); + match ty.kind() { ty::FnPtr(_) => true, ty::Ref(..) => true, @@ -1004,7 +1011,7 @@ fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) - def.variants() .iter() .filter_map(|variant| transparent_newtype_field(tcx, variant)) - .any(|field| ty_is_known_nonnull(tcx, field.ty(tcx, args), mode)) + .any(|field| ty_is_known_nonnull(tcx, param_env, field.ty(tcx, args), mode)) } _ => false, } @@ -1012,7 +1019,13 @@ fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) - /// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type. /// If the type passed in was not scalar, returns None. -fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option> { +fn get_nullable_type<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> Option> { + let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty); + Some(match *ty.kind() { ty::Adt(field_def, field_args) => { let inner_field_ty = { @@ -1028,22 +1041,19 @@ fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option> .expect("No non-zst fields in transparent type.") .ty(tcx, field_args) }; - return get_nullable_type(tcx, inner_field_ty); + return get_nullable_type(tcx, param_env, inner_field_ty); } ty::Int(ty) => Ty::new_int(tcx, ty), ty::Uint(ty) => Ty::new_uint(tcx, ty), ty::RawPtr(ty_mut) => Ty::new_ptr(tcx, ty_mut), // As these types are always non-null, the nullable equivalent of - // Option of these types are their raw pointer counterparts. + // `Option` of these types are their raw pointer counterparts. ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty::TypeAndMut { ty, mutbl }), - ty::FnPtr(..) => { - // There is no nullable equivalent for Rust's function pointers -- you - // must use an Option _> to represent it. - ty - } - - // We should only ever reach this case if ty_is_known_nonnull is extended - // to other types. + // There is no nullable equivalent for Rust's function pointers, + // you must use an `Option _>` to represent it. + ty::FnPtr(..) => ty, + // We should only ever reach this case if `ty_is_known_nonnull` is + // extended to other types. ref unhandled => { debug!( "get_nullable_type: Unhandled scalar kind: {:?} while checking {:?}", @@ -1056,7 +1066,7 @@ fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option> /// Check if this enum can be safely exported based on the "nullable pointer optimization". If it /// can, return the type that `ty` can be safely converted to, otherwise return `None`. -/// Currently restricted to function pointers, boxes, references, `core::num::NonZero*`, +/// Currently restricted to function pointers, boxes, references, `core::num::NonZero`, /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes. /// FIXME: This duplicates code in codegen. pub(crate) fn repr_nullable_ptr<'tcx>( @@ -1075,7 +1085,7 @@ pub(crate) fn repr_nullable_ptr<'tcx>( _ => return None, }; - if !ty_is_known_nonnull(tcx, field_ty, ckind) { + if !ty_is_known_nonnull(tcx, param_env, field_ty, ckind) { return None; } @@ -1099,10 +1109,10 @@ pub(crate) fn repr_nullable_ptr<'tcx>( WrappingRange { start: 0, end } if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => { - return Some(get_nullable_type(tcx, field_ty).unwrap()); + return Some(get_nullable_type(tcx, param_env, field_ty).unwrap()); } WrappingRange { start: 1, .. } => { - return Some(get_nullable_type(tcx, field_ty).unwrap()); + return Some(get_nullable_type(tcx, param_env, field_ty).unwrap()); } WrappingRange { start, end } => { unreachable!("Unhandled start and end range: ({}, {})", start, end) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index b853771b9ea..89d2b4f7dc1 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -103,6 +103,7 @@ unsafe impl const ZeroablePrimitive for $primitive { /// ``` #[unstable(feature = "generic_nonzero", issue = "120257")] #[repr(transparent)] +#[rustc_nonnull_optimization_guaranteed] #[rustc_diagnostic_item = "NonZero"] pub struct NonZero(T::NonZeroInner); diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 22d9b4d76f1..86ee789aeb2 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -1,31 +1,3 @@ -warning: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:369:43 - | -LL | fn option_non_zero_usize() -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - = note: `#[warn(improper_ctypes)]` on by default - -warning: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:370:43 - | -LL | fn option_non_zero_isize() -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -warning: `extern` block uses type `Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:428:46 - | -LL | fn hidden_niche_transparent() -> Option; - | ^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - warning: `extern` block uses type `Option`, which is not FFI-safe --> $DIR/clashing-extern-fn.rs:430:55 | @@ -34,6 +6,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option>>`, which is not FFI-safe --> $DIR/clashing-extern-fn.rs:434:46 @@ -205,30 +178,6 @@ LL | fn non_null_ptr() -> *const usize; = note: expected `unsafe extern "C" fn() -> NonNull` found `unsafe extern "C" fn() -> *const usize` -warning: `option_non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:369:13 - | -LL | fn option_non_zero_usize() -> usize; - | ----------------------------------- `option_non_zero_usize` previously declared here -... -LL | fn option_non_zero_usize() -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> usize` - found `unsafe extern "C" fn() -> Option>` - -warning: `option_non_zero_isize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:370:13 - | -LL | fn option_non_zero_isize() -> isize; - | ----------------------------------- `option_non_zero_isize` previously declared here -... -LL | fn option_non_zero_isize() -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> isize` - found `unsafe extern "C" fn() -> Option>` - warning: `option_non_zero_usize_incorrect` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:374:13 | @@ -253,18 +202,6 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize; = note: expected `unsafe extern "C" fn() -> *const usize` found `unsafe extern "C" fn() -> *const isize` -warning: `hidden_niche_transparent` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:428:13 - | -LL | fn hidden_niche_transparent() -> usize; - | -------------------------------------- `hidden_niche_transparent` previously declared here -... -LL | fn hidden_niche_transparent() -> Option; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> usize` - found `unsafe extern "C" fn() -> Option` - warning: `hidden_niche_transparent_no_niche` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:430:13 | @@ -289,5 +226,5 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` found `unsafe extern "C" fn() -> Option>>` -warning: 25 warnings emitted +warning: 19 warnings emitted diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr index b1bacbeceda..48be3eb5a56 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/lint-ctypes-enum.stderr @@ -45,131 +45,21 @@ note: the type is defined here LL | enum T { | ^^^^^^ -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:71:21 - | -LL | fn nonzero_u8(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:72:22 - | -LL | fn nonzero_u16(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:73:22 - | -LL | fn nonzero_u32(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:74:22 - | -LL | fn nonzero_u64(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe +error: `extern` block uses type `u128`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:75:23 | LL | fn nonzero_u128(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint + = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:77:24 - | -LL | fn nonzero_usize(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:78:21 - | -LL | fn nonzero_i8(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:79:22 - | -LL | fn nonzero_i16(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:80:22 - | -LL | fn nonzero_i32(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:81:22 - | -LL | fn nonzero_i64(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe +error: `extern` block uses type `i128`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:82:23 | LL | fn nonzero_i128(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:84:24 - | -LL | fn nonzero_isize(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:85:29 - | -LL | fn transparent_struct(x: Option>>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:86:27 - | -LL | fn transparent_enum(x: Option>>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint + = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Option>>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:87:28 @@ -198,5 +88,5 @@ LL | fn no_result(x: Result<(), num::NonZero>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: aborting due to 20 previous errors +error: aborting due to 8 previous errors