Skip to content

Commit 45e8d20

Browse files
committed
Merge from rustc
2 parents 6609fe8 + 37d6af6 commit 45e8d20

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+818
-628
lines changed

alloc/src/raw_vec.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,15 @@ impl<T, A: Allocator> RawVec<T, A> {
241241
if T::IS_ZST || self.cap == 0 {
242242
None
243243
} else {
244-
// We have an allocated chunk of memory, so we can bypass runtime
245-
// checks to get our current layout.
244+
// We could use Layout::array here which ensures the absence of isize and usize overflows
245+
// and could hypothetically handle differences between stride and size, but this memory
246+
// has already been allocated so we know it can't overflow and currently rust does not
247+
// support such types. So we can do better by skipping some checks and avoid an unwrap.
248+
let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
246249
unsafe {
247-
let layout = Layout::array::<T>(self.cap).unwrap_unchecked();
250+
let align = mem::align_of::<T>();
251+
let size = mem::size_of::<T>().unchecked_mul(self.cap);
252+
let layout = Layout::from_size_align_unchecked(size, align);
248253
Some((self.ptr.cast().into(), layout))
249254
}
250255
}
@@ -426,11 +431,13 @@ impl<T, A: Allocator> RawVec<T, A> {
426431
assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity");
427432

428433
let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
429-
434+
// See current_memory() why this assert is here
435+
let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
430436
let ptr = unsafe {
431437
// `Layout::array` cannot overflow here because it would have
432438
// overflowed earlier when capacity was larger.
433-
let new_layout = Layout::array::<T>(cap).unwrap_unchecked();
439+
let new_size = mem::size_of::<T>().unchecked_mul(cap);
440+
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
434441
self.alloc
435442
.shrink(ptr, layout, new_layout)
436443
.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?

alloc/src/string.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@
4242
4343
#![stable(feature = "rust1", since = "1.0.0")]
4444

45-
#[cfg(not(no_global_oom_handling))]
46-
use core::char::{decode_utf16, REPLACEMENT_CHARACTER};
4745
use core::error::Error;
4846
use core::fmt;
4947
use core::hash;
@@ -683,7 +681,7 @@ impl String {
683681
// This isn't done via collect::<Result<_, _>>() for performance reasons.
684682
// FIXME: the function can be simplified again when #48994 is closed.
685683
let mut ret = String::with_capacity(v.len());
686-
for c in decode_utf16(v.iter().cloned()) {
684+
for c in char::decode_utf16(v.iter().cloned()) {
687685
if let Ok(c) = c {
688686
ret.push(c);
689687
} else {
@@ -722,7 +720,9 @@ impl String {
722720
#[inline]
723721
#[stable(feature = "rust1", since = "1.0.0")]
724722
pub fn from_utf16_lossy(v: &[u16]) -> String {
725-
decode_utf16(v.iter().cloned()).map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)).collect()
723+
char::decode_utf16(v.iter().cloned())
724+
.map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
725+
.collect()
726726
}
727727

728728
/// Decomposes a `String` into its raw components.

core/benches/array.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use test::black_box;
2+
use test::Bencher;
3+
4+
macro_rules! map_array {
5+
($func_name:ident, $start_item: expr, $map_item: expr, $arr_size: expr) => {
6+
#[bench]
7+
fn $func_name(b: &mut Bencher) {
8+
let arr = [$start_item; $arr_size];
9+
b.iter(|| black_box(arr).map(|_| black_box($map_item)));
10+
}
11+
};
12+
}
13+
14+
map_array!(map_8byte_8byte_8, 0u64, 1u64, 80);
15+
map_array!(map_8byte_8byte_64, 0u64, 1u64, 640);
16+
map_array!(map_8byte_8byte_256, 0u64, 1u64, 2560);
17+
18+
map_array!(map_8byte_256byte_256, 0u64, [0u64; 4], 2560);
19+
map_array!(map_256byte_8byte_256, [0u64; 4], 0u64, 2560);

core/benches/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
extern crate test;
1010

1111
mod any;
12+
mod array;
1213
mod ascii;
1314
mod char;
1415
mod fmt;

core/src/alloc/global.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,18 +203,19 @@ pub unsafe trait GlobalAlloc {
203203
ptr
204204
}
205205

206-
/// Shrink or grow a block of memory to the given `new_size`.
206+
/// Shrink or grow a block of memory to the given `new_size` in bytes.
207207
/// The block is described by the given `ptr` pointer and `layout`.
208208
///
209209
/// If this returns a non-null pointer, then ownership of the memory block
210210
/// referenced by `ptr` has been transferred to this allocator.
211211
/// Any access to the old `ptr` is Undefined Behavior, even if the
212212
/// allocation remained in-place. The newly returned pointer is the only valid pointer
213213
/// for accessing this memory now.
214+
///
214215
/// The new memory block is allocated with `layout`,
215-
/// but with the `size` updated to `new_size`. This new layout must be
216-
/// used when deallocating the new memory block with `dealloc`. The range
217-
/// `0..min(layout.size(), new_size)` of the new memory block is
216+
/// but with the `size` updated to `new_size` in bytes.
217+
/// This new layout must be used when deallocating the new memory block with `dealloc`.
218+
/// The range `0..min(layout.size(), new_size)` of the new memory block is
218219
/// guaranteed to have the same values as the original block.
219220
///
220221
/// If this method returns null, then ownership of the memory

core/src/array/drain.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use crate::iter::{TrustedLen, UncheckedIterator};
2+
use crate::mem::ManuallyDrop;
3+
use crate::ptr::drop_in_place;
4+
use crate::slice;
5+
6+
/// A situationally-optimized version of `array.into_iter().for_each(func)`.
7+
///
8+
/// [`crate::array::IntoIter`]s are great when you need an owned iterator, but
9+
/// storing the entire array *inside* the iterator like that can sometimes
10+
/// pessimize code. Notable, it can be more bytes than you really want to move
11+
/// around, and because the array accesses index into it SRoA has a harder time
12+
/// optimizing away the type than it does iterators that just hold a couple pointers.
13+
///
14+
/// Thus this function exists, which gives a way to get *moved* access to the
15+
/// elements of an array using a small iterator -- no bigger than a slice iterator.
16+
///
17+
/// The function-taking-a-closure structure makes it safe, as it keeps callers
18+
/// from looking at already-dropped elements.
19+
pub(crate) fn drain_array_with<T, R, const N: usize>(
20+
array: [T; N],
21+
func: impl for<'a> FnOnce(Drain<'a, T>) -> R,
22+
) -> R {
23+
let mut array = ManuallyDrop::new(array);
24+
// SAFETY: Now that the local won't drop it, it's ok to construct the `Drain` which will.
25+
let drain = Drain(array.iter_mut());
26+
func(drain)
27+
}
28+
29+
/// See [`drain_array_with`] -- this is `pub(crate)` only so it's allowed to be
30+
/// mentioned in the signature of that method. (Otherwise it hits `E0446`.)
31+
// INVARIANT: It's ok to drop the remainder of the inner iterator.
32+
pub(crate) struct Drain<'a, T>(slice::IterMut<'a, T>);
33+
34+
impl<T> Drop for Drain<'_, T> {
35+
fn drop(&mut self) {
36+
// SAFETY: By the type invariant, we're allowed to drop all these.
37+
unsafe { drop_in_place(self.0.as_mut_slice()) }
38+
}
39+
}
40+
41+
impl<T> Iterator for Drain<'_, T> {
42+
type Item = T;
43+
44+
#[inline]
45+
fn next(&mut self) -> Option<T> {
46+
let p: *const T = self.0.next()?;
47+
// SAFETY: The iterator was already advanced, so we won't drop this later.
48+
Some(unsafe { p.read() })
49+
}
50+
51+
#[inline]
52+
fn size_hint(&self) -> (usize, Option<usize>) {
53+
let n = self.len();
54+
(n, Some(n))
55+
}
56+
}
57+
58+
impl<T> ExactSizeIterator for Drain<'_, T> {
59+
#[inline]
60+
fn len(&self) -> usize {
61+
self.0.len()
62+
}
63+
}
64+
65+
// SAFETY: This is a 1:1 wrapper for a slice iterator, which is also `TrustedLen`.
66+
unsafe impl<T> TrustedLen for Drain<'_, T> {}
67+
68+
impl<T> UncheckedIterator for Drain<'_, T> {
69+
unsafe fn next_unchecked(&mut self) -> T {
70+
// SAFETY: `Drain` is 1:1 with the inner iterator, so if the caller promised
71+
// that there's an element left, the inner iterator has one too.
72+
let p: *const T = unsafe { self.0.next_unchecked() };
73+
// SAFETY: The iterator was already advanced, so we won't drop this later.
74+
unsafe { p.read() }
75+
}
76+
}

0 commit comments

Comments
 (0)