Skip to content

Commit c90bcb9

Browse files
committed
Auto merge of #148573 - matthiaskrgr:rollup-cn5viia, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #146861 (add extend_front to VecDeque with specialization like extend) - #148213 (Fix invalid tag closing when leaving expansion "original code") - #148292 (Un-shadow object bound candidate in `NormalizesTo` goal if self_ty is trait object) - #148528 (run-make tests: use edition 2024) - #148554 (Add regression test for issue 148542) - #148561 (Fix ICE from async closure variance) - #148563 (rustdoc-search: remove broken index special case) r? `@ghost` `@rustbot` modify labels: rollup
2 parents c5e283b + 1a6770c commit c90bcb9

File tree

26 files changed

+557
-34
lines changed

26 files changed

+557
-34
lines changed

compiler/rustc_middle/src/ty/diagnostics.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
698698
}
699699

700700
Closure(..)
701+
| CoroutineClosure(..)
701702
| FnDef(..)
702703
| Infer(..)
703704
| Coroutine(..)

compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,16 @@ where
454454
self.assemble_object_bound_candidates(goal, &mut candidates);
455455
}
456456
}
457-
AssembleCandidatesFrom::EnvAndBounds => {}
457+
AssembleCandidatesFrom::EnvAndBounds => {
458+
// This is somewhat inconsistent and may make #57893 slightly easier to exploit.
459+
// However, it matches the behavior of the old solver. See
460+
// `tests/ui/traits/next-solver/normalization-shadowing/use_object_if_empty_env.rs`.
461+
if matches!(normalized_self_ty.kind(), ty::Dynamic(..))
462+
&& !candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
463+
{
464+
self.assemble_object_bound_candidates(goal, &mut candidates);
465+
}
466+
}
458467
}
459468

460469
(candidates, failed_candidate_info)

library/alloc/src/collections/vec_deque/mod.rs

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub use self::iter::Iter;
5252

5353
mod iter;
5454

55-
use self::spec_extend::SpecExtend;
55+
use self::spec_extend::{SpecExtend, SpecExtendFront};
5656

5757
mod spec_extend;
5858

@@ -179,6 +179,21 @@ impl<T, A: Allocator> VecDeque<T, A> {
179179
self.len += 1;
180180
}
181181

182+
/// Prepends an element to the buffer.
183+
///
184+
/// # Safety
185+
///
186+
/// May only be called if `deque.len() < deque.capacity()`
187+
#[inline]
188+
unsafe fn push_front_unchecked(&mut self, element: T) {
189+
self.head = self.wrap_sub(self.head, 1);
190+
// SAFETY: Because of the precondition, it's guaranteed that there is space
191+
// in the logical array before the first element (where self.head is now).
192+
unsafe { self.buffer_write(self.head, element) };
193+
// This can't overflow because `deque.len() < deque.capacity() <= usize::MAX`.
194+
self.len += 1;
195+
}
196+
182197
/// Moves an element out of the buffer
183198
#[inline]
184199
unsafe fn buffer_read(&mut self, off: usize) -> T {
@@ -505,6 +520,35 @@ impl<T, A: Allocator> VecDeque<T, A> {
505520
}
506521
}
507522

523+
/// Copies all values from `src` to `dst` in reversed order, wrapping around if needed.
524+
/// Assumes capacity is sufficient.
525+
/// Equivalent to calling [`VecDeque::copy_slice`] with a [reversed](https://doc.rust-lang.org/std/primitive.slice.html#method.reverse) slice.
526+
#[inline]
527+
unsafe fn copy_slice_reversed(&mut self, dst: usize, src: &[T]) {
528+
/// # Safety
529+
///
530+
/// See [`ptr::copy_nonoverlapping`].
531+
unsafe fn copy_nonoverlapping_reversed<T>(src: *const T, dst: *mut T, count: usize) {
532+
for i in 0..count {
533+
unsafe { ptr::copy_nonoverlapping(src.add(count - 1 - i), dst.add(i), 1) };
534+
}
535+
}
536+
537+
debug_assert!(src.len() <= self.capacity());
538+
let head_room = self.capacity() - dst;
539+
if src.len() <= head_room {
540+
unsafe {
541+
copy_nonoverlapping_reversed(src.as_ptr(), self.ptr().add(dst), src.len());
542+
}
543+
} else {
544+
let (left, right) = src.split_at(src.len() - head_room);
545+
unsafe {
546+
copy_nonoverlapping_reversed(right.as_ptr(), self.ptr().add(dst), right.len());
547+
copy_nonoverlapping_reversed(left.as_ptr(), self.ptr(), left.len());
548+
}
549+
}
550+
}
551+
508552
/// Writes all values from `iter` to `dst`.
509553
///
510554
/// # Safety
@@ -2122,6 +2166,73 @@ impl<T, A: Allocator> VecDeque<T, A> {
21222166
unsafe { self.buffer_write(self.to_physical_idx(len), value) }
21232167
}
21242168

2169+
/// Prepends all contents of the iterator to the front of the deque.
2170+
/// The order of the contents is preserved.
2171+
///
2172+
/// To get behavior like [`append`][VecDeque::append] where elements are moved
2173+
/// from the other collection to this one, use `self.prepend(other.drain(..))`.
2174+
///
2175+
/// # Examples
2176+
///
2177+
/// ```
2178+
/// #![feature(deque_extend_front)]
2179+
/// use std::collections::VecDeque;
2180+
///
2181+
/// let mut deque = VecDeque::from([4, 5, 6]);
2182+
/// deque.prepend([1, 2, 3]);
2183+
/// assert_eq!(deque, [1, 2, 3, 4, 5, 6]);
2184+
/// ```
2185+
///
2186+
/// Move values between collections like [`append`][VecDeque::append] does but prepend to the front:
2187+
///
2188+
/// ```
2189+
/// #![feature(deque_extend_front)]
2190+
/// use std::collections::VecDeque;
2191+
///
2192+
/// let mut deque1 = VecDeque::from([4, 5, 6]);
2193+
/// let mut deque2 = VecDeque::from([1, 2, 3]);
2194+
/// deque1.prepend(deque2.drain(..));
2195+
/// assert_eq!(deque1, [1, 2, 3, 4, 5, 6]);
2196+
/// assert!(deque2.is_empty());
2197+
/// ```
2198+
#[unstable(feature = "deque_extend_front", issue = "146975")]
2199+
#[track_caller]
2200+
pub fn prepend<I: IntoIterator<Item = T, IntoIter: DoubleEndedIterator>>(&mut self, other: I) {
2201+
self.extend_front(other.into_iter().rev())
2202+
}
2203+
2204+
/// Prepends all contents of the iterator to the front of the deque,
2205+
/// as if [`push_front`][VecDeque::push_front] was called repeatedly with
2206+
/// the values yielded by the iterator.
2207+
///
2208+
/// # Examples
2209+
///
2210+
/// ```
2211+
/// #![feature(deque_extend_front)]
2212+
/// use std::collections::VecDeque;
2213+
///
2214+
/// let mut deque = VecDeque::from([4, 5, 6]);
2215+
/// deque.extend_front([3, 2, 1]);
2216+
/// assert_eq!(deque, [1, 2, 3, 4, 5, 6]);
2217+
/// ```
2218+
///
2219+
/// This behaves like [`push_front`][VecDeque::push_front] was called repeatedly:
2220+
///
2221+
/// ```
2222+
/// use std::collections::VecDeque;
2223+
///
2224+
/// let mut deque = VecDeque::from([4, 5, 6]);
2225+
/// for v in [3, 2, 1] {
2226+
/// deque.push_front(v);
2227+
/// }
2228+
/// assert_eq!(deque, [1, 2, 3, 4, 5, 6]);
2229+
/// ```
2230+
#[unstable(feature = "deque_extend_front", issue = "146975")]
2231+
#[track_caller]
2232+
pub fn extend_front<I: IntoIterator<Item = T>>(&mut self, iter: I) {
2233+
<Self as SpecExtendFront<T, I::IntoIter>>::spec_extend_front(self, iter.into_iter());
2234+
}
2235+
21252236
#[inline]
21262237
fn is_contiguous(&self) -> bool {
21272238
// Do the calculation like this to avoid overflowing if len + head > usize::MAX

library/alloc/src/collections/vec_deque/spec_extend.rs

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::iter::TrustedLen;
1+
use core::iter::{Copied, Rev, TrustedLen};
22
use core::slice;
33

44
use super::VecDeque;
@@ -114,3 +114,113 @@ where
114114
}
115115
}
116116
}
117+
118+
// Specialization trait used for VecDeque::extend_front
119+
pub(super) trait SpecExtendFront<T, I> {
120+
#[track_caller]
121+
fn spec_extend_front(&mut self, iter: I);
122+
}
123+
124+
impl<T, I, A: Allocator> SpecExtendFront<T, I> for VecDeque<T, A>
125+
where
126+
I: Iterator<Item = T>,
127+
{
128+
#[track_caller]
129+
default fn spec_extend_front(&mut self, mut iter: I) {
130+
// This function should be the moral equivalent of:
131+
//
132+
// for item in iter {
133+
// self.push_front(item);
134+
// }
135+
136+
while let Some(element) = iter.next() {
137+
let (lower, _) = iter.size_hint();
138+
self.reserve(lower.saturating_add(1));
139+
140+
// SAFETY: We just reserved space for at least one element.
141+
unsafe { self.push_front_unchecked(element) };
142+
143+
// Inner loop to avoid repeatedly calling `reserve`.
144+
while self.len < self.capacity() {
145+
let Some(element) = iter.next() else {
146+
return;
147+
};
148+
// SAFETY: The loop condition guarantees that `self.len() < self.capacity()`.
149+
unsafe { self.push_front_unchecked(element) };
150+
}
151+
}
152+
}
153+
}
154+
155+
#[cfg(not(test))]
156+
impl<T, A: Allocator> SpecExtendFront<T, vec::IntoIter<T>> for VecDeque<T, A> {
157+
#[track_caller]
158+
fn spec_extend_front(&mut self, mut iterator: vec::IntoIter<T>) {
159+
let slice = iterator.as_slice();
160+
// SAFETY: elements in the slice are forgotten after this call
161+
unsafe { prepend_reversed(self, slice) };
162+
iterator.forget_remaining_elements();
163+
}
164+
}
165+
166+
#[cfg(not(test))]
167+
impl<T, A: Allocator> SpecExtendFront<T, Rev<vec::IntoIter<T>>> for VecDeque<T, A> {
168+
#[track_caller]
169+
fn spec_extend_front(&mut self, iterator: Rev<vec::IntoIter<T>>) {
170+
let mut iterator = iterator.into_inner();
171+
let slice = iterator.as_slice();
172+
// SAFETY: elements in the slice are forgotten after this call
173+
unsafe { prepend(self, slice) };
174+
iterator.forget_remaining_elements();
175+
}
176+
}
177+
178+
impl<'a, T, A: Allocator> SpecExtendFront<T, Copied<slice::Iter<'a, T>>> for VecDeque<T, A>
179+
where
180+
Copied<slice::Iter<'a, T>>: Iterator<Item = T>,
181+
{
182+
#[track_caller]
183+
fn spec_extend_front(&mut self, iter: Copied<slice::Iter<'a, T>>) {
184+
let slice = iter.into_inner().as_slice();
185+
// SAFETY: T is Copy because Copied<slice::Iter<'a, T>> is Iterator
186+
unsafe { prepend_reversed(self, slice) };
187+
}
188+
}
189+
190+
impl<'a, T, A: Allocator> SpecExtendFront<T, Rev<Copied<slice::Iter<'a, T>>>> for VecDeque<T, A>
191+
where
192+
Rev<Copied<slice::Iter<'a, T>>>: Iterator<Item = T>,
193+
{
194+
#[track_caller]
195+
fn spec_extend_front(&mut self, iter: Rev<Copied<slice::Iter<'a, T>>>) {
196+
let slice = iter.into_inner().into_inner().as_slice();
197+
// SAFETY: T is Copy because Rev<Copied<slice::Iter<'a, T>>> is Iterator
198+
unsafe { prepend(self, slice) };
199+
}
200+
}
201+
202+
/// # Safety
203+
///
204+
/// Elements of `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`.
205+
unsafe fn prepend<T, A: Allocator>(deque: &mut VecDeque<T, A>, slice: &[T]) {
206+
deque.reserve(slice.len());
207+
208+
unsafe {
209+
deque.head = deque.wrap_sub(deque.head, slice.len());
210+
deque.copy_slice(deque.head, slice);
211+
deque.len += slice.len();
212+
}
213+
}
214+
215+
/// # Safety
216+
///
217+
/// Elements of `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`.
218+
unsafe fn prepend_reversed<T, A: Allocator>(deque: &mut VecDeque<T, A>, slice: &[T]) {
219+
deque.reserve(slice.len());
220+
221+
unsafe {
222+
deque.head = deque.wrap_sub(deque.head, slice.len());
223+
deque.copy_slice_reversed(deque.head, slice);
224+
deque.len += slice.len();
225+
}
226+
}

library/alloc/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
#![feature(const_default)]
107107
#![feature(const_eval_select)]
108108
#![feature(const_heap)]
109+
#![feature(copied_into_inner)]
109110
#![feature(core_intrinsics)]
110111
#![feature(deprecated_suggestion)]
111112
#![feature(deref_pure_trait)]
@@ -134,6 +135,7 @@
134135
#![feature(ptr_alignment_type)]
135136
#![feature(ptr_internals)]
136137
#![feature(ptr_metadata)]
138+
#![feature(rev_into_inner)]
137139
#![feature(set_ptr_value)]
138140
#![feature(sized_type_properties)]
139141
#![feature(slice_from_ptr_range)]

library/alloctests/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#![feature(assert_matches)]
2121
#![feature(char_internals)]
2222
#![feature(char_max_len)]
23+
#![feature(copied_into_inner)]
2324
#![feature(core_intrinsics)]
2425
#![feature(exact_size_is_empty)]
2526
#![feature(extend_one)]
@@ -32,6 +33,7 @@
3233
#![feature(maybe_uninit_uninit_array_transpose)]
3334
#![feature(ptr_alignment_type)]
3435
#![feature(ptr_internals)]
36+
#![feature(rev_into_inner)]
3537
#![feature(sized_type_properties)]
3638
#![feature(slice_iter_mut_as_mut_slice)]
3739
#![feature(slice_ptr_get)]

library/alloctests/tests/vec_deque.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,3 +2081,77 @@ fn test_extend_and_prepend_from_within() {
20812081
v.extend_from_within(..);
20822082
assert_eq!(v.iter().map(|s| &**s).collect::<String>(), "123123123123");
20832083
}
2084+
2085+
#[test]
2086+
fn test_extend_front() {
2087+
let mut v = VecDeque::new();
2088+
v.extend_front(0..3);
2089+
assert_eq!(v, [2, 1, 0]);
2090+
v.extend_front(3..6);
2091+
assert_eq!(v, [5, 4, 3, 2, 1, 0]);
2092+
v.prepend([1; 4]);
2093+
assert_eq!(v, [1, 1, 1, 1, 5, 4, 3, 2, 1, 0]);
2094+
2095+
let mut v = VecDeque::with_capacity(8);
2096+
let cap = v.capacity();
2097+
v.extend(0..4);
2098+
v.truncate_front(2);
2099+
v.extend_front(4..8);
2100+
assert_eq!(v.as_slices(), ([7, 6].as_slice(), [5, 4, 2, 3].as_slice()));
2101+
assert_eq!(v.capacity(), cap);
2102+
2103+
let mut v = VecDeque::new();
2104+
v.extend_front([]);
2105+
v.extend_front(None);
2106+
v.extend_front(vec![]);
2107+
v.prepend([]);
2108+
v.prepend(None);
2109+
v.prepend(vec![]);
2110+
assert_eq!(v.capacity(), 0);
2111+
v.extend_front(Some(123));
2112+
assert_eq!(v, [123]);
2113+
}
2114+
2115+
#[test]
2116+
fn test_extend_front_specialization_vec_into_iter() {
2117+
// trigger 4 code paths: all combinations of prepend and extend_front, wrap and no wrap
2118+
let mut v = VecDeque::with_capacity(4);
2119+
v.prepend(vec![1, 2, 3]);
2120+
assert_eq!(v, [1, 2, 3]);
2121+
v.pop_back();
2122+
// this should wrap around the physical buffer
2123+
v.prepend(vec![-1, 0]);
2124+
// check it really wrapped
2125+
assert_eq!(v.as_slices(), ([-1].as_slice(), [0, 1, 2].as_slice()));
2126+
2127+
let mut v = VecDeque::with_capacity(4);
2128+
v.extend_front(vec![1, 2, 3]);
2129+
assert_eq!(v, [3, 2, 1]);
2130+
v.pop_back();
2131+
// this should wrap around the physical buffer
2132+
v.extend_front(vec![4, 5]);
2133+
// check it really wrapped
2134+
assert_eq!(v.as_slices(), ([5].as_slice(), [4, 3, 2].as_slice()));
2135+
}
2136+
2137+
#[test]
2138+
fn test_extend_front_specialization_copy_slice() {
2139+
// trigger 4 code paths: all combinations of prepend and extend_front, wrap and no wrap
2140+
let mut v = VecDeque::with_capacity(4);
2141+
v.prepend([1, 2, 3].as_slice().iter().copied());
2142+
assert_eq!(v, [1, 2, 3]);
2143+
v.pop_back();
2144+
// this should wrap around the physical buffer
2145+
v.prepend([-1, 0].as_slice().iter().copied());
2146+
// check it really wrapped
2147+
assert_eq!(v.as_slices(), ([-1].as_slice(), [0, 1, 2].as_slice()));
2148+
2149+
let mut v = VecDeque::with_capacity(4);
2150+
v.extend_front([1, 2, 3].as_slice().iter().copied());
2151+
assert_eq!(v, [3, 2, 1]);
2152+
v.pop_back();
2153+
// this should wrap around the physical buffer
2154+
v.extend_front([4, 5].as_slice().iter().copied());
2155+
// check it really wrapped
2156+
assert_eq!(v.as_slices(), ([5].as_slice(), [4, 3, 2].as_slice()));
2157+
}

0 commit comments

Comments
 (0)