Rust changes for v7.1

Toolchain and infrastructure:
 
  - Bump the minimum Rust version to 1.85.0 (and 'bindgen' to 0.71.1).
 
    As proposed in LPC 2025 and the Maintainers Summit [1], we are going
    to follow Debian Stable's Rust versions as our minimum versions.
 
    Debian Trixie was released on 2025-08-09 with a Rust 1.85.0 and
    'bindgen' 0.71.1 toolchain, which is a fair amount of time for e.g.
    kernel developers to upgrade.
 
    Other major distributions support a Rust version that is high enough
    as well, including:
 
      + Arch Linux.
      + Fedora Linux.
      + Gentoo Linux.
      + Nix.
      + openSUSE Slowroll and openSUSE Tumbleweed.
      + Ubuntu 25.10 and 26.04 LTS. In addition, 24.04 LTS using
        their versioned packages.
 
    The merged patch series comes with the associated cleanups and
    simplifications treewide that can be performed thanks to both bumps,
    as well as documentation updates.
 
    In addition, start using 'bindgen''s '--with-attribute-custom-enum'
    feature to set the 'cfi_encoding' attribute for the 'lru_status' enum
    used in Binder.
 
    Link: https://lwn.net/Articles/1050174/ [1]
 
  - Add experimental Kconfig option ('CONFIG_RUST_INLINE_HELPERS') that
    inlines C helpers into Rust.
 
    Essentially, it performs a step similar to LTO, but just for the
    helpers, i.e. very local and fast.
 
    It relies on 'llvm-link' and its '--internalize' flag, and requires
    a compatible LLVM between Clang and 'rustc' (i.e. same major version,
    'CONFIG_RUSTC_CLANG_LLVM_COMPATIBLE'). It is only enabled for two
    architectures for now.
 
    The result is a measurable speedup in different workloads that
    different users have tested. For instance, for the null block driver,
    it amounts to a 2%.
 
  - Support global per-version flags.
 
    While we already have per-version flags in many places, we didn't
    have a place to set global ones that depend on the compiler version,
    i.e. in 'rust_common_flags', which sometimes is needed to e.g. tweak
    the lints set per version.
 
    Use that to allow the 'clippy::precedence' lint for Rust < 1.86.0,
    since it had a change in behavior.
 
  - Support overriding the crate name and apply it to Rust Binder, which
    wanted the module to be called 'rust_binder'.
 
  - Add the remaining '__rust_helper' annotations (started in the
    previous cycle).
 
 'kernel' crate:
 
  - Introduce the 'const_assert!' macro: a more powerful version of
    'static_assert!' that can refer to generics inside functions or
    implementation bodies, e.g.:
 
        fn f<const N: usize>() {
            const_assert!(N > 1);
        }
 
        fn g<T>() {
            const_assert!(size_of::<T>() > 0, "T cannot be ZST");
        }
 
    In addition, reorganize our set of build-time assertion macros
    ('{build,const,static_assert}!') to live in the 'build_assert'
    module.
 
    Finally, improve the docs as well to clarify how these are different
    from one another and how to pick the right one to use, and their
    equivalence (if any) to the existing C ones for extra clarity.
 
  - 'sizes' module: add 'SizeConstants' trait.
 
    This gives us typed 'SZ_*' constants (avoiding casts) for use in
    device address spaces where the address width depends on the hardware
    (e.g. 32-bit MMIO windows, 64-bit GPU framebuffers, etc.), e.g.:
 
        let gpu_heap = 14 * u64::SZ_1M;
        let mmio_window = u32::SZ_16M;
 
  - 'clk' module: implement 'Send' and 'Sync' for 'Clk' and thus simplify
    the users in Tyr and PWM.
 
  - 'ptr' module: add 'const_align_up'.
 
  - 'str' module: improve the documentation of the 'c_str!' macro to
    explain that one should only use it for non-literal cases (for the
    other case we instead use C string literals, e.g. 'c"abc"').
 
  - Disallow the use of 'CStr::{as_ptr,from_ptr}' and clean one such use
    in the 'task' module.
 
  - 'sync' module: finish the move of 'ARef' and 'AlwaysRefCounted'
    outside of the 'types' module, i.e. update the last remaining
    instances and finally remove the re-exports.
 
  - 'error' module: clarify that 'from_err_ptr' can return 'Ok(NULL)',
    including runtime-tested examples.
 
    The intention is to hopefully prevent UB that assumes the result of
    the function is not 'NULL' if successful. This originated from a case
    of UB I noticed in 'regulator' that created a 'NonNull' on it.
 
 Timekeeping:
 
  - Expand the example section in the 'HrTimer' documentation.
 
  - Mark the 'ClockSource' trait as unsafe to ensure valid values for
    'ktime_get()'.
 
  - Add 'Delta::from_nanos()'.
 
 'pin-init' crate:
 
  - Replace the 'Zeroable' impls for 'Option<NonZero*>' with impls of
    'ZeroableOption' for 'NonZero*'.
 
  - Improve feature gate handling for unstable features.
 
  - Declutter the documentation of implementations of 'Zeroable' for
    tuples.
 
  - Replace uses of 'addr_of[_mut]!' with '&raw [mut]'.
 
 rust-analyzer:
 
  - Add type annotations to 'generate_rust_analyzer.py'.
 
  - Add support for scripts written in Rust ('generate_rust_target.rs',
    'rustdoc_test_builder.rs', 'rustdoc_test_gen.rs').
 
  - Refactor 'generate_rust_analyzer.py' to explicitly identify host and
    target crates, improve readability, and reduce duplication.
 
 And some other fixes, cleanups and improvements.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEPjU5OPd5QIZ9jqqOGXyLc2htIW0FAmnZVNQACgkQGXyLc2ht
 IW09aA/9GIbluNhc5xNvfkMvv9Ki70TK+e/W78pQWoRlSmZU1MO6R5K2rMN+iYlu
 98S53EO38P5wBWOjIVFHm9mD1b59T945gcyGk9DxxFdl6I5mFKGZvE0Z8onTE/9b
 GUnO5dlWjmEwTfwD0csr4moLC8eoCGVmGpe4TEfvscAISeZJZwQ90UCoNSFy6TQS
 rJyzmIOBraZPrf1qptt3Sk6KY3b9HaxLv3kh1TAPYH0Dmrhhp+ckHvn5lT8uB8ZW
 xr1ThoP44Zwm+nq6JahiK1NWFXTs12vpoCQLbckJsN8r3GTmt9CfHll/0UcW5W7i
 bCUeCJDNwfbpVALNmQxHjtkvmDAuhqypxCTFSMMrWS66LOUaKxZ+u0ioi/1Ljfp4
 tCR1Uzpr3QD6c8rK0hJ28vW/5DjoqkMMwUDeUm6c36msST37xrDZPa/vN+VLxxhK
 H8sQ3SyvE0JdK8wBvd/pHGHv+RvIdi7cbV5H/WqBpwzCcupExuXiKBdFHeVIfXkQ
 zn7lsZtnBuL+hLpG1pz6BoCTW1KbR38YomaKupElkYCUYytu0H+0Af/lkK3HhviM
 9uynUVsn0+JaS9QvogArW/d+I0w49yjRHkWxfXIJZd0+mkT9V3JrGY7/iXwewl5R
 fRRP0hMx0vhY4f/Uss1qEu3RPfsafxnU1NBiVRZZtc37azSOKjE=
 =xRA/
 -----END PGP SIGNATURE-----

Merge tag 'rust-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux

Pull Rust updates from Miguel Ojeda:
 "Toolchain and infrastructure:

   - Bump the minimum Rust version to 1.85.0 (and 'bindgen' to 0.71.1).

     As proposed in LPC 2025 and the Maintainers Summit [1], we are
     going to follow Debian Stable's Rust versions as our minimum
     versions.

     Debian Trixie was released on 2025-08-09 with a Rust 1.85.0 and
     'bindgen' 0.71.1 toolchain, which is a fair amount of time for e.g.
     kernel developers to upgrade.

     Other major distributions support a Rust version that is high
     enough as well, including:

       + Arch Linux.
       + Fedora Linux.
       + Gentoo Linux.
       + Nix.
       + openSUSE Slowroll and openSUSE Tumbleweed.
       + Ubuntu 25.10 and 26.04 LTS. In addition, 24.04 LTS using
         their versioned packages.

     The merged patch series comes with the associated cleanups and
     simplifications treewide that can be performed thanks to both
     bumps, as well as documentation updates.

     In addition, start using 'bindgen''s '--with-attribute-custom-enum'
     feature to set the 'cfi_encoding' attribute for the 'lru_status'
     enum used in Binder.

     Link: https://lwn.net/Articles/1050174/ [1]

   - Add experimental Kconfig option ('CONFIG_RUST_INLINE_HELPERS') that
     inlines C helpers into Rust.

     Essentially, it performs a step similar to LTO, but just for the
     helpers, i.e. very local and fast.

     It relies on 'llvm-link' and its '--internalize' flag, and requires
     a compatible LLVM between Clang and 'rustc' (i.e. same major
     version, 'CONFIG_RUSTC_CLANG_LLVM_COMPATIBLE'). It is only enabled
     for two architectures for now.

     The result is a measurable speedup in different workloads that
     different users have tested. For instance, for the null block
     driver, it amounts to a 2%.

   - Support global per-version flags.

     While we already have per-version flags in many places, we didn't
     have a place to set global ones that depend on the compiler
     version, i.e. in 'rust_common_flags', which sometimes is needed to
     e.g. tweak the lints set per version.

     Use that to allow the 'clippy::precedence' lint for Rust < 1.86.0,
     since it had a change in behavior.

   - Support overriding the crate name and apply it to Rust Binder,
     which wanted the module to be called 'rust_binder'.

   - Add the remaining '__rust_helper' annotations (started in the
     previous cycle).

  'kernel' crate:

   - Introduce the 'const_assert!' macro: a more powerful version of
     'static_assert!' that can refer to generics inside functions or
     implementation bodies, e.g.:

         fn f<const N: usize>() {
             const_assert!(N > 1);
         }

         fn g<T>() {
             const_assert!(size_of::<T>() > 0, "T cannot be ZST");
         }

     In addition, reorganize our set of build-time assertion macros
     ('{build,const,static_assert}!') to live in the 'build_assert'
     module.

     Finally, improve the docs as well to clarify how these are
     different from one another and how to pick the right one to use,
     and their equivalence (if any) to the existing C ones for extra
     clarity.

   - 'sizes' module: add 'SizeConstants' trait.

     This gives us typed 'SZ_*' constants (avoiding casts) for use in
     device address spaces where the address width depends on the
     hardware (e.g. 32-bit MMIO windows, 64-bit GPU framebuffers, etc.),
     e.g.:

         let gpu_heap = 14 * u64::SZ_1M;
         let mmio_window = u32::SZ_16M;

   - 'clk' module: implement 'Send' and 'Sync' for 'Clk' and thus
     simplify the users in Tyr and PWM.

   - 'ptr' module: add 'const_align_up'.

   - 'str' module: improve the documentation of the 'c_str!' macro to
     explain that one should only use it for non-literal cases (for the
     other case we instead use C string literals, e.g. 'c"abc"').

   - Disallow the use of 'CStr::{as_ptr,from_ptr}' and clean one such
     use in the 'task' module.

   - 'sync' module: finish the move of 'ARef' and 'AlwaysRefCounted'
     outside of the 'types' module, i.e. update the last remaining
     instances and finally remove the re-exports.

   - 'error' module: clarify that 'from_err_ptr' can return 'Ok(NULL)',
     including runtime-tested examples.

     The intention is to hopefully prevent UB that assumes the result of
     the function is not 'NULL' if successful. This originated from a
     case of UB I noticed in 'regulator' that created a 'NonNull' on it.

  Timekeeping:

   - Expand the example section in the 'HrTimer' documentation.

   - Mark the 'ClockSource' trait as unsafe to ensure valid values for
     'ktime_get()'.

   - Add 'Delta::from_nanos()'.

  'pin-init' crate:

   - Replace the 'Zeroable' impls for 'Option<NonZero*>' with impls of
     'ZeroableOption' for 'NonZero*'.

   - Improve feature gate handling for unstable features.

   - Declutter the documentation of implementations of 'Zeroable' for
     tuples.

   - Replace uses of 'addr_of[_mut]!' with '&raw [mut]'.

  rust-analyzer:

   - Add type annotations to 'generate_rust_analyzer.py'.

   - Add support for scripts written in Rust ('generate_rust_target.rs',
     'rustdoc_test_builder.rs', 'rustdoc_test_gen.rs').

   - Refactor 'generate_rust_analyzer.py' to explicitly identify host
     and target crates, improve readability, and reduce duplication.

  And some other fixes, cleanups and improvements"

* tag 'rust-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (79 commits)
  rust: sizes: add SizeConstants trait for device address space constants
  rust: kernel: update `file_with_nul` comment
  rust: kbuild: allow `clippy::precedence` for Rust < 1.86.0
  rust: kbuild: support global per-version flags
  rust: declare cfi_encoding for lru_status
  docs: rust: general-information: use real example
  docs: rust: general-information: simplify Kconfig example
  docs: rust: quick-start: remove GDB/Binutils mention
  docs: rust: quick-start: remove Nix "unstable channel" note
  docs: rust: quick-start: remove Gentoo "testing" note
  docs: rust: quick-start: add Ubuntu 26.04 LTS and remove subsection title
  docs: rust: quick-start: update minimum Ubuntu version
  docs: rust: quick-start: update Ubuntu versioned packages
  docs: rust: quick-start: openSUSE provides `rust-src` package nowadays
  rust: kbuild: remove "dummy parameter" workaround for `bindgen` < 0.71.1
  rust: kbuild: update `bindgen --rust-target` version and replace comment
  rust: rust_is_available: remove warning for `bindgen` < 0.69.5 && libclang >= 19.1
  rust: rust_is_available: remove warning for `bindgen` 0.66.[01]
  rust: bump `bindgen` minimum supported version to 0.71.1 (Debian Trixie)
  rust: block: update `const_refs_to_static` MSRV TODO comment
  ...
This commit is contained in:
Linus Torvalds 2026-04-13 09:54:20 -07:00
commit 26ff969926
78 changed files with 1396 additions and 826 deletions

View File

@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
msrv = "1.78.0"
msrv = "1.85.0"
check-private-items = true
@ -9,3 +9,13 @@ disallowed-macros = [
# it here, see: https://github.com/rust-lang/rust-clippy/issues/11303.
{ path = "kernel::dbg", reason = "the `dbg!` macro is intended as a debugging tool", allow-invalid = true },
]
[[disallowed-methods]]
path = "core::ffi::CStr::as_ptr"
replacement = "kernel::prelude::CStrExt::as_char_ptr"
reason = "kernel's `char` is always unsigned, use `as_char_ptr` instead"
[[disallowed-methods]]
path = "core::ffi::CStr::from_ptr"
replacement = "kernel::prelude::CStrExt::from_char_ptr"
reason = "kernel's `char` is always unsigned, use `from_char_ptr` instead"

4
.gitignore vendored
View File

@ -13,6 +13,7 @@
.*
*.a
*.asn1.[ch]
*.bc
*.bin
*.bz2
*.c.[012]*.*
@ -184,3 +185,6 @@ sphinx_*/
# Rust analyzer configuration
/rust-project.json
# bc language scripts (not LLVM bitcode)
!kernel/time/timeconst.bc

View File

@ -31,8 +31,8 @@ you probably needn't concern yourself with pcmciautils.
====================== =============== ========================================
GNU C 8.1 gcc --version
Clang/LLVM (optional) 15.0.0 clang --version
Rust (optional) 1.78.0 rustc --version
bindgen (optional) 0.65.1 bindgen --version
Rust (optional) 1.85.0 rustc --version
bindgen (optional) 0.71.1 bindgen --version
GNU make 4.0 make --version
bash 4.2 bash --version
binutils 2.30 ld -v

View File

@ -157,5 +157,5 @@ numerical comparisons, one may define a new Kconfig symbol:
.. code-block:: kconfig
config RUSTC_VERSION_MIN_107900
def_bool y if RUSTC_VERSION >= 107900
config RUSTC_HAS_SPAN_FILE
def_bool RUSTC_VERSION >= 108800

View File

@ -57,8 +57,8 @@ of the box, e.g.::
Gentoo Linux
************
Gentoo Linux (and especially the testing branch) provides recent Rust releases
and thus it should generally work out of the box, e.g.::
Gentoo Linux provides recent Rust releases and thus it should generally work out
of the box, e.g.::
USE='rust-src rustfmt clippy' emerge dev-lang/rust dev-util/bindgen
@ -68,8 +68,8 @@ and thus it should generally work out of the box, e.g.::
Nix
***
Nix (unstable channel) provides recent Rust releases and thus it should
generally work out of the box, e.g.::
Nix provides recent Rust releases and thus it should generally work out of the
box, e.g.::
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
@ -84,16 +84,13 @@ openSUSE
openSUSE Slowroll and openSUSE Tumbleweed provide recent Rust releases and thus
they should generally work out of the box, e.g.::
zypper install rust rust1.79-src rust-bindgen clang
zypper install rust rust-src rust-bindgen clang
Ubuntu
******
25.04
~~~~~
The latest Ubuntu releases provide recent Rust releases and thus they should
Ubuntu 25.10 and 26.04 LTS provide recent Rust releases and thus they should
generally work out of the box, e.g.::
apt install rustc rust-src bindgen rustfmt rust-clippy
@ -112,33 +109,33 @@ Though Ubuntu 24.04 LTS and older versions still provide recent Rust
releases, they require some additional configuration to be set, using
the versioned packages, e.g.::
apt install rustc-1.80 rust-1.80-src bindgen-0.65 rustfmt-1.80 \
rust-1.80-clippy
ln -s /usr/lib/rust-1.80/bin/rustfmt /usr/bin/rustfmt-1.80
ln -s /usr/lib/rust-1.80/bin/clippy-driver /usr/bin/clippy-driver-1.80
apt install rustc-1.85 rust-1.85-src bindgen-0.71 rustfmt-1.85 \
rust-1.85-clippy
ln -s /usr/lib/rust-1.85/bin/rustfmt /usr/bin/rustfmt-1.85
ln -s /usr/lib/rust-1.85/bin/clippy-driver /usr/bin/clippy-driver-1.85
None of these packages set their tools as defaults; therefore they should be
specified explicitly, e.g.::
make LLVM=1 RUSTC=rustc-1.80 RUSTDOC=rustdoc-1.80 RUSTFMT=rustfmt-1.80 \
CLIPPY_DRIVER=clippy-driver-1.80 BINDGEN=bindgen-0.65
make LLVM=1 RUSTC=rustc-1.85 RUSTDOC=rustdoc-1.85 RUSTFMT=rustfmt-1.85 \
CLIPPY_DRIVER=clippy-driver-1.85 BINDGEN=bindgen-0.71
Alternatively, modify the ``PATH`` variable to place the Rust 1.80 binaries
Alternatively, modify the ``PATH`` variable to place the Rust 1.85 binaries
first and set ``bindgen`` as the default, e.g.::
PATH=/usr/lib/rust-1.80/bin:$PATH
PATH=/usr/lib/rust-1.85/bin:$PATH
update-alternatives --install /usr/bin/bindgen bindgen \
/usr/bin/bindgen-0.65 100
update-alternatives --set bindgen /usr/bin/bindgen-0.65
/usr/bin/bindgen-0.71 100
update-alternatives --set bindgen /usr/bin/bindgen-0.71
``RUST_LIB_SRC`` needs to be set when using the versioned packages, e.g.::
``RUST_LIB_SRC`` may need to be set when using the versioned packages, e.g.::
RUST_LIB_SRC=/usr/src/rustc-$(rustc-1.80 --version | cut -d' ' -f2)/library
RUST_LIB_SRC=/usr/src/rustc-$(rustc-1.85 --version | cut -d' ' -f2)/library
For convenience, ``RUST_LIB_SRC`` can be exported to the global environment.
In addition, ``bindgen-0.65`` is available in newer releases (24.04 LTS and
24.10), but it may not be available in older ones (20.04 LTS and 22.04 LTS),
In addition, ``bindgen-0.71`` is available in newer releases (24.04 LTS),
but it may not be available in older ones (20.04 LTS and 22.04 LTS),
thus ``bindgen`` may need to be built manually (please see below).
@ -355,12 +352,3 @@ Hacking
To dive deeper, take a look at the source code of the samples
at ``samples/rust/``, the Rust support code under ``rust/`` and
the ``Rust hacking`` menu under ``Kernel hacking``.
If GDB/Binutils is used and Rust symbols are not getting demangled, the reason
is the toolchain does not support Rust's new v0 mangling scheme yet.
There are a few ways out:
- Install a newer release (GDB >= 10.2, Binutils >= 2.36).
- Some versions of GDB (e.g. vanilla GDB 10.1) are able to use
the pre-demangled names embedded in the debug info (``CONFIG_DEBUG_INFO``).

View File

@ -23166,6 +23166,7 @@ C: zulip://rust-for-linux.zulipchat.com
P: https://rust-for-linux.com/contributing
T: git https://github.com/Rust-for-Linux/linux.git rust-next
F: .clippy.toml
F: .rustfmt.toml
F: Documentation/rust/
F: include/trace/events/rust_sample.h
F: rust/

View File

@ -487,6 +487,7 @@ export rust_common_flags := --edition=2021 \
-Wclippy::as_underscore \
-Wclippy::cast_lossless \
-Wclippy::ignored_unit_patterns \
-Aclippy::incompatible_msrv \
-Wclippy::mut_mut \
-Wclippy::needless_bitwise_bool \
-Aclippy::needless_lifetimes \
@ -495,6 +496,7 @@ export rust_common_flags := --edition=2021 \
-Wclippy::ptr_cast_constness \
-Wclippy::ref_as_ptr \
-Wclippy::undocumented_unsafe_blocks \
-Aclippy::uninlined_format_args \
-Wclippy::unnecessary_safety_comment \
-Wclippy::unnecessary_safety_doc \
-Wrustdoc::missing_crate_level_docs \
@ -505,7 +507,7 @@ KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) \
KBUILD_HOSTCXXFLAGS := -Wall -O2 $(HOST_LFS_CFLAGS) $(HOSTCXXFLAGS) \
-I $(srctree)/scripts/include
KBUILD_HOSTRUSTFLAGS := $(rust_common_flags) -O -Cstrip=debuginfo \
-Zallow-features= $(HOSTRUSTFLAGS)
-Zallow-features=
KBUILD_HOSTLDFLAGS := $(HOST_LFS_LDFLAGS) $(HOSTLDFLAGS)
KBUILD_HOSTLDLIBS := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
KBUILD_PROCMACROLDFLAGS := $(or $(PROCMACROLDFLAGS),$(KBUILD_HOSTLDFLAGS))
@ -516,6 +518,7 @@ ifneq ($(LLVM),)
CC = $(LLVM_PREFIX)clang$(LLVM_SUFFIX)
LD = $(LLVM_PREFIX)ld.lld$(LLVM_SUFFIX)
AR = $(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX)
LLVM_LINK = $(LLVM_PREFIX)llvm-link$(LLVM_SUFFIX)
NM = $(LLVM_PREFIX)llvm-nm$(LLVM_SUFFIX)
OBJCOPY = $(LLVM_PREFIX)llvm-objcopy$(LLVM_SUFFIX)
OBJDUMP = $(LLVM_PREFIX)llvm-objdump$(LLVM_SUFFIX)
@ -629,7 +632,7 @@ export RUSTC_BOOTSTRAP := 1
export CLIPPY_CONF_DIR := $(srctree)
export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG
export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN
export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN LLVM_LINK
export HOSTRUSTC KBUILD_HOSTRUSTFLAGS
export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL
export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
@ -834,6 +837,20 @@ endif # CONFIG_TRACEPOINTS
export WARN_ON_UNUSED_TRACEPOINTS
# Per-version Rust flags. These are like `rust_common_flags`, but may
# depend on the Rust compiler version (e.g. using `rustc-min-version`).
#
# `-Aclippy::precedence`: the lint was extended in Rust 1.85.0 to
# include bitmasking and shift operations. However, because it generated
# many hits, in Rust 1.86.0 it was split into a new `precedence_bits`
# lint which is not enabled by default.
rust_common_flags_per_version := \
$(if $(call rustc-min-version,108600),,-Aclippy::precedence)
rust_common_flags += $(rust_common_flags_per_version)
KBUILD_HOSTRUSTFLAGS += $(rust_common_flags_per_version) $(HOSTRUSTFLAGS)
KBUILD_RUSTFLAGS += $(rust_common_flags_per_version)
include $(srctree)/arch/$(SRCARCH)/Makefile
ifdef need-config

View File

@ -968,10 +968,9 @@ config HAVE_CFI_ICALL_NORMALIZE_INTEGERS
config HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
def_bool y
depends on HAVE_CFI_ICALL_NORMALIZE_INTEGERS
depends on RUSTC_VERSION >= 107900
depends on ARM64 || X86_64
# With GCOV/KASAN we need this fix: https://github.com/rust-lang/rust/pull/129373
depends on (RUSTC_LLVM_VERSION >= 190103 && RUSTC_VERSION >= 108200) || \
depends on RUSTC_LLVM_VERSION >= 190103 || \
(!GCOV_KERNEL && !KASAN_GENERIC && !KASAN_SW_TAGS)
config CFI_PERMISSIVE

View File

@ -292,14 +292,6 @@ config ARM64
config RUSTC_SUPPORTS_ARM64
def_bool y
depends on CPU_LITTLE_ENDIAN
# Shadow call stack is only supported on certain rustc versions.
#
# When using the UNWIND_PATCH_PAC_INTO_SCS option, rustc version 1.80+ is
# required due to use of the -Zfixed-x18 flag.
#
# Otherwise, rustc version 1.82+ is required due to use of the
# -Zsanitizer=shadow-call-stack flag.
depends on !SHADOW_CALL_STACK || RUSTC_VERSION >= 108200 || RUSTC_VERSION >= 108000 && UNWIND_PATCH_PAC_INTO_SCS
config CLANG_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS
def_bool CC_IS_CLANG

View File

@ -232,9 +232,6 @@ config RISCV
config RUSTC_SUPPORTS_RISCV
def_bool y
depends on 64BIT
# Shadow call stack requires rustc version 1.82+ due to use of the
# -Zsanitizer=shadow-call-stack flag.
depends on !SHADOW_CALL_STACK || RUSTC_VERSION >= 108200
config CLANG_SUPPORTS_DYNAMIC_FTRACE
def_bool CC_IS_CLANG

View File

@ -5,5 +5,4 @@ obj-$(CONFIG_ANDROID_BINDER_IPC_RUST) += rust_binder.o
rust_binder-y := \
rust_binder_main.o \
rust_binderfs.o \
rust_binder_events.o \
page_range_helper.o
rust_binder_events.o

View File

@ -683,15 +683,15 @@ fn drop(self: Pin<&mut Self>) {
unsafe {
bindings::list_lru_walk(
list_lru,
Some(bindings::rust_shrink_free_page_wrap),
Some(rust_shrink_free_page),
ptr::null_mut(),
nr_to_scan,
)
}
}
const LRU_SKIP: bindings::lru_status = bindings::lru_status_LRU_SKIP;
const LRU_REMOVED_ENTRY: bindings::lru_status = bindings::lru_status_LRU_REMOVED_RETRY;
const LRU_SKIP: bindings::lru_status = bindings::lru_status::LRU_SKIP;
const LRU_REMOVED_ENTRY: bindings::lru_status = bindings::lru_status::LRU_REMOVED_RETRY;
/// # Safety
/// Called by the shrinker.

View File

@ -1,24 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/* C helper for page_range.rs to work around a CFI violation.
*
* Bindgen currently pretends that `enum lru_status` is the same as an integer.
* This assumption is fine ABI-wise, but once you add CFI to the mix, it
* triggers a CFI violation because `enum lru_status` gets a different CFI tag.
*
* This file contains a workaround until bindgen can be fixed.
*
* Copyright (C) 2025 Google LLC.
*/
#include "page_range_helper.h"
unsigned int rust_shrink_free_page(struct list_head *item,
struct list_lru_one *list,
void *cb_arg);
enum lru_status
rust_shrink_free_page_wrap(struct list_head *item, struct list_lru_one *list,
void *cb_arg)
{
return rust_shrink_free_page(item, list, cb_arg);
}

View File

@ -1,15 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2025 Google, Inc.
*/
#ifndef _LINUX_PAGE_RANGE_HELPER_H
#define _LINUX_PAGE_RANGE_HELPER_H
#include <linux/list_lru.h>
enum lru_status
rust_shrink_free_page_wrap(struct list_head *item, struct list_lru_one *list,
void *cb_arg);
#endif /* _LINUX_PAGE_RANGE_HELPER_H */

View File

@ -3,6 +3,8 @@
// Copyright (C) 2025 Google LLC.
//! Binder -- the Android IPC mechanism.
#![crate_name = "rust_binder"]
#![recursion_limit = "256"]
#![allow(
clippy::as_underscore,

View File

@ -53,18 +53,6 @@ pub(crate) struct TyrData {
pub(crate) gpu_info: GpuInfo,
}
// Both `Clk` and `Regulator` do not implement `Send` or `Sync`, but they
// should. There are patches on the mailing list to address this, but they have
// not landed yet.
//
// For now, add this workaround so that this patch compiles with the promise
// that it will be removed in a future patch.
//
// SAFETY: This will be removed in a future patch.
unsafe impl Send for TyrData {}
// SAFETY: This will be removed in a future patch.
unsafe impl Sync for TyrData {}
fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result {
regs::GPU_CMD.write(dev, iomem, regs::GPU_CMD_SOFT_RESET)?;

View File

@ -293,7 +293,6 @@ fn allocate_command(&mut self, size: usize) -> Result<GspCommand<'_>> {
let (slice_1, slice_2) = {
let (slice_1, slice_2) = self.driver_write_area();
#[allow(clippy::incompatible_msrv)]
(slice_1.as_flattened_mut(), slice_2.as_flattened_mut())
};
@ -545,10 +544,7 @@ fn wait_for_msg(&self, timeout: Delta) -> Result<GspMessage<'_>> {
Delta::from_millis(1),
timeout,
)
.map(|(slice_1, slice_2)| {
#[allow(clippy::incompatible_msrv)]
(slice_1.as_flattened(), slice_2.as_flattened())
})?;
.map(|(slice_1, slice_2)| (slice_1.as_flattened(), slice_2.as_flattened()))?;
// Extract the `GspMsgElement`.
let (header, slice_1) = GspMsgElement::from_bytes_prefix(slice_1).ok_or(EIO)?;

View File

@ -7,9 +7,6 @@
//! This module may not be directly used. Please abstract or re-export the needed symbols in the
//! parent module instead.
#![cfg_attr(test, allow(deref_nullptr))]
#![cfg_attr(test, allow(unaligned_references))]
#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
#![allow(
dead_code,
clippy::all,

View File

@ -99,21 +99,6 @@ struct Th1520PwmDriverData {
clk: Clk,
}
// This `unsafe` implementation is a temporary necessity because the underlying `kernel::clk::Clk`
// type does not yet expose `Send` and `Sync` implementations. This block should be removed
// as soon as the clock abstraction provides these guarantees directly.
// TODO: Remove those unsafe impl's when Clk will support them itself.
// SAFETY: The `devres` framework requires the driver's private data to be `Send` and `Sync`.
// We can guarantee this because the PWM core synchronizes all callbacks, preventing concurrent
// access to the contained `iomem` and `clk` resources.
unsafe impl Send for Th1520PwmDriverData {}
// SAFETY: The same reasoning applies as for `Send`. The PWM core's synchronization
// guarantees that it is safe for multiple threads to have shared access (`&self`)
// to the driver data during callbacks.
unsafe impl Sync for Th1520PwmDriverData {}
impl pwm::PwmOps for Th1520PwmDriverData {
type WfHw = Th1520WfHw;

View File

@ -82,6 +82,21 @@ config RUSTC_LLVM_VERSION
int
default $(rustc-llvm-version)
config RUSTC_LLVM_MAJOR_VERSION
int
default $(shell,expr $(rustc-llvm-version) / 10000)
config RUSTC_CLANG_LLVM_COMPATIBLE
bool
default y if CC_IS_CLANG && RUSTC_LLVM_MAJOR_VERSION = $(shell,expr $(cc-version) / 10000)
help
This indicates whether Rust and Clang use LLVM of the same major
version.
Operations involving handling LLVM IR or bitcode (e.g. cross-language
LTO) require the same LLVM major version to work properly. For best
compatibility it is recommended that the exact same LLVM is used.
config ARCH_HAS_CC_CAN_LINK
bool
@ -163,12 +178,6 @@ config LD_CAN_USE_KEEP_IN_OVERLAY
# https://github.com/llvm/llvm-project/pull/130661
def_bool LD_IS_BFD || LLD_VERSION >= 210000
config RUSTC_HAS_SLICE_AS_FLATTENED
def_bool RUSTC_VERSION >= 108000
config RUSTC_HAS_COERCE_POINTEE
def_bool RUSTC_VERSION >= 108400
config RUSTC_HAS_SPAN_FILE
def_bool RUSTC_VERSION >= 108800
@ -2178,9 +2187,7 @@ config RUST
depends on !DEBUG_INFO_BTF || (PAHOLE_HAS_LANG_EXCLUDE && !LTO)
depends on !CFI || HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
select CFI_ICALL_NORMALIZE_INTEGERS if CFI
depends on !CALL_PADDING || RUSTC_VERSION >= 108100
depends on !KASAN_SW_TAGS
depends on !(MITIGATION_RETHUNK && KASAN) || RUSTC_VERSION >= 108300
help
Enables Rust support in the kernel.
@ -2204,12 +2211,7 @@ config RUSTC_VERSION_TEXT
config BINDGEN_VERSION_TEXT
string
depends on RUST
# The dummy parameter `workaround-for-0.69.0` is required to support 0.69.0
# (https://github.com/rust-lang/rust-bindgen/pull/2678) and 0.71.0
# (https://github.com/rust-lang/rust-bindgen/pull/3040). It can be removed
# when the minimum version is upgraded past the latter (0.69.1 and 0.71.1
# both fixed the issue).
default "$(shell,$(BINDGEN) --version workaround-for-0.69.0 2>/dev/null)"
default "$(shell,$(BINDGEN) --version 2>/dev/null)"
#
# Place an empty function call at each tracepoint site. Can be

View File

@ -3577,6 +3577,23 @@ config RUST_KERNEL_DOCTESTS
If unsure, say N.
config RUST_INLINE_HELPERS
bool "Inline C helpers into Rust code (EXPERIMENTAL)"
depends on RUST && RUSTC_CLANG_LLVM_COMPATIBLE
depends on EXPERT
depends on ARM64 || X86_64
depends on !UML
help
Inlines C helpers into Rust code using Link Time Optimization.
If this option is enabled, C helper functions declared in
rust/helpers/ are inlined into Rust code, which is helpful for
performance of Rust code. This requires a matching LLVM version for
Clang and rustc.
If you are sure that you're using Clang and rustc with matching LLVM
versions, say Y. Otherwise say N.
endmenu # "Rust"
endmenu # Kernel hacking

View File

@ -6,15 +6,19 @@ rustdoc_output := $(objtree)/Documentation/output/rust/rustdoc
obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o
always-$(CONFIG_RUST) += exports_core_generated.h
ifdef CONFIG_RUST_INLINE_HELPERS
always-$(CONFIG_RUST) += helpers/helpers.bc helpers/helpers_module.bc
else
obj-$(CONFIG_RUST) += helpers/helpers.o
always-$(CONFIG_RUST) += exports_helpers_generated.h
endif
# Missing prototypes are expected in the helpers since these are exported
# for Rust only, thus there is no header nor prototypes.
obj-$(CONFIG_RUST) += helpers/helpers.o
CFLAGS_REMOVE_helpers/helpers.o = -Wmissing-prototypes -Wmissing-declarations
always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs
obj-$(CONFIG_RUST) += bindings.o pin_init.o kernel.o
always-$(CONFIG_RUST) += exports_helpers_generated.h \
exports_bindings_generated.h exports_kernel_generated.h
always-$(CONFIG_RUST) += exports_bindings_generated.h exports_kernel_generated.h
always-$(CONFIG_RUST) += uapi/uapi_generated.rs
obj-$(CONFIG_RUST) += uapi.o
@ -71,8 +75,7 @@ core-edition := $(if $(call rustc-min-version,108700),2024,2021)
core-skip_flags := \
--edition=2021 \
-Wunreachable_pub \
-Wrustdoc::unescaped_backticks
-Wunreachable_pub
core-flags := \
--edition=$(core-edition) \
@ -83,10 +86,8 @@ proc_macro2-cfgs := \
wrap_proc_macro \
$(if $(call rustc-min-version,108800),proc_macro_span_file proc_macro_span_location)
# Stable since Rust 1.79.0: `feature(proc_macro_byte_character,proc_macro_c_str_literals)`.
proc_macro2-flags := \
--cap-lints=allow \
-Zcrate-attr='feature(proc_macro_byte_character,proc_macro_c_str_literals)' \
$(call cfgs-to-flags,$(proc_macro2-cfgs))
quote-cfgs := \
@ -118,7 +119,7 @@ syn-flags := \
$(call cfgs-to-flags,$(syn-cfgs))
pin_init_internal-cfgs := \
kernel
kernel USE_RUSTC_FEATURES
pin_init_internal-flags := \
--extern proc_macro2 \
@ -127,7 +128,7 @@ pin_init_internal-flags := \
$(call cfgs-to-flags,$(pin_init_internal-cfgs))
pin_init-cfgs := \
kernel
kernel USE_RUSTC_FEATURES
pin_init-flags := \
--extern pin_init_internal \
@ -141,15 +142,10 @@ rustdoc_modifiers_workaround := $(if $(call rustc-min-version,108800),-Cunsafe-a
# Similarly, for doctests (https://github.com/rust-lang/rust/issues/146465).
doctests_modifiers_workaround := $(rustdoc_modifiers_workaround)$(if $(call rustc-min-version,109100),$(comma)sanitizer)
# `rustc` recognizes `--remap-path-prefix` since 1.26.0, but `rustdoc` only
# since Rust 1.81.0. Moreover, `rustdoc` ICEs on out-of-tree builds since Rust
# 1.82.0 (https://github.com/rust-lang/rust/issues/138520). Thus workaround both
# issues skipping the flag. The former also applies to `RUSTDOC TK`.
quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
cmd_rustdoc = \
OBJTREE=$(abspath $(objtree)) \
$(RUSTDOC) $(filter-out $(skip_flags) --remap-path-prefix=% --remap-path-scope=%, \
$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
$(RUSTDOC) $(filter-out $(skip_flags) --remap-path-scope=%,$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
$(rustc_target_flags) -L$(objtree)/$(obj) \
-Zunstable-options --generate-link-to-definition \
--output $(rustdoc_output) \
@ -210,8 +206,6 @@ rustdoc-macros: $(src)/macros/lib.rs rustdoc-clean rustdoc-proc_macro2 \
rustdoc-quote rustdoc-syn FORCE
+$(call if_changed,rustdoc)
# Starting with Rust 1.82.0, skipping `-Wrustdoc::unescaped_backticks` should
# not be needed -- see https://github.com/rust-lang/rust/pull/128307.
rustdoc-core: private skip_flags = $(core-skip_flags)
rustdoc-core: private rustc_target_flags = $(core-flags)
rustdoc-core: $(RUST_LIB_SRC)/core/src/lib.rs rustdoc-clean FORCE
@ -335,7 +329,7 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
rm -rf $(objtree)/$(obj)/test/doctests/kernel; \
mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
OBJTREE=$(abspath $(objtree)) \
$(RUSTDOC) --test $(filter-out --remap-path-prefix=% --remap-path-scope=%,$(rust_flags)) \
$(RUSTDOC) --test $(filter-out --remap-path-scope=%,$(rust_flags)) \
-L$(objtree)/$(obj) --extern ffi --extern pin_init \
--extern kernel --extern build_error --extern macros \
--extern bindings --extern uapi \
@ -447,22 +441,10 @@ endif
# architecture instead of generating `usize`.
bindgen_c_flags_final = $(bindgen_c_flags_lto) -fno-builtin -D__BINDGEN__
# Each `bindgen` release may upgrade the list of Rust target versions. By
# default, the highest stable release in their list is used. Thus we need to set
# a `--rust-target` to avoid future `bindgen` releases emitting code that
# `rustc` may not understand. On top of that, `bindgen` does not support passing
# an unknown Rust target version.
#
# Therefore, the Rust target for `bindgen` can be only as high as the minimum
# Rust version the kernel supports and only as high as the greatest stable Rust
# target supported by the minimum `bindgen` version the kernel supports (that
# is, if we do not test the actual `rustc`/`bindgen` versions running).
#
# Starting with `bindgen` 0.71.0, we will be able to set any future Rust version
# instead, i.e. we will be able to set here our minimum supported Rust version.
# `--rust-target` points to our minimum supported Rust version.
quiet_cmd_bindgen = BINDGEN $@
cmd_bindgen = \
$(BINDGEN) $< $(bindgen_target_flags) --rust-target 1.68 \
$(BINDGEN) $< $(bindgen_target_flags) --rust-target 1.85 \
--use-core --with-derive-default --ctypes-prefix ffi --no-layout-tests \
--no-debug '.*' --enable-function-attribute-detection \
-o $@ -- $(bindgen_c_flags_final) -DMODULE \
@ -496,6 +478,16 @@ $(obj)/bindings/bindings_helpers_generated.rs: private bindgen_target_extra = ;
$(obj)/bindings/bindings_helpers_generated.rs: $(src)/helpers/helpers.c FORCE
$(call if_changed_dep,bindgen)
quiet_cmd_rust_helper = HELPER $@
cmd_rust_helper = \
$(CC) $(filter-out $(CFLAGS_REMOVE_helpers/helpers.o), $(c_flags)) \
-c -g0 $< -emit-llvm -o $@
$(obj)/helpers/helpers.bc: private part-of-builtin := y
$(obj)/helpers/helpers_module.bc: private part-of-module := y
$(obj)/helpers/helpers.bc $(obj)/helpers/helpers_module.bc: $(src)/helpers/helpers.c FORCE
+$(call if_changed_dep,rust_helper)
rust_exports = $(NM) -p --defined-only $(1) | awk '$$2~/(T|R|D|B)/ && $$3!~/__(pfx|cfi|odr_asan)/ { printf $(2),$$3 }'
quiet_cmd_exports = EXPORTS $@
@ -576,12 +568,16 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L
OBJTREE=$(abspath $(objtree)) \
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
$(filter-out $(skip_flags),$(rust_flags)) $(rustc_target_flags) \
--emit=dep-info=$(depfile) --emit=obj=$@ \
--emit=dep-info=$(depfile) --emit=$(if $(link_helper),llvm-bc=$(patsubst %.o,%.bc,$@),obj=$@) \
--emit=metadata=$(dir $@)$(patsubst %.o,lib%.rmeta,$(notdir $@)) \
--crate-type rlib -L$(objtree)/$(obj) \
--crate-name $(patsubst %.o,%,$(notdir $@)) $< \
--sysroot=/dev/null \
-Zunstable-options \
$(if $(link_helper),;$(LLVM_LINK) --internalize --suppress-warnings $(patsubst %.o,%.bc,$@) \
$(obj)/helpers/helpers$(if $(part-of-module),_module).bc -o $(patsubst %.o,%.m.bc,$@); \
$(CC) $(CLANG_FLAGS) $(KBUILD_CFLAGS) -Wno-override-module -c $(patsubst %.o,%.m.bc,$@) -o $@ \
$(cmd_ld_single)) \
$(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@) \
$(cmd_objtool)
@ -591,6 +587,8 @@ rust-analyzer:
--cfgs='proc_macro2=$(proc_macro2-cfgs)' \
--cfgs='quote=$(quote-cfgs)' \
--cfgs='syn=$(syn-cfgs)' \
--cfgs='pin_init_internal=$(pin_init_internal-cfgs)' \
--cfgs='pin_init=$(pin_init-cfgs)' \
$(realpath $(srctree)) $(realpath $(objtree)) \
$(rustc_sysroot) $(RUST_LIB_SRC) $(if $(KBUILD_EXTMOD),$(srcroot)) \
> rust-project.json
@ -711,4 +709,9 @@ $(obj)/kernel.o: $(obj)/kernel/generated_arch_warn_asm.rs $(obj)/kernel/generate
endif
endif
ifdef CONFIG_RUST_INLINE_HELPERS
$(obj)/kernel.o: private link_helper = 1
$(obj)/kernel.o: $(obj)/helpers/helpers.bc
endif
endif # CONFIG_RUST

View File

@ -15,14 +15,14 @@
--opaque-type x86_msi_data
--opaque-type x86_msi_addr_lo
# `try` is a reserved keyword since Rust 2018; solved in `bindgen` v0.59.2,
# commit 2aed6b021680 ("context: Escape the try keyword properly").
--opaque-type kunit_try_catch
# If SMP is disabled, `arch_spinlock_t` is defined as a ZST which triggers a Rust
# warning. We don't need to peek into it anyway.
--opaque-type spinlock
# enums that appear in indirect function calls should specify a cfi type
--newtype-enum lru_status
--with-attribute-custom-enum=lru_status='#[cfi_encoding="10lru_status"]'
# `seccomp`'s comment gets understood as a doctest
--no-doc-comments

View File

@ -149,5 +149,4 @@ const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE;
#if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST)
#include "../../drivers/android/binder/rust_binder.h"
#include "../../drivers/android/binder/rust_binder_events.h"
#include "../../drivers/android/binder/page_range_helper.h"
#endif

View File

@ -9,10 +9,6 @@
//! using this crate.
#![no_std]
// See <https://github.com/rust-lang/rust-bindgen/issues/1651>.
#![cfg_attr(test, allow(deref_nullptr))]
#![cfg_attr(test, allow(unaligned_references))]
#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
#![allow(
clippy::all,
missing_docs,
@ -23,6 +19,7 @@
unreachable_pub,
unsafe_op_in_unsafe_fn
)]
#![feature(cfi_encoding)]
#[allow(dead_code)]
#[allow(clippy::cast_lossless)]

View File

@ -16,10 +16,13 @@
#define EXPORT_SYMBOL_RUST_GPL(sym) extern int sym; EXPORT_SYMBOL_GPL(sym)
#include "exports_core_generated.h"
#include "exports_helpers_generated.h"
#include "exports_bindings_generated.h"
#include "exports_kernel_generated.h"
#ifndef CONFIG_RUST_INLINE_HELPERS
#include "exports_helpers_generated.h"
#endif
// For modules using `rust/build_error.rs`.
#ifdef CONFIG_RUST_BUILD_ASSERT_ALLOW
EXPORT_SYMBOL_RUST_GPL(rust_build_error);

View File

@ -7,60 +7,62 @@
* CONFIG_HAVE_CLK or CONFIG_HAVE_CLK_PREPARE aren't set.
*/
#ifndef CONFIG_HAVE_CLK
struct clk *rust_helper_clk_get(struct device *dev, const char *id)
__rust_helper struct clk *rust_helper_clk_get(struct device *dev,
const char *id)
{
return clk_get(dev, id);
}
void rust_helper_clk_put(struct clk *clk)
__rust_helper void rust_helper_clk_put(struct clk *clk)
{
clk_put(clk);
}
int rust_helper_clk_enable(struct clk *clk)
__rust_helper int rust_helper_clk_enable(struct clk *clk)
{
return clk_enable(clk);
}
void rust_helper_clk_disable(struct clk *clk)
__rust_helper void rust_helper_clk_disable(struct clk *clk)
{
clk_disable(clk);
}
unsigned long rust_helper_clk_get_rate(struct clk *clk)
__rust_helper unsigned long rust_helper_clk_get_rate(struct clk *clk)
{
return clk_get_rate(clk);
}
int rust_helper_clk_set_rate(struct clk *clk, unsigned long rate)
__rust_helper int rust_helper_clk_set_rate(struct clk *clk, unsigned long rate)
{
return clk_set_rate(clk, rate);
}
#endif
#ifndef CONFIG_HAVE_CLK_PREPARE
int rust_helper_clk_prepare(struct clk *clk)
__rust_helper int rust_helper_clk_prepare(struct clk *clk)
{
return clk_prepare(clk);
}
void rust_helper_clk_unprepare(struct clk *clk)
__rust_helper void rust_helper_clk_unprepare(struct clk *clk)
{
clk_unprepare(clk);
}
#endif
struct clk *rust_helper_clk_get_optional(struct device *dev, const char *id)
__rust_helper struct clk *rust_helper_clk_get_optional(struct device *dev,
const char *id)
{
return clk_get_optional(dev, id);
}
int rust_helper_clk_prepare_enable(struct clk *clk)
__rust_helper int rust_helper_clk_prepare_enable(struct clk *clk)
{
return clk_prepare_enable(clk);
}
void rust_helper_clk_disable_unprepare(struct clk *clk)
__rust_helper void rust_helper_clk_disable_unprepare(struct clk *clk)
{
clk_disable_unprepare(clk);
}

View File

@ -7,7 +7,36 @@
* Sorted alphabetically.
*/
#include <linux/compiler_types.h>
#ifdef __BINDGEN__
// Omit `inline` for bindgen as it ignores inline functions.
#define __rust_helper
#else
// The helper functions are all inline functions.
//
// We use `__always_inline` here to bypass LLVM inlining checks, in case the
// helpers are inlined directly into Rust CGUs.
//
// The LLVM inlining checks are false positives:
// * LLVM doesn't want to inline functions compiled with
// `-fno-delete-null-pointer-checks` with code compiled without.
// The C CGUs all have this enabled and Rust CGUs don't. Inlining is okay
// since this is one of the hardening features that does not change the ABI,
// and we shouldn't have null pointer dereferences in these helpers.
// * LLVM doesn't want to inline functions with different list of builtins. C
// side has `-fno-builtin-wcslen`; `wcslen` is not a Rust builtin, so they
// should be compatible, but LLVM does not perform inlining due to attributes
// mismatch.
// * clang and Rust doesn't have the exact target string. Clang generates
// `+cmov,+cx8,+fxsr` but Rust doesn't enable them (in fact, Rust will
// complain if `-Ctarget-feature=+cmov,+cx8,+fxsr` is used). x86-64 always
// enable these features, so they are in fact the same target string, but
// LLVM doesn't understand this and so inlining is inhibited. This can be
// bypassed with `--ignore-tti-inline-compatible`, but this is a hidden
// option.
#define __rust_helper __always_inline
#endif
#include "atomic.c"
#include "atomic_ext.c"

View File

@ -7,7 +7,7 @@
#include <linux/jump_label.h>
#ifndef CONFIG_JUMP_LABEL
int rust_helper_static_key_count(struct static_key *key)
__rust_helper int rust_helper_static_key_count(struct static_key *key)
{
return static_key_count(key);
}

View File

@ -42,15 +42,9 @@ fn next(&mut self) -> Option<Self::Item> {
return None;
}
// TODO: Use `NonNull::add()` instead, once the minimum supported compiler version is
// bumped to 1.80 or later.
//
// SAFETY: `offset` is in the interval `[0, (self.page_count() - 1) * page::PAGE_SIZE]`,
// hence the resulting pointer is guaranteed to be within the same allocation.
let ptr = unsafe { self.buf.as_ptr().add(offset) };
// SAFETY: `ptr` is guaranteed to be non-null given that it is derived from `self.buf`.
let ptr = unsafe { NonNull::new_unchecked(ptr) };
let ptr = unsafe { self.buf.add(offset) };
// SAFETY:
// - `ptr` is a valid pointer to a `Vmalloc` allocation.

View File

@ -77,33 +77,8 @@
/// `self.0` is always properly aligned and either points to memory allocated with `A` or, for
/// zero-sized types, is a dangling, well aligned pointer.
#[repr(transparent)]
#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
pub struct Box<#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, pointee)] T: ?Sized, A: Allocator>(
NonNull<T>,
PhantomData<A>,
);
// This is to allow coercion from `Box<T, A>` to `Box<U, A>` if `T` can be converted to the
// dynamically-sized type (DST) `U`.
#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
impl<T, U, A> core::ops::CoerceUnsized<Box<U, A>> for Box<T, A>
where
T: ?Sized + core::marker::Unsize<U>,
U: ?Sized,
A: Allocator,
{
}
// This is to allow `Box<U, A>` to be dispatched on when `Box<T, A>` can be coerced into `Box<U,
// A>`.
#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
impl<T, U, A> core::ops::DispatchFromDyn<Box<U, A>> for Box<T, A>
where
T: ?Sized + core::marker::Unsize<U>,
U: ?Sized,
A: Allocator,
{
}
#[derive(core::marker::CoercePointee)]
pub struct Box<#[pointee] T: ?Sized, A: Allocator>(NonNull<T>, PhantomData<A>);
/// Type alias for [`Box`] with a [`Kmalloc`] allocator.
///

View File

@ -15,6 +15,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
impl<T> From<PushError<T>> for Error {
#[inline]
fn from(_: PushError<T>) -> Error {
// Returning ENOMEM isn't appropriate because the system is not out of memory. The vector
// is just full and we are refusing to resize it.
@ -32,6 +33,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
impl From<RemoveError> for Error {
#[inline]
fn from(_: RemoveError) -> Error {
EINVAL
}
@ -55,6 +57,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
impl<T> From<InsertError<T>> for Error {
#[inline]
fn from(_: InsertError<T>) -> Error {
EINVAL
}

View File

@ -140,9 +140,7 @@ pub fn build<T: Operations>(
devnode: None,
alternative_gpt_sector: None,
get_unique_id: None,
// TODO: Set to THIS_MODULE. Waiting for const_refs_to_static feature to
// be merged (unstable in rustc 1.78 which is staged for linux 6.10)
// <https://github.com/rust-lang/rust/issues/119618>
// TODO: Set to `THIS_MODULE`.
owner: core::ptr::null_mut(),
pr_ops: core::ptr::null_mut(),
free_disk: None,

View File

@ -1,10 +1,144 @@
// SPDX-License-Identifier: GPL-2.0
//! Build-time assert.
//! Various assertions that happen during build-time.
//!
//! There are three types of build-time assertions that you can use:
//! - [`static_assert!`]
//! - [`const_assert!`]
//! - [`build_assert!`]
//!
//! The ones towards the bottom of the list are more expressive, while the ones towards the top of
//! the list are more robust and trigger earlier in the compilation pipeline. Therefore, you should
//! prefer the ones towards the top of the list wherever possible.
//!
//! # Choosing the correct assertion
//!
//! If you're asserting outside any bodies (e.g. initializers or function bodies), you should use
//! [`static_assert!`] as it is the only assertion that can be used in that context.
//!
//! Inside bodies, if your assertion condition does not depend on any variable or generics, you
//! should use [`static_assert!`]. If the condition depends on generics, but not variables
//! (including function arguments), you should use [`const_assert!`]. Otherwise, use
//! [`build_assert!`]. The same is true regardless if the function is `const fn`.
//!
//! ```
//! // Outside any bodies.
//! static_assert!(core::mem::size_of::<u8>() == 1);
//! // `const_assert!` and `build_assert!` cannot be used here, they will fail to compile.
//!
//! #[inline(always)]
//! fn foo<const N: usize>(v: usize) {
//! static_assert!(core::mem::size_of::<u8>() == 1); // Preferred.
//! const_assert!(core::mem::size_of::<u8>() == 1); // Discouraged.
//! build_assert!(core::mem::size_of::<u8>() == 1); // Discouraged.
//!
//! // `static_assert!(N > 1);` is not allowed.
//! const_assert!(N > 1); // Preferred.
//! build_assert!(N > 1); // Discouraged.
//!
//! // `static_assert!(v > 1);` is not allowed.
//! // `const_assert!(v > 1);` is not allowed.
//! build_assert!(v > 1); // Works.
//! }
//! ```
//!
//! # Detailed behavior
//!
//! `static_assert!()` is equivalent to `static_assert` in C. It requires `expr` to be a constant
//! expression. This expression cannot refer to any generics. A `static_assert!(expr)` in a program
//! is always evaluated, regardless if the function it appears in is used or not. This is also the
//! only usable assertion outside a body.
//!
//! `const_assert!()` has no direct C equivalence. It is a more powerful version of
//! `static_assert!()`, where it may refer to generics in a function. Note that due to the ability
//! to refer to generics, the assertion is tied to a specific instance of a function. So if it is
//! used in a generic function that is not instantiated, the assertion will not be checked. For this
//! reason, `static_assert!()` is preferred wherever possible.
//!
//! `build_assert!()` is equivalent to `BUILD_BUG_ON`. It is even more powerful than
//! `const_assert!()` because it can be used to check tautologies that depend on runtime value (this
//! is the same as `BUILD_BUG_ON`). However, the assertion failure mechanism can possibly be
//! undefined symbols and linker errors, it is not developer friendly to debug, so it is recommended
//! to avoid it and prefer other two assertions where possible.
pub use crate::{
build_assert,
build_error,
const_assert,
static_assert, //
};
#[doc(hidden)]
pub use build_error::build_error;
/// Static assert (i.e. compile-time assert).
///
/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
///
/// An optional panic message can be supplied after the expression.
/// Currently only a string literal without formatting is supported
/// due to constness limitations of the [`assert!`] macro.
///
/// The feature may be added to Rust in the future: see [RFC 2790].
///
/// You cannot refer to generics or variables with [`static_assert!`]. If you need to refer to
/// generics, use [`const_assert!`]; if you need to refer to variables, use [`build_assert!`]. See
/// the [module documentation](self).
///
/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
///
/// # Examples
///
/// ```
/// static_assert!(42 > 24);
/// static_assert!(core::mem::size_of::<u8>() == 1);
///
/// const X: &[u8] = b"bar";
/// static_assert!(X[1] == b'a');
///
/// const fn f(x: i32) -> i32 {
/// x + 2
/// }
/// static_assert!(f(40) == 42);
/// static_assert!(f(40) == 42, "f(x) must add 2 to the given input.");
/// ```
#[macro_export]
macro_rules! static_assert {
($condition:expr $(,$arg:literal)?) => {
const _: () = ::core::assert!($condition $(,$arg)?);
};
}
/// Assertion during constant evaluation.
///
/// This is a more powerful version of [`static_assert!`] that can refer to generics inside
/// functions or implementation blocks. However, it also has a limitation where it can only appear
/// in places where statements can appear; for example, you cannot use it as an item in the module.
///
/// [`static_assert!`] should be preferred if no generics are referred to in the condition. You
/// cannot refer to variables with [`const_assert!`] (even inside `const fn`); if you need the
/// capability, use [`build_assert!`]. See the [module documentation](self).
///
/// # Examples
///
/// ```
/// fn foo<const N: usize>() {
/// const_assert!(N > 1);
/// }
///
/// fn bar<T>() {
/// const_assert!(size_of::<T>() > 0, "T cannot be ZST");
/// }
/// ```
#[macro_export]
macro_rules! const_assert {
($condition:expr $(,$arg:literal)?) => {
const { ::core::assert!($condition $(,$arg)?) };
};
}
/// Fails the build if the code path calling `build_error!` can possibly be executed.
///
/// If the macro is executed in const context, `build_error!` will panic.
@ -38,44 +172,33 @@ macro_rules! build_error {
/// will panic. If the compiler or optimizer cannot guarantee the condition will
/// be evaluated to `true`, a build error will be triggered.
///
/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
///
/// # Examples
///
/// These examples show that different types of [`assert!`] will trigger errors
/// at different stage of compilation. It is preferred to err as early as
/// possible, so [`static_assert!`] should be used whenever possible.
/// ```ignore
/// fn foo() {
/// static_assert!(1 > 1); // Compile-time error
/// build_assert!(1 > 1); // Build-time error
/// assert!(1 > 1); // Run-time error
/// }
/// ```
///
/// When the condition refers to generic parameters or parameters of an inline function,
/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
/// ```
/// fn foo<const N: usize>() {
/// // `static_assert!(N > 1);` is not allowed
/// build_assert!(N > 1); // Build-time check
/// assert!(N > 1); // Run-time check
/// }
/// ```
///
/// When a condition depends on a function argument, the function must be annotated with
/// `#[inline(always)]`. Without this attribute, the compiler may choose to not inline the
/// function, preventing it from optimizing out the error path.
/// ```
/// #[inline(always)]
/// fn bar(n: usize) {
/// // `static_assert!(n > 1);` is not allowed
/// build_assert!(n > 1); // Build-time check
/// assert!(n > 1); // Run-time check
/// }
/// ```
///
/// [`static_assert!`]: crate::static_assert!
/// If the assertion condition does not depend on any variables or generics, you should use
/// [`static_assert!`]. If the assertion condition does not depend on variables, but does depend on
/// generics, you should use [`const_assert!`]. See the [module documentation](self).
///
/// # Examples
///
/// ```
/// #[inline(always)] // Important.
/// fn bar(n: usize) {
/// build_assert!(n > 1);
/// }
///
/// fn foo() {
/// bar(2);
/// }
///
/// #[inline(always)] // Important.
/// const fn const_bar(n: usize) {
/// build_assert!(n > 1);
/// }
///
/// const _: () = const_bar(2);
/// ```
#[macro_export]
macro_rules! build_assert {
($cond:expr $(,)?) => {{

View File

@ -128,6 +128,13 @@ mod common_clk {
#[repr(transparent)]
pub struct Clk(*mut bindings::clk);
// SAFETY: It is safe to call `clk_put` on another thread than where `clk_get` was called.
unsafe impl Send for Clk {}
// SAFETY: It is safe to call any combination of the `&self` methods in parallel, as the
// methods are synchronized internally.
unsafe impl Sync for Clk {}
impl Clk {
/// Gets [`Clk`] corresponding to a [`Device`] and a connection id.
///

View File

@ -216,36 +216,42 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
impl From<AllocError> for Error {
#[inline]
fn from(_: AllocError) -> Error {
code::ENOMEM
}
}
impl From<TryFromIntError> for Error {
#[inline]
fn from(_: TryFromIntError) -> Error {
code::EINVAL
}
}
impl From<Utf8Error> for Error {
#[inline]
fn from(_: Utf8Error) -> Error {
code::EINVAL
}
}
impl From<LayoutError> for Error {
#[inline]
fn from(_: LayoutError) -> Error {
code::ENOMEM
}
}
impl From<fmt::Error> for Error {
#[inline]
fn from(_: fmt::Error) -> Error {
code::EINVAL
}
}
impl From<core::convert::Infallible> for Error {
#[inline]
fn from(e: core::convert::Infallible) -> Error {
match e {}
}
@ -446,6 +452,9 @@ pub fn to_result(err: crate::ffi::c_int) -> Result {
/// for errors. This function performs the check and converts the "error pointer"
/// to a normal pointer in an idiomatic fashion.
///
/// Note that a `NULL` pointer is not considered an error pointer, and is returned
/// as-is, wrapped in [`Ok`].
///
/// # Examples
///
/// ```ignore
@ -460,6 +469,34 @@ pub fn to_result(err: crate::ffi::c_int) -> Result {
/// from_err_ptr(unsafe { bindings::devm_platform_ioremap_resource(pdev.to_ptr(), index) })
/// }
/// ```
///
/// ```
/// # use kernel::error::from_err_ptr;
/// # mod bindings {
/// # #![expect(clippy::missing_safety_doc)]
/// # use kernel::prelude::*;
/// # pub(super) unsafe fn einval_err_ptr() -> *mut kernel::ffi::c_void {
/// # EINVAL.to_ptr()
/// # }
/// # pub(super) unsafe fn null_ptr() -> *mut kernel::ffi::c_void {
/// # core::ptr::null_mut()
/// # }
/// # pub(super) unsafe fn non_null_ptr() -> *mut kernel::ffi::c_void {
/// # 0x1234 as *mut kernel::ffi::c_void
/// # }
/// # }
/// // SAFETY: ...
/// let einval_err = from_err_ptr(unsafe { bindings::einval_err_ptr() });
/// assert_eq!(einval_err, Err(EINVAL));
///
/// // SAFETY: ...
/// let null_ok = from_err_ptr(unsafe { bindings::null_ptr() });
/// assert_eq!(null_ok, Ok(core::ptr::null_mut()));
///
/// // SAFETY: ...
/// let non_null = from_err_ptr(unsafe { bindings::non_null_ptr() }).unwrap();
/// assert_ne!(non_null, core::ptr::null_mut());
/// ```
pub fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
// CAST: Casting a pointer to `*const crate::ffi::c_void` is always valid.
let const_ptr: *const crate::ffi::c_void = ptr.cast();

View File

@ -16,10 +16,11 @@
error::*,
of,
prelude::*,
types::{
AlwaysRefCounted,
Opaque, //
}, //
sync::aref::{
ARef,
AlwaysRefCounted, //
},
types::Opaque, //
};
use core::{
@ -31,8 +32,6 @@
}, //
};
use kernel::types::ARef;
/// An I2C device id table.
#[repr(transparent)]
#[derive(Clone, Copy)]
@ -416,7 +415,7 @@ pub fn get(index: i32) -> Result<ARef<Self>> {
kernel::impl_device_context_into_aref!(I2cAdapter);
// SAFETY: Instances of `I2cAdapter` are always reference-counted.
unsafe impl crate::types::AlwaysRefCounted for I2cAdapter {
unsafe impl AlwaysRefCounted for I2cAdapter {
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
unsafe { bindings::i2c_get_adapter(self.index()) };

View File

@ -16,45 +16,14 @@
// Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on
// the unstable features in use.
//
// Stable since Rust 1.79.0.
#![feature(generic_nonzero)]
#![feature(inline_const)]
#![feature(pointer_is_aligned)]
#![feature(slice_ptr_len)]
//
// Stable since Rust 1.80.0.
#![feature(slice_flatten)]
//
// Stable since Rust 1.81.0.
#![feature(lint_reasons)]
//
// Stable since Rust 1.82.0.
#![feature(raw_ref_op)]
//
// Stable since Rust 1.83.0.
#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_mut_refs)]
#![feature(const_option)]
#![feature(const_ptr_write)]
#![feature(const_refs_to_cell)]
//
// Stable since Rust 1.84.0.
#![feature(strict_provenance)]
//
// Expected to become stable.
#![feature(arbitrary_self_types)]
#![feature(derive_coerce_pointee)]
//
// To be determined.
#![feature(used_with_arg)]
//
// `feature(derive_coerce_pointee)` is expected to become stable. Before Rust
// 1.84.0, it did not exist, so enable the predecessor features.
#![cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, feature(derive_coerce_pointee))]
#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(coerce_unsized))]
#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(dispatch_from_dyn))]
#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(unsize))]
//
// `feature(file_with_nul)` is expected to become stable. Before Rust 1.89.0, it did not exist, so
// `feature(file_with_nul)` is stable since Rust 1.92.0. Before Rust 1.89.0, it did not exist, so
// enable it conditionally.
#![cfg_attr(CONFIG_RUSTC_HAS_FILE_WITH_NUL, feature(file_with_nul))]
@ -77,7 +46,6 @@
#[cfg(CONFIG_BLOCK)]
pub mod block;
pub mod bug;
#[doc(hidden)]
pub mod build_assert;
pub mod clk;
#[cfg(CONFIG_CONFIGFS_FS)]
@ -145,10 +113,8 @@
pub mod security;
pub mod seq_file;
pub mod sizes;
pub mod slice;
#[cfg(CONFIG_SOC_BUS)]
pub mod soc;
mod static_assert;
#[doc(hidden)]
pub mod std_vendor;
pub mod str;

View File

@ -12,15 +12,31 @@
use pin_init::PinInit;
mod impl_list_item_mod;
#[doc(inline)]
pub use self::impl_list_item_mod::{
impl_has_list_links, impl_has_list_links_self_ptr, impl_list_item, HasListLinks, HasSelfPtr,
impl_has_list_links,
impl_has_list_links_self_ptr,
impl_list_item,
HasListLinks,
HasSelfPtr, //
};
mod arc;
pub use self::arc::{impl_list_arc_safe, AtomicTracker, ListArc, ListArcSafe, TryNewListArc};
#[doc(inline)]
pub use self::arc::{
impl_list_arc_safe,
AtomicTracker,
ListArc,
ListArcSafe,
TryNewListArc, //
};
mod arc_field;
pub use self::arc_field::{define_list_arc_field_getter, ListArcField};
#[doc(inline)]
pub use self::arc_field::{
define_list_arc_field_getter,
ListArcField, //
};
/// A linked list.
///

View File

@ -82,6 +82,7 @@ pub unsafe trait TryNewListArc<const ID: u64 = 0>: ListArcSafe<ID> {
/// [`AtomicTracker`]. However, it is also possible to defer the tracking to another struct
/// using also using this macro.
#[macro_export]
#[doc(hidden)]
macro_rules! impl_list_arc_safe {
(impl$({$($generics:tt)*})? ListArcSafe<$num:tt> for $t:ty { untracked; } $($rest:tt)*) => {
impl$(<$($generics)*>)? $crate::list::ListArcSafe<$num> for $t {
@ -159,7 +160,7 @@ fn try_new_list_arc(&self) -> bool {
///
/// [`List`]: crate::list::List
#[repr(transparent)]
#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
#[derive(core::marker::CoercePointee)]
pub struct ListArc<T, const ID: u64 = 0>
where
T: ListArcSafe<ID> + ?Sized,
@ -442,26 +443,6 @@ fn as_ref(&self) -> &Arc<T> {
}
}
// This is to allow coercion from `ListArc<T>` to `ListArc<U>` if `T` can be converted to the
// dynamically-sized type (DST) `U`.
#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
impl<T, U, const ID: u64> core::ops::CoerceUnsized<ListArc<U, ID>> for ListArc<T, ID>
where
T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized,
U: ListArcSafe<ID> + ?Sized,
{
}
// This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into
// `ListArc<U>`.
#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID>
where
T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized,
U: ListArcSafe<ID> + ?Sized,
{
}
/// A utility for tracking whether a [`ListArc`] exists using an atomic.
///
/// # Invariants

View File

@ -66,6 +66,7 @@ pub unsafe fn assert_mut(&self) -> &mut T {
/// Defines getters for a [`ListArcField`].
#[macro_export]
#[doc(hidden)]
macro_rules! define_list_arc_field_getter {
($pub:vis fn $name:ident(&self $(<$id:tt>)?) -> &$typ:ty { $field:ident }
$($rest:tt)*

View File

@ -29,6 +29,7 @@ pub unsafe trait HasListLinks<const ID: u64 = 0> {
/// Implements the [`HasListLinks`] trait for the given type.
#[macro_export]
#[doc(hidden)]
macro_rules! impl_has_list_links {
($(impl$({$($generics:tt)*})?
HasListLinks$(<$id:tt>)?
@ -74,6 +75,7 @@ pub unsafe trait HasSelfPtr<T: ?Sized, const ID: u64 = 0>
/// Implements the [`HasListLinks`] and [`HasSelfPtr`] traits for the given type.
#[macro_export]
#[doc(hidden)]
macro_rules! impl_has_list_links_self_ptr {
($(impl$({$($generics:tt)*})?
HasSelfPtr<$item_type:ty $(, $id:tt)?>
@ -181,6 +183,7 @@ unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut $crate::list::ListLinks$(<$
/// }
/// ```
#[macro_export]
#[doc(hidden)]
macro_rules! impl_list_item {
(
$(impl$({$($generics:tt)*})? ListItem<$num:tt> for $self:ty {

View File

@ -255,9 +255,7 @@ impl<const N: u32> Bounded<$type, N> {
/// ```
pub const fn new<const VALUE: $type>() -> Self {
// Statically assert that `VALUE` fits within the set number of bits.
const {
assert!(fits_within!(VALUE, $type, N));
}
const_assert!(fits_within!(VALUE, $type, N));
// SAFETY: `fits_within` confirmed that `VALUE` can be represented within
// `N` bits.
@ -287,12 +285,10 @@ impl<T, const N: u32> Bounded<T, N>
/// The caller must ensure that `value` can be represented within `N` bits.
const unsafe fn __new(value: T) -> Self {
// Enforce the type invariants.
const {
// `N` cannot be zero.
assert!(N != 0);
// The backing type is at least as large as `N` bits.
assert!(N <= T::BITS);
}
// `N` cannot be zero.
const_assert!(N != 0);
// The backing type is at least as large as `N` bits.
const_assert!(N <= T::BITS);
// INVARIANT: The caller ensures `value` fits within `N` bits.
Self(value)
@ -406,12 +402,10 @@ pub fn get(self) -> T {
/// assert_eq!(larger_v, v);
/// ```
pub const fn extend<const M: u32>(self) -> Bounded<T, M> {
const {
assert!(
M >= N,
"Requested number of bits is less than the current representation."
);
}
const_assert!(
M >= N,
"Requested number of bits is less than the current representation."
);
// SAFETY: The value did fit within `N` bits, so it will all the more fit within
// the larger `M` bits.

View File

@ -13,43 +13,97 @@
#[doc(no_inline)]
pub use core::{
mem::{align_of, align_of_val, size_of, size_of_val},
pin::Pin,
mem::{
align_of,
align_of_val,
size_of,
size_of_val, //
},
pin::Pin, //
};
pub use ::ffi::{
c_char, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong,
c_ushort, c_void, CStr,
c_char,
c_int,
c_long,
c_longlong,
c_schar,
c_short,
c_uchar,
c_uint,
c_ulong,
c_ulonglong,
c_ushort,
c_void,
CStr, //
};
pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec};
#[doc(no_inline)]
pub use macros::{export, fmt, kunit_tests, module, vtable};
pub use macros::{
export,
fmt,
kunit_tests,
module,
vtable, //
};
pub use pin_init::{init, pin_data, pin_init, pinned_drop, InPlaceWrite, Init, PinInit, Zeroable};
pub use pin_init::{
init,
pin_data,
pin_init,
pinned_drop,
InPlaceWrite,
Init,
PinInit,
Zeroable, //
};
pub use super::{build_assert, build_error};
pub use super::{
alloc::{
flags::*,
Box,
KBox,
KVBox,
KVVec,
KVec,
VBox,
VVec,
Vec, //
},
build_assert,
build_error,
const_assert,
current,
dev_alert,
dev_crit,
dev_dbg,
dev_emerg,
dev_err,
dev_info,
dev_notice,
dev_warn,
error::{
code::*,
Error,
Result, //
},
init::InPlaceInit,
pr_alert,
pr_crit,
pr_debug,
pr_emerg,
pr_err,
pr_info,
pr_notice,
pr_warn,
static_assert,
str::CStrExt as _,
try_init,
try_pin_init,
uaccess::UserPtr,
ThisModule, //
};
// `super::std_vendor` is hidden, which makes the macro inline for some reason.
#[doc(no_inline)]
pub use super::dbg;
pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn};
pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
pub use super::{try_init, try_pin_init};
pub use super::static_assert;
pub use super::error::{code::*, Error, Result};
pub use super::{str::CStrExt as _, ThisModule};
pub use super::init::InPlaceInit;
pub use super::current;
pub use super::uaccess::UserPtr;
#[cfg(not(CONFIG_RUSTC_HAS_SLICE_AS_FLATTENED))]
pub use super::slice::AsFlattened;

View File

@ -11,6 +11,8 @@
};
use core::num::NonZero;
use crate::const_assert;
/// Type representing an alignment, which is always a power of two.
///
/// It is used to validate that a given value is a valid alignment, and to perform masking and
@ -44,12 +46,10 @@ impl Alignment {
/// ```
#[inline(always)]
pub const fn new<const ALIGN: usize>() -> Self {
const {
assert!(
ALIGN.is_power_of_two(),
"Provided alignment is not a power of two."
);
}
const_assert!(
ALIGN.is_power_of_two(),
"Provided alignment is not a power of two."
);
// INVARIANT: `align` is a power of two.
// SAFETY: `align` is a power of two, and thus non-zero.
@ -87,7 +87,6 @@ pub const fn new_checked(align: usize) -> Option<Self> {
/// This is equivalent to [`align_of`], but with the return value provided as an [`Alignment`].
#[inline(always)]
pub const fn of<T>() -> Self {
#![allow(clippy::incompatible_msrv)]
// This cannot panic since alignments are always powers of two.
//
// We unfortunately cannot use `new` as it would require the `generic_const_exprs` feature.
@ -253,3 +252,32 @@ fn size(p: *const Self) -> usize {
p.len() * size_of::<T>()
}
}
/// Aligns `value` up to `align`.
///
/// This is the const-compatible equivalent of [`Alignable::align_up`].
///
/// Returns [`None`] on overflow.
///
/// # Examples
///
/// ```
/// use kernel::{
/// ptr::{
/// const_align_up,
/// Alignment, //
/// },
/// sizes::SZ_4K, //
/// };
///
/// assert_eq!(const_align_up(0x4f, Alignment::new::<16>()), Some(0x50));
/// assert_eq!(const_align_up(0x40, Alignment::new::<16>()), Some(0x40));
/// assert_eq!(const_align_up(1, Alignment::new::<SZ_4K>()), Some(SZ_4K));
/// ```
#[inline(always)]
pub const fn const_align_up(value: usize, align: Alignment) -> Option<usize> {
match value.checked_add(align.as_usize() - 1) {
Some(v) => Some(v & align.mask()),
None => None,
}
}

View File

@ -3,48 +3,132 @@
//! Commonly used sizes.
//!
//! C headers: [`include/linux/sizes.h`](srctree/include/linux/sizes.h).
//!
//! The top-level `SZ_*` constants are [`usize`]-typed, for use in kernel page
//! arithmetic and similar CPU-side work.
//!
//! The [`SizeConstants`] trait provides the same constants as associated constants
//! on [`u32`], [`u64`], and [`usize`], for use in device address spaces where
//! the address width depends on the hardware. Device drivers frequently need
//! these constants as [`u64`] (or [`u32`]) rather than [`usize`], because
//! device address spaces are sized independently of the CPU pointer width.
//!
//! # Examples
//!
//! ```
//! use kernel::{
//! page::PAGE_SIZE,
//! sizes::{
//! SizeConstants,
//! SZ_1M, //
//! }, //
//! };
//!
//! // Module-level constants continue to work without a type qualifier.
//! let num_pages_in_1m = SZ_1M / PAGE_SIZE;
//!
//! // Trait associated constants require a type qualifier.
//! let heap_size = 14 * u64::SZ_1M;
//! let small = u32::SZ_4K;
//! ```
/// 0x00000400
pub const SZ_1K: usize = bindings::SZ_1K as usize;
/// 0x00000800
pub const SZ_2K: usize = bindings::SZ_2K as usize;
/// 0x00001000
pub const SZ_4K: usize = bindings::SZ_4K as usize;
/// 0x00002000
pub const SZ_8K: usize = bindings::SZ_8K as usize;
/// 0x00004000
pub const SZ_16K: usize = bindings::SZ_16K as usize;
/// 0x00008000
pub const SZ_32K: usize = bindings::SZ_32K as usize;
/// 0x00010000
pub const SZ_64K: usize = bindings::SZ_64K as usize;
/// 0x00020000
pub const SZ_128K: usize = bindings::SZ_128K as usize;
/// 0x00040000
pub const SZ_256K: usize = bindings::SZ_256K as usize;
/// 0x00080000
pub const SZ_512K: usize = bindings::SZ_512K as usize;
/// 0x00100000
pub const SZ_1M: usize = bindings::SZ_1M as usize;
/// 0x00200000
pub const SZ_2M: usize = bindings::SZ_2M as usize;
/// 0x00400000
pub const SZ_4M: usize = bindings::SZ_4M as usize;
/// 0x00800000
pub const SZ_8M: usize = bindings::SZ_8M as usize;
/// 0x01000000
pub const SZ_16M: usize = bindings::SZ_16M as usize;
/// 0x02000000
pub const SZ_32M: usize = bindings::SZ_32M as usize;
/// 0x04000000
pub const SZ_64M: usize = bindings::SZ_64M as usize;
/// 0x08000000
pub const SZ_128M: usize = bindings::SZ_128M as usize;
/// 0x10000000
pub const SZ_256M: usize = bindings::SZ_256M as usize;
/// 0x20000000
pub const SZ_512M: usize = bindings::SZ_512M as usize;
/// 0x40000000
pub const SZ_1G: usize = bindings::SZ_1G as usize;
/// 0x80000000
pub const SZ_2G: usize = bindings::SZ_2G as usize;
macro_rules! define_sizes {
($($type:ty),* $(,)?) => {
define_sizes!(@internal [$($type),*]
/// `0x0000_0400`.
SZ_1K,
/// `0x0000_0800`.
SZ_2K,
/// `0x0000_1000`.
SZ_4K,
/// `0x0000_2000`.
SZ_8K,
/// `0x0000_4000`.
SZ_16K,
/// `0x0000_8000`.
SZ_32K,
/// `0x0001_0000`.
SZ_64K,
/// `0x0002_0000`.
SZ_128K,
/// `0x0004_0000`.
SZ_256K,
/// `0x0008_0000`.
SZ_512K,
/// `0x0010_0000`.
SZ_1M,
/// `0x0020_0000`.
SZ_2M,
/// `0x0040_0000`.
SZ_4M,
/// `0x0080_0000`.
SZ_8M,
/// `0x0100_0000`.
SZ_16M,
/// `0x0200_0000`.
SZ_32M,
/// `0x0400_0000`.
SZ_64M,
/// `0x0800_0000`.
SZ_128M,
/// `0x1000_0000`.
SZ_256M,
/// `0x2000_0000`.
SZ_512M,
/// `0x4000_0000`.
SZ_1G,
/// `0x8000_0000`.
SZ_2G,
);
};
(@internal [$($type:ty),*] $($names_and_metas:tt)*) => {
define_sizes!(@consts_and_trait $($names_and_metas)*);
define_sizes!(@impls [$($type),*] $($names_and_metas)*);
};
(@consts_and_trait $($(#[$meta:meta])* $name:ident,)*) => {
$(
$(#[$meta])*
pub const $name: usize = bindings::$name as usize;
)*
/// Size constants for device address spaces.
///
/// Implemented for [`u32`], [`u64`], and [`usize`] so drivers can
/// choose the width that matches their hardware. All `SZ_*` values fit
/// in a [`u32`], so all implementations are lossless.
///
/// # Examples
///
/// ```
/// use kernel::sizes::SizeConstants;
///
/// let gpu_heap = 14 * u64::SZ_1M;
/// let mmio_window = u32::SZ_16M;
/// ```
pub trait SizeConstants {
$(
$(#[$meta])*
const $name: Self;
)*
}
};
(@impls [] $($(#[$meta:meta])* $name:ident,)*) => {};
(@impls [$first:ty $(, $rest:ty)*] $($(#[$meta:meta])* $name:ident,)*) => {
impl SizeConstants for $first {
$(
const $name: Self = {
assert!((self::$name as u128) <= (<$first>::MAX as u128));
self::$name as $first
};
)*
}
define_sizes!(@impls [$($rest),*] $($(#[$meta])* $name,)*);
};
}
define_sizes!(u32, u64, usize);

View File

@ -1,49 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
//! Additional (and temporary) slice helpers.
/// Extension trait providing a portable version of [`as_flattened`] and
/// [`as_flattened_mut`].
///
/// In Rust 1.80, the previously unstable `slice::flatten` family of methods
/// have been stabilized and renamed from `flatten` to `as_flattened`.
///
/// This creates an issue for as long as the MSRV is < 1.80, as the same functionality is provided
/// by different methods depending on the compiler version.
///
/// This extension trait solves this by abstracting `as_flatten` and calling the correct method
/// depending on the Rust version.
///
/// This trait can be removed once the MSRV passes 1.80.
///
/// [`as_flattened`]: https://doc.rust-lang.org/std/primitive.slice.html#method.as_flattened
/// [`as_flattened_mut`]: https://doc.rust-lang.org/std/primitive.slice.html#method.as_flattened_mut
#[cfg(not(CONFIG_RUSTC_HAS_SLICE_AS_FLATTENED))]
pub trait AsFlattened<T> {
/// Takes a `&[[T; N]]` and flattens it to a `&[T]`.
///
/// This is an portable layer on top of [`as_flattened`]; see its documentation for details.
///
/// [`as_flattened`]: https://doc.rust-lang.org/std/primitive.slice.html#method.as_flattened
fn as_flattened(&self) -> &[T];
/// Takes a `&mut [[T; N]]` and flattens it to a `&mut [T]`.
///
/// This is an portable layer on top of [`as_flattened_mut`]; see its documentation for details.
///
/// [`as_flattened_mut`]: https://doc.rust-lang.org/std/primitive.slice.html#method.as_flattened_mut
fn as_flattened_mut(&mut self) -> &mut [T];
}
#[cfg(not(CONFIG_RUSTC_HAS_SLICE_AS_FLATTENED))]
impl<T, const N: usize> AsFlattened<T> for [[T; N]] {
#[allow(clippy::incompatible_msrv)]
fn as_flattened(&self) -> &[T] {
self.flatten()
}
#[allow(clippy::incompatible_msrv)]
fn as_flattened_mut(&mut self) -> &mut [T] {
self.flatten_mut()
}
}

View File

@ -1,39 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
//! Static assert.
/// Static assert (i.e. compile-time assert).
///
/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
///
/// An optional panic message can be supplied after the expression.
/// Currently only a string literal without formatting is supported
/// due to constness limitations of the [`assert!`] macro.
///
/// The feature may be added to Rust in the future: see [RFC 2790].
///
/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
///
/// # Examples
///
/// ```
/// static_assert!(42 > 24);
/// static_assert!(core::mem::size_of::<u8>() == 1);
///
/// const X: &[u8] = b"bar";
/// static_assert!(X[1] == b'a');
///
/// const fn f(x: i32) -> i32 {
/// x + 2
/// }
/// static_assert!(f(40) == 42);
/// static_assert!(f(40) == 42, "f(x) must add 2 to the given input.");
/// ```
#[macro_export]
macro_rules! static_assert {
($condition:expr $(,$arg:literal)?) => {
const _: () = ::core::assert!($condition $(,$arg)?);
};
}

View File

@ -189,6 +189,7 @@ macro_rules! b_str {
//
// - error[E0379]: functions in trait impls cannot be declared const
#[inline]
#[expect(clippy::disallowed_methods, reason = "internal implementation")]
pub const fn as_char_ptr_in_const_context(c_str: &CStr) -> *const c_char {
c_str.as_ptr().cast()
}
@ -319,6 +320,7 @@ unsafe fn to_bytes_mut(s: &mut CStr) -> &mut [u8] {
impl CStrExt for CStr {
#[inline]
#[expect(clippy::disallowed_methods, reason = "internal implementation")]
unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self {
// SAFETY: The safety preconditions are the same as for `CStr::from_ptr`.
unsafe { CStr::from_ptr(ptr.cast()) }
@ -334,6 +336,7 @@ unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut Self {
}
#[inline]
#[expect(clippy::disallowed_methods, reason = "internal implementation")]
fn as_char_ptr(&self) -> *const c_char {
self.as_ptr().cast()
}
@ -376,19 +379,32 @@ fn as_ref(&self) -> &BStr {
}
}
/// Creates a new [`CStr`] from a string literal.
/// Creates a new [`CStr`] at compile time.
///
/// The string literal should not contain any `NUL` bytes.
/// Rust supports C string literals since Rust 1.77, and they should be used instead of this macro
/// where possible. This macro exists to allow static *non-literal* C strings to be created at
/// compile time. This is most often used in other macros.
///
/// # Panics
///
/// This macro panics if the operand contains an interior `NUL` byte.
///
/// # Examples
///
/// ```
/// # use kernel::c_str;
/// # use kernel::str::CStr;
/// const MY_CSTR: &CStr = c_str!("My awesome CStr!");
/// // This is allowed, but `c"literal"` should be preferred for literals.
/// const BAD: &CStr = c_str!("literal");
///
/// // `c_str!` is still needed for static non-literal C strings.
/// const GOOD: &CStr = c_str!(concat!(file!(), ":", line!(), ": My CStr!"));
/// ```
#[macro_export]
macro_rules! c_str {
// NB: We could write `($str:lit) => compile_error!("use a C string literal instead");` here but
// that would trigger when the literal is at the top of several macro expansions. That would be
// too limiting to macro authors.
($str:expr) => {{
const S: &str = concat!($str, "\0");
const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) {
@ -828,7 +844,10 @@ pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> {
f.write_str("\0")?;
// SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is
// `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`.
// `buf`'s capacity. The `Formatter` is created with `size` as its limit, and the `?`
// operators on `write_fmt` and `write_str` above ensure that if writing exceeds this
// limit, an error is returned early. The contents of the buffer have been initialised
// by writes to `f`.
unsafe { buf.inc_len(f.bytes_written()) };
// Check that there are no `NUL` bytes before the end.

View File

@ -128,7 +128,7 @@
/// # Ok::<(), Error>(())
/// ```
#[repr(transparent)]
#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
#[derive(core::marker::CoercePointee)]
pub struct Arc<T: ?Sized> {
ptr: NonNull<ArcInner<T>>,
// NB: this informs dropck that objects of type `ArcInner<T>` may be used in `<Arc<T> as
@ -182,15 +182,6 @@ unsafe fn container_of(ptr: *const T) -> NonNull<ArcInner<T>> {
}
}
// This is to allow coercion from `Arc<T>` to `Arc<U>` if `T` can be converted to the
// dynamically-sized type (DST) `U`.
#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Arc<U>> for Arc<T> {}
// This is to allow `Arc<U>` to be dispatched on when `Arc<T>` can be coerced into `Arc<U>`.
#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Arc<U>> for Arc<T> {}
// SAFETY: It is safe to send `Arc<T>` to another thread when the underlying `T` is `Sync` because
// it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs
// `T` to be `Send` because any thread that has an `Arc<T>` may ultimately access `T` using a
@ -547,20 +538,12 @@ fn from(item: Pin<UniqueArc<T>>) -> Self {
/// # Ok::<(), Error>(())
/// ```
#[repr(transparent)]
#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
#[derive(core::marker::CoercePointee)]
pub struct ArcBorrow<'a, T: ?Sized + 'a> {
inner: NonNull<ArcInner<T>>,
_p: PhantomData<&'a ()>,
}
// This is to allow `ArcBorrow<U>` to be dispatched on when `ArcBorrow<T>` can be coerced into
// `ArcBorrow<U>`.
#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>>
for ArcBorrow<'_, T>
{
}
impl<T: ?Sized> Clone for ArcBorrow<'_, T> {
fn clone(&self) -> Self {
*self

View File

@ -6,16 +6,15 @@
use crate::{
bindings,
ffi::{c_int, c_long, c_uint},
mm::MmWithUser,
pid_namespace::PidNamespace,
prelude::*,
sync::aref::ARef,
types::{NotThreadSafe, Opaque},
};
use core::{
cmp::{Eq, PartialEq},
ops::Deref,
ptr,
ptr, //
};
/// A sentinel value used for infinite timeouts.
@ -419,7 +418,7 @@ pub fn might_sleep() {
let file = kernel::file_from_location(loc);
// SAFETY: `file.as_ptr()` is valid for reading and guaranteed to be nul-terminated.
unsafe { crate::bindings::__might_sleep(file.as_ptr().cast(), loc.line() as i32) }
unsafe { crate::bindings::__might_sleep(file.as_char_ptr(), loc.line() as i32) }
}
// SAFETY: Always safe to call.

View File

@ -60,7 +60,13 @@ pub fn msecs_to_jiffies(msecs: Msecs) -> Jiffies {
/// cases the user of the clock has to decide which clock is best suited for the
/// purpose. In most scenarios clock [`Monotonic`] is the best choice as it
/// provides a accurate monotonic notion of time (leap second smearing ignored).
pub trait ClockSource {
///
/// # Safety
///
/// Implementers must ensure that `ktime_get()` returns a value in the inclusive range
/// `0..=KTIME_MAX` (i.e., greater than or equal to 0 and less than or equal to
/// `KTIME_MAX`, where `KTIME_MAX` equals `i64::MAX`).
pub unsafe trait ClockSource {
/// The kernel clock ID associated with this clock source.
///
/// This constant corresponds to the C side `clockid_t` value.
@ -68,7 +74,7 @@ pub trait ClockSource {
/// Get the current time from the clock source.
///
/// The function must return a value in the range from 0 to `KTIME_MAX`.
/// The function must return a value in the range `0..=KTIME_MAX`.
fn ktime_get() -> bindings::ktime_t;
}
@ -85,7 +91,9 @@ pub trait ClockSource {
/// count time that the system is suspended.
pub struct Monotonic;
impl ClockSource for Monotonic {
// SAFETY: The kernel's `ktime_get()` is guaranteed to return a value
// in `0..=KTIME_MAX`.
unsafe impl ClockSource for Monotonic {
const ID: bindings::clockid_t = bindings::CLOCK_MONOTONIC as bindings::clockid_t;
fn ktime_get() -> bindings::ktime_t {
@ -110,7 +118,9 @@ fn ktime_get() -> bindings::ktime_t {
/// the clock will experience discontinuity around leap second adjustment.
pub struct RealTime;
impl ClockSource for RealTime {
// SAFETY: The kernel's `ktime_get_real()` is guaranteed to return a value
// in `0..=KTIME_MAX`.
unsafe impl ClockSource for RealTime {
const ID: bindings::clockid_t = bindings::CLOCK_REALTIME as bindings::clockid_t;
fn ktime_get() -> bindings::ktime_t {
@ -128,7 +138,9 @@ fn ktime_get() -> bindings::ktime_t {
/// discontinuities if the time is changed using settimeofday(2) or similar.
pub struct BootTime;
impl ClockSource for BootTime {
// SAFETY: The kernel's `ktime_get_boottime()` is guaranteed to return a value
// in `0..=KTIME_MAX`.
unsafe impl ClockSource for BootTime {
const ID: bindings::clockid_t = bindings::CLOCK_BOOTTIME as bindings::clockid_t;
fn ktime_get() -> bindings::ktime_t {
@ -150,7 +162,9 @@ fn ktime_get() -> bindings::ktime_t {
/// The acronym TAI refers to International Atomic Time.
pub struct Tai;
impl ClockSource for Tai {
// SAFETY: The kernel's `ktime_get_clocktai()` is guaranteed to return a value
// in `0..=KTIME_MAX`.
unsafe impl ClockSource for Tai {
const ID: bindings::clockid_t = bindings::CLOCK_TAI as bindings::clockid_t;
fn ktime_get() -> bindings::ktime_t {
@ -363,6 +377,12 @@ impl Delta {
/// A span of time equal to zero.
pub const ZERO: Self = Self { nanos: 0 };
/// Create a new [`Delta`] from a number of nanoseconds.
#[inline]
pub const fn from_nanos(nanos: i64) -> Self {
Self { nanos }
}
/// Create a new [`Delta`] from a number of microseconds.
///
/// The `micros` can range from -9_223_372_036_854_775 to 9_223_372_036_854_775.

View File

@ -66,6 +66,342 @@
//!
//! A `restart` operation on a timer in the **stopped** state is equivalent to a
//! `start` operation.
//!
//! When a type implements both `HrTimerPointer` and `Clone`, it is possible to
//! issue the `start` operation while the timer is in the **started** state. In
//! this case the `start` operation is equivalent to the `restart` operation.
//!
//! # Examples
//!
//! ## Using an intrusive timer living in a [`Box`]
//!
//! ```
//! # use kernel::{
//! # alloc::flags,
//! # impl_has_hr_timer,
//! # prelude::*,
//! # sync::{
//! # atomic::{ordering, Atomic},
//! # completion::Completion,
//! # Arc,
//! # },
//! # time::{
//! # hrtimer::{
//! # RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer,
//! # HrTimerRestart, HrTimerCallbackContext
//! # },
//! # Delta, Monotonic,
//! # },
//! # };
//!
//! #[pin_data]
//! struct Shared {
//! #[pin]
//! flag: Atomic<u64>,
//! #[pin]
//! cond: Completion,
//! }
//!
//! impl Shared {
//! fn new() -> impl PinInit<Self> {
//! pin_init!(Self {
//! flag <- Atomic::new(0),
//! cond <- Completion::new(),
//! })
//! }
//! }
//!
//! #[pin_data]
//! struct BoxIntrusiveHrTimer {
//! #[pin]
//! timer: HrTimer<Self>,
//! shared: Arc<Shared>,
//! }
//!
//! impl BoxIntrusiveHrTimer {
//! fn new() -> impl PinInit<Self, kernel::error::Error> {
//! try_pin_init!(Self {
//! timer <- HrTimer::new(),
//! shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?,
//! })
//! }
//! }
//!
//! impl HrTimerCallback for BoxIntrusiveHrTimer {
//! type Pointer<'a> = Pin<KBox<Self>>;
//!
//! fn run(this: Pin<&mut Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {
//! pr_info!("Timer called\n");
//!
//! let flag = this.shared.flag.fetch_add(1, ordering::Full);
//! this.shared.cond.complete_all();
//!
//! if flag == 4 {
//! HrTimerRestart::NoRestart
//! } else {
//! HrTimerRestart::Restart
//! }
//! }
//! }
//!
//! impl_has_hr_timer! {
//! impl HasHrTimer<Self> for BoxIntrusiveHrTimer {
//! mode: RelativeMode<Monotonic>, field: self.timer
//! }
//! }
//!
//! let has_timer = Box::pin_init(BoxIntrusiveHrTimer::new(), GFP_KERNEL)?;
//! let shared = has_timer.shared.clone();
//! let _handle = has_timer.start(Delta::from_micros(200));
//!
//! while shared.flag.load(ordering::Relaxed) != 5 {
//! shared.cond.wait_for_completion();
//! }
//!
//! pr_info!("Counted to 5\n");
//! # Ok::<(), kernel::error::Error>(())
//! ```
//!
//! ## Using an intrusive timer in an [`Arc`]
//!
//! ```
//! # use kernel::{
//! # alloc::flags,
//! # impl_has_hr_timer,
//! # prelude::*,
//! # sync::{
//! # atomic::{ordering, Atomic},
//! # completion::Completion,
//! # Arc, ArcBorrow,
//! # },
//! # time::{
//! # hrtimer::{
//! # RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,
//! # HasHrTimer, HrTimerCallbackContext
//! # },
//! # Delta, Monotonic,
//! # },
//! # };
//!
//! #[pin_data]
//! struct ArcIntrusiveHrTimer {
//! #[pin]
//! timer: HrTimer<Self>,
//! #[pin]
//! flag: Atomic<u64>,
//! #[pin]
//! cond: Completion,
//! }
//!
//! impl ArcIntrusiveHrTimer {
//! fn new() -> impl PinInit<Self> {
//! pin_init!(Self {
//! timer <- HrTimer::new(),
//! flag <- Atomic::new(0),
//! cond <- Completion::new(),
//! })
//! }
//! }
//!
//! impl HrTimerCallback for ArcIntrusiveHrTimer {
//! type Pointer<'a> = Arc<Self>;
//!
//! fn run(
//! this: ArcBorrow<'_, Self>,
//! _ctx: HrTimerCallbackContext<'_, Self>,
//! ) -> HrTimerRestart {
//! pr_info!("Timer called\n");
//!
//! let flag = this.flag.fetch_add(1, ordering::Full);
//! this.cond.complete_all();
//!
//! if flag == 4 {
//! HrTimerRestart::NoRestart
//! } else {
//! HrTimerRestart::Restart
//! }
//! }
//! }
//!
//! impl_has_hr_timer! {
//! impl HasHrTimer<Self> for ArcIntrusiveHrTimer {
//! mode: RelativeMode<Monotonic>, field: self.timer
//! }
//! }
//!
//! let has_timer = Arc::pin_init(ArcIntrusiveHrTimer::new(), GFP_KERNEL)?;
//! let _handle = has_timer.clone().start(Delta::from_micros(200));
//!
//! while has_timer.flag.load(ordering::Relaxed) != 5 {
//! has_timer.cond.wait_for_completion();
//! }
//!
//! pr_info!("Counted to 5\n");
//! # Ok::<(), kernel::error::Error>(())
//! ```
//!
//! ## Using a stack-based timer
//!
//! ```
//! # use kernel::{
//! # impl_has_hr_timer,
//! # prelude::*,
//! # sync::{
//! # atomic::{ordering, Atomic},
//! # completion::Completion,
//! # },
//! # time::{
//! # hrtimer::{
//! # ScopedHrTimerPointer, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,
//! # HasHrTimer, RelativeMode, HrTimerCallbackContext
//! # },
//! # Delta, Monotonic,
//! # },
//! # };
//! # use pin_init::stack_pin_init;
//!
//! #[pin_data]
//! struct IntrusiveHrTimer {
//! #[pin]
//! timer: HrTimer<Self>,
//! #[pin]
//! flag: Atomic<u64>,
//! #[pin]
//! cond: Completion,
//! }
//!
//! impl IntrusiveHrTimer {
//! fn new() -> impl PinInit<Self> {
//! pin_init!(Self {
//! timer <- HrTimer::new(),
//! flag <- Atomic::new(0),
//! cond <- Completion::new(),
//! })
//! }
//! }
//!
//! impl HrTimerCallback for IntrusiveHrTimer {
//! type Pointer<'a> = Pin<&'a Self>;
//!
//! fn run(this: Pin<&Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {
//! pr_info!("Timer called\n");
//!
//! this.flag.store(1, ordering::Release);
//! this.cond.complete_all();
//!
//! HrTimerRestart::NoRestart
//! }
//! }
//!
//! impl_has_hr_timer! {
//! impl HasHrTimer<Self> for IntrusiveHrTimer {
//! mode: RelativeMode<Monotonic>, field: self.timer
//! }
//! }
//!
//! stack_pin_init!( let has_timer = IntrusiveHrTimer::new() );
//! has_timer.as_ref().start_scoped(Delta::from_micros(200), || {
//! while has_timer.flag.load(ordering::Relaxed) != 1 {
//! has_timer.cond.wait_for_completion();
//! }
//! });
//!
//! pr_info!("Flag raised\n");
//! # Ok::<(), kernel::error::Error>(())
//! ```
//!
//! ## Using a mutable stack-based timer
//!
//! ```
//! # use kernel::{
//! # alloc::flags,
//! # impl_has_hr_timer,
//! # prelude::*,
//! # sync::{
//! # atomic::{ordering, Atomic},
//! # completion::Completion,
//! # Arc,
//! # },
//! # time::{
//! # hrtimer::{
//! # ScopedHrTimerPointer, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,
//! # HasHrTimer, RelativeMode, HrTimerCallbackContext
//! # },
//! # Delta, Monotonic,
//! # },
//! # };
//! # use pin_init::stack_try_pin_init;
//!
//! #[pin_data]
//! struct Shared {
//! #[pin]
//! flag: Atomic<u64>,
//! #[pin]
//! cond: Completion,
//! }
//!
//! impl Shared {
//! fn new() -> impl PinInit<Self> {
//! pin_init!(Self {
//! flag <- Atomic::new(0),
//! cond <- Completion::new(),
//! })
//! }
//! }
//!
//! #[pin_data]
//! struct IntrusiveHrTimer {
//! #[pin]
//! timer: HrTimer<Self>,
//! shared: Arc<Shared>,
//! }
//!
//! impl IntrusiveHrTimer {
//! fn new() -> impl PinInit<Self, kernel::error::Error> {
//! try_pin_init!(Self {
//! timer <- HrTimer::new(),
//! shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?,
//! })
//! }
//! }
//!
//! impl HrTimerCallback for IntrusiveHrTimer {
//! type Pointer<'a> = Pin<&'a mut Self>;
//!
//! fn run(this: Pin<&mut Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {
//! pr_info!("Timer called\n");
//!
//! let flag = this.shared.flag.fetch_add(1, ordering::Full);
//! this.shared.cond.complete_all();
//!
//! if flag == 4 {
//! HrTimerRestart::NoRestart
//! } else {
//! HrTimerRestart::Restart
//! }
//! }
//! }
//!
//! impl_has_hr_timer! {
//! impl HasHrTimer<Self> for IntrusiveHrTimer {
//! mode: RelativeMode<Monotonic>, field: self.timer
//! }
//! }
//!
//! stack_try_pin_init!( let has_timer =? IntrusiveHrTimer::new() );
//! let shared = has_timer.shared.clone();
//!
//! has_timer.as_mut().start_scoped(Delta::from_micros(200), || {
//! while shared.flag.load(ordering::Relaxed) != 5 {
//! shared.cond.wait_for_completion();
//! }
//! });
//!
//! pr_info!("Counted to 5\n");
//! # Ok::<(), kernel::error::Error>(())
//! ```
//!
//! [`Arc`]: kernel::sync::Arc
use super::{ClockSource, Delta, Instant};
use crate::{prelude::*, types::Opaque};

View File

@ -49,7 +49,6 @@ fn from_bytes(bytes: &[u8]) -> Option<&Self>
let slice_ptr = bytes.as_ptr().cast::<Self>();
let size = size_of::<Self>();
#[allow(clippy::incompatible_msrv)]
if bytes.len() == size && slice_ptr.is_aligned() {
// SAFETY: Size and alignment were just checked.
unsafe { Some(&*slice_ptr) }
@ -67,16 +66,9 @@ fn from_bytes_prefix(bytes: &[u8]) -> Option<(&Self, &[u8])>
where
Self: Sized,
{
if bytes.len() < size_of::<Self>() {
None
} else {
// PANIC: We checked that `bytes.len() >= size_of::<Self>`, thus `split_at` cannot
// panic.
// TODO: replace with `split_at_checked` once the MSRV is >= 1.80.
let (prefix, remainder) = bytes.split_at(size_of::<Self>());
let (prefix, remainder) = bytes.split_at_checked(size_of::<Self>())?;
Self::from_bytes(prefix).map(|s| (s, remainder))
}
Self::from_bytes(prefix).map(|s| (s, remainder))
}
/// Converts a mutable slice of bytes to a reference to `Self`.
@ -92,7 +84,6 @@ fn from_bytes_mut(bytes: &mut [u8]) -> Option<&mut Self>
let slice_ptr = bytes.as_mut_ptr().cast::<Self>();
let size = size_of::<Self>();
#[allow(clippy::incompatible_msrv)]
if bytes.len() == size && slice_ptr.is_aligned() {
// SAFETY: Size and alignment were just checked.
unsafe { Some(&mut *slice_ptr) }
@ -110,16 +101,9 @@ fn from_bytes_mut_prefix(bytes: &mut [u8]) -> Option<(&mut Self, &mut [u8])>
where
Self: AsBytes + Sized,
{
if bytes.len() < size_of::<Self>() {
None
} else {
// PANIC: We checked that `bytes.len() >= size_of::<Self>`, thus `split_at_mut` cannot
// panic.
// TODO: replace with `split_at_mut_checked` once the MSRV is >= 1.80.
let (prefix, remainder) = bytes.split_at_mut(size_of::<Self>());
let (prefix, remainder) = bytes.split_at_mut_checked(size_of::<Self>())?;
Self::from_bytes_mut(prefix).map(|s| (s, remainder))
}
Self::from_bytes_mut(prefix).map(|s| (s, remainder))
}
/// Creates an owned instance of `Self` by copying `bytes`.
@ -149,16 +133,9 @@ fn from_bytes_copy_prefix(bytes: &[u8]) -> Option<(Self, &[u8])>
where
Self: Sized,
{
if bytes.len() < size_of::<Self>() {
None
} else {
// PANIC: We checked that `bytes.len() >= size_of::<Self>`, thus `split_at` cannot
// panic.
// TODO: replace with `split_at_checked` once the MSRV is >= 1.80.
let (prefix, remainder) = bytes.split_at(size_of::<Self>());
let (prefix, remainder) = bytes.split_at_checked(size_of::<Self>())?;
Self::from_bytes_copy(prefix).map(|s| (s, remainder))
}
Self::from_bytes_copy(prefix).map(|s| (s, remainder))
}
}

View File

@ -11,8 +11,6 @@
};
use pin_init::{PinInit, Wrapper, Zeroable};
pub use crate::sync::aref::{ARef, AlwaysRefCounted};
/// Used to transfer ownership to and from foreign (non-Rust) languages.
///
/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and

View File

@ -18,10 +18,8 @@
to_result, //
},
prelude::*,
types::{
AlwaysRefCounted,
Opaque, //
},
sync::aref::AlwaysRefCounted,
types::Opaque,
ThisModule, //
};
use core::{

View File

@ -172,6 +172,7 @@ pub struct StoreError<T> {
}
impl<T> From<StoreError<T>> for Error {
#[inline]
fn from(value: StoreError<T>) -> Self {
value.error
}

View File

@ -49,7 +49,6 @@ pub(crate) fn file() -> String {
}
#[cfg(CONFIG_RUSTC_HAS_SPAN_FILE)]
#[allow(clippy::incompatible_msrv)]
{
proc_macro::Span::call_site().file()
}

View File

@ -87,10 +87,11 @@ pub(crate) fn kunit_tests(test_suite: Ident, mut module: ItemMod) -> Result<Toke
continue;
};
// TODO: Replace below with `extract_if` when MSRV is bumped above 1.85.
let before_len = f.attrs.len();
f.attrs.retain(|attr| !attr.path().is_ident("test"));
if f.attrs.len() == before_len {
if f.attrs
.extract_if(.., |attr| attr.path().is_ident("test"))
.count()
== 0
{
processed_items.push(Item::Fn(f));
continue;
}

View File

@ -6,6 +6,9 @@
// and thus add a dependency on `include/config/RUSTC_VERSION_TEXT`, which is
// touched by Kconfig when the version string from the compiler changes.
// Stable since Rust 1.87.0.
#![feature(extract_if)]
//
// Stable since Rust 1.88.0 under a different name, `proc_macro_span_file`,
// which was added in Rust 1.88.0. This is why `cfg_attr` is used here, i.e.
// to avoid depending on the full `proc_macro_span` on Rust >= 1.88.0.

View File

@ -52,12 +52,7 @@ fn new(module: &'a str) -> Self {
fn emit_base(&mut self, field: &str, content: &str, builtin: bool, param: bool) {
let string = if builtin {
// Built-in modules prefix their modinfo strings by `module.`.
format!(
"{module}.{field}={content}\0",
module = self.module,
field = field,
content = content
)
format!("{module}.{field}={content}\0", module = self.module)
} else {
// Loadable modules' modinfo strings go as-is.
format!("{field}={content}\0")
@ -109,7 +104,7 @@ fn emit_internal(&mut self, field: &str, content: &str, param: bool) {
}
fn emit_param(&mut self, field: &str, param: &str, content: &str) {
let content = format!("{param}:{content}", param = param, content = content);
let content = format!("{param}:{content}");
self.emit_internal(field, &content, true);
}

View File

@ -160,7 +160,6 @@ actually does the initialization in the correct way. Here are the things to look
```rust
use pin_init::{pin_data, pinned_drop, PinInit, PinnedDrop, pin_init_from_closure};
use core::{
ptr::addr_of_mut,
marker::PhantomPinned,
cell::UnsafeCell,
pin::Pin,
@ -199,7 +198,7 @@ impl RawFoo {
unsafe {
pin_init_from_closure(move |slot: *mut Self| {
// `slot` contains uninit memory, avoid creating a reference.
let foo = addr_of_mut!((*slot).foo);
let foo = &raw mut (*slot).foo;
let foo = UnsafeCell::raw_get(foo).cast::<bindings::foo>();
// Initialize the `foo`

View File

@ -1,5 +1,8 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
use pin_init::*;
// Struct with size over 1GiB

View File

@ -2,7 +2,8 @@
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
use core::{
cell::Cell,

View File

@ -2,7 +2,8 @@
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
#![allow(clippy::missing_safety_doc)]
use core::{

View File

@ -3,7 +3,8 @@
// inspired by <https://github.com/nbdd0121/pin-init/blob/trunk/examples/pthread_mutex.rs>
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
#[cfg(not(windows))]
mod pthread_mtx {

View File

@ -2,7 +2,8 @@
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
#![allow(unused_imports)]
use core::{

View File

@ -173,6 +173,12 @@ fn assert_zeroable<T: ?::core::marker::Sized>(_: *mut T)
};
// SAFETY: TODO
let init = unsafe { ::pin_init::#init_from_closure::<_, #error>(init) };
// FIXME: this let binding is required to avoid a compiler error (cycle when computing the
// opaque type returned by this function) before Rust 1.81. Remove after MSRV bump.
#[allow(
clippy::let_and_return,
reason = "some clippy versions warn about the let binding"
)]
init
}})
}
@ -264,7 +270,7 @@ fn init_fields(
{
#value_prep
// SAFETY: TODO
unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) };
unsafe { #write(&raw mut (*#slot).#ident, #value_ident) };
}
#(#cfgs)*
#[allow(unused_variables)]
@ -287,7 +293,7 @@ fn init_fields(
// return when an error/panic occurs.
// - We also use `#data` to require the correct trait (`Init` or `PinInit`)
// for `#ident`.
unsafe { #data.#ident(::core::ptr::addr_of_mut!((*#slot).#ident), #init)? };
unsafe { #data.#ident(&raw mut (*#slot).#ident, #init)? };
},
quote! {
// SAFETY: TODO
@ -302,7 +308,7 @@ fn init_fields(
unsafe {
::pin_init::Init::__init(
#init,
::core::ptr::addr_of_mut!((*#slot).#ident),
&raw mut (*#slot).#ident,
)?
};
},
@ -342,7 +348,7 @@ fn init_fields(
// SAFETY: We forget the guard later when initialization has succeeded.
let #guard = unsafe {
::pin_init::__internal::DropGuard::new(
::core::ptr::addr_of_mut!((*slot).#ident)
&raw mut (*slot).#ident
)
};
});

View File

@ -6,7 +6,7 @@
//! `pin-init` proc macros.
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
// Documentation is done in the pin-init crate instead.
#![allow(missing_docs)]

View File

@ -172,7 +172,6 @@
//! # #![feature(extern_types)]
//! use pin_init::{pin_data, pinned_drop, PinInit, PinnedDrop, pin_init_from_closure};
//! use core::{
//! ptr::addr_of_mut,
//! marker::PhantomPinned,
//! cell::UnsafeCell,
//! pin::Pin,
@ -211,7 +210,7 @@
//! unsafe {
//! pin_init_from_closure(move |slot: *mut Self| {
//! // `slot` contains uninit memory, avoid creating a reference.
//! let foo = addr_of_mut!((*slot).foo);
//! let foo = &raw mut (*slot).foo;
//! let foo = UnsafeCell::raw_get(foo).cast::<bindings::foo>();
//!
//! // Initialize the `foo`
@ -264,12 +263,10 @@
//! [`impl Init<T, E>`]: crate::Init
//! [Rust-for-Linux]: https://rust-for-linux.com/
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
#![cfg_attr(
all(
any(feature = "alloc", feature = "std"),
not(RUSTC_NEW_UNINIT_IS_STABLE)
),
all(any(feature = "alloc", feature = "std"), USE_RUSTC_FEATURES),
feature(new_uninit)
)]
#![forbid(missing_docs, unsafe_op_in_unsafe_fn)]
@ -279,6 +276,8 @@
all(feature = "unsafe-pinned", CONFIG_RUSTC_HAS_UNSAFE_PINNED),
feature(unsafe_pinned)
)]
#![cfg_attr(all(USE_RUSTC_FEATURES, doc), allow(internal_features))]
#![cfg_attr(all(USE_RUSTC_FEATURES, doc), feature(rustdoc_internals))]
use core::{
cell::UnsafeCell,
@ -755,7 +754,7 @@ macro_rules! stack_try_pin_init {
///
/// ```rust
/// # use pin_init::*;
/// # use core::{ptr::addr_of_mut, marker::PhantomPinned};
/// # use core::marker::PhantomPinned;
/// #[pin_data]
/// #[derive(Zeroable)]
/// struct Buf {
@ -769,7 +768,7 @@ macro_rules! stack_try_pin_init {
/// let init = pin_init!(&this in Buf {
/// buf: [0; 64],
/// // SAFETY: TODO.
/// ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() },
/// ptr: unsafe { (&raw mut (*this.as_ptr()).buf).cast() },
/// pin: PhantomPinned,
/// });
/// let init = pin_init!(Buf {
@ -1147,9 +1146,12 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
// SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety
// requirements.
let res = unsafe { pin_init_from_closure(|ptr: *mut U| init.__pinned_init(ptr.cast::<T>())) };
// FIXME: remove the let statement once the nightly-MSRV allows it (1.78 otherwise encounters a
// cycle when computing the type returned by this function)
#[allow(clippy::let_and_return)]
// FIXME: this let binding is required to avoid a compiler error (cycle when computing the opaque
// type returned by this function) before Rust 1.81. Remove after MSRV bump.
#[allow(
clippy::let_and_return,
reason = "some clippy versions warn about the let binding"
)]
res
}
@ -1163,9 +1165,12 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
// SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety
// requirements.
let res = unsafe { init_from_closure(|ptr: *mut U| init.__init(ptr.cast::<T>())) };
// FIXME: remove the let statement once the nightly-MSRV allows it (1.78 otherwise encounters a
// cycle when computing the type returned by this function)
#[allow(clippy::let_and_return)]
// FIXME: this let binding is required to avoid a compiler error (cycle when computing the opaque
// type returned by this function) before Rust 1.81. Remove after MSRV bump.
#[allow(
clippy::let_and_return,
reason = "some clippy versions warn about the let binding"
)]
res
}
@ -1610,13 +1615,6 @@ macro_rules! impl_zeroable {
// SAFETY: `T: Zeroable` and `UnsafeCell` is `repr(transparent)`.
{<T: ?Sized + Zeroable>} UnsafeCell<T>,
// SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee:
// <https://doc.rust-lang.org/stable/std/option/index.html#representation>).
Option<NonZeroU8>, Option<NonZeroU16>, Option<NonZeroU32>, Option<NonZeroU64>,
Option<NonZeroU128>, Option<NonZeroUsize>,
Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>,
Option<NonZeroI128>, Option<NonZeroIsize>,
// SAFETY: `null` pointer is valid.
//
// We cannot use `T: ?Sized`, since the VTABLE pointer part of fat pointers is not allowed to be
@ -1635,8 +1633,14 @@ macro_rules! impl_zeroable {
}
macro_rules! impl_tuple_zeroable {
($(,)?) => {};
($first:ident, $(,)?) => {
#[cfg_attr(all(USE_RUSTC_FEATURES, doc), doc(fake_variadic))]
/// Implemented for tuples up to 10 items long.
// SAFETY: All elements are zeroable and padding can be zero.
unsafe impl<$first: Zeroable> Zeroable for ($first,) {}
};
($first:ident, $($t:ident),* $(,)?) => {
#[cfg_attr(doc, doc(hidden))]
// SAFETY: All elements are zeroable and padding can be zero.
unsafe impl<$first: Zeroable, $($t: Zeroable),*> Zeroable for ($first, $($t),*) {}
impl_tuple_zeroable!($($t),* ,);
@ -1651,7 +1655,16 @@ macro_rules! impl_fn_zeroable_option {
$(impl_fn_zeroable_option!({unsafe extern $abi} $args);)*
};
({$($prefix:tt)*} {$(,)?}) => {};
({$($prefix:tt)*} {$ret:ident, $arg:ident $(,)?}) => {
#[cfg_attr(all(USE_RUSTC_FEATURES, doc), doc(fake_variadic))]
/// Implemented for function pointers with up to 20 arity.
// SAFETY: function pointers are part of the option layout optimization:
// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
unsafe impl<$ret, $arg> ZeroableOption for $($prefix)* fn($arg) -> $ret {}
impl_fn_zeroable_option!({$($prefix)*} {$arg,});
};
({$($prefix:tt)*} {$ret:ident, $($rest:ident),* $(,)?}) => {
#[cfg_attr(doc, doc(hidden))]
// SAFETY: function pointers are part of the option layout optimization:
// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
unsafe impl<$ret, $($rest),*> ZeroableOption for $($prefix)* fn($($rest),*) -> $ret {}
@ -1661,6 +1674,20 @@ unsafe impl<$ret, $($rest),*> ZeroableOption for $($prefix)* fn($($rest),*) -> $
impl_fn_zeroable_option!(["Rust", "C"] { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U });
macro_rules! impl_non_zero_int_zeroable_option {
($($int:ty),* $(,)?) => {
// SAFETY: Safety comment written in the macro invocation.
$(unsafe impl ZeroableOption for $int {})*
};
}
impl_non_zero_int_zeroable_option! {
// SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee:
// <https://doc.rust-lang.org/stable/std/option/index.html#representation>).
NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize,
}
/// This trait allows creating an instance of `Self` which contains exactly one
/// [structurally pinned value](https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning).
///

View File

@ -8,10 +8,6 @@
//! userspace APIs.
#![no_std]
// See <https://github.com/rust-lang/rust-bindgen/issues/1651>.
#![cfg_attr(test, allow(deref_nullptr))]
#![cfg_attr(test, allow(unaligned_references))]
#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
#![allow(
clippy::all,
clippy::cast_lossless,
@ -28,6 +24,7 @@
unsafe_op_in_unsafe_fn
)]
#![cfg_attr(CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES, allow(unnecessary_transmutes))]
#![feature(cfi_encoding)]
// Manual definition of blocklisted types.
type __kernel_size_t = usize;

View File

@ -310,18 +310,13 @@ $(obj)/%.lst: $(obj)/%.c FORCE
# The features in this list are the ones allowed for non-`rust/` code.
#
# - Stable since Rust 1.79.0: `feature(slice_ptr_len)`.
# - Stable since Rust 1.81.0: `feature(lint_reasons)`.
# - Stable since Rust 1.82.0: `feature(asm_const)`,
# `feature(offset_of_nested)`, `feature(raw_ref_op)`.
# - Stable since Rust 1.84.0: `feature(strict_provenance)`.
# - Stable since Rust 1.87.0: `feature(asm_goto)`.
# - Expected to become stable: `feature(arbitrary_self_types)`.
# - To be determined: `feature(used_with_arg)`.
#
# Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on
# the unstable features in use.
rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,offset_of_nested,raw_ref_op,slice_ptr_len,strict_provenance,used_with_arg
rust_allowed_features := arbitrary_self_types,asm_goto,used_with_arg
# `--out-dir` is required to avoid temporaries being created by `rustc` in the
# current working directory, which may be not accessible in the out-of-tree
@ -334,7 +329,6 @@ rust_common_cmd = \
-Zcrate-attr='feature($(rust_allowed_features))' \
-Zunstable-options --extern pin_init --extern kernel \
--crate-type rlib -L $(objtree)/rust/ \
--crate-name $(basename $(notdir $@)) \
--sysroot=/dev/null \
--out-dir $(dir $@) --emit=dep-info=$(depfile)
@ -347,7 +341,12 @@ rust_common_cmd = \
# would not match each other.
quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $< $(cmd_objtool)
cmd_rustc_o_rs = $(rust_common_cmd) --emit=$(if $(CONFIG_RUST_INLINE_HELPERS),llvm-bc=$(patsubst %.o,%.bc,$@),obj=$@) $< \
$(if $(CONFIG_RUST_INLINE_HELPERS),;$(LLVM_LINK) --internalize --suppress-warnings $(patsubst %.o,%.bc,$@) \
$(objtree)/rust/helpers/helpers$(if $(part-of-module),_module).bc -o $(patsubst %.o,%.m.bc,$@); \
$(CC) $(CLANG_FLAGS) $(KBUILD_CFLAGS) -Wno-override-module -c $(patsubst %.o,%.m.bc,$@) -o $@ \
$(cmd_ld_single)) \
$(cmd_objtool)
define rule_rustc_o_rs
$(call cmd_and_fixdep,rustc_o_rs)

View File

@ -10,8 +10,15 @@ import os
import pathlib
import subprocess
import sys
from typing import Dict, Iterable, List, Literal, Optional, TypedDict
def args_crates_cfgs(cfgs):
def invoke_rustc(args: List[str]) -> str:
return subprocess.check_output(
[os.environ["RUSTC"]] + args,
stdin=subprocess.DEVNULL,
).decode('utf-8').strip()
def args_crates_cfgs(cfgs: List[str]) -> Dict[str, List[str]]:
crates_cfgs = {}
for cfg in cfgs:
crate, vals = cfg.split("=", 1)
@ -19,54 +26,153 @@ def args_crates_cfgs(cfgs):
return crates_cfgs
def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edition):
class Dependency(TypedDict):
crate: int
name: str
class Source(TypedDict):
include_dirs: List[str]
exclude_dirs: List[str]
class Crate(TypedDict):
display_name: str
root_module: str
is_workspace_member: bool
deps: List[Dependency]
cfg: List[str]
edition: str
env: Dict[str, str]
class ProcMacroCrate(Crate):
is_proc_macro: Literal[True]
proc_macro_dylib_path: str # `pathlib.Path` is not JSON serializable.
class CrateWithGenerated(Crate):
source: Source
def generate_crates(
srctree: pathlib.Path,
objtree: pathlib.Path,
sysroot_src: pathlib.Path,
external_src: Optional[pathlib.Path],
cfgs: List[str],
core_edition: str,
) -> List[Crate]:
# Generate the configuration list.
cfg = []
generated_cfg = []
with open(objtree / "include" / "generated" / "rustc_cfg") as fd:
for line in fd:
line = line.replace("--cfg=", "")
line = line.replace("\n", "")
cfg.append(line)
generated_cfg.append(line)
# Now fill the crates list -- dependencies need to come first.
#
# Avoid O(n^2) iterations by keeping a map of indexes.
crates = []
crates_indexes = {}
# Now fill the crates list.
crates: List[Crate] = []
crates_cfgs = args_crates_cfgs(cfgs)
def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False, edition="2021"):
crate = {
def get_crate_name(path: pathlib.Path) -> str:
return invoke_rustc(["--print", "crate-name", str(path)])
def build_crate(
display_name: str,
root_module: pathlib.Path,
deps: List[Dependency],
*,
cfg: Optional[List[str]],
is_workspace_member: Optional[bool],
edition: Optional[str],
) -> Crate:
cfg = cfg if cfg is not None else crates_cfgs.get(display_name, [])
is_workspace_member = (
is_workspace_member if is_workspace_member is not None else True
)
edition = edition if edition is not None else "2021"
return {
"display_name": display_name,
"root_module": str(root_module),
"is_workspace_member": is_workspace_member,
"is_proc_macro": is_proc_macro,
"deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps],
"deps": deps,
"cfg": cfg,
"edition": edition,
"env": {
"RUST_MODFILE": "This is only for rust-analyzer"
}
}
if is_proc_macro:
proc_macro_dylib_name = subprocess.check_output(
[os.environ["RUSTC"], "--print", "file-names", "--crate-name", display_name, "--crate-type", "proc-macro", "-"],
stdin=subprocess.DEVNULL,
).decode('utf-8').strip()
crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}"
crates_indexes[display_name] = len(crates)
def append_proc_macro_crate(
display_name: str,
root_module: pathlib.Path,
deps: List[Dependency],
*,
cfg: Optional[List[str]] = None,
is_workspace_member: Optional[bool] = None,
edition: Optional[str] = None,
) -> Dependency:
crate = build_crate(
display_name,
root_module,
deps,
cfg=cfg,
is_workspace_member=is_workspace_member,
edition=edition,
)
proc_macro_dylib_name = invoke_rustc([
"--print",
"file-names",
"--crate-name",
display_name,
"--crate-type",
"proc-macro",
"-",
])
proc_macro_crate: ProcMacroCrate = {
**crate,
"is_proc_macro": True,
"proc_macro_dylib_path": str(objtree / "rust" / proc_macro_dylib_name),
}
return register_crate(proc_macro_crate)
def register_crate(crate: Crate) -> Dependency:
index = len(crates)
crates.append(crate)
return {"crate": index, "name": crate["display_name"]}
def append_crate(
display_name: str,
root_module: pathlib.Path,
deps: List[Dependency],
*,
cfg: Optional[List[str]] = None,
is_workspace_member: Optional[bool] = None,
edition: Optional[str] = None,
) -> Dependency:
return register_crate(
build_crate(
display_name,
root_module,
deps,
cfg=cfg,
is_workspace_member=is_workspace_member,
edition=edition,
)
)
def append_sysroot_crate(
display_name,
deps,
cfg=[],
):
append_crate(
display_name: str,
deps: List[Dependency],
*,
cfg: Optional[List[str]] = None,
) -> Dependency:
return append_crate(
display_name,
sysroot_src / display_name / "src" / "lib.rs",
deps,
cfg,
cfg=cfg,
is_workspace_member=False,
# Miguel Ojeda writes:
#
@ -98,129 +204,146 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit
# NB: sysroot crates reexport items from one another so setting up our transitive dependencies
# here is important for ensuring that rust-analyzer can resolve symbols. The sources of truth
# for this dependency graph are `(sysroot_src / crate / "Cargo.toml" for crate in crates)`.
append_sysroot_crate("core", [], cfg=crates_cfgs.get("core", []))
append_sysroot_crate("alloc", ["core"])
append_sysroot_crate("std", ["alloc", "core"])
append_sysroot_crate("proc_macro", ["core", "std"])
core = append_sysroot_crate("core", [])
alloc = append_sysroot_crate("alloc", [core])
std = append_sysroot_crate("std", [alloc, core])
proc_macro = append_sysroot_crate("proc_macro", [core, std])
append_crate(
compiler_builtins = append_crate(
"compiler_builtins",
srctree / "rust" / "compiler_builtins.rs",
["core"],
[core],
)
append_crate(
proc_macro2 = append_crate(
"proc_macro2",
srctree / "rust" / "proc-macro2" / "lib.rs",
["core", "alloc", "std", "proc_macro"],
cfg=crates_cfgs["proc_macro2"],
[core, alloc, std, proc_macro],
)
append_crate(
quote = append_crate(
"quote",
srctree / "rust" / "quote" / "lib.rs",
["core", "alloc", "std", "proc_macro", "proc_macro2"],
cfg=crates_cfgs["quote"],
[core, alloc, std, proc_macro, proc_macro2],
edition="2018",
)
append_crate(
syn = append_crate(
"syn",
srctree / "rust" / "syn" / "lib.rs",
["std", "proc_macro", "proc_macro2", "quote"],
cfg=crates_cfgs["syn"],
[std, proc_macro, proc_macro2, quote],
)
append_crate(
macros = append_proc_macro_crate(
"macros",
srctree / "rust" / "macros" / "lib.rs",
["std", "proc_macro", "proc_macro2", "quote", "syn"],
is_proc_macro=True,
[std, proc_macro, proc_macro2, quote, syn],
)
append_crate(
build_error = append_crate(
"build_error",
srctree / "rust" / "build_error.rs",
["core", "compiler_builtins"],
[core, compiler_builtins],
)
append_crate(
pin_init_internal = append_proc_macro_crate(
"pin_init_internal",
srctree / "rust" / "pin-init" / "internal" / "src" / "lib.rs",
["std", "proc_macro", "proc_macro2", "quote", "syn"],
cfg=["kernel"],
is_proc_macro=True,
[std, proc_macro, proc_macro2, quote, syn],
)
append_crate(
pin_init = append_crate(
"pin_init",
srctree / "rust" / "pin-init" / "src" / "lib.rs",
["core", "compiler_builtins", "pin_init_internal", "macros"],
cfg=["kernel"],
[core, compiler_builtins, pin_init_internal, macros],
)
append_crate(
ffi = append_crate(
"ffi",
srctree / "rust" / "ffi.rs",
["core", "compiler_builtins"],
[core, compiler_builtins],
)
def append_crate_with_generated(
display_name,
deps,
):
append_crate(
display_name: str,
deps: List[Dependency],
) -> Dependency:
crate = build_crate(
display_name,
srctree / "rust"/ display_name / "lib.rs",
deps,
cfg=cfg,
cfg=generated_cfg,
is_workspace_member=True,
edition=None,
)
crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True))
crates[-1]["source"] = {
"include_dirs": [
str(srctree / "rust" / display_name),
str(objtree / "rust")
],
"exclude_dirs": [],
crate["env"]["OBJTREE"] = str(objtree.resolve(True))
crate_with_generated: CrateWithGenerated = {
**crate,
"source": {
"include_dirs": [
str(srctree / "rust" / display_name),
str(objtree / "rust"),
],
"exclude_dirs": [],
},
}
return register_crate(crate_with_generated)
append_crate_with_generated("bindings", ["core", "ffi", "pin_init"])
append_crate_with_generated("uapi", ["core", "ffi", "pin_init"])
append_crate_with_generated("kernel", ["core", "macros", "build_error", "pin_init", "ffi", "bindings", "uapi"])
bindings = append_crate_with_generated("bindings", [core, ffi, pin_init])
uapi = append_crate_with_generated("uapi", [core, ffi, pin_init])
kernel = append_crate_with_generated(
"kernel", [core, macros, build_error, pin_init, ffi, bindings, uapi]
)
def is_root_crate(build_file, target):
scripts = srctree / "scripts"
makefile = (scripts / "Makefile").read_text()
for path in scripts.glob("*.rs"):
name = path.stem
if f"{name}-rust" not in makefile:
continue
append_crate(
name,
path,
[std],
)
def is_root_crate(build_file: pathlib.Path, target: str) -> bool:
try:
return f"{target}.o" in open(build_file).read()
contents = build_file.read_text()
except FileNotFoundError:
return False
return f"{target}.o" in contents
# Then, the rest outside of `rust/`.
#
# We explicitly mention the top-level folders we want to cover.
extra_dirs = map(lambda dir: srctree / dir, ("samples", "drivers"))
extra_dirs: Iterable[pathlib.Path] = (
srctree / dir for dir in ("samples", "drivers")
)
if external_src is not None:
extra_dirs = [external_src]
for folder in extra_dirs:
for path in folder.rglob("*.rs"):
logging.info("Checking %s", path)
name = path.name.replace(".rs", "")
file_name = path.stem
# Skip those that are not crate roots.
if not is_root_crate(path.parent / "Makefile", name) and \
not is_root_crate(path.parent / "Kbuild", name):
if not is_root_crate(path.parent / "Makefile", file_name) and \
not is_root_crate(path.parent / "Kbuild", file_name):
continue
logging.info("Adding %s", name)
crate_name = get_crate_name(path)
logging.info("Adding %s", crate_name)
append_crate(
name,
crate_name,
path,
["core", "kernel", "pin_init"],
cfg=cfg,
[core, kernel, pin_init],
cfg=generated_cfg,
)
return crates
def main():
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument('--verbose', '-v', action='store_true')
parser.add_argument('--cfgs', action='append', default=[])
@ -230,7 +353,18 @@ def main():
parser.add_argument("sysroot", type=pathlib.Path)
parser.add_argument("sysroot_src", type=pathlib.Path)
parser.add_argument("exttree", type=pathlib.Path, nargs="?")
args = parser.parse_args()
class Args(argparse.Namespace):
verbose: bool
cfgs: List[str]
srctree: pathlib.Path
objtree: pathlib.Path
sysroot: pathlib.Path
sysroot_src: pathlib.Path
exttree: Optional[pathlib.Path]
core_edition: str
args = parser.parse_args(namespace=Args())
logging.basicConfig(
format="[%(asctime)s] [%(levelname)s] %(message)s",

View File

@ -31,10 +31,10 @@ llvm)
fi
;;
rustc)
echo 1.78.0
echo 1.85.0
;;
bindgen)
echo 0.65.1
echo 0.71.1
;;
*)
echo "$1: unknown tool" >&2

View File

@ -121,14 +121,8 @@ fi
# Check that the Rust bindings generator is suitable.
#
# Non-stable and distributions' versions may have a version suffix, e.g. `-dev`.
#
# The dummy parameter `workaround-for-0.69.0` is required to support 0.69.0
# (https://github.com/rust-lang/rust-bindgen/pull/2678) and 0.71.0
# (https://github.com/rust-lang/rust-bindgen/pull/3040). It can be removed when
# the minimum version is upgraded past the latter (0.69.1 and 0.71.1 both fixed
# the issue).
rust_bindings_generator_output=$( \
LC_ALL=C "$BINDGEN" --version workaround-for-0.69.0 2>/dev/null
LC_ALL=C "$BINDGEN" --version 2>/dev/null
) || rust_bindings_generator_code=$?
if [ -n "$rust_bindings_generator_code" ]; then
echo >&2 "***"
@ -163,19 +157,6 @@ if [ "$rust_bindings_generator_cversion" -lt "$rust_bindings_generator_min_cvers
echo >&2 "***"
exit 1
fi
if [ "$rust_bindings_generator_cversion" -eq 6600 ] ||
[ "$rust_bindings_generator_cversion" -eq 6601 ]; then
# Distributions may have patched the issue (e.g. Debian did).
if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_0_66.h >/dev/null; then
echo >&2 "***"
echo >&2 "*** Rust bindings generator '$BINDGEN' versions 0.66.0 and 0.66.1 may not"
echo >&2 "*** work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2567),"
echo >&2 "*** unless patched (like Debian's)."
echo >&2 "*** Your version: $rust_bindings_generator_version"
echo >&2 "***"
warning=1
fi
fi
# Check that the `libclang` used by the Rust bindings generator is suitable.
#
@ -227,21 +208,6 @@ if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then
exit 1
fi
if [ "$bindgen_libclang_cversion" -ge 1900100 ] &&
[ "$rust_bindings_generator_cversion" -lt 6905 ]; then
# Distributions may have patched the issue (e.g. Debian did).
if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang_concat.h | grep -q foofoo; then
echo >&2 "***"
echo >&2 "*** Rust bindings generator '$BINDGEN' < 0.69.5 together with libclang >= 19.1"
echo >&2 "*** may not work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2824),"
echo >&2 "*** unless patched (like Debian's)."
echo >&2 "*** Your bindgen version: $rust_bindings_generator_version"
echo >&2 "*** Your libclang version: $bindgen_libclang_version"
echo >&2 "***"
warning=1
fi
fi
# If the C compiler is Clang, then we can also check whether its version
# matches the `libclang` version used by the Rust bindings generator.
#

View File

@ -1,2 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#define A "\0"

View File

@ -1,3 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#define F(x) int x##x
F(foo);

View File

@ -54,37 +54,23 @@ else:
""")
@classmethod
def generate_bindgen(cls, version_stdout, libclang_stderr, version_0_66_patched=False, libclang_concat_patched=False):
def generate_bindgen(cls, version_stdout, libclang_stderr):
if libclang_stderr is None:
libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})"
else:
libclang_case = f"print({repr(libclang_stderr)}, file=sys.stderr)"
if version_0_66_patched:
version_0_66_case = "pass"
else:
version_0_66_case = "raise SystemExit(1)"
if libclang_concat_patched:
libclang_concat_case = "print('pub static mut foofoo: ::std::os::raw::c_int;')"
else:
libclang_concat_case = "pass"
return cls.generate_executable(f"""#!/usr/bin/env python3
import sys
if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv):
{libclang_case}
elif "rust_is_available_bindgen_0_66.h" in " ".join(sys.argv):
{version_0_66_case}
elif "rust_is_available_bindgen_libclang_concat.h" in " ".join(sys.argv):
{libclang_concat_case}
else:
print({repr(version_stdout)})
""")
@classmethod
def generate_bindgen_version(cls, stdout, version_0_66_patched=False):
return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr, version_0_66_patched)
def generate_bindgen_version(cls, stdout):
return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr)
@classmethod
def generate_bindgen_libclang_failure(cls):
@ -245,19 +231,6 @@ else:
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
self.assertIn(f"Rust bindings generator '{bindgen}' is too old.", result.stderr)
def test_bindgen_bad_version_0_66_0_and_0_66_1(self):
for version in ("0.66.0", "0.66.1"):
with self.subTest(version=version):
bindgen = self.generate_bindgen_version(f"bindgen {version}")
result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen })
self.assertIn(f"Rust bindings generator '{bindgen}' versions 0.66.0 and 0.66.1 may not", result.stderr)
def test_bindgen_bad_version_0_66_0_and_0_66_1_patched(self):
for version in ("0.66.0", "0.66.1"):
with self.subTest(version=version):
bindgen = self.generate_bindgen_version(f"bindgen {version}", True)
result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen })
def test_bindgen_libclang_failure(self):
bindgen = self.generate_bindgen_libclang_failure()
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
@ -275,31 +248,6 @@ else:
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
self.assertIn(f"libclang (used by the Rust bindings generator '{bindgen}') is too old.", result.stderr)
def test_bindgen_bad_libclang_concat(self):
for (bindgen_version, libclang_version, expected_not_patched) in (
("0.69.4", "18.0.0", self.Expected.SUCCESS),
("0.69.4", "19.1.0", self.Expected.SUCCESS_WITH_WARNINGS),
("0.69.4", "19.2.0", self.Expected.SUCCESS_WITH_WARNINGS),
("0.69.5", "18.0.0", self.Expected.SUCCESS),
("0.69.5", "19.1.0", self.Expected.SUCCESS),
("0.69.5", "19.2.0", self.Expected.SUCCESS),
("0.70.0", "18.0.0", self.Expected.SUCCESS),
("0.70.0", "19.1.0", self.Expected.SUCCESS),
("0.70.0", "19.2.0", self.Expected.SUCCESS),
):
with self.subTest(bindgen_version=bindgen_version, libclang_version=libclang_version):
cc = self.generate_clang(f"clang version {libclang_version}")
libclang_stderr = f"scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version {libclang_version} [-W#pragma-messages], err: false"
bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr)
result = self.run_script(expected_not_patched, { "BINDGEN": bindgen, "CC": cc })
if expected_not_patched == self.Expected.SUCCESS_WITH_WARNINGS:
self.assertIn(f"Rust bindings generator '{bindgen}' < 0.69.5 together with libclang >= 19.1", result.stderr)
bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr, libclang_concat_patched=True)
result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen, "CC": cc })
def test_clang_matches_bindgen_libclang_different_bindgen(self):
bindgen = self.generate_bindgen_libclang("scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version 999.0.0 [-W#pragma-messages], err: false")
result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen })