|  | 
| 7 | 7 | 
 | 
| 8 | 8 | use crate::alloc::Layout; | 
| 9 | 9 | use crate::marker::DiscriminantKind; | 
|  | 10 | +use crate::panic::const_assert; | 
| 10 | 11 | use crate::{clone, cmp, fmt, hash, intrinsics, ptr}; | 
| 11 | 12 | 
 | 
| 12 | 13 | mod manually_drop; | 
| @@ -1407,3 +1408,60 @@ pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) { | 
| 1407 | 1408 |     // The `{}` is for better error messages | 
| 1408 | 1409 |     {builtin # offset_of($Container, $($fields)+)} | 
| 1409 | 1410 | } | 
|  | 1411 | + | 
|  | 1412 | +/// Create a fresh instance of the inhabited ZST type `T`. | 
|  | 1413 | +/// | 
|  | 1414 | +/// Prefer this to [`zeroed`] or [`uninitialized`] or [`transmute_copy`] | 
|  | 1415 | +/// in places where you know that `T` is zero-sized, but don't have a bound | 
|  | 1416 | +/// (such as [`Default`]) that would allow you to instantiate it using safe code. | 
|  | 1417 | +/// | 
|  | 1418 | +/// If you're not sure whether `T` is an inhabited ZST, then you should be | 
|  | 1419 | +/// using [`MaybeUninit`], not this function. | 
|  | 1420 | +/// | 
|  | 1421 | +/// # Panics | 
|  | 1422 | +/// | 
|  | 1423 | +/// If `size_of::<T>() != 0`. | 
|  | 1424 | +/// | 
|  | 1425 | +/// # Safety | 
|  | 1426 | +/// | 
|  | 1427 | +/// - `T` must be *[inhabited]*, i.e. possible to construct. This means that types | 
|  | 1428 | +///   like zero-variant enums and [`!`] are unsound to conjure. | 
|  | 1429 | +/// - You must use the value only in ways which do not violate any *safety* | 
|  | 1430 | +///   invariants of the type. | 
|  | 1431 | +/// | 
|  | 1432 | +/// While it's easy to create a *valid* instance of an inhabited ZST, since having | 
|  | 1433 | +/// no bits in its representation means there's only one possible value, that | 
|  | 1434 | +/// doesn't mean that it's always *sound* to do so. | 
|  | 1435 | +/// | 
|  | 1436 | +/// For example, a library could design zero-sized tokens that are `!Default + !Clone`, limiting | 
|  | 1437 | +/// their creation to functions that initialize some state or establish a scope. Conjuring such a | 
|  | 1438 | +/// token could break invariants and lead to unsoundness. | 
|  | 1439 | +/// | 
|  | 1440 | +/// # Examples | 
|  | 1441 | +/// | 
|  | 1442 | +/// ``` | 
|  | 1443 | +/// #![feature(mem_conjure_zst)] | 
|  | 1444 | +/// use std::mem::conjure_zst; | 
|  | 1445 | +/// | 
|  | 1446 | +/// assert_eq!(unsafe { conjure_zst::<()>() }, ()); | 
|  | 1447 | +/// assert_eq!(unsafe { conjure_zst::<[i32; 0]>() }, []); | 
|  | 1448 | +/// ``` | 
|  | 1449 | +/// | 
|  | 1450 | +/// [inhabited]: https://doc.rust-lang.org/reference/glossary.html#inhabited | 
|  | 1451 | +#[unstable(feature = "mem_conjure_zst", issue = "95383")] | 
|  | 1452 | +pub const unsafe fn conjure_zst<T>() -> T { | 
|  | 1453 | +    const_assert!( | 
|  | 1454 | +        size_of::<T>() == 0, | 
|  | 1455 | +        "mem::conjure_zst invoked on a nonzero-sized type", | 
|  | 1456 | +        "mem::conjure_zst invoked on type {t}, which is not zero-sized", | 
|  | 1457 | +        t: &str = stringify!(T) | 
|  | 1458 | +    ); | 
|  | 1459 | + | 
|  | 1460 | +    // SAFETY: because the caller must guarantee that it's inhabited and zero-sized, | 
|  | 1461 | +    // there's nothing in the representation that needs to be set. | 
|  | 1462 | +    // `assume_init` calls `assert_inhabited`, so we don't need to here. | 
|  | 1463 | +    unsafe { | 
|  | 1464 | +        #[allow(clippy::uninit_assumed_init)] | 
|  | 1465 | +        MaybeUninit::uninit().assume_init() | 
|  | 1466 | +    } | 
|  | 1467 | +} | 
0 commit comments