mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-03-03 18:28:01 +01:00
Pull rust updates from Miguel Ojeda:
"Toolchain and infrastructure:
- Add '__rust_helper' annotation to the C helpers
This is needed to inline these helpers into Rust code
- Remove imports available via the prelude, treewide
This was possible thanks to a new lint in Klint that Gary has
implemented -- more Klint-related changes, including initial
upstream support, are coming
- Deduplicate pin-init flags
'kernel' crate:
- Add support for calling a function exactly once with the new
'do_once_lite!' macro (and 'OnceLite' type)
Based on this, add 'pr_*_once!' macros to print only once
- Add 'impl_flags!' macro for defining common bitflags operations:
impl_flags!(
/// Represents multiple permissions.
#[derive(Debug, Clone, Default, Copy, PartialEq, Eq)]
pub struct Permissions(u32);
/// Represents a single permission.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Permission {
/// Read permission.
Read = 1 << 0,
/// Write permission.
Write = 1 << 1,
/// Execute permission.
Execute = 1 << 2,
}
);
let mut f: Permissions = Permission::Read | Permission::Write;
assert!(f.contains(Permission::Read));
assert!(!f.contains(Permission::Execute));
f |= Permission::Execute;
assert!(f.contains(Permission::Execute));
let f2: Permissions = Permission::Write | Permission::Execute;
assert!((f ^ f2).contains(Permission::Read));
assert!(!(f ^ f2).contains(Permission::Write));
- 'bug' module: support 'CONFIG_DEBUG_BUGVERBOSE_DETAILED' in the
'warn_on!' macro in order to show the evaluated condition alongside
the file path:
------------[ cut here ]------------
WARNING: [val == 1] linux/samples/rust/rust_minimal.rs:27 at ...
Modules linked in: rust_minimal(+)
- Add safety module with 'unsafe_precondition_assert!' macro,
currently a wrapper for 'debug_assert!', intended to mark the
validation of safety preconditions where possible:
/// # Safety
///
/// The caller must ensure that `index` is less than `N`.
unsafe fn set_unchecked(&mut self, index: usize, value: T) {
unsafe_precondition_assert!(
index < N,
"set_unchecked() requires index ({index}) < N ({N})"
);
...
}
- Add instructions to 'build_assert!' documentation requesting to
always inline functions when used with function arguments
- 'ptr' module: replace 'build_assert!' with a 'const' one
- 'rbtree' module: reduce unsafe blocks on pointer derefs
- 'transmute' module: implement 'FromBytes' and 'AsBytes' for
inhabited ZSTs, and use it in Nova
- More treewide replacements of 'c_str!' with C string literals
'macros' crate:
- Rewrite most procedural macros ('module!', 'concat_idents!',
'#[export]', '#[vtable]', '#[kunit_tests]') to use the 'syn'
parsing library which we introduced last cycle, with better
diagnostics
This also allows to support '#[cfg]' properly in the '#[vtable]'
macro, to support arbitrary types in 'module!' macro (not just an
identifier) and to remove several custom parsing helpers we had
- Use 'quote!' from the recently vendored 'quote' library and remove
our custom one
The vendored one also allows us to avoid quoting '"' and '{}'
inside the template anymore and editors can now highlight it. In
addition, it improves robustness as it eliminates the need for
string quoting and escaping
- Use 'pin_init::zeroed()' to simplify KUnit code
'pin-init' crate:
- Rewrite all procedural macros ('[pin_]init!', '#[pin_data]',
'#[pinned_drop]', 'derive([Maybe]Zeroable)') to use the 'syn'
parsing library which we introduced last cycle, with better
diagnostics
- Implement 'InPlaceWrite' for '&'static mut MaybeUninit<T>'. This
enables users to use external allocation mechanisms such as
'static_cell'
- Support tuple structs in 'derive([Maybe]Zeroable)'
- Support attributes on fields in '[pin_]init!' (such as
'#[cfg(...)]')
- Add a '#[default_error(<type>)]' attribute to '[pin_]init!' to
override the default error (when no '? Error' is specified)
- Support packed structs in '[pin_]init!' with
'#[disable_initialized_field_access]'
- Remove 'try_[pin_]init!' in favor of merging their feature with
'[pin_]init!'. Update the kernel's own 'try_[pin_]init!' macros to
use the 'default_error' attribute
- Correct 'T: Sized' bounds to 'T: ?Sized' in the generated
'PinnedDrop' check by '#[pin_data]'
Documentation:
- Conclude the Rust experiment
MAINTAINERS:
- Add "RUST [RUST-ANALYZER]" entry for the rust-analyzer support.
Tamir and Jesung will take care of it. They have both been active
around it for a while. The new tree will flow through the Rust one
- Add Gary as maintainer for "RUST [PIN-INIT]"
- Update Boqun and Tamir emails to their kernel.org accounts
And a few other cleanups and improvements"
* tag 'rust-6.20-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (59 commits)
rust: safety: introduce `unsafe_precondition_assert!` macro
rust: add `impl_flags!` macro for defining common bitflag operations
rust: print: Add pr_*_once macros
rust: bug: Support DEBUG_BUGVERBOSE_DETAILED option
rust: print: Add support for calling a function exactly once
rust: kbuild: deduplicate pin-init flags
gpu: nova-core: remove imports available via prelude
rust: clk: replace `kernel::c_str!` with C-Strings
MAINTAINERS: Update my email address to @kernel.org
rust: macros: support `#[cfg]` properly in `#[vtable]` macro.
rust: kunit: use `pin_init::zeroed` instead of custom null value
rust: macros: rearrange `#[doc(hidden)]` in `module!` macro
rust: macros: allow arbitrary types to be used in `module!` macro
rust: macros: convert `#[kunit_tests]` macro to use `syn`
rust: macros: convert `concat_idents!` to use `syn`
rust: macros: convert `#[export]` to use `syn`
rust: macros: use `quote!` for `module!` macro
rust: macros: use `syn` to parse `module!` macro
rust: macros: convert `#[vtable]` macro to use `syn`
rust: macros: use `quote!` from vendored crate
...
97 lines
3.5 KiB
Rust
97 lines
3.5 KiB
Rust
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
use std::collections::BTreeSet;
|
|
|
|
use proc_macro2::{Ident, TokenStream, TokenTree};
|
|
use quote::quote_spanned;
|
|
|
|
/// Please see [`crate::fmt`] for documentation.
|
|
pub(crate) fn fmt(input: TokenStream) -> TokenStream {
|
|
let mut input = input.into_iter();
|
|
|
|
let first_opt = input.next();
|
|
let first_owned_str;
|
|
let mut names = BTreeSet::new();
|
|
let first_span = {
|
|
let Some((mut first_str, first_span)) = (match first_opt.as_ref() {
|
|
Some(TokenTree::Literal(first_lit)) => {
|
|
first_owned_str = first_lit.to_string();
|
|
Some(first_owned_str.as_str()).and_then(|first| {
|
|
let first = first.strip_prefix('"')?;
|
|
let first = first.strip_suffix('"')?;
|
|
Some((first, first_lit.span()))
|
|
})
|
|
}
|
|
_ => None,
|
|
}) else {
|
|
return first_opt.into_iter().chain(input).collect();
|
|
};
|
|
|
|
// Parse `identifier`s from the format string.
|
|
//
|
|
// See https://doc.rust-lang.org/std/fmt/index.html#syntax.
|
|
while let Some((_, rest)) = first_str.split_once('{') {
|
|
first_str = rest;
|
|
if let Some(rest) = first_str.strip_prefix('{') {
|
|
first_str = rest;
|
|
continue;
|
|
}
|
|
if let Some((name, rest)) = first_str.split_once('}') {
|
|
first_str = rest;
|
|
let name = name.split_once(':').map_or(name, |(name, _)| name);
|
|
if !name.is_empty() && !name.chars().all(|c| c.is_ascii_digit()) {
|
|
names.insert(name);
|
|
}
|
|
}
|
|
}
|
|
first_span
|
|
};
|
|
|
|
let adapter = quote_spanned!(first_span => ::kernel::fmt::Adapter);
|
|
|
|
let mut args = TokenStream::from_iter(first_opt);
|
|
{
|
|
let mut flush = |args: &mut TokenStream, current: &mut TokenStream| {
|
|
let current = std::mem::take(current);
|
|
if !current.is_empty() {
|
|
let (lhs, rhs) = (|| {
|
|
let mut current = current.into_iter();
|
|
let mut acc = TokenStream::new();
|
|
while let Some(tt) = current.next() {
|
|
// Split on `=` only once to handle cases like `a = b = c`.
|
|
if matches!(&tt, TokenTree::Punct(p) if p.as_char() == '=') {
|
|
names.remove(acc.to_string().as_str());
|
|
// Include the `=` itself to keep the handling below uniform.
|
|
acc.extend([tt]);
|
|
return (Some(acc), current.collect::<TokenStream>());
|
|
}
|
|
acc.extend([tt]);
|
|
}
|
|
(None, acc)
|
|
})();
|
|
args.extend(quote_spanned!(first_span => #lhs #adapter(&(#rhs))));
|
|
}
|
|
};
|
|
|
|
let mut current = TokenStream::new();
|
|
for tt in input {
|
|
match &tt {
|
|
TokenTree::Punct(p) if p.as_char() == ',' => {
|
|
flush(&mut args, &mut current);
|
|
&mut args
|
|
}
|
|
_ => &mut current,
|
|
}
|
|
.extend([tt]);
|
|
}
|
|
flush(&mut args, &mut current);
|
|
}
|
|
|
|
for name in names {
|
|
let name = Ident::new(name, first_span);
|
|
args.extend(quote_spanned!(first_span => , #name = #adapter(&#name)));
|
|
}
|
|
|
|
quote_spanned!(first_span => ::core::format_args!(#args))
|
|
}
|