diff --git a/.clippy.toml b/.clippy.toml index 137f41d203de..b0a78cc8be20 100644 --- a/.clippy.toml +++ b/.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" diff --git a/.gitignore b/.gitignore index 3a7241c941f5..3044b9590f05 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index 6b373e193548..84156d031365 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -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 diff --git a/Documentation/rust/general-information.rst b/Documentation/rust/general-information.rst index 6146b49b6a98..09234bed272c 100644 --- a/Documentation/rust/general-information.rst +++ b/Documentation/rust/general-information.rst @@ -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 diff --git a/Documentation/rust/quick-start.rst b/Documentation/rust/quick-start.rst index 152289f0bed2..a6ec3fa94d33 100644 --- a/Documentation/rust/quick-start.rst +++ b/Documentation/rust/quick-start.rst @@ -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 {} }: 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``). diff --git a/MAINTAINERS b/MAINTAINERS index d1cc0e12fe1f..cff10617372e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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/ diff --git a/Makefile b/Makefile index 36d0a32fbe49..2345552219e9 100644 --- a/Makefile +++ b/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 diff --git a/arch/Kconfig b/arch/Kconfig index 102ddbd4298e..84089e80584b 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -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 diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 9ea19b74b6c3..4de630e398ca 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -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 diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 90c531e6abf5..ddc534402400 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -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 diff --git a/drivers/android/binder/Makefile b/drivers/android/binder/Makefile index 09eabb527fa0..7e0cd9782a8b 100644 --- a/drivers/android/binder/Makefile +++ b/drivers/android/binder/Makefile @@ -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 diff --git a/drivers/android/binder/page_range.rs b/drivers/android/binder/page_range.rs index b57e0c7ba3f1..60e20fcf7c94 100644 --- a/drivers/android/binder/page_range.rs +++ b/drivers/android/binder/page_range.rs @@ -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. diff --git a/drivers/android/binder/page_range_helper.c b/drivers/android/binder/page_range_helper.c deleted file mode 100644 index 496887723ee0..000000000000 --- a/drivers/android/binder/page_range_helper.c +++ /dev/null @@ -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); -} diff --git a/drivers/android/binder/page_range_helper.h b/drivers/android/binder/page_range_helper.h deleted file mode 100644 index 18dd2dd117b2..000000000000 --- a/drivers/android/binder/page_range_helper.h +++ /dev/null @@ -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 - -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 */ diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/binder/rust_binder_main.rs index 014010662df8..632b54714e44 100644 --- a/drivers/android/binder/rust_binder_main.rs +++ b/drivers/android/binder/rust_binder_main.rs @@ -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, diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index beeffe36b6cb..e833e9f537b0 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -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, iomem: &Devres) -> Result { regs::GPU_CMD.write(dev, iomem, regs::GPU_CMD_SOFT_RESET)?; diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs index 03a4f3599849..c1fbc54d9a41 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -293,7 +293,6 @@ fn allocate_command(&mut self, size: usize) -> Result> { 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> { 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)?; diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144.rs b/drivers/gpu/nova-core/gsp/fw/r570_144.rs index e99d315ae74c..2e6f0d298756 100644 --- a/drivers/gpu/nova-core/gsp/fw/r570_144.rs +++ b/drivers/gpu/nova-core/gsp/fw/r570_144.rs @@ -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, diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index b0e24ee724e4..6cd6fa3d2984 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -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; diff --git a/init/Kconfig b/init/Kconfig index 7484cd703bc1..e18fa242ed86 100644 --- a/init/Kconfig +++ b/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 diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 93f356d2b3d9..30d069676309 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -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 diff --git a/rust/Makefile b/rust/Makefile index 9801af2e1e02..b361bfedfdf0 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -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 diff --git a/rust/bindgen_parameters b/rust/bindgen_parameters index fd2fd1c3cb9a..6f02d9720ad2 100644 --- a/rust/bindgen_parameters +++ b/rust/bindgen_parameters @@ -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 diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 083cc44aa952..faf3ee634ced 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -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 diff --git a/rust/bindings/lib.rs b/rust/bindings/lib.rs index 19f57c5b2fa2..854e7c471434 100644 --- a/rust/bindings/lib.rs +++ b/rust/bindings/lib.rs @@ -9,10 +9,6 @@ //! using this crate. #![no_std] -// See . -#![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)] diff --git a/rust/exports.c b/rust/exports.c index 587f0e776aba..1b52460b0f4e 100644 --- a/rust/exports.c +++ b/rust/exports.c @@ -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); diff --git a/rust/helpers/clk.c b/rust/helpers/clk.c index 6d04372c9f3b..15fd7e469cdd 100644 --- a/rust/helpers/clk.c +++ b/rust/helpers/clk.c @@ -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); } diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index a3c42e51f00a..e05c6e7e4abb 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -7,7 +7,36 @@ * Sorted alphabetically. */ +#include + +#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" diff --git a/rust/helpers/jump_label.c b/rust/helpers/jump_label.c index fc1f1e0df08e..7ca384e73121 100644 --- a/rust/helpers/jump_label.c +++ b/rust/helpers/jump_label.c @@ -7,7 +7,7 @@ #include #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); } diff --git a/rust/kernel/alloc/allocator/iter.rs b/rust/kernel/alloc/allocator/iter.rs index 5759f86029b7..e0a70b7a744a 100644 --- a/rust/kernel/alloc/allocator/iter.rs +++ b/rust/kernel/alloc/allocator/iter.rs @@ -42,15 +42,9 @@ fn next(&mut self) -> Option { 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. diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index 622b3529edfc..bd6da02c7ab8 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -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, - PhantomData, -); - -// This is to allow coercion from `Box` to `Box` if `T` can be converted to the -// dynamically-sized type (DST) `U`. -#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] -impl core::ops::CoerceUnsized> for Box -where - T: ?Sized + core::marker::Unsize, - U: ?Sized, - A: Allocator, -{ -} - -// This is to allow `Box` to be dispatched on when `Box` can be coerced into `Box`. -#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] -impl core::ops::DispatchFromDyn> for Box -where - T: ?Sized + core::marker::Unsize, - U: ?Sized, - A: Allocator, -{ -} +#[derive(core::marker::CoercePointee)] +pub struct Box<#[pointee] T: ?Sized, A: Allocator>(NonNull, PhantomData); /// Type alias for [`Box`] with a [`Kmalloc`] allocator. /// diff --git a/rust/kernel/alloc/kvec/errors.rs b/rust/kernel/alloc/kvec/errors.rs index e7de5049ee47..985c5f2c3962 100644 --- a/rust/kernel/alloc/kvec/errors.rs +++ b/rust/kernel/alloc/kvec/errors.rs @@ -15,6 +15,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } impl From> for Error { + #[inline] fn from(_: PushError) -> 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 for Error { + #[inline] fn from(_: RemoveError) -> Error { EINVAL } @@ -55,6 +57,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } impl From> for Error { + #[inline] fn from(_: InsertError) -> Error { EINVAL } diff --git a/rust/kernel/block/mq/gen_disk.rs b/rust/kernel/block/mq/gen_disk.rs index c8b0ecb17082..912cb805caf5 100644 --- a/rust/kernel/block/mq/gen_disk.rs +++ b/rust/kernel/block/mq/gen_disk.rs @@ -140,9 +140,7 @@ pub fn build( 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) - // + // TODO: Set to `THIS_MODULE`. owner: core::ptr::null_mut(), pr_ops: core::ptr::null_mut(), free_disk: None, diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs index f8124dbc663f..2ea2154ec30c 100644 --- a/rust/kernel/build_assert.rs +++ b/rust/kernel/build_assert.rs @@ -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::() == 1); +//! // `const_assert!` and `build_assert!` cannot be used here, they will fail to compile. +//! +//! #[inline(always)] +//! fn foo(v: usize) { +//! static_assert!(core::mem::size_of::() == 1); // Preferred. +//! const_assert!(core::mem::size_of::() == 1); // Discouraged. +//! build_assert!(core::mem::size_of::() == 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::() == 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_assert!(N > 1); +/// } +/// +/// fn bar() { +/// const_assert!(size_of::() > 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() { -/// // `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 $(,)?) => {{ diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs index 4059aff34d09..7abbd0767d8c 100644 --- a/rust/kernel/clk.rs +++ b/rust/kernel/clk.rs @@ -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. /// diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 258b12afdcba..decceb6ae855 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -216,36 +216,42 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } impl From for Error { + #[inline] fn from(_: AllocError) -> Error { code::ENOMEM } } impl From for Error { + #[inline] fn from(_: TryFromIntError) -> Error { code::EINVAL } } impl From for Error { + #[inline] fn from(_: Utf8Error) -> Error { code::EINVAL } } impl From for Error { + #[inline] fn from(_: LayoutError) -> Error { code::ENOMEM } } impl From for Error { + #[inline] fn from(_: fmt::Error) -> Error { code::EINVAL } } impl From 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(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(); diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index bb5b830f48c3..7b908f0c5a58 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -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> { 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()) }; diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index d93292d47420..0fa9d820fe7c 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -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; diff --git a/rust/kernel/list.rs b/rust/kernel/list.rs index 8349ff32fc37..406e3a028c55 100644 --- a/rust/kernel/list.rs +++ b/rust/kernel/list.rs @@ -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. /// diff --git a/rust/kernel/list/arc.rs b/rust/kernel/list/arc.rs index 2282f33913ee..a9a2b0178f65 100644 --- a/rust/kernel/list/arc.rs +++ b/rust/kernel/list/arc.rs @@ -82,6 +82,7 @@ pub unsafe trait TryNewListArc: ListArcSafe { /// [`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 where T: ListArcSafe + ?Sized, @@ -442,26 +443,6 @@ fn as_ref(&self) -> &Arc { } } -// This is to allow coercion from `ListArc` to `ListArc` if `T` can be converted to the -// dynamically-sized type (DST) `U`. -#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] -impl core::ops::CoerceUnsized> for ListArc -where - T: ListArcSafe + core::marker::Unsize + ?Sized, - U: ListArcSafe + ?Sized, -{ -} - -// This is to allow `ListArc` to be dispatched on when `ListArc` can be coerced into -// `ListArc`. -#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] -impl core::ops::DispatchFromDyn> for ListArc -where - T: ListArcSafe + core::marker::Unsize + ?Sized, - U: ListArcSafe + ?Sized, -{ -} - /// A utility for tracking whether a [`ListArc`] exists using an atomic. /// /// # Invariants diff --git a/rust/kernel/list/arc_field.rs b/rust/kernel/list/arc_field.rs index c4b9dd503982..2ad8aea55993 100644 --- a/rust/kernel/list/arc_field.rs +++ b/rust/kernel/list/arc_field.rs @@ -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)* diff --git a/rust/kernel/list/impl_list_item_mod.rs b/rust/kernel/list/impl_list_item_mod.rs index ee53d0387e63..5a3eac9f3cf0 100644 --- a/rust/kernel/list/impl_list_item_mod.rs +++ b/rust/kernel/list/impl_list_item_mod.rs @@ -29,6 +29,7 @@ pub unsafe trait HasListLinks { /// 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 /// 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 { diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs index fa81acbdc8c2..54d0ce3ba595 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -255,9 +255,7 @@ impl Bounded<$type, N> { /// ``` pub const fn new() -> 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 Bounded /// 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(self) -> Bounded { - 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. diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 2877e3f7b6d3..44edf72a4a24 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -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; diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs index bdc2d79ff669..3f3e529e9f58 100644 --- a/rust/kernel/ptr.rs +++ b/rust/kernel/ptr.rs @@ -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() -> 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 { /// This is equivalent to [`align_of`], but with the return value provided as an [`Alignment`]. #[inline(always)] pub const fn of() -> 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::() } } + +/// 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::()), Some(SZ_4K)); +/// ``` +#[inline(always)] +pub const fn const_align_up(value: usize, align: Alignment) -> Option { + match value.checked_add(align.as_usize() - 1) { + Some(v) => Some(v & align.mask()), + None => None, + } +} diff --git a/rust/kernel/sizes.rs b/rust/kernel/sizes.rs index 661e680d9330..521b2b38bfe7 100644 --- a/rust/kernel/sizes.rs +++ b/rust/kernel/sizes.rs @@ -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); diff --git a/rust/kernel/slice.rs b/rust/kernel/slice.rs deleted file mode 100644 index ca2cde135061..000000000000 --- a/rust/kernel/slice.rs +++ /dev/null @@ -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 { - /// 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 AsFlattened 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() - } -} diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs deleted file mode 100644 index a57ba14315a0..000000000000 --- a/rust/kernel/static_assert.rs +++ /dev/null @@ -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::() == 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)?); - }; -} diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 3f8918764640..8311d91549e1 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -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 { 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. diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 921e19333b89..18d6c0d62ce0 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -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 { ptr: NonNull>, // NB: this informs dropck that objects of type `ArcInner` may be used in ` as @@ -182,15 +182,6 @@ unsafe fn container_of(ptr: *const T) -> NonNull> { } } -// This is to allow coercion from `Arc` to `Arc` if `T` can be converted to the -// dynamically-sized type (DST) `U`. -#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] -impl, U: ?Sized> core::ops::CoerceUnsized> for Arc {} - -// This is to allow `Arc` to be dispatched on when `Arc` can be coerced into `Arc`. -#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] -impl, U: ?Sized> core::ops::DispatchFromDyn> for Arc {} - // SAFETY: It is safe to send `Arc` 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` may ultimately access `T` using a @@ -547,20 +538,12 @@ fn from(item: Pin>) -> 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>, _p: PhantomData<&'a ()>, } -// This is to allow `ArcBorrow` to be dispatched on when `ArcBorrow` can be coerced into -// `ArcBorrow`. -#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] -impl, U: ?Sized> core::ops::DispatchFromDyn> - for ArcBorrow<'_, T> -{ -} - impl Clone for ArcBorrow<'_, T> { fn clone(&self) -> Self { *self diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index cc907fb531bc..049c8a4d45d8 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -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. diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs index 6ea98dfcd027..363e93cbb139 100644 --- a/rust/kernel/time.rs +++ b/rust/kernel/time.rs @@ -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. diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index 856d2d929a00..2d7f1131a813 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -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, +//! #[pin] +//! cond: Completion, +//! } +//! +//! impl Shared { +//! fn new() -> impl PinInit { +//! pin_init!(Self { +//! flag <- Atomic::new(0), +//! cond <- Completion::new(), +//! }) +//! } +//! } +//! +//! #[pin_data] +//! struct BoxIntrusiveHrTimer { +//! #[pin] +//! timer: HrTimer, +//! shared: Arc, +//! } +//! +//! impl BoxIntrusiveHrTimer { +//! fn new() -> impl PinInit { +//! try_pin_init!(Self { +//! timer <- HrTimer::new(), +//! shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?, +//! }) +//! } +//! } +//! +//! impl HrTimerCallback for BoxIntrusiveHrTimer { +//! type Pointer<'a> = Pin>; +//! +//! 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 for BoxIntrusiveHrTimer { +//! mode: RelativeMode, 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, +//! #[pin] +//! flag: Atomic, +//! #[pin] +//! cond: Completion, +//! } +//! +//! impl ArcIntrusiveHrTimer { +//! fn new() -> impl PinInit { +//! pin_init!(Self { +//! timer <- HrTimer::new(), +//! flag <- Atomic::new(0), +//! cond <- Completion::new(), +//! }) +//! } +//! } +//! +//! impl HrTimerCallback for ArcIntrusiveHrTimer { +//! type Pointer<'a> = Arc; +//! +//! 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 for ArcIntrusiveHrTimer { +//! mode: RelativeMode, 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, +//! #[pin] +//! flag: Atomic, +//! #[pin] +//! cond: Completion, +//! } +//! +//! impl IntrusiveHrTimer { +//! fn new() -> impl PinInit { +//! 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 for IntrusiveHrTimer { +//! mode: RelativeMode, 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, +//! #[pin] +//! cond: Completion, +//! } +//! +//! impl Shared { +//! fn new() -> impl PinInit { +//! pin_init!(Self { +//! flag <- Atomic::new(0), +//! cond <- Completion::new(), +//! }) +//! } +//! } +//! +//! #[pin_data] +//! struct IntrusiveHrTimer { +//! #[pin] +//! timer: HrTimer, +//! shared: Arc, +//! } +//! +//! impl IntrusiveHrTimer { +//! fn new() -> impl PinInit { +//! 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 for IntrusiveHrTimer { +//! mode: RelativeMode, 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}; diff --git a/rust/kernel/transmute.rs b/rust/kernel/transmute.rs index 5711580c9f9b..654b5ede2fe2 100644 --- a/rust/kernel/transmute.rs +++ b/rust/kernel/transmute.rs @@ -49,7 +49,6 @@ fn from_bytes(bytes: &[u8]) -> Option<&Self> let slice_ptr = bytes.as_ptr().cast::(); let size = size_of::(); - #[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::() { - None - } else { - // PANIC: We checked that `bytes.len() >= size_of::`, 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::()); + let (prefix, remainder) = bytes.split_at_checked(size_of::())?; - 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::(); let size = size_of::(); - #[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::() { - None - } else { - // PANIC: We checked that `bytes.len() >= size_of::`, 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::()); + let (prefix, remainder) = bytes.split_at_mut_checked(size_of::())?; - 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::() { - None - } else { - // PANIC: We checked that `bytes.len() >= size_of::`, 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::()); + let (prefix, remainder) = bytes.split_at_checked(size_of::())?; - Self::from_bytes_copy(prefix).map(|s| (s, remainder)) - } + Self::from_bytes_copy(prefix).map(|s| (s, remainder)) } } diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 9c5e7dbf1632..4329d3c2c2e5 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -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 diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 0e1b9a88f4f1..9c17a672cd27 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -18,10 +18,8 @@ to_result, // }, prelude::*, - types::{ - AlwaysRefCounted, - Opaque, // - }, + sync::aref::AlwaysRefCounted, + types::Opaque, ThisModule, // }; use core::{ diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index a49d6db28845..46e5f43223fe 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -172,6 +172,7 @@ pub struct StoreError { } impl From> for Error { + #[inline] fn from(value: StoreError) -> Self { value.error } diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs index 37ef6a6f2c85..d18fbf4daa0a 100644 --- a/rust/macros/helpers.rs +++ b/rust/macros/helpers.rs @@ -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() } diff --git a/rust/macros/kunit.rs b/rust/macros/kunit.rs index 6be880d634e2..ae20ed6768f1 100644 --- a/rust/macros/kunit.rs +++ b/rust/macros/kunit.rs @@ -87,10 +87,11 @@ pub(crate) fn kunit_tests(test_suite: Ident, mut module: ItemMod) -> Result= 1.88.0. diff --git a/rust/macros/module.rs b/rust/macros/module.rs index e16298e520c7..06c18e207508 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -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); } diff --git a/rust/pin-init/README.md b/rust/pin-init/README.md index 6cee6ab1eb57..9095d6661ff6 100644 --- a/rust/pin-init/README.md +++ b/rust/pin-init/README.md @@ -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::(); // Initialize the `foo` diff --git a/rust/pin-init/examples/big_struct_in_place.rs b/rust/pin-init/examples/big_struct_in_place.rs index c05139927486..80f89b5f8fd6 100644 --- a/rust/pin-init/examples/big_struct_in_place.rs +++ b/rust/pin-init/examples/big_struct_in_place.rs @@ -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 diff --git a/rust/pin-init/examples/linked_list.rs b/rust/pin-init/examples/linked_list.rs index 8445a5890cb7..119169e4dc41 100644 --- a/rust/pin-init/examples/linked_list.rs +++ b/rust/pin-init/examples/linked_list.rs @@ -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, diff --git a/rust/pin-init/examples/mutex.rs b/rust/pin-init/examples/mutex.rs index 9f295226cd64..d53671f0edb8 100644 --- a/rust/pin-init/examples/mutex.rs +++ b/rust/pin-init/examples/mutex.rs @@ -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::{ diff --git a/rust/pin-init/examples/pthread_mutex.rs b/rust/pin-init/examples/pthread_mutex.rs index 4e082ec7d5de..f3b5cc9b7134 100644 --- a/rust/pin-init/examples/pthread_mutex.rs +++ b/rust/pin-init/examples/pthread_mutex.rs @@ -3,7 +3,8 @@ // inspired by #![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 { diff --git a/rust/pin-init/examples/static_init.rs b/rust/pin-init/examples/static_init.rs index 0e165daa9798..f7e53d1a5ae6 100644 --- a/rust/pin-init/examples/static_init.rs +++ b/rust/pin-init/examples/static_init.rs @@ -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::{ diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs index 2fe918f4d82a..daa3f1c6466e 100644 --- a/rust/pin-init/internal/src/init.rs +++ b/rust/pin-init/internal/src/init.rs @@ -173,6 +173,12 @@ fn assert_zeroable(_: *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 ) }; }); diff --git a/rust/pin-init/internal/src/lib.rs b/rust/pin-init/internal/src/lib.rs index 08372c8f65f0..b08dfe003031 100644 --- a/rust/pin-init/internal/src/lib.rs +++ b/rust/pin-init/internal/src/lib.rs @@ -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)] diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index fe4c85ae3f02..64eec095c859 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -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::(); //! //! // Initialize the `foo` @@ -264,12 +263,10 @@ //! [`impl Init`]: 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::())) }; - // 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::())) }; - // 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)`. {} UnsafeCell, - // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee: - // ). - Option, Option, Option, Option, - Option, Option, - Option, Option, Option, Option, - Option, Option, - // 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: + // . + 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: // . 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: + // ). + 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). /// diff --git a/rust/uapi/lib.rs b/rust/uapi/lib.rs index 1d5fd9efb93e..b8a515de31ca 100644 --- a/rust/uapi/lib.rs +++ b/rust/uapi/lib.rs @@ -8,10 +8,6 @@ //! userspace APIs. #![no_std] -// See . -#![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; diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 3652b85be545..57cff77c2897 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -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) diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index f9b545104f21..d5f9a0ca742c 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -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", diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh index 99b5575c1ef7..b96ec2d379b6 100755 --- a/scripts/min-tool-version.sh +++ b/scripts/min-tool-version.sh @@ -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 diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh index d2323de0692c..551f1ebd0dcb 100755 --- a/scripts/rust_is_available.sh +++ b/scripts/rust_is_available.sh @@ -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. # diff --git a/scripts/rust_is_available_bindgen_0_66.h b/scripts/rust_is_available_bindgen_0_66.h deleted file mode 100644 index c0431293421c..000000000000 --- a/scripts/rust_is_available_bindgen_0_66.h +++ /dev/null @@ -1,2 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#define A "\0" diff --git a/scripts/rust_is_available_bindgen_libclang_concat.h b/scripts/rust_is_available_bindgen_libclang_concat.h deleted file mode 100644 index efc6e98d0f1d..000000000000 --- a/scripts/rust_is_available_bindgen_libclang_concat.h +++ /dev/null @@ -1,3 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#define F(x) int x##x -F(foo); diff --git a/scripts/rust_is_available_test.py b/scripts/rust_is_available_test.py index 4fcc319dea84..d6d54b7ea42a 100755 --- a/scripts/rust_is_available_test.py +++ b/scripts/rust_is_available_test.py @@ -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 })