Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 245a28e

Browse files
committedNov 24, 2024
Support vec![const { ... }; n] syntax
1 parent 124eb96 commit 245a28e

File tree

4 files changed

+78
-0
lines changed

4 files changed

+78
-0
lines changed
 

‎library/alloc/src/macros.rs

+4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ macro_rules! vec {
4343
() => (
4444
$crate::vec::Vec::new()
4545
);
46+
(const $elem:block; $n:expr) => (
47+
// SAFETY: The `const` keyword asserts the value being the result of a const expression.
48+
unsafe { $crate::vec::from_const_elem(const $elem, $n) }
49+
);
4650
($elem:expr; $n:expr) => (
4751
$crate::vec::from_elem($elem, $n)
4852
);

‎library/alloc/src/vec/mod.rs

+51
Original file line numberDiff line numberDiff line change
@@ -3183,6 +3183,57 @@ pub fn from_elem_in<T: Clone, A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<
31833183
<T as SpecFromElem>::from_elem(elem, n, alloc)
31843184
}
31853185

3186+
/// # Safety
3187+
///
3188+
/// `value` must points to a valid `T` value that is the result of some const expression.
3189+
unsafe fn fill_const_value<T>(buffer: &mut [MaybeUninit<T>], value: *const T) {
3190+
for target in buffer {
3191+
// SAFETY: If `value` is the result of some const expression, we can make as many copies as
3192+
// needed.
3193+
unsafe { target.write(ptr::read(value)) };
3194+
}
3195+
}
3196+
3197+
/// # Safety
3198+
///
3199+
/// `elem` must be the result of some const expression.
3200+
#[doc(hidden)]
3201+
#[cfg(not(no_global_oom_handling))]
3202+
#[unstable(feature = "vec_of_const_expr", issue = "none")]
3203+
#[track_caller]
3204+
pub unsafe fn from_const_elem<T>(elem: T, n: usize) -> Vec<T> {
3205+
// SAFETY: Caller has guaranteed `elem` being the result of some const expression.
3206+
unsafe { from_const_elem_in(elem, n, Global) }
3207+
}
3208+
3209+
/// # Safety
3210+
///
3211+
/// `elem` must be the result of some const expression.
3212+
#[doc(hidden)]
3213+
#[cfg(not(no_global_oom_handling))]
3214+
#[unstable(feature = "vec_of_const_expr", issue = "none")]
3215+
#[track_caller]
3216+
unsafe fn from_const_elem_in<T, A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> {
3217+
// Avoid calling the destructor of `elem`.
3218+
let elem = ManuallyDrop::new(elem);
3219+
let elem_ptr = ptr::from_ref(&*elem);
3220+
let mut result = Vec::<T, A>::with_capacity_in(n, alloc);
3221+
let buffer_ptr = result.as_mut_ptr().cast::<MaybeUninit<T>>();
3222+
3223+
// SAFETY: `with_capacity_in` makes sure the capacity is at least `n`, so we can make a buffer
3224+
// of length `n` out of it.
3225+
let buffer = unsafe { slice::from_raw_parts_mut(buffer_ptr, n) };
3226+
3227+
// SAFETY: Caller has guaranteed `elem` being the result of some const expression.
3228+
unsafe { fill_const_value(buffer, elem_ptr) };
3229+
3230+
// SAFETY: We have initialized exactly `n` values at the start of the buffer, so we are safe to
3231+
// set the length accordingly.
3232+
unsafe { result.set_len(n) };
3233+
3234+
result
3235+
}
3236+
31863237
#[cfg(not(no_global_oom_handling))]
31873238
trait ExtendFromWithinSpec {
31883239
/// # Safety

‎library/alloc/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
3737
#![feature(drain_keep_rest)]
3838
#![feature(local_waker)]
39+
#![feature(vec_of_const_expr)]
3940
#![feature(vec_pop_if)]
4041
#![feature(unique_rc_arc)]
4142
#![feature(macro_metavar_expr_concat)]

‎library/alloc/tests/vec.rs

+22
Original file line numberDiff line numberDiff line change
@@ -2311,6 +2311,28 @@ fn test_vec_macro_repeat() {
23112311
assert_eq!(vec![el; n], vec![Box::new(1), Box::new(1), Box::new(1)]);
23122312
}
23132313

2314+
#[test]
2315+
fn test_vec_macro_repeat_const() {
2316+
#[derive(Eq, PartialEq, Debug)]
2317+
struct Item {
2318+
x: u64,
2319+
y: u32, // Paddings are added to test the uninitialized bytes case.
2320+
}
2321+
2322+
impl Clone for Item {
2323+
fn clone(&self) -> Self {
2324+
panic!("no clone should be called");
2325+
}
2326+
}
2327+
2328+
const ITEM: Item = Item { x: 2, y: 3 };
2329+
2330+
assert_eq!(vec![const { ITEM }; 0], vec![ITEM; 0]);
2331+
assert_eq!(vec![const { ITEM }; 1], vec![ITEM]);
2332+
assert_eq!(vec![const { ITEM }; 2], vec![ITEM, ITEM]);
2333+
assert_eq!(vec![const { ITEM }; 3], vec![ITEM, ITEM, ITEM]);
2334+
}
2335+
23142336
#[test]
23152337
fn test_vec_swap() {
23162338
let mut a: Vec<isize> = vec![0, 1, 2, 3, 4, 5, 6];

0 commit comments

Comments
 (0)
Failed to load comments.