Rollup merge of #146187 - clarfonthey:const-drop-in-place, r=oli-obk

Unstably constify `ptr::drop_in_place` and related methods

Tracking: rust-lang/rust#109342
Supercedes: rust-lang/rust#145725

Makes methods const:

* `core::ptr::drop_in_place`
* `core::mem::ManuallyDrop::drop`
* `core::mem::MaybeUninit::assume_init_drop`
* `<[core::mem::MaybeUninit<_>]>::assume_init_drop`
* `<*mut _>::drop_in_place`
* `core::ptr::NonNull::drop_in_place`
This commit is contained in:
Matthias Krüger 2025-10-14 19:47:28 +02:00 committed by GitHub
commit 252974a717
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 84 additions and 14 deletions

View file

@ -1,3 +1,4 @@
use crate::marker::Destruct;
use crate::ops::{Deref, DerefMut, DerefPure};
use crate::ptr;
@ -249,7 +250,11 @@ impl<T: ?Sized> ManuallyDrop<T> {
/// [pinned]: crate::pin
#[stable(feature = "manually_drop", since = "1.20.0")]
#[inline]
pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
pub const unsafe fn drop(slot: &mut ManuallyDrop<T>)
where
T: [const] Destruct,
{
// SAFETY: we are dropping the value pointed to by a mutable reference
// which is guaranteed to be valid for writes.
// It is up to the caller to make sure that `slot` isn't dropped again.

View file

@ -1,4 +1,5 @@
use crate::any::type_name;
use crate::marker::Destruct;
use crate::mem::ManuallyDrop;
use crate::{fmt, intrinsics, ptr, slice};
@ -714,7 +715,11 @@ impl<T> MaybeUninit<T> {
///
/// [`assume_init`]: MaybeUninit::assume_init
#[stable(feature = "maybe_uninit_extra", since = "1.60.0")]
pub unsafe fn assume_init_drop(&mut self) {
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
pub const unsafe fn assume_init_drop(&mut self)
where
T: [const] Destruct,
{
// SAFETY: the caller must guarantee that `self` is initialized and
// satisfies all invariants of `T`.
// Dropping the value in place is safe if that is the case.
@ -1390,7 +1395,11 @@ impl<T> [MaybeUninit<T>] {
/// behaviour.
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[inline(always)]
pub unsafe fn assume_init_drop(&mut self) {
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
pub const unsafe fn assume_init_drop(&mut self)
where
T: [const] Destruct,
{
if !self.is_empty() {
// SAFETY: the caller must guarantee that every element of `self`
// is initialized and satisfies all invariants of `T`.

View file

@ -403,7 +403,7 @@
use crate::cmp::Ordering;
use crate::intrinsics::const_eval_select;
use crate::marker::{FnPtr, PointeeSized};
use crate::marker::{Destruct, FnPtr, PointeeSized};
use crate::mem::{self, MaybeUninit, SizedTypeProperties};
use crate::num::NonZero;
use crate::{fmt, hash, intrinsics, ub_checks};
@ -801,7 +801,11 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
#[lang = "drop_in_place"]
#[allow(unconditional_recursion)]
#[rustc_diagnostic_item = "ptr_drop_in_place"]
pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
pub const unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T)
where
T: [const] Destruct,
{
// Code here does not matter - this is replaced by the
// real drop glue by the compiler.

View file

@ -1,7 +1,7 @@
use super::*;
use crate::cmp::Ordering::{Equal, Greater, Less};
use crate::intrinsics::const_eval_select;
use crate::marker::PointeeSized;
use crate::marker::{Destruct, PointeeSized};
use crate::mem::{self, SizedTypeProperties};
use crate::slice::{self, SliceIndex};
@ -1390,8 +1390,12 @@ impl<T: PointeeSized> *mut T {
///
/// [`ptr::drop_in_place`]: crate::ptr::drop_in_place()
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
#[inline(always)]
pub unsafe fn drop_in_place(self) {
pub const unsafe fn drop_in_place(self)
where
T: [const] Destruct,
{
// SAFETY: the caller must uphold the safety contract for `drop_in_place`.
unsafe { drop_in_place(self) }
}

View file

@ -1,5 +1,5 @@
use crate::cmp::Ordering;
use crate::marker::{PointeeSized, Unsize};
use crate::marker::{Destruct, PointeeSized, Unsize};
use crate::mem::{MaybeUninit, SizedTypeProperties};
use crate::num::NonZero;
use crate::ops::{CoerceUnsized, DispatchFromDyn};
@ -1118,7 +1118,11 @@ impl<T: PointeeSized> NonNull<T> {
/// [`ptr::drop_in_place`]: crate::ptr::drop_in_place()
#[inline(always)]
#[stable(feature = "non_null_convenience", since = "1.80.0")]
pub unsafe fn drop_in_place(self) {
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
pub const unsafe fn drop_in_place(self)
where
T: [const] Destruct,
{
// SAFETY: the caller must uphold the safety contract for `drop_in_place`.
unsafe { ptr::drop_in_place(self.as_ptr()) }
}

View file

@ -19,6 +19,7 @@
#![feature(const_cmp)]
#![feature(const_convert)]
#![feature(const_destruct)]
#![feature(const_drop_in_place)]
#![feature(const_eval_select)]
#![feature(const_mul_add)]
#![feature(const_ops)]

View file

@ -1,6 +1,6 @@
use core::cell::RefCell;
use core::marker::Freeze;
use core::mem::MaybeUninit;
use core::mem::{ManuallyDrop, MaybeUninit};
use core::num::NonZero;
use core::ptr;
use core::ptr::*;
@ -1045,3 +1045,42 @@ fn test_ptr_default() {
let default = PtrMutDefaultTest::default();
assert!(default.ptr.is_null());
}
#[test]
fn test_const_drop_in_place() {
const COUNTER: usize = {
let mut counter = 0;
let counter_ptr = &raw mut counter;
// only exists to make `Drop` indirect impl
#[allow(dead_code)]
struct Test(Dropped);
struct Dropped(*mut usize);
impl const Drop for Dropped {
fn drop(&mut self) {
unsafe {
*self.0 += 1;
}
}
}
let mut one = ManuallyDrop::new(Test(Dropped(counter_ptr)));
let mut two = ManuallyDrop::new(Test(Dropped(counter_ptr)));
let mut three = ManuallyDrop::new(Test(Dropped(counter_ptr)));
assert!(counter == 0);
unsafe {
ManuallyDrop::drop(&mut one);
}
assert!(counter == 1);
unsafe {
ManuallyDrop::drop(&mut two);
}
assert!(counter == 2);
unsafe {
ManuallyDrop::drop(&mut three);
}
counter
};
assert_eq!(COUNTER, 3);
}

View file

@ -1,8 +1,10 @@
error: Undefined Behavior: trying to retag from <TAG> for Unique permission at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location
--> RUSTLIB/core/src/ptr/mod.rs:LL:CC
|
LL | pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this error occurs as part of retag at ALLOC[0x0..0x1]
LL | / pub const unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T)
LL | | where
LL | | T: [const] Destruct,
| |________________________^ this error occurs as part of retag at ALLOC[0x0..0x1]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information

View file

@ -1,8 +1,10 @@
error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN)
--> RUSTLIB/core/src/ptr/mod.rs:LL:CC
|
LL | pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
LL | / pub const unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T)
LL | | where
LL | | T: [const] Destruct,
| |________________________^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information