Commit 96f42635 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'rust-6.2' of https://github.com/Rust-for-Linux/linux

Pull rust updates from Miguel Ojeda:
 "The first set of changes after the merge, the major ones being:

   - String and formatting: new types 'CString', 'CStr', 'BStr' and
     'Formatter'; new macros 'c_str!', 'b_str!' and 'fmt!'.

   - Errors: the rest of the error codes from 'errno-base.h', as well as
     some 'From' trait implementations for the 'Error' type.

   - Printing: the rest of the 'pr_*!' levels and the continuation one
     'pr_cont!', as well as a new sample.

   - 'alloc' crate: new constructors 'try_with_capacity()' and
     'try_with_capacity_in()' for 'RawVec' and 'Vec'.

   - Procedural macros: new macros '#[vtable]' and 'concat_idents!', as
     well as better ergonomics for 'module!' users.

   - Asserting: new macros 'static_assert!', 'build_error!' and
     'build_assert!', as well as a new crate 'build_error' to support
     them.

   - Vocabulary types: new types 'Opaque' and 'Either'.

   - Debugging: new macro 'dbg!'"

* tag 'rust-6.2' of https://github.com/Rust-for-Linux/linux: (28 commits)
  rust: types: add `Opaque` type
  rust: types: add `Either` type
  rust: build_assert: add `build_{error,assert}!` macros
  rust: add `build_error` crate
  rust: static_assert: add `static_assert!` macro
  rust: std_vendor: add `dbg!` macro based on `std`'s one
  rust: str: add `fmt!` macro
  rust: str: add `CString` type
  rust: str: add `Formatter` type
  rust: str: add `c_str!` macro
  rust: str: add `CStr` unit tests
  rust: str: implement several traits for `CStr`
  rust: str: add `CStr` type
  rust: str: add `b_str!` macro
  rust: str: add `BStr` type
  rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors
  rust: alloc: add `RawVec::try_with_capacity_in()` constructor
  rust: prelude: add `error::code::*` constant items
  rust: error: add `From` implementations for `Error`
  rust: error: add codes from `errno-base.h`
  ...
parents eb451153 b9ecf9b9
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -2823,6 +2823,22 @@ config RUST_OVERFLOW_CHECKS

	  If unsure, say Y.

config RUST_BUILD_ASSERT_ALLOW
	bool "Allow unoptimized build-time assertions"
	depends on RUST
	help
	  Controls how are `build_error!` and `build_assert!` handled during build.

	  If calls to them exist in the binary, it may indicate a violated invariant
	  or that the optimizer failed to verify the invariant during compilation.

	  This should not happen, thus by default the build is aborted. However,
	  as an escape hatch, you can choose Y here to ignore them during build
	  and let the check be carried at runtime (with `panic!` being called if
	  the check fails).

	  If unsure, say N.

endmenu # "Rust"

source "Documentation/Kconfig"
+17 −5
Original line number Diff line number Diff line
@@ -19,6 +19,12 @@ obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o
always-$(CONFIG_RUST) += exports_alloc_generated.h exports_bindings_generated.h \
    exports_kernel_generated.h

ifdef CONFIG_RUST_BUILD_ASSERT_ALLOW
obj-$(CONFIG_RUST) += build_error.o
else
always-$(CONFIG_RUST) += build_error.o
endif

obj-$(CONFIG_RUST) += exports.o

# Avoids running `$(RUSTC)` for the sysroot when it may not be available.
@@ -108,7 +114,7 @@ rustdoc-alloc: $(src)/alloc/lib.rs rustdoc-core rustdoc-compiler_builtins FORCE
	$(call if_changed,rustdoc)

rustdoc-kernel: private rustc_target_flags = --extern alloc \
    --extern macros=$(objtree)/$(obj)/libmacros.so \
    --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \
    --extern bindings
rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \
    rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \
@@ -126,6 +132,9 @@ quiet_cmd_rustc_test_library = RUSTC TL $<
		-L$(objtree)/$(obj)/test \
		--crate-name $(subst rusttest-,,$(subst rusttestlib-,,$@)) $<

rusttestlib-build_error: $(src)/build_error.rs rusttest-prepare FORCE
	$(call if_changed,rustc_test_library)

rusttestlib-macros: private rustc_target_flags = --extern proc_macro
rusttestlib-macros: private rustc_test_library_proc = yes
rusttestlib-macros: $(src)/macros/lib.rs rusttest-prepare FORCE
@@ -216,9 +225,9 @@ rusttest-macros: $(src)/macros/lib.rs rusttest-prepare FORCE
	$(call if_changed,rustdoc_test)

rusttest-kernel: private rustc_target_flags = --extern alloc \
    --extern macros --extern bindings
    --extern build_error --extern macros --extern bindings
rusttest-kernel: $(src)/kernel/lib.rs rusttest-prepare \
    rusttestlib-macros rusttestlib-bindings FORCE
    rusttestlib-build_error rusttestlib-macros rusttestlib-bindings FORCE
	$(call if_changed,rustc_test)
	$(call if_changed,rustc_test_library)

@@ -366,6 +375,9 @@ $(obj)/alloc.o: private rustc_target_flags = $(alloc-cfgs)
$(obj)/alloc.o: $(src)/alloc/lib.rs $(obj)/compiler_builtins.o FORCE
	$(call if_changed_dep,rustc_library)

$(obj)/build_error.o: $(src)/build_error.rs $(obj)/compiler_builtins.o FORCE
	$(call if_changed_dep,rustc_library)

$(obj)/bindings.o: $(src)/bindings/lib.rs \
    $(obj)/compiler_builtins.o \
    $(obj)/bindings/bindings_generated.rs \
@@ -373,8 +385,8 @@ $(obj)/bindings.o: $(src)/bindings/lib.rs \
	$(call if_changed_dep,rustc_library)

$(obj)/kernel.o: private rustc_target_flags = --extern alloc \
    --extern macros --extern bindings
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o \
    --extern build_error --extern macros --extern bindings
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \
    $(obj)/libmacros.so $(obj)/bindings.o FORCE
	$(call if_changed_dep,rustc_library)

+32 −1
Original line number Diff line number Diff line
@@ -20,11 +20,11 @@ use crate::collections::TryReserveErrorKind::*;
#[cfg(test)]
mod tests;

#[cfg(not(no_global_oom_handling))]
enum AllocInit {
    /// The contents of the new memory are uninitialized.
    Uninitialized,
    /// The new memory is guaranteed to be zeroed.
    #[allow(dead_code)]
    Zeroed,
}

@@ -133,6 +133,13 @@ impl<T, A: Allocator> RawVec<T, A> {
        Self::allocate_in(capacity, AllocInit::Uninitialized, alloc)
    }

    /// Like `try_with_capacity`, but parameterized over the choice of
    /// allocator for the returned `RawVec`.
    #[inline]
    pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
        Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc)
    }

    /// Like `with_capacity_zeroed`, but parameterized over the choice
    /// of allocator for the returned `RawVec`.
    #[cfg(not(no_global_oom_handling))]
@@ -203,6 +210,30 @@ impl<T, A: Allocator> RawVec<T, A> {
        }
    }

    fn try_allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Result<Self, TryReserveError> {
        // Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
        if mem::size_of::<T>() == 0 || capacity == 0 {
            return Ok(Self::new_in(alloc));
        }

        let layout = Layout::array::<T>(capacity).map_err(|_| CapacityOverflow)?;
        alloc_guard(layout.size())?;
        let result = match init {
            AllocInit::Uninitialized => alloc.allocate(layout),
            AllocInit::Zeroed => alloc.allocate_zeroed(layout),
        };
        let ptr = result.map_err(|_| AllocError { layout, non_exhaustive: () })?;

        // Allocators currently return a `NonNull<[u8]>` whose length
        // matches the size requested. If that ever changes, the capacity
        // here should change to `ptr.len() / mem::size_of::<T>()`.
        Ok(Self {
            ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) },
            cap: capacity,
            alloc,
        })
    }

    /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator.
    ///
    /// # Safety
+89 −0
Original line number Diff line number Diff line
@@ -472,6 +472,48 @@ impl<T> Vec<T> {
        Self::with_capacity_in(capacity, Global)
    }

    /// Tries to construct a new, empty `Vec<T>` with the specified capacity.
    ///
    /// The vector will be able to hold exactly `capacity` elements without
    /// reallocating. If `capacity` is 0, the vector will not allocate.
    ///
    /// It is important to note that although the returned vector has the
    /// *capacity* specified, the vector will have a zero *length*. For an
    /// explanation of the difference between length and capacity, see
    /// *[Capacity and reallocation]*.
    ///
    /// [Capacity and reallocation]: #capacity-and-reallocation
    ///
    /// # Examples
    ///
    /// ```
    /// let mut vec = Vec::try_with_capacity(10).unwrap();
    ///
    /// // The vector contains no items, even though it has capacity for more
    /// assert_eq!(vec.len(), 0);
    /// assert_eq!(vec.capacity(), 10);
    ///
    /// // These are all done without reallocating...
    /// for i in 0..10 {
    ///     vec.push(i);
    /// }
    /// assert_eq!(vec.len(), 10);
    /// assert_eq!(vec.capacity(), 10);
    ///
    /// // ...but this may make the vector reallocate
    /// vec.push(11);
    /// assert_eq!(vec.len(), 11);
    /// assert!(vec.capacity() >= 11);
    ///
    /// let mut result = Vec::try_with_capacity(usize::MAX);
    /// assert!(result.is_err());
    /// ```
    #[inline]
    #[stable(feature = "kernel", since = "1.0.0")]
    pub fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
        Self::try_with_capacity_in(capacity, Global)
    }

    /// Creates a `Vec<T>` directly from the raw components of another vector.
    ///
    /// # Safety
@@ -617,6 +659,53 @@ impl<T, A: Allocator> Vec<T, A> {
        Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
    }

    /// Tries to construct a new, empty `Vec<T, A>` with the specified capacity
    /// with the provided allocator.
    ///
    /// The vector will be able to hold exactly `capacity` elements without
    /// reallocating. If `capacity` is 0, the vector will not allocate.
    ///
    /// It is important to note that although the returned vector has the
    /// *capacity* specified, the vector will have a zero *length*. For an
    /// explanation of the difference between length and capacity, see
    /// *[Capacity and reallocation]*.
    ///
    /// [Capacity and reallocation]: #capacity-and-reallocation
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(allocator_api)]
    ///
    /// use std::alloc::System;
    ///
    /// let mut vec = Vec::try_with_capacity_in(10, System).unwrap();
    ///
    /// // The vector contains no items, even though it has capacity for more
    /// assert_eq!(vec.len(), 0);
    /// assert_eq!(vec.capacity(), 10);
    ///
    /// // These are all done without reallocating...
    /// for i in 0..10 {
    ///     vec.push(i);
    /// }
    /// assert_eq!(vec.len(), 10);
    /// assert_eq!(vec.capacity(), 10);
    ///
    /// // ...but this may make the vector reallocate
    /// vec.push(11);
    /// assert_eq!(vec.len(), 11);
    /// assert!(vec.capacity() >= 11);
    ///
    /// let mut result = Vec::try_with_capacity_in(usize::MAX, System);
    /// assert!(result.is_err());
    /// ```
    #[inline]
    #[stable(feature = "kernel", since = "1.0.0")]
    pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
        Ok(Vec { buf: RawVec::try_with_capacity_in(capacity, alloc)?, len: 0 })
    }

    /// Creates a `Vec<T, A>` directly from the raw components of another vector.
    ///
    /// # Safety

rust/build_error.rs

0 → 100644
+31 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

//! Build-time error.
//!
//! This crate provides a [const function][const-functions] `build_error`, which will panic in
//! compile-time if executed in [const context][const-context], and will cause a build error
//! if not executed at compile time and the optimizer does not optimise away the call.
//!
//! It is used by `build_assert!` in the kernel crate, allowing checking of
//! conditions that could be checked statically, but could not be enforced in
//! Rust yet (e.g. perform some checks in [const functions][const-functions], but those
//! functions could still be called in the runtime).
//!
//! For details on constant evaluation in Rust, please see the [Reference][const-eval].
//!
//! [const-eval]: https://doc.rust-lang.org/reference/const_eval.html
//! [const-functions]: https://doc.rust-lang.org/reference/const_eval.html#const-functions
//! [const-context]: https://doc.rust-lang.org/reference/const_eval.html#const-context

#![no_std]

/// Panics if executed in [const context][const-context], or triggers a build error if not.
///
/// [const-context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
#[inline(never)]
#[cold]
#[export_name = "rust_build_error"]
#[track_caller]
pub const fn build_error(msg: &'static str) -> ! {
    panic!("{}", msg);
}
Loading