From 2a8215db54be4ee913bf6ddb7c263b23d41616d1 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Wed, 3 Jun 2026 08:28:01 +0700 Subject: [PATCH 1/3] Add `rustc_as_ptr` to `Vec::as_non_null` This makes the `dangling_pointers_from_temporaries` lint work with it. --- library/alloc/src/vec/mod.rs | 1 + .../methods.rs | 3 +++ .../methods.stderr | 19 ++++++++++++++++--- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 3e03acab6a701..6da38017f518b 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2117,6 +2117,7 @@ impl Vec { /// [`as_non_null`]: Vec::as_non_null #[unstable(feature = "box_vec_non_null", issue = "130364")] #[rustc_const_unstable(feature = "box_vec_non_null", issue = "130364")] + #[rustc_as_ptr] #[inline] pub const fn as_non_null(&mut self) -> NonNull { self.buf.non_null() diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs index 10666e0a82823..9459ea1108014 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs @@ -1,8 +1,11 @@ #![deny(dangling_pointers_from_temporaries)] +#![feature(box_vec_non_null)] fn main() { vec![0u8].as_ptr(); //~^ ERROR dangling pointer vec![0u8].as_mut_ptr(); //~^ ERROR dangling pointer + vec![0u8].as_non_null(); + //~^ ERROR dangling pointer } diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr index 367dfae9e65d4..87ee49e7c6120 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr @@ -1,5 +1,5 @@ error: this creates a dangling pointer because temporary `Vec` is dropped at end of statement - --> $DIR/methods.rs:4:15 + --> $DIR/methods.rs:5:15 | LL | vec![0u8].as_ptr(); | --------- ^^^^^^ pointer created here @@ -17,7 +17,7 @@ LL | #![deny(dangling_pointers_from_temporaries)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this creates a dangling pointer because temporary `Vec` is dropped at end of statement - --> $DIR/methods.rs:6:15 + --> $DIR/methods.rs:7:15 | LL | vec![0u8].as_mut_ptr(); | --------- ^^^^^^^^^^ pointer created here @@ -29,5 +29,18 @@ LL | vec![0u8].as_mut_ptr(); = note: returning a pointer to a local variable will always result in a dangling pointer = note: for more information, see -error: aborting due to 2 previous errors +error: this creates a dangling pointer because temporary `Vec` is dropped at end of statement + --> $DIR/methods.rs:9:15 + | +LL | vec![0u8].as_non_null(); + | --------- ^^^^^^^^^^^ pointer created here + | | + | this `Vec` is dropped at end of statement + | + = help: bind the `Vec` to a variable such that it outlives the pointer returned by `as_non_null` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see + +error: aborting due to 3 previous errors From 1a2857c5d5cbf64c6f55aa2f5a3408c6e207c6e4 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Sat, 13 Jun 2026 09:12:11 +0700 Subject: [PATCH 2/3] Split `Vec::as_non_null()` into a separate `vec_as_non_null` feature --- library/alloc/src/vec/mod.rs | 8 ++++---- .../ui/lint/dangling-pointers-from-temporaries/methods.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 6da38017f518b..ac6771d9a3516 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2079,7 +2079,7 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(box_vec_non_null)] + /// #![feature(vec_as_non_null)] /// /// // Allocate vector big enough for 4 elements. /// let size = 4; @@ -2099,7 +2099,7 @@ impl Vec { /// Due to the aliasing guarantee, the following code is legal: /// /// ```rust - /// #![feature(box_vec_non_null)] + /// #![feature(vec_as_non_null)] /// /// unsafe { /// let mut v = vec![0]; @@ -2115,8 +2115,8 @@ impl Vec { /// [`as_mut_ptr`]: Vec::as_mut_ptr /// [`as_ptr`]: Vec::as_ptr /// [`as_non_null`]: Vec::as_non_null - #[unstable(feature = "box_vec_non_null", issue = "130364")] - #[rustc_const_unstable(feature = "box_vec_non_null", issue = "130364")] + #[unstable(feature = "vec_as_non_null", issue = "157843")] + #[rustc_const_unstable(feature = "vec_as_non_null", issue = "157843")] #[rustc_as_ptr] #[inline] pub const fn as_non_null(&mut self) -> NonNull { diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs index 9459ea1108014..f28ea20e1790b 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs @@ -1,5 +1,5 @@ #![deny(dangling_pointers_from_temporaries)] -#![feature(box_vec_non_null)] +#![feature(vec_as_non_null)] fn main() { vec![0u8].as_ptr(); From a18a9720af08914751b866c7cb45c468501b246f Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Mon, 1 Jun 2026 08:40:25 +0700 Subject: [PATCH 3/3] Stabilize `box_vec_non_null` --- library/alloc/src/boxed.rs | 16 ++-------------- library/alloc/src/vec/mod.rs | 16 ++++------------ 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index bd3f10a16dd9b..8b66ccedcb823 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1347,16 +1347,12 @@ impl Box { /// Recreate a `Box` which was previously converted to a `NonNull` /// pointer using [`Box::into_non_null`]: /// ``` - /// #![feature(box_vec_non_null)] - /// /// let x = Box::new(5); /// let non_null = Box::into_non_null(x); /// let x = unsafe { Box::from_non_null(non_null) }; /// ``` /// Manually create a `Box` from scratch by using the global allocator: /// ``` - /// #![feature(box_vec_non_null)] - /// /// use std::alloc::{alloc, Layout}; /// use std::ptr::NonNull; /// @@ -1372,7 +1368,7 @@ impl Box { /// /// [memory layout]: self#memory-layout /// [considerations for unsafe code]: self#considerations-for-unsafe-code - #[unstable(feature = "box_vec_non_null", issue = "130364")] + #[stable(feature = "box_vec_non_null", since = "CURRENT_RUSTC_VERSION")] #[inline] #[must_use = "call `drop(Box::from_non_null(ptr))` if you intend to drop the `Box`"] pub unsafe fn from_non_null(ptr: NonNull) -> Self { @@ -1461,8 +1457,6 @@ impl Box { /// Converting the `NonNull` pointer back into a `Box` with [`Box::from_non_null`] /// for automatic cleanup: /// ``` - /// #![feature(box_vec_non_null)] - /// /// let x = Box::new(String::from("Hello")); /// let non_null = Box::into_non_null(x); /// let x = unsafe { Box::from_non_null(non_null) }; @@ -1470,8 +1464,6 @@ impl Box { /// Manual cleanup by explicitly running the destructor and deallocating /// the memory: /// ``` - /// #![feature(box_vec_non_null)] - /// /// use std::alloc::{dealloc, Layout}; /// /// let x = Box::new(String::from("Hello")); @@ -1483,8 +1475,6 @@ impl Box { /// ``` /// Note: This is equivalent to the following: /// ``` - /// #![feature(box_vec_non_null)] - /// /// let x = Box::new(String::from("Hello")); /// let non_null = Box::into_non_null(x); /// unsafe { @@ -1494,7 +1484,7 @@ impl Box { /// /// [memory layout]: self#memory-layout #[must_use = "losing the pointer will leak memory"] - #[unstable(feature = "box_vec_non_null", issue = "130364")] + #[stable(feature = "box_vec_non_null", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn into_non_null(b: Self) -> NonNull { // SAFETY: `Box` is guaranteed to be non-null. @@ -1611,7 +1601,6 @@ impl Box { /// [memory layout]: self#memory-layout /// [considerations for unsafe code]: self#considerations-for-unsafe-code #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "box_vec_non_null", issue = "130364")] #[inline] pub unsafe fn from_non_null_in(raw: NonNull, alloc: A) -> Self { // SAFETY: guaranteed by the caller. @@ -1726,7 +1715,6 @@ impl Box { /// [memory layout]: self#memory-layout #[must_use = "losing the pointer will leak memory"] #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "box_vec_non_null", issue = "130364")] #[inline] pub fn into_non_null_with_allocator(b: Self) -> (NonNull, A) { let (ptr, alloc) = Box::into_raw_with_allocator(b); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ac6771d9a3516..e8342c9f8e64e 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -697,8 +697,6 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(box_vec_non_null)] - /// /// let v = vec![1, 2, 3]; /// /// // Deconstruct the vector into parts. @@ -719,8 +717,6 @@ impl Vec { /// Using memory that was allocated elsewhere: /// /// ```rust - /// #![feature(box_vec_non_null)] - /// /// use std::alloc::{alloc, Layout}; /// use std::ptr::NonNull; /// @@ -742,8 +738,8 @@ impl Vec { /// } /// ``` #[inline] - #[unstable(feature = "box_vec_non_null", issue = "130364")] - #[rustc_const_unstable(feature = "box_vec_non_null", issue = "130364")] + #[stable(feature = "box_vec_non_null", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] pub const unsafe fn from_parts(ptr: NonNull, length: usize, capacity: usize) -> Self { unsafe { Self::from_parts_in(ptr, length, capacity, Global) } } @@ -863,8 +859,6 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(box_vec_non_null)] - /// /// let v: Vec = vec![-1, 0, 1]; /// /// let (ptr, len, cap) = v.into_parts(); @@ -879,8 +873,8 @@ impl Vec { /// assert_eq!(rebuilt, [4294967295, 0, 1]); /// ``` #[must_use = "losing the pointer will leak memory"] - #[unstable(feature = "box_vec_non_null", issue = "130364")] - #[rustc_const_unstable(feature = "box_vec_non_null", issue = "130364")] + #[stable(feature = "box_vec_non_null", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] pub const fn into_parts(self) -> (NonNull, usize, usize) { let (ptr, len, capacity) = self.into_raw_parts(); // SAFETY: A `Vec` always has a non-null pointer. @@ -1305,7 +1299,6 @@ impl Vec { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "box_vec_non_null", issue = "130364")] pub const unsafe fn from_parts_in( ptr: NonNull, length: usize, @@ -1410,7 +1403,6 @@ impl Vec { #[must_use = "losing the pointer will leak memory"] #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "box_vec_non_null", issue = "130364")] pub const fn into_parts_with_alloc(self) -> (NonNull, usize, usize, A) { let (ptr, len, capacity, alloc) = self.into_raw_parts_with_alloc(); // SAFETY: A `Vec` always has a non-null pointer.