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
This commit is contained in:
Linus Torvalds
2026-03-14 12:35:16 -07:00
6 changed files with 59 additions and 58 deletions

View File

@@ -476,6 +476,7 @@ KBUILD_USERLDFLAGS := $(USERLDFLAGS)
export rust_common_flags := --edition=2021 \
-Zbinary_dep_depinfo=y \
-Astable_features \
-Aunused_features \
-Dnon_ascii_idents \
-Dunsafe_op_in_unsafe_fn \
-Wmissing_docs \
@@ -1113,6 +1114,9 @@ KBUILD_CFLAGS += -fno-builtin-wcslen
# change __FILE__ to the relative path to the source directory
ifdef building_out_of_srctree
KBUILD_CPPFLAGS += -fmacro-prefix-map=$(srcroot)/=
ifeq ($(call rustc-option-yn, --remap-path-scope=macro),y)
KBUILD_RUSTFLAGS += --remap-path-prefix=$(srcroot)/= --remap-path-scope=macro
endif
endif
# include additional Makefiles when needed

View File

@@ -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)

View File

@@ -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)

View File

@@ -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:

View File

@@ -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"))
}

View File

@@ -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
}