diff options
Diffstat (limited to 'rust/macros')
| -rw-r--r-- | rust/macros/helpers.rs | 17 | ||||
| -rw-r--r-- | rust/macros/kunit.rs | 67 | ||||
| -rw-r--r-- | rust/macros/lib.rs | 15 | ||||
| -rw-r--r-- | rust/macros/module.rs | 66 | ||||
| -rw-r--r-- | rust/macros/paste.rs | 2 | 
5 files changed, 103 insertions, 64 deletions
| diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs index a3ee27e29a6f..e2602be402c1 100644 --- a/rust/macros/helpers.rs +++ b/rust/macros/helpers.rs @@ -86,3 +86,20 @@ pub(crate) fn function_name(input: TokenStream) -> Option<Ident> {      }      None  } + +pub(crate) fn file() -> String { +    #[cfg(not(CONFIG_RUSTC_HAS_SPAN_FILE))] +    { +        proc_macro::Span::call_site() +            .source_file() +            .path() +            .to_string_lossy() +            .into_owned() +    } + +    #[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 4f553ecf40c0..81d18149a0cc 100644 --- a/rust/macros/kunit.rs +++ b/rust/macros/kunit.rs @@ -15,10 +15,7 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {      }      if attr.len() > 255 { -        panic!( -            "The test suite name `{}` exceeds the maximum length of 255 bytes", -            attr -        ) +        panic!("The test suite name `{attr}` exceeds the maximum length of 255 bytes")      }      let mut tokens: Vec<_> = ts.into_iter().collect(); @@ -60,8 +57,8 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {          }      } -    // Add `#[cfg(CONFIG_KUNIT)]` before the module declaration. -    let config_kunit = "#[cfg(CONFIG_KUNIT)]".to_owned().parse().unwrap(); +    // Add `#[cfg(CONFIG_KUNIT="y")]` before the module declaration. +    let config_kunit = "#[cfg(CONFIG_KUNIT=\"y\")]".to_owned().parse().unwrap();      tokens.insert(          0,          TokenTree::Group(Group::new(Delimiter::None, config_kunit)), @@ -88,30 +85,52 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {      // Looks like:      //      // ``` -    // unsafe extern "C" fn kunit_rust_wrapper_foo(_test: *mut kernel::bindings::kunit) { foo(); } -    // unsafe extern "C" fn kunit_rust_wrapper_bar(_test: *mut kernel::bindings::kunit) { bar(); } +    // unsafe extern "C" fn kunit_rust_wrapper_foo(_test: *mut ::kernel::bindings::kunit) { foo(); } +    // unsafe extern "C" fn kunit_rust_wrapper_bar(_test: *mut ::kernel::bindings::kunit) { bar(); }      // -    // static mut TEST_CASES: [kernel::bindings::kunit_case; 3] = [ -    //     kernel::kunit::kunit_case(kernel::c_str!("foo"), kunit_rust_wrapper_foo), -    //     kernel::kunit::kunit_case(kernel::c_str!("bar"), kunit_rust_wrapper_bar), -    //     kernel::kunit::kunit_case_null(), +    // static mut TEST_CASES: [::kernel::bindings::kunit_case; 3] = [ +    //     ::kernel::kunit::kunit_case(::kernel::c_str!("foo"), kunit_rust_wrapper_foo), +    //     ::kernel::kunit::kunit_case(::kernel::c_str!("bar"), kunit_rust_wrapper_bar), +    //     ::kernel::kunit::kunit_case_null(),      // ];      // -    // kernel::kunit_unsafe_test_suite!(kunit_test_suit_name, TEST_CASES); +    // ::kernel::kunit_unsafe_test_suite!(kunit_test_suit_name, TEST_CASES);      // ```      let mut kunit_macros = "".to_owned();      let mut test_cases = "".to_owned(); +    let mut assert_macros = "".to_owned(); +    let path = crate::helpers::file();      for test in &tests { -        let kunit_wrapper_fn_name = format!("kunit_rust_wrapper_{}", test); +        let kunit_wrapper_fn_name = format!("kunit_rust_wrapper_{test}"); +        // An extra `use` is used here to reduce the length of the message.          let kunit_wrapper = format!( -            "unsafe extern \"C\" fn {}(_test: *mut kernel::bindings::kunit) {{ {}(); }}", -            kunit_wrapper_fn_name, test +            "unsafe extern \"C\" fn {kunit_wrapper_fn_name}(_test: *mut ::kernel::bindings::kunit) {{ use ::kernel::kunit::is_test_result_ok; assert!(is_test_result_ok({test}())); }}",          );          writeln!(kunit_macros, "{kunit_wrapper}").unwrap();          writeln!(              test_cases, -            "    kernel::kunit::kunit_case(kernel::c_str!(\"{}\"), {}),", -            test, kunit_wrapper_fn_name +            "    ::kernel::kunit::kunit_case(::kernel::c_str!(\"{test}\"), {kunit_wrapper_fn_name})," +        ) +        .unwrap(); +        writeln!( +            assert_macros, +            r#" +/// Overrides the usual [`assert!`] macro with one that calls KUnit instead. +#[allow(unused)] +macro_rules! assert {{ +    ($cond:expr $(,)?) => {{{{ +        kernel::kunit_assert!("{test}", "{path}", 0, $cond); +    }}}} +}} + +/// Overrides the usual [`assert_eq!`] macro with one that calls KUnit instead. +#[allow(unused)] +macro_rules! assert_eq {{ +    ($left:expr, $right:expr $(,)?) => {{{{ +        kernel::kunit_assert_eq!("{test}", "{path}", 0, $left, $right); +    }}}} +}} +        "#          )          .unwrap();      } @@ -119,14 +138,14 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {      writeln!(kunit_macros).unwrap();      writeln!(          kunit_macros, -        "static mut TEST_CASES: [kernel::bindings::kunit_case; {}] = [\n{test_cases}    kernel::kunit::kunit_case_null(),\n];", +        "static mut TEST_CASES: [::kernel::bindings::kunit_case; {}] = [\n{test_cases}    ::kernel::kunit::kunit_case_null(),\n];",          tests.len() + 1      )      .unwrap();      writeln!(          kunit_macros, -        "kernel::kunit_unsafe_test_suite!({attr}, TEST_CASES);" +        "::kernel::kunit_unsafe_test_suite!({attr}, TEST_CASES);"      )      .unwrap(); @@ -152,10 +171,12 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {          }      } -    let mut new_body = TokenStream::from_iter(new_body); -    new_body.extend::<TokenStream>(kunit_macros.parse().unwrap()); +    let mut final_body = TokenStream::new(); +    final_body.extend::<TokenStream>(assert_macros.parse().unwrap()); +    final_body.extend(new_body); +    final_body.extend::<TokenStream>(kunit_macros.parse().unwrap()); -    tokens.push(TokenTree::Group(Group::new(Delimiter::Brace, new_body))); +    tokens.push(TokenTree::Group(Group::new(Delimiter::Brace, final_body)));      tokens.into_iter().collect()  } diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 9acaa68c974e..fa847cf3a9b5 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -6,6 +6,11 @@  // and thus add a dependency on `include/config/RUSTC_VERSION_TEXT`, which is  // touched by Kconfig when the version string from the compiler changes. +// Stable since Rust 1.88.0 under a different name, `proc_macro_span_file`, +// which was added in Rust 1.88.0. This is why `cfg_attr` is used here, i.e. +// to avoid depending on the full `proc_macro_span` on Rust >= 1.88.0. +#![cfg_attr(not(CONFIG_RUSTC_HAS_SPAN_FILE), feature(proc_macro_span))] +  #[macro_use]  mod quote;  mod concat_idents; @@ -263,7 +268,7 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream {  /// literals (lifetimes and documentation strings are not supported). There is a difference in  /// supported modifiers as well.  /// -/// # Example +/// # Examples  ///  /// ```  /// # const binder_driver_return_protocol_BR_OK: u32 = 0; @@ -283,7 +288,7 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream {  /// # const binder_driver_return_protocol_BR_FAILED_REPLY: u32 = 14;  /// macro_rules! pub_no_prefix {  ///     ($prefix:ident, $($newname:ident),+) => { -///         kernel::macros::paste! { +///         ::kernel::macros::paste! {  ///             $(pub(crate) const $newname: u32 = [<$prefix $newname>];)+  ///         }  ///     }; @@ -340,7 +345,7 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream {  /// # const binder_driver_return_protocol_BR_FAILED_REPLY: u32 = 14;  /// macro_rules! pub_no_prefix {  ///     ($prefix:ident, $($newname:ident),+) => { -///         kernel::macros::paste! { +///         ::kernel::macros::paste! {  ///             $(pub(crate) const fn [<$newname:lower:span>]() -> u32 { [<$prefix $newname:span>] })+  ///         }  ///     }; @@ -375,7 +380,7 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream {  /// ```  /// macro_rules! create_numbered_fn {  ///     ($name:literal, $val:literal) => { -///         kernel::macros::paste! { +///         ::kernel::macros::paste! {  ///             fn [<some_ $name _fn $val>]() -> u32 { $val }  ///         }  ///     }; @@ -402,7 +407,7 @@ pub fn paste(input: TokenStream) -> TokenStream {  /// # Examples  ///  /// ```ignore -/// # use macros::kunit_tests; +/// # use kernel::prelude::*;  /// #[kunit_tests(kunit_test_suit_name)]  /// mod tests {  ///     #[test] diff --git a/rust/macros/module.rs b/rust/macros/module.rs index a9418fbc9b44..2ddd2eeb2852 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -48,7 +48,7 @@ impl<'a> ModInfoBuilder<'a> {              )          } else {              // Loadable modules' modinfo strings go as-is. -            format!("{field}={content}\0", field = field, content = content) +            format!("{field}={content}\0")          };          write!( @@ -126,10 +126,7 @@ impl ModuleInfo {              };              if seen_keys.contains(&key) { -                panic!( -                    "Duplicated key \"{}\". Keys can only be specified once.", -                    key -                ); +                panic!("Duplicated key \"{key}\". Keys can only be specified once.");              }              assert_eq!(expect_punct(it), ':'); @@ -143,10 +140,7 @@ impl ModuleInfo {                  "license" => info.license = expect_string_ascii(it),                  "alias" => info.alias = Some(expect_string_array(it)),                  "firmware" => info.firmware = Some(expect_string_array(it)), -                _ => panic!( -                    "Unknown key \"{}\". Valid keys are: {:?}.", -                    key, EXPECTED_KEYS -                ), +                _ => panic!("Unknown key \"{key}\". Valid keys are: {EXPECTED_KEYS:?}."),              }              assert_eq!(expect_punct(it), ','); @@ -158,7 +152,7 @@ impl ModuleInfo {          for key in REQUIRED_KEYS {              if !seen_keys.iter().any(|e| e == key) { -                panic!("Missing required key \"{}\".", key); +                panic!("Missing required key \"{key}\".");              }          } @@ -170,10 +164,7 @@ impl ModuleInfo {          }          if seen_keys != ordered_keys { -            panic!( -                "Keys are not ordered as expected. Order them like: {:?}.", -                ordered_keys -            ); +            panic!("Keys are not ordered as expected. Order them like: {ordered_keys:?}.");          }          info @@ -185,7 +176,9 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {      let info = ModuleInfo::parse(&mut it); -    let mut modinfo = ModInfoBuilder::new(info.name.as_ref()); +    // Rust does not allow hyphens in identifiers, use underscore instead. +    let ident = info.name.replace('-', "_"); +    let mut modinfo = ModInfoBuilder::new(ident.as_ref());      if let Some(author) = info.author {          modinfo.emit("author", &author);      } @@ -224,24 +217,24 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {              // SAFETY: `__this_module` is constructed by the kernel at load time and will not be              // freed until the module is unloaded.              #[cfg(MODULE)] -            static THIS_MODULE: kernel::ThisModule = unsafe {{ +            static THIS_MODULE: ::kernel::ThisModule = unsafe {{                  extern \"C\" {{ -                    static __this_module: kernel::types::Opaque<kernel::bindings::module>; +                    static __this_module: ::kernel::types::Opaque<::kernel::bindings::module>;                  }} -                kernel::ThisModule::from_ptr(__this_module.get()) +                ::kernel::ThisModule::from_ptr(__this_module.get())              }};              #[cfg(not(MODULE))] -            static THIS_MODULE: kernel::ThisModule = unsafe {{ -                kernel::ThisModule::from_ptr(core::ptr::null_mut()) +            static THIS_MODULE: ::kernel::ThisModule = unsafe {{ +                ::kernel::ThisModule::from_ptr(::core::ptr::null_mut())              }};              /// The `LocalModule` type is the type of the module created by `module!`,              /// `module_pci_driver!`, `module_platform_driver!`, etc.              type LocalModule = {type_}; -            impl kernel::ModuleMetadata for {type_} {{ -                const NAME: &'static kernel::str::CStr = kernel::c_str!(\"{name}\"); +            impl ::kernel::ModuleMetadata for {type_} {{ +                const NAME: &'static ::kernel::str::CStr = ::kernel::c_str!(\"{name}\");              }}              // Double nested modules, since then nobody can access the public items inside. @@ -259,8 +252,8 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {                      #[used]                      static __IS_RUST_MODULE: () = (); -                    static mut __MOD: core::mem::MaybeUninit<{type_}> = -                        core::mem::MaybeUninit::uninit(); +                    static mut __MOD: ::core::mem::MaybeUninit<{type_}> = +                        ::core::mem::MaybeUninit::uninit();                      // Loadable modules need to export the `{{init,cleanup}}_module` identifiers.                      /// # Safety @@ -271,7 +264,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {                      #[doc(hidden)]                      #[no_mangle]                      #[link_section = \".init.text\"] -                    pub unsafe extern \"C\" fn init_module() -> kernel::ffi::c_int {{ +                    pub unsafe extern \"C\" fn init_module() -> ::kernel::ffi::c_int {{                          // SAFETY: This function is inaccessible to the outside due to the double                          // module wrapping it. It is called exactly once by the C side via its                          // unique name. @@ -287,6 +280,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {                      #[cfg(MODULE)]                      #[doc(hidden)]                      #[no_mangle] +                    #[link_section = \".exit.text\"]                      pub extern \"C\" fn cleanup_module() {{                          // SAFETY:                          // - This function is inaccessible to the outside due to the double @@ -310,14 +304,15 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {                      #[doc(hidden)]                      #[link_section = \"{initcall_section}\"]                      #[used] -                    pub static __{name}_initcall: extern \"C\" fn() -> kernel::ffi::c_int = __{name}_init; +                    pub static __{ident}_initcall: extern \"C\" fn() -> +                        ::kernel::ffi::c_int = __{ident}_init;                      #[cfg(not(MODULE))]                      #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)] -                    core::arch::global_asm!( +                    ::core::arch::global_asm!(                          r#\".section \"{initcall_section}\", \"a\" -                        __{name}_initcall: -                            .long   __{name}_init - . +                        __{ident}_initcall: +                            .long   __{ident}_init - .                              .previous                          \"#                      ); @@ -325,7 +320,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {                      #[cfg(not(MODULE))]                      #[doc(hidden)]                      #[no_mangle] -                    pub extern \"C\" fn __{name}_init() -> kernel::ffi::c_int {{ +                    pub extern \"C\" fn __{ident}_init() -> ::kernel::ffi::c_int {{                          // SAFETY: This function is inaccessible to the outside due to the double                          // module wrapping it. It is called exactly once by the C side via its                          // placement above in the initcall section. @@ -335,22 +330,22 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {                      #[cfg(not(MODULE))]                      #[doc(hidden)]                      #[no_mangle] -                    pub extern \"C\" fn __{name}_exit() {{ +                    pub extern \"C\" fn __{ident}_exit() {{                          // SAFETY:                          // - This function is inaccessible to the outside due to the double                          //   module wrapping it. It is called exactly once by the C side via its                          //   unique name, -                        // - furthermore it is only called after `__{name}_init` has returned `0` -                        //   (which delegates to `__init`). +                        // - furthermore it is only called after `__{ident}_init` has +                        //   returned `0` (which delegates to `__init`).                          unsafe {{ __exit() }}                      }}                      /// # Safety                      ///                      /// This function must only be called once. -                    unsafe fn __init() -> kernel::ffi::c_int {{ +                    unsafe fn __init() -> ::kernel::ffi::c_int {{                          let initer = -                            <{type_} as kernel::InPlaceModule>::init(&super::super::THIS_MODULE); +                            <{type_} as ::kernel::InPlaceModule>::init(&super::super::THIS_MODULE);                          // SAFETY: No data race, since `__MOD` can only be accessed by this module                          // and there only `__init` and `__exit` access it. These functions are only                          // called once and `__exit` cannot be called before or during `__init`. @@ -381,6 +376,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {          ",          type_ = info.type_,          name = info.name, +        ident = ident,          modinfo = modinfo.buffer,          initcall_section = ".initcall6.init"      ) diff --git a/rust/macros/paste.rs b/rust/macros/paste.rs index 6529a387673f..cce712d19855 100644 --- a/rust/macros/paste.rs +++ b/rust/macros/paste.rs @@ -50,7 +50,7 @@ fn concat_helper(tokens: &[TokenTree]) -> Vec<(String, Span)> {                  let tokens = group.stream().into_iter().collect::<Vec<TokenTree>>();                  segments.append(&mut concat_helper(tokens.as_slice()));              } -            token => panic!("unexpected token in paste segments: {:?}", token), +            token => panic!("unexpected token in paste segments: {token:?}"),          };      } | 
