Skip to content

Commit dd9084a

Browse files
ojedachessturo
authored andcommitted
rust: upgrade to Rust 1.71.0
This is the second upgrade to the Rust toolchain, from 1.68.2 to 1.71.0 (i.e. the latest). See the upgrade policy [1] and the comments on the first upgrade in commit 3ed03f4 ("rust: upgrade to Rust 1.68.2"). No unstable features (that we use) were stabilized. Therefore, the only unstable feature allowed to be used outside the `kernel` crate is still `new_uninit`, though other code to be upstreamed may increase the list. Please see [2] for details. For the upgrade, this patch requires the following changes: - Removal of the `__rust_*` allocator functions, together with the addition of the `__rust_no_alloc_shim_is_unstable` static. See [3] for details. - Some more compiler builtins added due to `<f{32,64}>::midpoint()` that got added in Rust 1.71 [4]. The vast majority of changes are due to our `alloc` fork being upgraded at once. There are two kinds of changes to be aware of: the ones coming from upstream, which we should follow as closely as possible, and the updates needed in our added fallible APIs to keep them matching the newer infallible APIs coming from upstream. Instead of taking a look at the diff of this patch, an alternative approach is reviewing a diff of the changes between upstream `alloc` and the kernel's. This allows to easily inspect the kernel additions only, especially to check if the fallible methods we already have still match the infallible ones in the new version coming from upstream. Another approach is reviewing the changes introduced in the additions in the kernel fork between the two versions. This is useful to spot potentially unintended changes to our additions. To apply these approaches, one may follow steps similar to the following to generate a pair of patches that show the differences between upstream Rust and the kernel (for the subset of `alloc` we use) before and after applying this patch: # Get the difference with respect to the old version. git -C rust checkout $(linux/scripts/min-tool-version.sh rustc) git -C linux ls-tree -r --name-only HEAD -- rust/alloc | cut -d/ -f3- | grep -Fv README.md | xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH git -C linux diff --patch-with-stat --summary -R > old.patch git -C linux restore rust/alloc # Apply this patch. git -C linux am rust-upgrade.patch # Get the difference with respect to the new version. git -C rust checkout $(linux/scripts/min-tool-version.sh rustc) git -C linux ls-tree -r --name-only HEAD -- rust/alloc | cut -d/ -f3- | grep -Fv README.md | xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH git -C linux diff --patch-with-stat --summary -R > new.patch git -C linux restore rust/alloc Now one may check the `new.patch` to take a look at the additions (first approach) or at the difference between those two patches (second approach). For the latter, a side-by-side tool is recommended. Link: https://rust-for-linux.com/rust-version-policy [1] Link: Rust-for-Linux#2 [2] Link: rust-lang/rust#86844 [3] Link: rust-lang/rust#92048 [4] Signed-off-by: Miguel Ojeda <[email protected]> Reviewed-by: Martin Rodriguez Reboredo <[email protected]> Link: https://lore.kernel.org/r/[email protected] [boqun: Resolve conflicts with bindgen 0.65.1 patch] [boqun: Resolve conflicts with __rust_alloc* fix ]
1 parent cf9906e commit dd9084a

File tree

3 files changed

+202
-0
lines changed

3 files changed

+202
-0
lines changed

rust/alloc/alloc.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ extern "Rust" {
4242
#[rustc_nounwind]
4343
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
4444

45+
#[cfg(not(bootstrap))]
4546
static __rust_no_alloc_shim_is_unstable: u8;
4647
}
4748

@@ -99,6 +100,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
99100
unsafe {
100101
// Make sure we don't accidentally allow omitting the allocator shim in
101102
// stable code until it is actually stabilized.
103+
#[cfg(not(bootstrap))]
102104
core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable);
103105

104106
__rust_alloc(layout.size(), layout.align())

rust/alloc/vec/drain_filter.rs

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
// SPDX-License-Identifier: Apache-2.0 OR MIT
2+
3+
use crate::alloc::{Allocator, Global};
4+
use core::mem::{ManuallyDrop, SizedTypeProperties};
5+
use core::ptr;
6+
use core::slice;
7+
8+
use super::Vec;
9+
10+
/// An iterator which uses a closure to determine if an element should be removed.
11+
///
12+
/// This struct is created by [`Vec::drain_filter`].
13+
/// See its documentation for more.
14+
///
15+
/// # Example
16+
///
17+
/// ```
18+
/// #![feature(drain_filter)]
19+
///
20+
/// let mut v = vec![0, 1, 2];
21+
/// let iter: std::vec::DrainFilter<'_, _, _> = v.drain_filter(|x| *x % 2 == 0);
22+
/// ```
23+
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
24+
#[derive(Debug)]
25+
pub struct DrainFilter<
26+
'a,
27+
T,
28+
F,
29+
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
30+
> where
31+
F: FnMut(&mut T) -> bool,
32+
{
33+
pub(super) vec: &'a mut Vec<T, A>,
34+
/// The index of the item that will be inspected by the next call to `next`.
35+
pub(super) idx: usize,
36+
/// The number of items that have been drained (removed) thus far.
37+
pub(super) del: usize,
38+
/// The original length of `vec` prior to draining.
39+
pub(super) old_len: usize,
40+
/// The filter test predicate.
41+
pub(super) pred: F,
42+
/// A flag that indicates a panic has occurred in the filter test predicate.
43+
/// This is used as a hint in the drop implementation to prevent consumption
44+
/// of the remainder of the `DrainFilter`. Any unprocessed items will be
45+
/// backshifted in the `vec`, but no further items will be dropped or
46+
/// tested by the filter predicate.
47+
pub(super) panic_flag: bool,
48+
}
49+
50+
impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
51+
where
52+
F: FnMut(&mut T) -> bool,
53+
{
54+
/// Returns a reference to the underlying allocator.
55+
#[unstable(feature = "allocator_api", issue = "32838")]
56+
#[inline]
57+
pub fn allocator(&self) -> &A {
58+
self.vec.allocator()
59+
}
60+
61+
/// Keep unyielded elements in the source `Vec`.
62+
///
63+
/// # Examples
64+
///
65+
/// ```
66+
/// #![feature(drain_filter)]
67+
/// #![feature(drain_keep_rest)]
68+
///
69+
/// let mut vec = vec!['a', 'b', 'c'];
70+
/// let mut drain = vec.drain_filter(|_| true);
71+
///
72+
/// assert_eq!(drain.next().unwrap(), 'a');
73+
///
74+
/// // This call keeps 'b' and 'c' in the vec.
75+
/// drain.keep_rest();
76+
///
77+
/// // If we wouldn't call `keep_rest()`,
78+
/// // `vec` would be empty.
79+
/// assert_eq!(vec, ['b', 'c']);
80+
/// ```
81+
#[unstable(feature = "drain_keep_rest", issue = "101122")]
82+
pub fn keep_rest(self) {
83+
// At this moment layout looks like this:
84+
//
85+
// _____________________/-- old_len
86+
// / \
87+
// [kept] [yielded] [tail]
88+
// \_______/ ^-- idx
89+
// \-- del
90+
//
91+
// Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`)
92+
//
93+
// 1. Move [tail] after [kept]
94+
// 2. Update length of the original vec to `old_len - del`
95+
// a. In case of ZST, this is the only thing we want to do
96+
// 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
97+
let mut this = ManuallyDrop::new(self);
98+
99+
unsafe {
100+
// ZSTs have no identity, so we don't need to move them around.
101+
if !T::IS_ZST && this.idx < this.old_len && this.del > 0 {
102+
let ptr = this.vec.as_mut_ptr();
103+
let src = ptr.add(this.idx);
104+
let dst = src.sub(this.del);
105+
let tail_len = this.old_len - this.idx;
106+
src.copy_to(dst, tail_len);
107+
}
108+
109+
let new_len = this.old_len - this.del;
110+
this.vec.set_len(new_len);
111+
}
112+
}
113+
}
114+
115+
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
116+
impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A>
117+
where
118+
F: FnMut(&mut T) -> bool,
119+
{
120+
type Item = T;
121+
122+
fn next(&mut self) -> Option<T> {
123+
unsafe {
124+
while self.idx < self.old_len {
125+
let i = self.idx;
126+
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
127+
self.panic_flag = true;
128+
let drained = (self.pred)(&mut v[i]);
129+
self.panic_flag = false;
130+
// Update the index *after* the predicate is called. If the index
131+
// is updated prior and the predicate panics, the element at this
132+
// index would be leaked.
133+
self.idx += 1;
134+
if drained {
135+
self.del += 1;
136+
return Some(ptr::read(&v[i]));
137+
} else if self.del > 0 {
138+
let del = self.del;
139+
let src: *const T = &v[i];
140+
let dst: *mut T = &mut v[i - del];
141+
ptr::copy_nonoverlapping(src, dst, 1);
142+
}
143+
}
144+
None
145+
}
146+
}
147+
148+
fn size_hint(&self) -> (usize, Option<usize>) {
149+
(0, Some(self.old_len - self.idx))
150+
}
151+
}
152+
153+
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
154+
impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
155+
where
156+
F: FnMut(&mut T) -> bool,
157+
{
158+
fn drop(&mut self) {
159+
struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator>
160+
where
161+
F: FnMut(&mut T) -> bool,
162+
{
163+
drain: &'b mut DrainFilter<'a, T, F, A>,
164+
}
165+
166+
impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A>
167+
where
168+
F: FnMut(&mut T) -> bool,
169+
{
170+
fn drop(&mut self) {
171+
unsafe {
172+
if self.drain.idx < self.drain.old_len && self.drain.del > 0 {
173+
// This is a pretty messed up state, and there isn't really an
174+
// obviously right thing to do. We don't want to keep trying
175+
// to execute `pred`, so we just backshift all the unprocessed
176+
// elements and tell the vec that they still exist. The backshift
177+
// is required to prevent a double-drop of the last successfully
178+
// drained item prior to a panic in the predicate.
179+
let ptr = self.drain.vec.as_mut_ptr();
180+
let src = ptr.add(self.drain.idx);
181+
let dst = src.sub(self.drain.del);
182+
let tail_len = self.drain.old_len - self.drain.idx;
183+
src.copy_to(dst, tail_len);
184+
}
185+
self.drain.vec.set_len(self.drain.old_len - self.drain.del);
186+
}
187+
}
188+
}
189+
190+
let backshift = BackshiftOnDrop { drain: self };
191+
192+
// Attempt to consume any remaining elements if the filter predicate
193+
// has not yet panicked. We'll backshift any remaining elements
194+
// whether we've already panicked or if the consumption here panics.
195+
if !backshift.drain.panic_flag {
196+
backshift.drain.for_each(drop);
197+
}
198+
}
199+
}

scripts/min-tool-version.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ llvm)
3232
;;
3333
rustc)
3434
echo 1.72.0
35+
echo 1.71.0
3536
;;
3637
bindgen)
3738
echo 0.65.1

0 commit comments

Comments
 (0)