diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 21d36ed54cdf4..5c6aff3d86439 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -350,6 +350,11 @@ language_item_table! { MaybeUninit, sym::maybe_uninit, maybe_uninit, Target::Union, GenericRequirement::None; + Init, sym::init_trait, init_trait, Target::Trait, GenericRequirement::Exact(1); + InitError, sym::init_error, init_error, Target::AssocTy, GenericRequirement::Exact(1); + InitLayout, sym::init_layout, init_layout, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::Exact(1); + InitInit, sym::init_init, init_init, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::Exact(1); + Termination, sym::termination, termination, Target::Trait, GenericRequirement::None; Try, sym::Try, try_trait, Target::Trait, GenericRequirement::None; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cb9ccf4cc3f23..53eac7081826c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1200,6 +1200,11 @@ symbols! { infer_static_outlives_requirements, inherent_associated_types, inherit, + init, + init_error, + init_init, + init_layout, + init_trait, inlateout, inline, inline_const, diff --git a/library/core/src/init.rs b/library/core/src/init.rs new file mode 100644 index 0000000000000..0ac0b5d75eb77 --- /dev/null +++ b/library/core/src/init.rs @@ -0,0 +1,93 @@ +//! In-place initialization. +//! +//! This module describes the interface through which types supporting in-place initialization +//! can perform initialization with minimal or zero additional allocations or moves. + +use crate::ptr::Pointee; + +/// In-place Initializer for `T`. +/// +/// An instance of `Init` carries all the information necessary to initialize a `T` in a +/// well-defined memory location, criteria of which is prescribed in the Safety section. +/// +/// # Fallibility +/// +/// The initialization might fail and return an error of type [`Self::Error`] instead. +/// In that case, the memory provided to [`Self::init`] shall be repurposed in any way, +/// even though it might have been written to by this initializer. +/// +/// # Examples +/// +/// ## Initializing unsized types +/// +/// To initialize an unsized type, first query the required layout for `T` using [`Self::layout`]. +/// Then provide a pointer to an allocation of at least the specified alignment and size. +/// +/// If initialization was successful, then [`Self::init`] returns the metadata that combined with +/// the pointer to the given to [`Self::init`] yields a valid pointer to `T`. +/// +/// ``` ignore (illustrative) +/// use std::alloc::alloc; +/// fn init_boxed>(init: I) -> Result, I::Error> { +/// let layout = init.layout(); +/// let memory = alloc(layout).cast::<()>(); +/// let meta = init.init(memory)?; +/// Box::from_raw(from_raw_parts_mut(memory, meta)) +/// } +/// ``` +/// +/// # Safety +/// +/// Implementers must ensure that if [`self.init(slot)`] returns `Ok(metadata)`, +/// then [`core::ptr::from_raw_parts_mut(slot, metadata)`] must reference a valid +/// value owned by the caller. +/// Furthermore, the layout returned by using +/// [`core::intrinsics::size_of_val`] and [`core::intrinsics::align_of_val`] on this pointer +/// must match what [`Self::layout()`] returns exactly. +/// +/// If `T` is sized, or in other words `T: Sized`, [`Init::layout`] in this case *must* +/// return the same layout as [`Layout::new::()`] would. +/// +/// Implementers must ensure that the implementation of `init()` does not rely +/// on the value being pinned. +/// +/// [`core::ptr::from_raw_parts_mut(slot, metadata)`]: core::ptr::from_raw_parts_mut +/// [`Self::layout()`]: Init::layout +/// [`self.init(slot)`]: Init::init +/// [`Layout::new::()`]: core::alloc::Layout::new +#[unstable(feature = "in_place_initialization", issue = "999999")] +#[lang = "init_trait"] +pub unsafe trait Init { + /// Error type upon initialization failure during the actual + /// in-place initialization procedure. + #[lang = "init_error"] + type Error; + + /// The layout needed by this initializer. + /// This method must return a layout that precisely matches + /// with `T`. + /// Namely the size and the alignment must be equal. + #[lang = "init_layout"] + fn layout(&self) -> crate::alloc::Layout; + + /// Writes a valid value of type `T` to `slot` or fails. + /// + /// If this call returns [`Ok`], then `slot` is guaranteed to contain a valid + /// value of type `T`. + /// Otherwise, in case the result is an [`Err`], the implementation must guarantee + /// that the `slot` may be repurposed for future reuse. + /// + /// If `T` is unsized, then `slot` may be combined with + /// the metadata to obtain a valid pointer to the value. + /// + /// Note that `slot` should be thought of as a `*mut T`. A unit type is used + /// so that the pointer is thin even if `T` is unsized. + /// + /// # Safety + /// + /// The caller must provide a pointer that references a location that `init` + /// may write to, and the location must have at least the size and alignment + /// specified by [`Init::layout`]. + #[lang = "init_init"] + unsafe fn init(self, slot: *mut ()) -> Result; +} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 88855831788db..e4c092ffc98a9 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -363,6 +363,10 @@ pub mod task; #[allow(missing_docs)] pub mod alloc; +/* In-place initialization */ +#[unstable(feature = "in_place_initialization", issue = "999999")] +pub mod init; + // note: does not need to be public mod bool; mod escape;