| 
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