Skip to content

Commit ee2cd24

Browse files
authored
Rollup merge of #96010 - eduardosm:Unique-on-top-of-NonNull, r=m-ou-se
Implement `core::ptr::Unique` on top of `NonNull` Removes the use `rustc_layout_scalar_valid_range_start` and some `unsafe` blocks.
2 parents 98ce30e + a22a9a9 commit ee2cd24

File tree

10 files changed

+46
-41
lines changed

10 files changed

+46
-41
lines changed

compiler/rustc_codegen_ssa/src/mir/place.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
448448

449449
// a box with a non-zst allocator should not be directly dereferenced
450450
if cg_base.layout.ty.is_box() && !cg_base.layout.field(cx, 1).is_zst() {
451-
let ptr = cg_base.extract_field(bx, 0).extract_field(bx, 0);
451+
// Extract `Box<T>` -> `Unique<T>` -> `NonNull<T>` -> `*const T`
452+
let ptr =
453+
cg_base.extract_field(bx, 0).extract_field(bx, 0).extract_field(bx, 0);
452454

453455
ptr.deref(bx.cx())
454456
} else {
@@ -464,7 +466,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
464466
mir::ProjectionElem::Deref => {
465467
// a box with a non-zst allocator should not be directly dereferenced
466468
if cg_base.layout.ty.is_box() && !cg_base.layout.field(cx, 1).is_zst() {
467-
let ptr = cg_base.project_field(bx, 0).project_field(bx, 0);
469+
// Project `Box<T>` -> `Unique<T>` -> `NonNull<T>` -> `*const T`
470+
let ptr =
471+
cg_base.project_field(bx, 0).project_field(bx, 0).project_field(bx, 0);
468472

469473
bx.load_operand(ptr).deref(bx.cx())
470474
} else {

library/core/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,14 @@
119119
#![feature(const_likely)]
120120
#![feature(const_maybe_uninit_as_mut_ptr)]
121121
#![feature(const_maybe_uninit_assume_init)]
122+
#![feature(const_nonnull_new)]
122123
#![feature(const_num_from_num)]
123124
#![feature(const_ops)]
124125
#![feature(const_option)]
125126
#![feature(const_option_ext)]
126127
#![feature(const_pin)]
127128
#![feature(const_replace)]
129+
#![feature(const_ptr_as_ref)]
128130
#![feature(const_ptr_is_null)]
129131
#![feature(const_ptr_offset_from)]
130132
#![feature(const_ptr_read)]

library/core/src/ptr/unique.rs

+22-19
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::convert::From;
22
use crate::fmt;
33
use crate::marker::{PhantomData, Unsize};
4-
use crate::mem;
54
use crate::ops::{CoerceUnsized, DispatchFromDyn};
5+
use crate::ptr::NonNull;
66

77
/// A wrapper around a raw non-null `*mut T` that indicates that the possessor
88
/// of this wrapper owns the referent. Useful for building abstractions like
@@ -32,9 +32,8 @@ use crate::ops::{CoerceUnsized, DispatchFromDyn};
3232
)]
3333
#[doc(hidden)]
3434
#[repr(transparent)]
35-
#[rustc_layout_scalar_valid_range_start(1)]
3635
pub struct Unique<T: ?Sized> {
37-
pointer: *const T,
36+
pointer: NonNull<T>,
3837
// NOTE: this marker has no consequences for variance, but is necessary
3938
// for dropck to understand that we logically own a `T`.
4039
//
@@ -71,9 +70,7 @@ impl<T: Sized> Unique<T> {
7170
#[must_use]
7271
#[inline]
7372
pub const fn dangling() -> Self {
74-
// SAFETY: mem::align_of() returns a valid, non-null pointer. The
75-
// conditions to call new_unchecked() are thus respected.
76-
unsafe { Unique::new_unchecked(crate::ptr::invalid_mut::<T>(mem::align_of::<T>())) }
73+
Self::from(NonNull::dangling())
7774
}
7875
}
7976

@@ -87,15 +84,14 @@ impl<T: ?Sized> Unique<T> {
8784
#[inline]
8885
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
8986
// SAFETY: the caller must guarantee that `ptr` is non-null.
90-
unsafe { Unique { pointer: ptr as _, _marker: PhantomData } }
87+
unsafe { Unique { pointer: NonNull::new_unchecked(ptr), _marker: PhantomData } }
9188
}
9289

9390
/// Creates a new `Unique` if `ptr` is non-null.
9491
#[inline]
9592
pub const fn new(ptr: *mut T) -> Option<Self> {
96-
if !ptr.is_null() {
97-
// SAFETY: The pointer has already been checked and is not null.
98-
Some(unsafe { Unique { pointer: ptr as _, _marker: PhantomData } })
93+
if let Some(pointer) = NonNull::new(ptr) {
94+
Some(Unique { pointer, _marker: PhantomData })
9995
} else {
10096
None
10197
}
@@ -105,7 +101,7 @@ impl<T: ?Sized> Unique<T> {
105101
#[must_use = "`self` will be dropped if the result is not used"]
106102
#[inline]
107103
pub const fn as_ptr(self) -> *mut T {
108-
self.pointer as *mut T
104+
self.pointer.as_ptr()
109105
}
110106

111107
/// Dereferences the content.
@@ -118,7 +114,7 @@ impl<T: ?Sized> Unique<T> {
118114
pub const unsafe fn as_ref(&self) -> &T {
119115
// SAFETY: the caller must guarantee that `self` meets all the
120116
// requirements for a reference.
121-
unsafe { &*self.as_ptr() }
117+
unsafe { self.pointer.as_ref() }
122118
}
123119

124120
/// Mutably dereferences the content.
@@ -131,17 +127,14 @@ impl<T: ?Sized> Unique<T> {
131127
pub const unsafe fn as_mut(&mut self) -> &mut T {
132128
// SAFETY: the caller must guarantee that `self` meets all the
133129
// requirements for a mutable reference.
134-
unsafe { &mut *self.as_ptr() }
130+
unsafe { self.pointer.as_mut() }
135131
}
136132

137133
/// Casts to a pointer of another type.
138134
#[must_use = "`self` will be dropped if the result is not used"]
139135
#[inline]
140136
pub const fn cast<U>(self) -> Unique<U> {
141-
// SAFETY: Unique::new_unchecked() creates a new unique and needs
142-
// the given pointer to not be null.
143-
// Since we are passing self as a pointer, it cannot be null.
144-
unsafe { Unique::new_unchecked(self.as_ptr() as *mut U) }
137+
Unique::from(self.pointer.cast())
145138
}
146139
}
147140

@@ -184,7 +177,17 @@ impl<T: ?Sized> const From<&mut T> for Unique<T> {
184177
/// This conversion is infallible since references cannot be null.
185178
#[inline]
186179
fn from(reference: &mut T) -> Self {
187-
// SAFETY: A mutable reference cannot be null
188-
unsafe { Unique { pointer: reference as *mut T, _marker: PhantomData } }
180+
Self::from(NonNull::from(reference))
181+
}
182+
}
183+
184+
#[unstable(feature = "ptr_internals", issue = "none")]
185+
impl<T: ?Sized> const From<NonNull<T>> for Unique<T> {
186+
/// Converts a `NonNull<T>` to a `Unique<T>`.
187+
///
188+
/// This conversion is infallible since `NonNull` cannot be null.
189+
#[inline]
190+
fn from(pointer: NonNull<T>) -> Self {
191+
Unique { pointer, _marker: PhantomData }
189192
}
190193
}

src/etc/gdb_providers.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
def unwrap_unique_or_non_null(unique_or_nonnull):
1313
# BACKCOMPAT: rust 1.32
1414
# https://github.com/rust-lang/rust/commit/7a0911528058e87d22ea305695f4047572c5e067
15+
# BACKCOMPAT: rust 1.60
16+
# https://github.com/rust-lang/rust/commit/17fbc63144e0834b2f5b5234c28ff9f998947154
1517
ptr = unique_or_nonnull["pointer"]
16-
return ptr if ptr.type.code == gdb.TYPE_CODE_PTR else ptr[ZERO_FIELD]
18+
return ptr if ptr.type.code == gdb.TYPE_CODE_PTR else ptr[ptr.type.fields()[0]]
1719

1820

1921
class EnumProvider:

src/etc/lldb_providers.py

+4
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ def from_uint(self, name, value):
6363
def unwrap_unique_or_non_null(unique_or_nonnull):
6464
# BACKCOMPAT: rust 1.32
6565
# https://github.com/rust-lang/rust/commit/7a0911528058e87d22ea305695f4047572c5e067
66+
# BACKCOMPAT: rust 1.60
67+
# https://github.com/rust-lang/rust/commit/17fbc63144e0834b2f5b5234c28ff9f998947154
6668
ptr = unique_or_nonnull.GetChildMemberWithName("pointer")
6769
return ptr if ptr.TypeIsPointerType() else ptr.GetChildAtIndex(0)
6870

@@ -268,7 +270,9 @@ class StdVecSyntheticProvider:
268270
struct RawVec<T> { ptr: Unique<T>, cap: usize, ... }
269271
rust 1.31.1: struct Unique<T: ?Sized> { pointer: NonZero<*const T>, ... }
270272
rust 1.33.0: struct Unique<T: ?Sized> { pointer: *const T, ... }
273+
rust 1.62.0: struct Unique<T: ?Sized> { pointer: NonNull<T>, ... }
271274
struct NonZero<T>(T)
275+
struct NonNull<T> { pointer: *const T }
272276
"""
273277

274278
def __init__(self, valobj, dict):

src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
+ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
3636
+ _7 = &mut (*_5); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
3737
+ Deinit((*_7)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
38-
+ ((*_7).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
38+
+ ((*_7).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: NonNull::<u32> { pointer: {0x4 as *const u32} }, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
3939
// mir::Constant
4040
- // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
4141
- // + user_ty: UserType(1)

src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
+ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
3636
+ _7 = &mut (*_5); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
3737
+ Deinit((*_7)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
38-
+ ((*_7).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
38+
+ ((*_7).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: NonNull::<u32> { pointer: {0x4 as *const u32} }, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
3939
// mir::Constant
4040
- // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
4141
- // + user_ty: UserType(1)

src/test/ui/lint/lint-ctypes-enum.rs

-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ extern "C" {
6767
fn option_fn(x: Option<extern "C" fn()>);
6868
fn nonnull(x: Option<std::ptr::NonNull<u8>>);
6969
fn unique(x: Option<std::ptr::Unique<u8>>);
70-
//~^ ERROR `extern` block uses type `Option<Unique<u8>>`
7170
fn nonzero_u8(x: Option<num::NonZeroU8>);
7271
fn nonzero_u16(x: Option<num::NonZeroU16>);
7372
fn nonzero_u32(x: Option<num::NonZeroU32>);

src/test/ui/lint/lint-ctypes-enum.stderr

+6-15
Original file line numberDiff line numberDiff line change
@@ -54,33 +54,24 @@ LL | | G,
5454
LL | | }
5555
| |_^
5656

57-
error: `extern` block uses type `Option<Unique<u8>>`, which is not FFI-safe
58-
--> $DIR/lint-ctypes-enum.rs:69:17
59-
|
60-
LL | fn unique(x: Option<std::ptr::Unique<u8>>);
61-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
62-
|
63-
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
64-
= note: enum has no representation hint
65-
6657
error: `extern` block uses type `u128`, which is not FFI-safe
67-
--> $DIR/lint-ctypes-enum.rs:75:23
58+
--> $DIR/lint-ctypes-enum.rs:74:23
6859
|
6960
LL | fn nonzero_u128(x: Option<num::NonZeroU128>);
7061
| ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
7162
|
7263
= note: 128-bit integers don't currently have a known stable ABI
7364

7465
error: `extern` block uses type `i128`, which is not FFI-safe
75-
--> $DIR/lint-ctypes-enum.rs:82:23
66+
--> $DIR/lint-ctypes-enum.rs:81:23
7667
|
7768
LL | fn nonzero_i128(x: Option<num::NonZeroI128>);
7869
| ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
7970
|
8071
= note: 128-bit integers don't currently have a known stable ABI
8172

8273
error: `extern` block uses type `Option<TransparentUnion<NonZeroU8>>`, which is not FFI-safe
83-
--> $DIR/lint-ctypes-enum.rs:87:28
74+
--> $DIR/lint-ctypes-enum.rs:86:28
8475
|
8576
LL | fn transparent_union(x: Option<TransparentUnion<num::NonZeroU8>>);
8677
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -89,7 +80,7 @@ LL | fn transparent_union(x: Option<TransparentUnion<num::NonZeroU8>>);
8980
= note: enum has no representation hint
9081

9182
error: `extern` block uses type `Option<Rust<NonZeroU8>>`, which is not FFI-safe
92-
--> $DIR/lint-ctypes-enum.rs:89:20
83+
--> $DIR/lint-ctypes-enum.rs:88:20
9384
|
9485
LL | fn repr_rust(x: Option<Rust<num::NonZeroU8>>);
9586
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -98,13 +89,13 @@ LL | fn repr_rust(x: Option<Rust<num::NonZeroU8>>);
9889
= note: enum has no representation hint
9990

10091
error: `extern` block uses type `Result<(), NonZeroI32>`, which is not FFI-safe
101-
--> $DIR/lint-ctypes-enum.rs:90:20
92+
--> $DIR/lint-ctypes-enum.rs:89:20
10293
|
10394
LL | fn no_result(x: Result<(), num::NonZeroI32>);
10495
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
10596
|
10697
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
10798
= note: enum has no representation hint
10899

109-
error: aborting due to 9 previous errors
100+
error: aborting due to 8 previous errors
110101

src/test/ui/traits/cycle-cache-err-60010.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0275]: overflow evaluating the requirement `SalsaStorage: RefUnwindSafe`
44
LL | _parse: <ParseQuery as Query<RootDatabase>>::Data,
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: required because it appears within the type `*const SalsaStorage`
7+
= note: required because it appears within the type `PhantomData<SalsaStorage>`
88
= note: required because it appears within the type `Unique<SalsaStorage>`
99
= note: required because it appears within the type `Box<SalsaStorage>`
1010
note: required because it appears within the type `Runtime<RootDatabase>`

0 commit comments

Comments
 (0)