Skip to content

Commit 1f9ed17

Browse files
committed
rust: start using the #[expect(...)] attribute
In Rust, it is possible to `allow` particular warnings (diagnostics, lints) locally, making the compiler ignore instances of a given warning within a given function, module, block, etc. It is similar to `#pragma GCC diagnostic push` + `ignored` + `pop` in C: #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" static void f(void) {} #pragma GCC diagnostic pop But way less verbose: #[allow(dead_code)] fn f() {} By that virtue, it makes it possible to comfortably enable more diagnostics by default (i.e. outside `W=` levels) that may have some false positives but that are otherwise quite useful to keep enabled to catch potential mistakes. The `#[expect(...)]` attribute [1] takes this further, and makes the compiler warn if the diagnostic was _not_ produced. For instance, the following will ensure that, when `f()` is called somewhere, we will have to remove the attribute: #[expect(dead_code)] fn f() {} If we do not, we get a warning from the compiler: warning: this lint expectation is unfulfilled --> x.rs:3:10 | 3 | #[expect(dead_code)] | ^^^^^^^^^ | = note: `#[warn(unfulfilled_lint_expectations)]` on by default This means that `expect`s do not get forgotten when they are not needed. See the next commit for more details, nuances on its usage and documentation on the feature. The attribute requires the `lint_reasons` [2] unstable feature, but it is becoming stable in 1.81.0 (to be released on 2024-09-05) and it has already been useful to clean things up in this patch series, finding cases where the `allow`s should not have been there. Thus, enable `lint_reasons` and convert some of our `allow`s to `expect`s where possible. This feature was also an example of the ongoing collaboration between Rust and the kernel -- we tested it in the kernel early on and found an issue that was quickly resolved [3]. Cc: Fridtjof Stoldt <[email protected]> Cc: Urgau <[email protected]> Link: https://rust-lang.github.io/rfcs/2383-lint-reasons.html#expect-lint-attribute [1] Link: rust-lang/rust#54503 [2] Link: rust-lang/rust#114557 [3] Reviewed-by: Alice Ryhl <[email protected]> Reviewed-by: Trevor Gross <[email protected]> Tested-by: Gary Guo <[email protected]> Reviewed-by: Gary Guo <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Miguel Ojeda <[email protected]>
1 parent 139d396 commit 1f9ed17

File tree

11 files changed

+31
-30
lines changed

11 files changed

+31
-30
lines changed

rust/kernel/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ impl Error {
133133
}
134134

135135
/// Returns the error encoded as a pointer.
136-
#[allow(dead_code)]
136+
#[expect(dead_code)]
137137
pub(crate) fn to_ptr<T>(self) -> *mut T {
138138
#[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))]
139139
// SAFETY: `self.0` is a valid error due to its invariant.

rust/kernel/init.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
//! that you need to write `<-` instead of `:` for fields that you want to initialize in-place.
3636
//!
3737
//! ```rust
38-
//! # #![allow(clippy::disallowed_names)]
38+
//! # #![expect(clippy::disallowed_names)]
3939
//! use kernel::sync::{new_mutex, Mutex};
4040
//! # use core::pin::Pin;
4141
//! #[pin_data]
@@ -55,7 +55,7 @@
5555
//! (or just the stack) to actually initialize a `Foo`:
5656
//!
5757
//! ```rust
58-
//! # #![allow(clippy::disallowed_names)]
58+
//! # #![expect(clippy::disallowed_names)]
5959
//! # use kernel::sync::{new_mutex, Mutex};
6060
//! # use core::pin::Pin;
6161
//! # #[pin_data]
@@ -120,12 +120,12 @@
120120
//! `slot` gets called.
121121
//!
122122
//! ```rust
123-
//! # #![allow(unreachable_pub, clippy::disallowed_names)]
123+
//! # #![expect(unreachable_pub, clippy::disallowed_names)]
124124
//! use kernel::{init, types::Opaque};
125125
//! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin};
126126
//! # mod bindings {
127-
//! # #![allow(non_camel_case_types)]
128-
//! # #![allow(clippy::missing_safety_doc)]
127+
//! # #![expect(non_camel_case_types)]
128+
//! # #![expect(clippy::missing_safety_doc)]
129129
//! # pub struct foo;
130130
//! # pub unsafe fn init_foo(_ptr: *mut foo) {}
131131
//! # pub unsafe fn destroy_foo(_ptr: *mut foo) {}
@@ -238,7 +238,7 @@ pub mod macros;
238238
/// # Examples
239239
///
240240
/// ```rust
241-
/// # #![allow(clippy::disallowed_names)]
241+
/// # #![expect(clippy::disallowed_names)]
242242
/// # use kernel::{init, macros::pin_data, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex};
243243
/// # use core::pin::Pin;
244244
/// #[pin_data]
@@ -290,7 +290,7 @@ macro_rules! stack_pin_init {
290290
/// # Examples
291291
///
292292
/// ```rust,ignore
293-
/// # #![allow(clippy::disallowed_names)]
293+
/// # #![expect(clippy::disallowed_names)]
294294
/// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex};
295295
/// # use macros::pin_data;
296296
/// # use core::{alloc::AllocError, pin::Pin};
@@ -316,7 +316,7 @@ macro_rules! stack_pin_init {
316316
/// ```
317317
///
318318
/// ```rust,ignore
319-
/// # #![allow(clippy::disallowed_names)]
319+
/// # #![expect(clippy::disallowed_names)]
320320
/// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex};
321321
/// # use macros::pin_data;
322322
/// # use core::{alloc::AllocError, pin::Pin};
@@ -438,7 +438,7 @@ macro_rules! stack_try_pin_init {
438438
/// Users of `Foo` can now create it like this:
439439
///
440440
/// ```rust
441-
/// # #![allow(clippy::disallowed_names)]
441+
/// # #![expect(clippy::disallowed_names)]
442442
/// # use kernel::{init, pin_init, macros::pin_data, init::*};
443443
/// # use core::pin::Pin;
444444
/// # #[pin_data]
@@ -852,7 +852,7 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
852852
/// # Examples
853853
///
854854
/// ```rust
855-
/// # #![allow(clippy::disallowed_names)]
855+
/// # #![expect(clippy::disallowed_names)]
856856
/// use kernel::{types::Opaque, init::pin_init_from_closure};
857857
/// #[repr(C)]
858858
/// struct RawFoo([u8; 16]);
@@ -964,7 +964,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
964964
/// # Examples
965965
///
966966
/// ```rust
967-
/// # #![allow(clippy::disallowed_names)]
967+
/// # #![expect(clippy::disallowed_names)]
968968
/// use kernel::{types::Opaque, init::{self, init_from_closure}};
969969
/// struct Foo {
970970
/// buf: [u8; 1_000_000],

rust/kernel/init/__internal.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ where
5454
pub unsafe trait HasPinData {
5555
type PinData: PinData;
5656

57-
#[allow(clippy::missing_safety_doc)]
57+
#[expect(clippy::missing_safety_doc)]
5858
unsafe fn __pin_data() -> Self::PinData;
5959
}
6060

@@ -84,7 +84,7 @@ pub unsafe trait PinData: Copy {
8484
pub unsafe trait HasInitData {
8585
type InitData: InitData;
8686

87-
#[allow(clippy::missing_safety_doc)]
87+
#[expect(clippy::missing_safety_doc)]
8888
unsafe fn __init_data() -> Self::InitData;
8989
}
9090

rust/kernel/init/macros.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -182,13 +182,13 @@
182182
//! // Normally `Drop` bounds do not have the correct semantics, but for this purpose they do
183183
//! // (normally people want to know if a type has any kind of drop glue at all, here we want
184184
//! // to know if it has any kind of custom drop glue, which is exactly what this bound does).
185-
//! #[allow(drop_bounds)]
185+
//! #[expect(drop_bounds)]
186186
//! impl<T: ::core::ops::Drop> MustNotImplDrop for T {}
187187
//! impl<T> MustNotImplDrop for Bar<T> {}
188188
//! // Here comes a convenience check, if one implemented `PinnedDrop`, but forgot to add it to
189189
//! // `#[pin_data]`, then this will error with the same mechanic as above, this is not needed
190190
//! // for safety, but a good sanity check, since no normal code calls `PinnedDrop::drop`.
191-
//! #[allow(non_camel_case_types)]
191+
//! #[expect(non_camel_case_types)]
192192
//! trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {}
193193
//! impl<
194194
//! T: ::kernel::init::PinnedDrop,
@@ -925,14 +925,14 @@ macro_rules! __pin_data {
925925
// `Drop`. Additionally we will implement this trait for the struct leading to a conflict,
926926
// if it also implements `Drop`
927927
trait MustNotImplDrop {}
928-
#[allow(drop_bounds)]
928+
#[expect(drop_bounds)]
929929
impl<T: ::core::ops::Drop> MustNotImplDrop for T {}
930930
impl<$($impl_generics)*> MustNotImplDrop for $name<$($ty_generics)*>
931931
where $($whr)* {}
932932
// We also take care to prevent users from writing a useless `PinnedDrop` implementation.
933933
// They might implement `PinnedDrop` correctly for the struct, but forget to give
934934
// `PinnedDrop` as the parameter to `#[pin_data]`.
935-
#[allow(non_camel_case_types)]
935+
#[expect(non_camel_case_types)]
936936
trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {}
937937
impl<T: $crate::init::PinnedDrop>
938938
UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {}
@@ -989,7 +989,7 @@ macro_rules! __pin_data {
989989
//
990990
// The functions are `unsafe` to prevent accidentally calling them.
991991
#[allow(dead_code)]
992-
#[allow(clippy::missing_safety_doc)]
992+
#[expect(clippy::missing_safety_doc)]
993993
impl<$($impl_generics)*> $pin_data<$($ty_generics)*>
994994
where $($whr)*
995995
{

rust/kernel/ioctl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//!
55
//! C header: [`include/asm-generic/ioctl.h`](srctree/include/asm-generic/ioctl.h)
66
7-
#![allow(non_snake_case)]
7+
#![expect(non_snake_case)]
88

99
use crate::build_assert;
1010

rust/kernel/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#![no_std]
1515
#![feature(coerce_unsized)]
1616
#![feature(dispatch_from_dyn)]
17+
#![feature(lint_reasons)]
1718
#![feature(new_uninit)]
1819
#![feature(receiver_trait)]
1920
#![feature(unsize)]

rust/kernel/list/arc_field.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ impl<T, const ID: u64> ListArcField<T, ID> {
5656
///
5757
/// The caller must have mutable access to the `ListArc<ID>` containing the struct with this
5858
/// field for the duration of the returned reference.
59-
#[allow(clippy::mut_from_ref)]
59+
#[expect(clippy::mut_from_ref)]
6060
pub unsafe fn assert_mut(&self) -> &mut T {
6161
// SAFETY: The caller has exclusive access to the `ListArc`, so they also have exclusive
6262
// access to this field.

rust/kernel/print.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use core::{
1414
use crate::str::RawFormatter;
1515

1616
// Called from `vsprintf` with format specifier `%pA`.
17-
#[allow(clippy::missing_safety_doc)]
17+
#[expect(clippy::missing_safety_doc)]
1818
#[no_mangle]
1919
unsafe extern "C" fn rust_fmt_argument(
2020
buf: *mut c_char,
@@ -140,7 +140,7 @@ pub fn call_printk_cont(args: fmt::Arguments<'_>) {
140140
#[doc(hidden)]
141141
#[cfg(not(testlib))]
142142
#[macro_export]
143-
#[allow(clippy::crate_in_macro_def)]
143+
#[expect(clippy::crate_in_macro_def)]
144144
macro_rules! print_macro (
145145
// The non-continuation cases (most of them, e.g. `INFO`).
146146
($format_string:path, false, $($arg:tt)+) => (

rust/kernel/std_vendor.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
///
1717
/// ```rust
1818
/// let a = 2;
19-
/// # #[allow(clippy::disallowed_macros)]
19+
/// # #[expect(clippy::disallowed_macros)]
2020
/// let b = dbg!(a * 2) + 1;
2121
/// // ^-- prints: [src/main.rs:2] a * 2 = 4
2222
/// assert_eq!(b, 5);
@@ -54,7 +54,7 @@
5454
/// With a method call:
5555
///
5656
/// ```rust
57-
/// # #[allow(clippy::disallowed_macros)]
57+
/// # #[expect(clippy::disallowed_macros)]
5858
/// fn foo(n: usize) {
5959
/// if dbg!(n.checked_sub(4)).is_some() {
6060
/// // ...
@@ -73,7 +73,7 @@
7373
/// Naive factorial implementation:
7474
///
7575
/// ```rust
76-
/// # #[allow(clippy::disallowed_macros)]
76+
/// # #[expect(clippy::disallowed_macros)]
7777
/// # {
7878
/// fn factorial(n: u32) -> u32 {
7979
/// if dbg!(n <= 1) {
@@ -120,7 +120,7 @@
120120
/// a tuple (and return it, too):
121121
///
122122
/// ```
123-
/// # #![allow(clippy::disallowed_macros)]
123+
/// # #![expect(clippy::disallowed_macros)]
124124
/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
125125
/// ```
126126
///
@@ -129,7 +129,7 @@
129129
/// invocations. You can use a 1-tuple directly if you need one:
130130
///
131131
/// ```
132-
/// # #[allow(clippy::disallowed_macros)]
132+
/// # #[expect(clippy::disallowed_macros)]
133133
/// # {
134134
/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
135135
/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple

samples/rust/rust_print.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ module! {
1515

1616
struct RustPrint;
1717

18-
#[allow(clippy::disallowed_macros)]
18+
#[expect(clippy::disallowed_macros)]
1919
fn arc_print() -> Result {
2020
use kernel::sync::*;
2121

scripts/Makefile.build

+1-1
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ $(obj)/%.lst: $(obj)/%.c FORCE
248248
# Compile Rust sources (.rs)
249249
# ---------------------------------------------------------------------------
250250

251-
rust_allowed_features := new_uninit
251+
rust_allowed_features := lint_reasons,new_uninit
252252

253253
# `--out-dir` is required to avoid temporaries being created by `rustc` in the
254254
# current working directory, which may be not accessible in the out-of-tree

0 commit comments

Comments
 (0)