mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
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:
commit
26ff969926
12
.clippy.toml
12
.clippy.toml
|
|
@ -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
4
.gitignore
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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``).
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
21
Makefile
21
Makefile
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
30
init/Kconfig
30
init/Kconfig
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 $(,)?) => {{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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()) };
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)*
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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)?);
|
||||
};
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@
|
|||
to_result, //
|
||||
},
|
||||
prelude::*,
|
||||
types::{
|
||||
AlwaysRefCounted,
|
||||
Opaque, //
|
||||
},
|
||||
sync::aref::AlwaysRefCounted,
|
||||
types::Opaque,
|
||||
ThisModule, //
|
||||
};
|
||||
use core::{
|
||||
|
|
|
|||
|
|
@ -172,6 +172,7 @@ pub struct StoreError<T> {
|
|||
}
|
||||
|
||||
impl<T> From<StoreError<T>> for Error {
|
||||
#[inline]
|
||||
fn from(value: StoreError<T>) -> Self {
|
||||
value.error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#define A "\0"
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#define F(x) int x##x
|
||||
F(foo);
|
||||
|
|
@ -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 })
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user