diff options
Diffstat (limited to 'rust/macros')
| -rw-r--r-- | rust/macros/helpers.rs | 122 | ||||
| -rw-r--r-- | rust/macros/lib.rs | 12 | ||||
| -rw-r--r-- | rust/macros/module.rs | 190 | ||||
| -rw-r--r-- | rust/macros/pin_data.rs | 2 | ||||
| -rw-r--r-- | rust/macros/zeroable.rs | 1 | 
5 files changed, 210 insertions, 117 deletions
diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs index afb0f2e3a36a..563dcd2b7ace 100644 --- a/rust/macros/helpers.rs +++ b/rust/macros/helpers.rs @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 -use proc_macro::{token_stream, Group, Punct, Spacing, TokenStream, TokenTree}; +use proc_macro::{token_stream, Group, TokenStream, TokenTree};  pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {      if let Some(TokenTree::Ident(ident)) = it.next() { @@ -70,8 +70,40 @@ pub(crate) fn expect_end(it: &mut token_stream::IntoIter) {      }  } +/// Parsed generics. +/// +/// See the field documentation for an explanation what each of the fields represents. +/// +/// # Examples +/// +/// ```rust,ignore +/// # let input = todo!(); +/// let (Generics { decl_generics, impl_generics, ty_generics }, rest) = parse_generics(input); +/// quote! { +///     struct Foo<$($decl_generics)*> { +///         // ... +///     } +/// +///     impl<$impl_generics> Foo<$ty_generics> { +///         fn foo() { +///             // ... +///         } +///     } +/// } +/// ```  pub(crate) struct Generics { +    /// The generics with bounds and default values (e.g. `T: Clone, const N: usize = 0`). +    /// +    /// Use this on type definitions e.g. `struct Foo<$decl_generics> ...` (or `union`/`enum`). +    pub(crate) decl_generics: Vec<TokenTree>, +    /// The generics with bounds (e.g. `T: Clone, const N: usize`). +    /// +    /// Use this on `impl` blocks e.g. `impl<$impl_generics> Trait for ...`.      pub(crate) impl_generics: Vec<TokenTree>, +    /// The generics without bounds and without default values (e.g. `T, N`). +    /// +    /// Use this when you use the type that is declared with these generics e.g. +    /// `Foo<$ty_generics>`.      pub(crate) ty_generics: Vec<TokenTree>,  } @@ -79,6 +111,8 @@ pub(crate) struct Generics {  ///  /// The generics are not present in the rest, but a where clause might remain.  pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) { +    // The generics with bounds and default values. +    let mut decl_generics = vec![];      // `impl_generics`, the declared generics with their bounds.      let mut impl_generics = vec![];      // Only the names of the generics, without any bounds. @@ -90,10 +124,17 @@ pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) {      let mut toks = input.into_iter();      // If we are at the beginning of a generic parameter.      let mut at_start = true; -    for tt in &mut toks { +    let mut skip_until_comma = false; +    while let Some(tt) = toks.next() { +        if nesting == 1 && matches!(&tt, TokenTree::Punct(p) if p.as_char() == '>') { +            // Found the end of the generics. +            break; +        } else if nesting >= 1 { +            decl_generics.push(tt.clone()); +        }          match tt.clone() {              TokenTree::Punct(p) if p.as_char() == '<' => { -                if nesting >= 1 { +                if nesting >= 1 && !skip_until_comma {                      // This is inside of the generics and part of some bound.                      impl_generics.push(tt);                  } @@ -105,49 +146,70 @@ pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) {                      break;                  } else {                      nesting -= 1; -                    if nesting >= 1 { +                    if nesting >= 1 && !skip_until_comma {                          // We are still inside of the generics and part of some bound.                          impl_generics.push(tt);                      } -                    if nesting == 0 { -                        break; -                    }                  }              } -            tt => { +            TokenTree::Punct(p) if skip_until_comma && p.as_char() == ',' => {                  if nesting == 1 { -                    // Here depending on the token, it might be a generic variable name. -                    match &tt { -                        // Ignore const. -                        TokenTree::Ident(i) if i.to_string() == "const" => {} -                        TokenTree::Ident(_) if at_start => { -                            ty_generics.push(tt.clone()); -                            // We also already push the `,` token, this makes it easier to append -                            // generics. -                            ty_generics.push(TokenTree::Punct(Punct::new(',', Spacing::Alone))); -                            at_start = false; -                        } -                        TokenTree::Punct(p) if p.as_char() == ',' => at_start = true, -                        // Lifetimes begin with `'`. -                        TokenTree::Punct(p) if p.as_char() == '\'' && at_start => { -                            ty_generics.push(tt.clone()); -                        } -                        _ => {} -                    } -                } -                if nesting >= 1 { +                    impl_generics.push(tt.clone());                      impl_generics.push(tt); -                } else if nesting == 0 { +                    skip_until_comma = false; +                } +            } +            _ if !skip_until_comma => { +                match nesting {                      // If we haven't entered the generics yet, we still want to keep these tokens. -                    rest.push(tt); +                    0 => rest.push(tt), +                    1 => { +                        // Here depending on the token, it might be a generic variable name. +                        match tt.clone() { +                            TokenTree::Ident(i) if at_start && i.to_string() == "const" => { +                                let Some(name) = toks.next() else { +                                    // Parsing error. +                                    break; +                                }; +                                impl_generics.push(tt); +                                impl_generics.push(name.clone()); +                                ty_generics.push(name.clone()); +                                decl_generics.push(name); +                                at_start = false; +                            } +                            TokenTree::Ident(_) if at_start => { +                                impl_generics.push(tt.clone()); +                                ty_generics.push(tt); +                                at_start = false; +                            } +                            TokenTree::Punct(p) if p.as_char() == ',' => { +                                impl_generics.push(tt.clone()); +                                ty_generics.push(tt); +                                at_start = true; +                            } +                            // Lifetimes begin with `'`. +                            TokenTree::Punct(p) if p.as_char() == '\'' && at_start => { +                                impl_generics.push(tt.clone()); +                                ty_generics.push(tt); +                            } +                            // Generics can have default values, we skip these. +                            TokenTree::Punct(p) if p.as_char() == '=' => { +                                skip_until_comma = true; +                            } +                            _ => impl_generics.push(tt), +                        } +                    } +                    _ => impl_generics.push(tt),                  }              } +            _ => {}          }      }      rest.extend(toks);      (          Generics {              impl_generics, +            decl_generics,              ty_generics,          },          rest, diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index f489f3157383..520eae5fd792 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -35,18 +35,6 @@ use proc_macro::TokenStream;  ///     author: "Rust for Linux Contributors",  ///     description: "My very own kernel module!",  ///     license: "GPL", -///     params: { -///        my_i32: i32 { -///            default: 42, -///            permissions: 0o000, -///            description: "Example of i32", -///        }, -///        writeable_i32: i32 { -///            default: 42, -///            permissions: 0o644, -///            description: "Example of i32", -///        }, -///    },  /// }  ///  /// struct MyModule; diff --git a/rust/macros/module.rs b/rust/macros/module.rs index 27979e582e4b..acd0393b5095 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -199,17 +199,6 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {              /// Used by the printing macros, e.g. [`info!`].              const __LOG_PREFIX: &[u8] = b\"{name}\\0\"; -            /// The \"Rust loadable module\" mark. -            // -            // This may be best done another way later on, e.g. as a new modinfo -            // key or a new section. For the moment, keep it simple. -            #[cfg(MODULE)] -            #[doc(hidden)] -            #[used] -            static __IS_RUST_MODULE: () = (); - -            static mut __MOD: Option<{type_}> = None; -              // SAFETY: `__this_module` is constructed by the kernel at load time and will not be              // freed until the module is unloaded.              #[cfg(MODULE)] @@ -221,81 +210,132 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {                  kernel::ThisModule::from_ptr(core::ptr::null_mut())              }}; -            // Loadable modules need to export the `{{init,cleanup}}_module` identifiers. -            /// # Safety -            /// -            /// This function must not be called after module initialization, because it may be -            /// freed after that completes. -            #[cfg(MODULE)] -            #[doc(hidden)] -            #[no_mangle] -            #[link_section = \".init.text\"] -            pub unsafe extern \"C\" fn init_module() -> core::ffi::c_int {{ -                __init() -            }} - -            #[cfg(MODULE)] -            #[doc(hidden)] -            #[no_mangle] -            pub extern \"C\" fn cleanup_module() {{ -                __exit() -            }} +            // Double nested modules, since then nobody can access the public items inside. +            mod __module_init {{ +                mod __module_init {{ +                    use super::super::{type_}; + +                    /// The \"Rust loadable module\" mark. +                    // +                    // This may be best done another way later on, e.g. as a new modinfo +                    // key or a new section. For the moment, keep it simple. +                    #[cfg(MODULE)] +                    #[doc(hidden)] +                    #[used] +                    static __IS_RUST_MODULE: () = (); + +                    static mut __MOD: Option<{type_}> = None; + +                    // Loadable modules need to export the `{{init,cleanup}}_module` identifiers. +                    /// # Safety +                    /// +                    /// This function must not be called after module initialization, because it may be +                    /// freed after that completes. +                    #[cfg(MODULE)] +                    #[doc(hidden)] +                    #[no_mangle] +                    #[link_section = \".init.text\"] +                    pub unsafe extern \"C\" fn init_module() -> core::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. +                        unsafe {{ __init() }} +                    }} -            // Built-in modules are initialized through an initcall pointer -            // and the identifiers need to be unique. -            #[cfg(not(MODULE))] -            #[cfg(not(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS))] -            #[doc(hidden)] -            #[link_section = \"{initcall_section}\"] -            #[used] -            pub static __{name}_initcall: extern \"C\" fn() -> core::ffi::c_int = __{name}_init; +                    #[cfg(MODULE)] +                    #[doc(hidden)] +                    #[no_mangle] +                    pub extern \"C\" fn cleanup_module() {{ +                        // 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 `init_module` has returned `0` +                        //   (which delegates to `__init`). +                        unsafe {{ __exit() }} +                    }} -            #[cfg(not(MODULE))] -            #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)] -            core::arch::global_asm!( -                r#\".section \"{initcall_section}\", \"a\" -                __{name}_initcall: -                    .long   __{name}_init - . -                    .previous -                \"# -            ); +                    // Built-in modules are initialized through an initcall pointer +                    // and the identifiers need to be unique. +                    #[cfg(not(MODULE))] +                    #[cfg(not(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS))] +                    #[doc(hidden)] +                    #[link_section = \"{initcall_section}\"] +                    #[used] +                    pub static __{name}_initcall: extern \"C\" fn() -> core::ffi::c_int = __{name}_init; + +                    #[cfg(not(MODULE))] +                    #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)] +                    core::arch::global_asm!( +                        r#\".section \"{initcall_section}\", \"a\" +                        __{name}_initcall: +                            .long   __{name}_init - . +                            .previous +                        \"# +                    ); + +                    #[cfg(not(MODULE))] +                    #[doc(hidden)] +                    #[no_mangle] +                    pub extern \"C\" fn __{name}_init() -> core::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. +                        unsafe {{ __init() }} +                    }} -            #[cfg(not(MODULE))] -            #[doc(hidden)] -            #[no_mangle] -            pub extern \"C\" fn __{name}_init() -> core::ffi::c_int {{ -                __init() -            }} +                    #[cfg(not(MODULE))] +                    #[doc(hidden)] +                    #[no_mangle] +                    pub extern \"C\" fn __{name}_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`). +                        unsafe {{ __exit() }} +                    }} -            #[cfg(not(MODULE))] -            #[doc(hidden)] -            #[no_mangle] -            pub extern \"C\" fn __{name}_exit() {{ -                __exit() -            }} +                    /// # Safety +                    /// +                    /// This function must only be called once. +                    unsafe fn __init() -> core::ffi::c_int {{ +                        match <{type_} as kernel::Module>::init(&super::super::THIS_MODULE) {{ +                            Ok(m) => {{ +                                // 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`. +                                unsafe {{ +                                    __MOD = Some(m); +                                }} +                                return 0; +                            }} +                            Err(e) => {{ +                                return e.to_errno(); +                            }} +                        }} +                    }} -            fn __init() -> core::ffi::c_int {{ -                match <{type_} as kernel::Module>::init(&THIS_MODULE) {{ -                    Ok(m) => {{ +                    /// # Safety +                    /// +                    /// This function must +                    /// - only be called once, +                    /// - be called after `__init` has been called and returned `0`. +                    unsafe fn __exit() {{ +                        // 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 `__init` was already called.                          unsafe {{ -                            __MOD = Some(m); +                            // Invokes `drop()` on `__MOD`, which should be used for cleanup. +                            __MOD = None;                          }} -                        return 0; -                    }} -                    Err(e) => {{ -                        return e.to_errno();                      }} -                }} -            }} -            fn __exit() {{ -                unsafe {{ -                    // Invokes `drop()` on `__MOD`, which should be used for cleanup. -                    __MOD = None; +                    {modinfo}                  }}              }} - -            {modinfo}          ",          type_ = info.type_,          name = info.name, diff --git a/rust/macros/pin_data.rs b/rust/macros/pin_data.rs index 6d58cfda9872..1d4a3547c684 100644 --- a/rust/macros/pin_data.rs +++ b/rust/macros/pin_data.rs @@ -10,6 +10,7 @@ pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream {      let (          Generics {              impl_generics, +            decl_generics,              ty_generics,          },          rest, @@ -76,6 +77,7 @@ pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream {          @sig(#(#rest)*),          @impl_generics(#(#impl_generics)*),          @ty_generics(#(#ty_generics)*), +        @decl_generics(#(#decl_generics)*),          @body(#last),      });      quoted.extend(errs); diff --git a/rust/macros/zeroable.rs b/rust/macros/zeroable.rs index 0d605c46ab3b..cfee2cec18d5 100644 --- a/rust/macros/zeroable.rs +++ b/rust/macros/zeroable.rs @@ -7,6 +7,7 @@ pub(crate) fn derive(input: TokenStream) -> TokenStream {      let (          Generics {              impl_generics, +            decl_generics: _,              ty_generics,          },          mut rest,  |