summaryrefslogtreecommitdiff
path: root/rust
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-03-14 12:35:16 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-03-14 12:35:16 -0700
commit267594792a71018788af69e836c52e34bb8054af (patch)
treee08fd00efa4903caaaf089db2b3d037747d6f564 /rust
parent69237f8c1f69112cca7388af7fab6d0ee45a2525 (diff)
parent592c61f3bfceaa29f8275696bd67c3dfad7ef72e (diff)
Merge tag 'rust-fixes-7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux
Pull Rust fixes from Miguel Ojeda: "Toolchain and infrastructure: - Remap paths to avoid absolute ones starting with the upcoming Rust 1.95.0 release. This improves build reproducibility, avoids leaking the exact path and avoids having the same path appear in two forms The approach here avoids remapping debug information as well, in order to avoid breaking tools that used the paths to access source files, which was the previous attempt that needed to be reverted - Allow 'unused_features' lint for the upcoming Rust 1.96.0 release. While well-intentioned, we do not benefit much from the new lint - Emit dependency information into '$(depfile)' directly to avoid a temporary '.d' file (it was an old approach) 'kernel' crate: - 'str' module: fix warning under '!CONFIG_BLOCK' by making 'NullTerminatedFormatter' public - 'cpufreq' module: suppress false positive Clippy warning 'pin-init' crate: - Remove '#[disable_initialized_field_access]' attribute which was unsound. This means removing the support for structs with unaligned fields (through the 'repr(packed)' attribute), for now And document the load-bearing fact of field accessors (i.e. that they are required for soundness) - Replace shadowed return token by 'unsafe'-to-create token in order to remain sound in the face of the likely upcoming Type Alias Impl Trait (TAIT) and the next trait solver in upstream Rust" * tag 'rust-fixes-7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: rust: kbuild: allow `unused_features` rust: cpufreq: suppress clippy::double_parens in Policy doctest rust: pin-init: replace shadowed return token by `unsafe`-to-create token rust: pin-init: internal: init: document load-bearing fact of field accessors rust: pin-init: internal: init: remove `#[disable_initialized_field_access]` rust: build: remap path to avoid absolute path rust: kbuild: emit dep-info into $(depfile) directly rust: str: make NullTerminatedFormatter public
Diffstat (limited to 'rust')
-rw-r--r--rust/Makefile11
-rw-r--r--rust/kernel/cpufreq.rs1
-rw-r--r--rust/kernel/str.rs4
-rw-r--r--rust/pin-init/internal/src/init.rs69
-rw-r--r--rust/pin-init/src/__internal.rs28
5 files changed, 55 insertions, 58 deletions
diff --git a/rust/Makefile b/rust/Makefile
index 629b3bdd2b20..9801af2e1e02 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -148,7 +148,8 @@ doctests_modifiers_workaround := $(rustdoc_modifiers_workaround)$(if $(call rust
quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
cmd_rustdoc = \
OBJTREE=$(abspath $(objtree)) \
- $(RUSTDOC) $(filter-out $(skip_flags) --remap-path-prefix=%,$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
+ $(RUSTDOC) $(filter-out $(skip_flags) --remap-path-prefix=% --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) \
@@ -334,7 +335,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=%,$(rust_flags)) \
+ $(RUSTDOC) --test $(filter-out --remap-path-prefix=% --remap-path-scope=%,$(rust_flags)) \
-L$(objtree)/$(obj) --extern ffi --extern pin_init \
--extern kernel --extern build_error --extern macros \
--extern bindings --extern uapi \
@@ -526,11 +527,9 @@ quiet_cmd_rustc_procmacrolibrary = $(RUSTC_OR_CLIPPY_QUIET) PL $@
cmd_rustc_procmacrolibrary = \
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
$(filter-out $(skip_flags),$(rust_common_flags) $(rustc_target_flags)) \
- --emit=dep-info,link --crate-type rlib -O \
+ --emit=dep-info=$(depfile) --emit=link=$@ --crate-type rlib -O \
--out-dir $(objtree)/$(obj) -L$(objtree)/$(obj) \
- --crate-name $(patsubst lib%.rlib,%,$(notdir $@)) $<; \
- mv $(objtree)/$(obj)/$(patsubst lib%.rlib,%,$(notdir $@)).d $(depfile); \
- sed -i '/^\#/d' $(depfile)
+ --crate-name $(patsubst lib%.rlib,%,$(notdir $@)) $<
$(obj)/libproc_macro2.rlib: private skip_clippy = 1
$(obj)/libproc_macro2.rlib: private rustc_target_flags = $(proc_macro2-flags)
diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
index 76faa1ac8501..f5adee48d40c 100644
--- a/rust/kernel/cpufreq.rs
+++ b/rust/kernel/cpufreq.rs
@@ -401,6 +401,7 @@ impl TableBuilder {
/// ```
/// use kernel::cpufreq::{DEFAULT_TRANSITION_LATENCY_NS, Policy};
///
+/// #[allow(clippy::double_parens, reason = "False positive before 1.92.0")]
/// fn update_policy(policy: &mut Policy) {
/// policy
/// .set_dvfs_possible_from_any_cpu(true)
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index fa87779d2253..3f8918764640 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -664,13 +664,13 @@ impl fmt::Write for Formatter<'_> {
///
/// * The first byte of `buffer` is always zero.
/// * The length of `buffer` is at least 1.
-pub(crate) struct NullTerminatedFormatter<'a> {
+pub struct NullTerminatedFormatter<'a> {
buffer: &'a mut [u8],
}
impl<'a> NullTerminatedFormatter<'a> {
/// Create a new [`Self`] instance.
- pub(crate) fn new(buffer: &'a mut [u8]) -> Option<NullTerminatedFormatter<'a>> {
+ pub fn new(buffer: &'a mut [u8]) -> Option<NullTerminatedFormatter<'a>> {
*(buffer.first_mut()?) = 0;
// INVARIANT:
diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index 42936f915a07..2fe918f4d82a 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -62,7 +62,6 @@ impl InitializerKind {
enum InitializerAttribute {
DefaultError(DefaultErrorAttribute),
- DisableInitializedFieldAccess,
}
struct DefaultErrorAttribute {
@@ -86,6 +85,7 @@ pub(crate) fn expand(
let error = error.map_or_else(
|| {
if let Some(default_error) = attrs.iter().fold(None, |acc, attr| {
+ #[expect(irrefutable_let_patterns)]
if let InitializerAttribute::DefaultError(DefaultErrorAttribute { ty }) = attr {
Some(ty.clone())
} else {
@@ -145,22 +145,9 @@ pub(crate) fn expand(
};
// `mixed_site` ensures that the data is not accessible to the user-controlled code.
let data = Ident::new("__data", Span::mixed_site());
- let init_fields = init_fields(
- &fields,
- pinned,
- !attrs
- .iter()
- .any(|attr| matches!(attr, InitializerAttribute::DisableInitializedFieldAccess)),
- &data,
- &slot,
- );
+ let init_fields = init_fields(&fields, pinned, &data, &slot);
let field_check = make_field_check(&fields, init_kind, &path);
Ok(quote! {{
- // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return
- // type and shadow it later when we insert the arbitrary user code. That way there will be
- // no possibility of returning without `unsafe`.
- struct __InitOk;
-
// Get the data about fields from the supplied type.
// SAFETY: TODO
let #data = unsafe {
@@ -170,18 +157,15 @@ pub(crate) fn expand(
#path::#get_data()
};
// Ensure that `#data` really is of type `#data` and help with type inference:
- let init = ::pin_init::__internal::#data_trait::make_closure::<_, __InitOk, #error>(
+ let init = ::pin_init::__internal::#data_trait::make_closure::<_, #error>(
#data,
move |slot| {
- {
- // Shadow the structure so it cannot be used to return early.
- struct __InitOk;
- #zeroable_check
- #this
- #init_fields
- #field_check
- }
- Ok(__InitOk)
+ #zeroable_check
+ #this
+ #init_fields
+ #field_check
+ // SAFETY: we are the `init!` macro that is allowed to call this.
+ Ok(unsafe { ::pin_init::__internal::InitOk::new() })
}
);
let init = move |slot| -> ::core::result::Result<(), #error> {
@@ -236,7 +220,6 @@ fn get_init_kind(rest: Option<(Token![..], Expr)>, dcx: &mut DiagCtxt) -> InitKi
fn init_fields(
fields: &Punctuated<InitializerField, Token![,]>,
pinned: bool,
- generate_initialized_accessors: bool,
data: &Ident,
slot: &Ident,
) -> TokenStream {
@@ -260,6 +243,10 @@ fn init_fields(
});
// Again span for better diagnostics
let write = quote_spanned!(ident.span()=> ::core::ptr::write);
+ // NOTE: the field accessor ensures that the initialized field is properly aligned.
+ // Unaligned fields will cause the compiler to emit E0793. We do not support
+ // unaligned fields since `Init::__init` requires an aligned pointer; the call to
+ // `ptr::write` below has the same requirement.
let accessor = if pinned {
let project_ident = format_ident!("__project_{ident}");
quote! {
@@ -272,13 +259,6 @@ fn init_fields(
unsafe { &mut (*#slot).#ident }
}
};
- let accessor = generate_initialized_accessors.then(|| {
- quote! {
- #(#cfgs)*
- #[allow(unused_variables)]
- let #ident = #accessor;
- }
- });
quote! {
#(#attrs)*
{
@@ -286,12 +266,18 @@ fn init_fields(
// SAFETY: TODO
unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) };
}
- #accessor
+ #(#cfgs)*
+ #[allow(unused_variables)]
+ let #ident = #accessor;
}
}
InitializerKind::Init { ident, value, .. } => {
// Again span for better diagnostics
let init = format_ident!("init", span = value.span());
+ // NOTE: the field accessor ensures that the initialized field is properly aligned.
+ // Unaligned fields will cause the compiler to emit E0793. We do not support
+ // unaligned fields since `Init::__init` requires an aligned pointer; the call to
+ // `ptr::write` below has the same requirement.
let (value_init, accessor) = if pinned {
let project_ident = format_ident!("__project_{ident}");
(
@@ -326,20 +312,15 @@ fn init_fields(
},
)
};
- let accessor = generate_initialized_accessors.then(|| {
- quote! {
- #(#cfgs)*
- #[allow(unused_variables)]
- let #ident = #accessor;
- }
- });
quote! {
#(#attrs)*
{
let #init = #value;
#value_init
}
- #accessor
+ #(#cfgs)*
+ #[allow(unused_variables)]
+ let #ident = #accessor;
}
}
InitializerKind::Code { block: value, .. } => quote! {
@@ -466,10 +447,6 @@ impl Parse for Initializer {
if a.path().is_ident("default_error") {
a.parse_args::<DefaultErrorAttribute>()
.map(InitializerAttribute::DefaultError)
- } else if a.path().is_ident("disable_initialized_field_access") {
- a.meta
- .require_path_only()
- .map(|_| InitializerAttribute::DisableInitializedFieldAccess)
} else {
Err(syn::Error::new_spanned(a, "unknown initializer attribute"))
}
diff --git a/rust/pin-init/src/__internal.rs b/rust/pin-init/src/__internal.rs
index 90f18e9a2912..90adbdc1893b 100644
--- a/rust/pin-init/src/__internal.rs
+++ b/rust/pin-init/src/__internal.rs
@@ -46,6 +46,24 @@ where
}
}
+/// Token type to signify successful initialization.
+///
+/// Can only be constructed via the unsafe [`Self::new`] function. The initializer macros use this
+/// token type to prevent returning `Ok` from an initializer without initializing all fields.
+pub struct InitOk(());
+
+impl InitOk {
+ /// Creates a new token.
+ ///
+ /// # Safety
+ ///
+ /// This function may only be called from the `init!` macro in `../internal/src/init.rs`.
+ #[inline(always)]
+ pub unsafe fn new() -> Self {
+ Self(())
+ }
+}
+
/// This trait is only implemented via the `#[pin_data]` proc-macro. It is used to facilitate
/// the pin projections within the initializers.
///
@@ -68,9 +86,10 @@ pub unsafe trait PinData: Copy {
type Datee: ?Sized + HasPinData;
/// Type inference helper function.
- fn make_closure<F, O, E>(self, f: F) -> F
+ #[inline(always)]
+ fn make_closure<F, E>(self, f: F) -> F
where
- F: FnOnce(*mut Self::Datee) -> Result<O, E>,
+ F: FnOnce(*mut Self::Datee) -> Result<InitOk, E>,
{
f
}
@@ -98,9 +117,10 @@ pub unsafe trait InitData: Copy {
type Datee: ?Sized + HasInitData;
/// Type inference helper function.
- fn make_closure<F, O, E>(self, f: F) -> F
+ #[inline(always)]
+ fn make_closure<F, E>(self, f: F) -> F
where
- F: FnOnce(*mut Self::Datee) -> Result<O, E>,
+ F: FnOnce(*mut Self::Datee) -> Result<InitOk, E>,
{
f
}