From e074db764a0f25af073cb3f472d39a86e6fa7f39 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Jul 2019 10:44:11 +0200 Subject: [PATCH 1/4] use const array repeat expressions for uninit_array --- src/liballoc/collections/btree/node.rs | 6 +++--- src/liballoc/lib.rs | 1 + src/libcore/fmt/num.rs | 4 ++-- src/libcore/lib.rs | 1 + src/libcore/macros.rs | 23 ++++++++++++++++++++--- src/libcore/mem/maybe_uninit.rs | 1 + src/libcore/slice/sort.rs | 4 ++-- 7 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index 7cf077d61d687..e067096f0c780 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -106,8 +106,8 @@ impl LeafNode { LeafNode { // As a general policy, we leave fields uninitialized if they can be, as this should // be both slightly faster and easier to track in Valgrind. - keys: uninitialized_array![_; CAPACITY], - vals: uninitialized_array![_; CAPACITY], + keys: uninit_array![_; CAPACITY], + vals: uninit_array![_; CAPACITY], parent: ptr::null(), parent_idx: MaybeUninit::uninit(), len: 0 @@ -159,7 +159,7 @@ impl InternalNode { unsafe fn new() -> Self { InternalNode { data: LeafNode::new(), - edges: uninitialized_array![_; 2*B], + edges: uninit_array![_; 2*B], } } } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 2e48825e81c29..68df0137ee637 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -77,6 +77,7 @@ #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] +#![cfg_attr(not(bootstrap), feature(const_in_array_repeat_expressions))] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index f9b4c26496cdc..e2d00e654ddb8 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -51,7 +51,7 @@ trait GenericRadix { // characters for a base 2 number. let zero = T::zero(); let is_nonnegative = x >= zero; - let mut buf = uninitialized_array![u8; 128]; + let mut buf = uninit_array![u8; 128]; let mut curr = buf.len(); let base = T::from_u8(Self::BASE); if is_nonnegative { @@ -189,7 +189,7 @@ static DEC_DIGITS_LUT: &[u8; 200] = macro_rules! impl_Display { ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => { fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut buf = uninitialized_array![u8; 39]; + let mut buf = uninit_array![u8; 39]; let mut curr = buf.len() as isize; let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index fe149d634e223..8d3c42cbf3501 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -75,6 +75,7 @@ #![feature(const_fn)] #![feature(const_fn_union)] #![cfg_attr(not(bootstrap), feature(const_generics))] +#![cfg_attr(not(bootstrap), feature(const_in_array_repeat_expressions))] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 293a2dd94922f..9855c5fb9c32f 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -626,20 +626,37 @@ macro_rules! todo { /// Creates an array of [`MaybeUninit`]. /// /// This macro constructs an uninitialized array of the type `[MaybeUninit; N]`. +/// It exists solely because bootstrap does not yet support const array-init expressions. /// /// [`MaybeUninit`]: mem/union.MaybeUninit.html +// FIXME: Remove both versions of this macro once bootstrap is 1.38. #[macro_export] #[unstable(feature = "maybe_uninit_array", issue = "53491")] -macro_rules! uninitialized_array { +#[cfg(bootstrap)] +macro_rules! uninit_array { // This `assume_init` is safe because an array of `MaybeUninit` does not // require initialization. - // FIXME(#49147): Could be replaced by an array initializer, once those can - // be any const expression. ($t:ty; $size:expr) => (unsafe { MaybeUninit::<[MaybeUninit<$t>; $size]>::uninit().assume_init() }); } +/// Creates an array of [`MaybeUninit`]. +/// +/// This macro constructs an uninitialized array of the type `[MaybeUninit; N]`. +/// It exists solely because bootstrap does not yet support const array-init expressions. +/// +/// [`MaybeUninit`]: mem/union.MaybeUninit.html +// FIXME: Just inline this version of the macro once bootstrap is 1.38. +#[macro_export] +#[unstable(feature = "maybe_uninit_array", issue = "53491")] +#[cfg(not(bootstrap))] +macro_rules! uninit_array { + ($t:ty; $size:expr) => ( + [MaybeUninit::<$t>::uninit(); $size] + ); +} + /// Built-in macros to the compiler itself. /// /// These macros do not have any corresponding definition with a `macro_rules!` diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index f6f7ccffdb005..1c69e7f90f6c7 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -248,6 +248,7 @@ impl MaybeUninit { /// [type]: union.MaybeUninit.html #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] + #[rustc_promotable] pub const fn uninit() -> MaybeUninit { MaybeUninit { uninit: () } } diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index c293b1900187e..fbf9caeaece56 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -216,14 +216,14 @@ fn partition_in_blocks(v: &mut [T], pivot: &T, is_less: &mut F) -> usize let mut block_l = BLOCK; let mut start_l = ptr::null_mut(); let mut end_l = ptr::null_mut(); - let mut offsets_l: [MaybeUninit; BLOCK] = uninitialized_array![u8; BLOCK]; + let mut offsets_l: [MaybeUninit; BLOCK] = uninit_array![u8; BLOCK]; // The current block on the right side (from `r.sub(block_r)` to `r`). let mut r = unsafe { l.add(v.len()) }; let mut block_r = BLOCK; let mut start_r = ptr::null_mut(); let mut end_r = ptr::null_mut(); - let mut offsets_r: [MaybeUninit; BLOCK] = uninitialized_array![u8; BLOCK]; + let mut offsets_r: [MaybeUninit; BLOCK] = uninit_array![u8; BLOCK]; // FIXME: When we get VLAs, try creating one array of length `min(v.len(), 2 * BLOCK)` rather // than two fixed-size arrays of length `BLOCK`. VLAs might be more cache-efficient. From ad261f6852c928d3ce0a6dd34ec6c3a38792e4de Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Jul 2019 17:23:47 +0200 Subject: [PATCH 2/4] avoid uninit_array! macro where it is not needed --- src/libcore/fmt/num.rs | 4 ++-- src/libcore/lib.rs | 1 - src/libcore/slice/sort.rs | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index e2d00e654ddb8..3b5c9fbff250a 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -51,7 +51,7 @@ trait GenericRadix { // characters for a base 2 number. let zero = T::zero(); let is_nonnegative = x >= zero; - let mut buf = uninit_array![u8; 128]; + let mut buf = [MaybeUninit::::uninit(); 128]; let mut curr = buf.len(); let base = T::from_u8(Self::BASE); if is_nonnegative { @@ -189,7 +189,7 @@ static DEC_DIGITS_LUT: &[u8; 200] = macro_rules! impl_Display { ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => { fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut buf = uninit_array![u8; 39]; + let mut buf = [MaybeUninit::::uninit(); 39]; let mut curr = buf.len() as isize; let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 8d3c42cbf3501..fe149d634e223 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -75,7 +75,6 @@ #![feature(const_fn)] #![feature(const_fn_union)] #![cfg_attr(not(bootstrap), feature(const_generics))] -#![cfg_attr(not(bootstrap), feature(const_in_array_repeat_expressions))] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index fbf9caeaece56..2f2170f7ff14c 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -216,14 +216,14 @@ fn partition_in_blocks(v: &mut [T], pivot: &T, is_less: &mut F) -> usize let mut block_l = BLOCK; let mut start_l = ptr::null_mut(); let mut end_l = ptr::null_mut(); - let mut offsets_l: [MaybeUninit; BLOCK] = uninit_array![u8; BLOCK]; + let mut offsets_l = [MaybeUninit::::uninit(); BLOCK]; // The current block on the right side (from `r.sub(block_r)` to `r`). let mut r = unsafe { l.add(v.len()) }; let mut block_r = BLOCK; let mut start_r = ptr::null_mut(); let mut end_r = ptr::null_mut(); - let mut offsets_r: [MaybeUninit; BLOCK] = uninit_array![u8; BLOCK]; + let mut offsets_r = [MaybeUninit::::uninit(); BLOCK]; // FIXME: When we get VLAs, try creating one array of length `min(v.len(), 2 * BLOCK)` rather // than two fixed-size arrays of length `BLOCK`. VLAs might be more cache-efficient. From 4b47e78a16524ed4878bfffaaf60c32bb18d88ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jul 2019 12:02:28 +0200 Subject: [PATCH 3/4] use a const to hack around promotion limitations --- src/liballoc/lib.rs | 1 + src/libcore/macros.rs | 2 +- src/libcore/mem/maybe_uninit.rs | 9 ++++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 68df0137ee637..dbc1f3b47c80d 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -85,6 +85,7 @@ #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(fundamental)] +#![feature(internal_uninit_const)] #![feature(lang_items)] #![feature(libc)] #![feature(nll)] diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 9855c5fb9c32f..296bb43f9fad4 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -653,7 +653,7 @@ macro_rules! uninit_array { #[cfg(not(bootstrap))] macro_rules! uninit_array { ($t:ty; $size:expr) => ( - [MaybeUninit::<$t>::uninit(); $size] + [MaybeUninit::<$t>::UNINIT; $size] ); } diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index 1c69e7f90f6c7..9ce89f9669d22 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -248,11 +248,18 @@ impl MaybeUninit { /// [type]: union.MaybeUninit.html #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] - #[rustc_promotable] pub const fn uninit() -> MaybeUninit { MaybeUninit { uninit: () } } + /// A promotable constant, equivalent to `uninit()`. + #[unstable( + feature = "internal_uninit_const", + issue = "0", + reason = "hack to work around promotability", + )] + pub const UNINIT: Self = Self::uninit(); + /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being /// filled with `0` bytes. It depends on `T` whether that already makes for /// proper initialization. For example, `MaybeUninit::zeroed()` is initialized, From f3abbf71035e469fce6db37bdb444ce3e50e870f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jul 2019 12:59:51 +0200 Subject: [PATCH 4/4] tidy is being silly --- src/libcore/mem/maybe_uninit.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index 9ce89f9669d22..2e88db8df1163 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -253,11 +253,8 @@ impl MaybeUninit { } /// A promotable constant, equivalent to `uninit()`. - #[unstable( - feature = "internal_uninit_const", - issue = "0", - reason = "hack to work around promotability", - )] + #[unstable(feature = "internal_uninit_const", issue = "0", + reason = "hack to work around promotability")] pub const UNINIT: Self = Self::uninit(); /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being