rtic-macros: forward attributes applied to app module

Instead of ignoring additional attributes applied to the app
module, we can forward them to the generated code.
This commit is contained in:
Johannes Cornelis Draaijer 2025-09-03 13:53:50 +02:00
parent 914acfb1bb
commit 4ebe6e0a7e
8 changed files with 78 additions and 2 deletions

View file

@ -44,12 +44,14 @@ pub fn app(app: &App, analysis: &Analysis) -> TokenStream2 {
let user_code = &app.user_code; let user_code = &app.user_code;
let name = &app.name; let name = &app.name;
let device = &app.args.device; let device = &app.args.device;
let attribute_metas = &app.attribute_metas;
let rt_err = util::rt_err_ident(); let rt_err = util::rt_err_ident();
let async_limit = bindings::async_prio_limit(app, analysis); let async_limit = bindings::async_prio_limit(app, analysis);
quote!( quote!(
/// The RTIC application module /// The RTIC application module
#(#[#attribute_metas])*
pub mod #name { pub mod #name {
/// Always include the device crate which contains the vector table /// Always include the device crate which contains the vector table
use #device as #rt_err; use #device as #rt_err;

View file

@ -1,6 +1,6 @@
//! Abstract Syntax Tree //! Abstract Syntax Tree
use syn::{Attribute, Expr, Ident, Item, ItemUse, Pat, PatType, Path, Stmt, Type}; use syn::{Attribute, Expr, Ident, Item, ItemUse, Meta, Pat, PatType, Path, Stmt, Type};
use crate::syntax::{backend::BackendArgs, Map}; use crate::syntax::{backend::BackendArgs, Map};
@ -11,6 +11,9 @@ pub struct App {
/// The arguments to the `#[app]` attribute /// The arguments to the `#[app]` attribute
pub args: AppArgs, pub args: AppArgs,
/// All attributes applied to the `#[app]` module (meta only)
pub attribute_metas: Vec<Meta>,
/// The name of the `const` item on which the `#[app]` attribute has been placed /// The name of the `const` item on which the `#[app]` attribute has been placed
pub name: Ident, pub name: Ident,

View file

@ -11,7 +11,7 @@ use syn::{
braced, braced,
parse::{self, Parse, ParseStream, Parser}, parse::{self, Parse, ParseStream, Parser},
token::Brace, token::Brace,
Ident, Item, LitInt, Token, Attribute, Ident, Item, LitInt, Meta, Token,
}; };
use crate::syntax::{ use crate::syntax::{
@ -28,6 +28,7 @@ pub fn app(args: TokenStream2, input: TokenStream2) -> parse::Result<App> {
} }
pub(crate) struct Input { pub(crate) struct Input {
pub attribute_metas: Vec<Meta>,
_mod_token: Token![mod], _mod_token: Token![mod],
pub ident: Ident, pub ident: Ident,
_brace_token: Brace, _brace_token: Brace,
@ -48,12 +49,18 @@ impl Parse for Input {
let content; let content;
let mut attributes = input.call(Attribute::parse_outer)?;
let _mod_token = input.parse()?; let _mod_token = input.parse()?;
let ident = input.parse()?; let ident = input.parse()?;
let _brace_token = braced!(content in input); let _brace_token = braced!(content in input);
let inner_attributes = content.call(Attribute::parse_inner)?;
let items = content.call(parse_items)?; let items = content.call(parse_items)?;
attributes.extend(inner_attributes);
let attribute_metas = attributes.into_iter().map(|a| a.meta).collect();
Ok(Input { Ok(Input {
attribute_metas,
_mod_token, _mod_token,
ident, ident,
_brace_token, _brace_token,

View file

@ -531,6 +531,7 @@ impl App {
} }
Ok(App { Ok(App {
attribute_metas: input.attribute_metas,
args, args,
name: input.ident, name: input.ident,
init, init,

View file

@ -0,0 +1,21 @@
#![no_main]
#![deny(unfulfilled_lint_expectations)]
#[rtic::app(device = lm3s6965)]
mod app {
#![expect(while_true)]
#[shared]
struct Shared {
#[unsafe(link_section = ".custom_section")]
foo: (),
}
#[local]
struct Local {}
#[init]
fn init(_cx: init::Context) -> (Shared, Local) {
(Shared { foo: () }, Local {})
}
}

View file

@ -0,0 +1,11 @@
error: this lint expectation is unfulfilled
--> ui/inner_attribute.rs:6:15
|
6 | #![expect(while_true)]
| ^^^^^^^^^^
|
note: the lint level is defined here
--> ui/inner_attribute.rs:2:9
|
2 | #![deny(unfulfilled_lint_expectations)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -0,0 +1,20 @@
#![no_main]
#![deny(unfulfilled_lint_expectations)]
#[rtic::app(device = lm3s6965)]
#[expect(while_true)]
mod app {
#[shared]
struct Shared {
#[unsafe(link_section = ".custom_section")]
foo: (),
}
#[local]
struct Local {}
#[init]
fn init(_cx: init::Context) -> (Shared, Local) {
(Shared { foo: () }, Local {})
}
}

View file

@ -0,0 +1,11 @@
error: this lint expectation is unfulfilled
--> ui/outer_attribute.rs:5:10
|
5 | #[expect(while_true)]
| ^^^^^^^^^^
|
note: the lint level is defined here
--> ui/outer_attribute.rs:2:9
|
2 | #![deny(unfulfilled_lint_expectations)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^