Commit b481dd85 authored by Miguel Ojeda's avatar Miguel Ojeda
Browse files

rust: upgrade to Rust 1.77.1

This is the next upgrade to the Rust toolchain, from 1.76.0 to 1.77.1
(i.e. the latest) [1].

See the upgrade policy [2] and the comments on the first upgrade in
commit 3ed03f4d ("rust: upgrade to Rust 1.68.2").

# Unstable features

The `offset_of` feature (single-field `offset_of!`) that we were using
got stabilized in Rust 1.77.0 [3].

Therefore, now the only unstable features allowed to be used outside the
`kernel` crate is `new_uninit`, though other code to be upstreamed may
increase the list.

Please see [4] for details.

# Required changes

Rust 1.77.0 merged the `unused_tuple_struct_fields` lint into `dead_code`,
thus upgrading it from `allow` to `warn` [5]. In turn, this made `rustc`
complain about the `ThisModule`'s pointer field being never read, but
the previous patch adds the `as_ptr` method to it, needed by Binder [6],
so that we do not need to locally `allow` it.

# Other changes

Rust 1.77.0 introduces the `--check-cfg` feature [7], for which there
is a Call for Testing going on [8]. We were requested to test it and
we found it useful [9] -- we will likely enable it in the future.

# `alloc` upgrade and reviewing

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://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-1770-2024-03-21 [1]
Link: https://rust-for-linux.com/rust-version-policy [2]
Link: https://github.com/rust-lang/rust/pull/118799 [3]
Link: https://github.com/Rust-for-Linux/linux/issues/2 [4]
Link: https://github.com/rust-lang/rust/pull/118297 [5]
Link: https://lore.kernel.org/rust-for-linux/20231101-rust-binder-v1-2-08ba9197f637@google.com/#Z31rust:kernel:lib.rs [6]
Link: https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html [7]
Link: https://github.com/rust-lang/rfcs/pull/3013#issuecomment-1936648479 [8]
Link: https://github.com/rust-lang/rust/issues/82450#issuecomment-1947462977

 [9]
Reviewed-by: default avatarAlice Ryhl <aliceryhl@google.com>
Tested-by: default avatarBoqun Feng <boqun.feng@gmail.com>
Link: https://lore.kernel.org/r/20240217002717.57507-1-ojeda@kernel.org


[ Upgraded to 1.77.1. Removed `allow(dead_code)` thanks to the previous
  patch. Reworded accordingly. No changes to `alloc` during the beta. ]
Signed-off-by: default avatarMiguel Ojeda <ojeda@kernel.org>
parent d0f0241d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ you probably needn't concern yourself with pcmciautils.
====================== ===============  ========================================
GNU C                  5.1              gcc --version
Clang/LLVM (optional)  13.0.1           clang --version
Rust (optional)        1.76.0           rustc --version
Rust (optional)        1.77.1           rustc --version
bindgen (optional)     0.65.1           bindgen --version
GNU make               3.82             make --version
bash                   4.2              bash --version
+3 −3
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
#![stable(feature = "alloc_module", since = "1.28.0")]

#[cfg(not(test))]
use core::intrinsics;
use core::hint;

#[cfg(not(test))]
use core::ptr::{self, NonNull};
@@ -210,7 +210,7 @@ unsafe fn grow_impl(
                let new_size = new_layout.size();

                // `realloc` probably checks for `new_size >= old_layout.size()` or something similar.
                intrinsics::assume(new_size >= old_layout.size());
                hint::assert_unchecked(new_size >= old_layout.size());

                let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
@@ -301,7 +301,7 @@ unsafe fn shrink(
            // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
            new_size if old_layout.align() == new_layout.align() => unsafe {
                // `realloc` probably checks for `new_size <= old_layout.size()` or something similar.
                intrinsics::assume(new_size <= old_layout.size());
                hint::assert_unchecked(new_size <= old_layout.size());

                let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
+2 −2
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
//! Creating a recursive data structure:
//!
//! ```
//! ##[allow(dead_code)]
//! #[derive(Debug)]
//! enum List<T> {
//!     Cons(T, Box<List<T>>),
@@ -194,8 +195,7 @@
#[fundamental]
#[stable(feature = "rust1", since = "1.0.0")]
// The declaration of the `Box` struct must be kept in sync with the
// `alloc::alloc::box_free` function or ICEs will happen. See the comment
// on `box_free` for more details.
// compiler or ICEs will happen.
pub struct Box<
    T: ?Sized,
    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+4 −3
Original line number Diff line number Diff line
@@ -105,7 +105,6 @@
#![feature(allocator_api)]
#![feature(array_chunks)]
#![feature(array_into_iter_constructors)]
#![feature(array_methods)]
#![feature(array_windows)]
#![feature(ascii_char)]
#![feature(assert_matches)]
@@ -122,7 +121,6 @@
#![feature(const_size_of_val)]
#![feature(const_waker)]
#![feature(core_intrinsics)]
#![feature(core_panic)]
#![feature(deprecated_suggestion)]
#![feature(dispatch_from_dyn)]
#![feature(error_generic_member_access)]
@@ -132,6 +130,7 @@
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(hasher_prefixfree_extras)]
#![feature(hint_assert_unchecked)]
#![feature(inline_const)]
#![feature(inplace_iteration)]
#![feature(iter_advance_by)]
@@ -141,6 +140,8 @@
#![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_uninit_array_transpose)]
#![feature(non_null_convenience)]
#![feature(panic_internals)]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(ptr_metadata)]
@@ -149,7 +150,6 @@
#![feature(set_ptr_value)]
#![feature(sized_type_properties)]
#![feature(slice_from_ptr_range)]
#![feature(slice_group_by)]
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
#![feature(slice_range)]
@@ -182,6 +182,7 @@
#![feature(const_ptr_write)]
#![feature(const_trait_impl)]
#![feature(const_try)]
#![feature(decl_macro)]
#![feature(dropck_eyepatch)]
#![feature(exclusive_range_pattern)]
#![feature(fundamental)]
+6 −7
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@

use core::alloc::LayoutError;
use core::cmp;
use core::intrinsics;
use core::hint;
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
use core::ptr::{self, NonNull, Unique};
use core::slice;
@@ -317,7 +317,7 @@ fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
    ///
    /// # Panics
    ///
    /// Panics if the new capacity exceeds `isize::MAX` bytes.
    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
    ///
    /// # Aborts
    ///
@@ -358,7 +358,7 @@ pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryRe
        }
        unsafe {
            // Inform the optimizer that the reservation has succeeded or wasn't needed
            core::intrinsics::assume(!self.needs_to_grow(len, additional));
            hint::assert_unchecked(!self.needs_to_grow(len, additional));
        }
        Ok(())
    }
@@ -381,7 +381,7 @@ pub fn try_reserve_for_push(&mut self, len: usize) -> Result<(), TryReserveError
    ///
    /// # Panics
    ///
    /// Panics if the new capacity exceeds `isize::MAX` bytes.
    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
    ///
    /// # Aborts
    ///
@@ -402,7 +402,7 @@ pub fn try_reserve_exact(
        }
        unsafe {
            // Inform the optimizer that the reservation has succeeded or wasn't needed
            core::intrinsics::assume(!self.needs_to_grow(len, additional));
            hint::assert_unchecked(!self.needs_to_grow(len, additional));
        }
        Ok(())
    }
@@ -553,7 +553,7 @@ fn finish_grow<A>(
        debug_assert_eq!(old_layout.align(), new_layout.align());
        unsafe {
            // The allocator checks for alignment equality
            intrinsics::assume(old_layout.align() == new_layout.align());
            hint::assert_unchecked(old_layout.align() == new_layout.align());
            alloc.grow(ptr, old_layout, new_layout)
        }
    } else {
@@ -591,7 +591,6 @@ fn handle_reserve(result: Result<(), TryReserveError>) {
// `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add
// an extra guard for this in case we're running on a platform which can use
// all 4GB in user-space, e.g., PAE or x32.

#[inline]
fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
    if usize::BITS < 64 && alloc_size > isize::MAX as usize {
Loading