Skip to content

Commit 84a8d2a

Browse files
committed
rust: macros: paste: add support for using var as part of group
The following code is currently working fine and will generate a struct named "Test0": kernel::macros::paste! { struct [<Test 0>]; } But if we need to use a "macro variable" like this: macro_rules! test { ($i: literal) => { kernel::macros::paste! { struct [<Test $i>]; } }; } test!(0); The code above will make the paste! macro panic: error: proc macro panicked --> drivers/regulator/ncv6336.rs:25:9 | 25 | / kernel::macros::paste! { 26 | | struct [<Test $i>]; 27 | | } | |_________^ ... 31 | test!(0); | -------- in this macro invocation | = help: message: unexpected token in paste segments The reason of this panic is that "macro variables" are creating `Groups` [0], with the `None` delimiter [1], and currently `Groups`are not handled by the paste! macro. This commit adds support for TokenTree::Group token where the delimiter is None in order to make the previous code snippet now work. [0] https://doc.rust-lang.org/proc_macro/struct.Group.html [1] https://doc.rust-lang.org/proc_macro/enum.Delimiter.html#variant.None Signed-off-by: Fabien Parent <[email protected]>
1 parent 1cf952d commit 84a8d2a

File tree

1 file changed

+20
-1
lines changed

1 file changed

+20
-1
lines changed

rust/macros/paste.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use proc_macro::{Delimiter, Group, Ident, Spacing, Span, TokenTree};
44

5-
fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree {
5+
fn process_tokens_into_segments(tokens: &[TokenTree]) -> (Vec<(String, Span)>, Option<Span>) {
66
let mut tokens = tokens.iter();
77
let mut segments = Vec::new();
88
let mut span = None;
@@ -46,10 +46,29 @@ fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree {
4646
};
4747
segments.push((value, sp));
4848
}
49+
Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::None => {
50+
let group_tokens: Vec<_> = group.stream().into_iter().collect();
51+
let (group_segments, group_span) = process_tokens_into_segments(&group_tokens);
52+
segments.extend(group_segments);
53+
54+
assert!(
55+
!(span.is_some() && group_span.is_some()),
56+
"span modifier should only appear at most once"
57+
);
58+
59+
if group_span.is_some() {
60+
span = group_span;
61+
}
62+
}
4963
_ => panic!("unexpected token in paste segments"),
5064
};
5165
}
5266

67+
(segments, span)
68+
}
69+
70+
fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree {
71+
let (segments, span) = process_tokens_into_segments(tokens);
5372
let pasted: String = segments.into_iter().map(|x| x.0).collect();
5473
TokenTree::Ident(Ident::new(&pasted, span.unwrap_or(group_span)))
5574
}

0 commit comments

Comments
 (0)