Skip to content

Commit 0a0e222

Browse files
committed
Make bare underscore token an Ident rather than Punct in proc-macro
1 parent 5cc8ad0 commit 0a0e222

File tree

6 files changed

+24
-12
lines changed

6 files changed

+24
-12
lines changed

crates/mbe/src/expander/matcher.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,7 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
710710
let tt_result = match kind {
711711
"ident" => input
712712
.expect_ident()
713+
.and_then(|ident| if ident.text == "_" { Err(()) } else { Ok(ident) })
713714
.map(|ident| Some(tt::Leaf::from(ident.clone()).into()))
714715
.map_err(|()| err!("expected ident")),
715716
"tt" => input.expect_tt().map(Some).map_err(|()| err!()),

crates/mbe/src/parser.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -177,16 +177,8 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
177177
Op::Repeat { tokens: MetaTemplate(tokens), separator, kind }
178178
}
179179
tt::TokenTree::Leaf(leaf) => match leaf {
180-
tt::Leaf::Punct(punct) => {
181-
static UNDERSCORE: SmolStr = SmolStr::new_inline("_");
182-
183-
if punct.char != '_' {
184-
return Err(ParseError::Expected("_".to_string()));
185-
}
186-
let name = UNDERSCORE.clone();
187-
let kind = eat_fragment_kind(src, mode)?;
188-
let id = punct.id;
189-
Op::Var { name, kind, id }
180+
tt::Leaf::Punct(_) => {
181+
return Err(ParseError::Expected("ident".to_string()));
190182
}
191183
tt::Leaf::Ident(ident) if ident.text == "crate" => {
192184
// We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path.

crates/mbe/src/subtree_source.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ fn convert_ident(ident: &tt::Ident) -> TtToken {
150150
let kind = match ident.text.as_ref() {
151151
"true" => T![true],
152152
"false" => T![false],
153+
"_" => UNDERSCORE,
153154
i if i.starts_with('\'') => LIFETIME_IDENT,
154155
_ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT),
155156
};

crates/mbe/src/syntax_bridge.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ trait TokenConvertor {
350350
return;
351351
}
352352

353-
result.push(if k.is_punct() {
353+
result.push(if k.is_punct() && k != UNDERSCORE {
354354
assert_eq!(range.len(), TextSize::of('.'));
355355
let delim = match k {
356356
T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])),
@@ -395,7 +395,9 @@ trait TokenConvertor {
395395
{
396396
tt::Spacing::Alone
397397
}
398-
Some(next) if next.kind().is_punct() => tt::Spacing::Joint,
398+
Some(next) if next.kind().is_punct() && next.kind() != UNDERSCORE => {
399+
tt::Spacing::Joint
400+
}
399401
_ => tt::Spacing::Alone,
400402
};
401403
let char = match token.to_char() {
@@ -415,6 +417,7 @@ trait TokenConvertor {
415417
let leaf: tt::Leaf = match k {
416418
T![true] | T![false] => make_leaf!(Ident),
417419
IDENT => make_leaf!(Ident),
420+
UNDERSCORE => make_leaf!(Ident),
418421
k if k.is_keyword() => make_leaf!(Ident),
419422
k if k.is_literal() => make_leaf!(Literal),
420423
LIFETIME_IDENT => {

crates/mbe/src/tests/expand.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,12 @@ macro_rules! q {
10791079
.assert_expand_items(r#"q![_]"#, r#"0"#);
10801080
}
10811081

1082+
#[test]
1083+
fn test_underscore_lifetime() {
1084+
parse_macro(r#"macro_rules! q { ($a:lifetime) => {0}; }"#)
1085+
.assert_expand_items(r#"q!['_]"#, r#"0"#);
1086+
}
1087+
10821088
#[test]
10831089
fn test_vertical_bar_with_pat() {
10841090
parse_macro(

crates/proc_macro_srv/src/rustc_server.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,5 +805,14 @@ mod tests {
805805
let t2 = TokenStream::from_str("(a);").unwrap();
806806
assert_eq!(t2.token_trees.len(), 2);
807807
assert_eq!(t2.token_trees[0], subtree_paren_a);
808+
809+
let underscore = TokenStream::from_str("_").unwrap();
810+
assert_eq!(
811+
underscore.token_trees[0],
812+
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
813+
text: "_".into(),
814+
id: tt::TokenId::unspecified(),
815+
}))
816+
);
808817
}
809818
}

0 commit comments

Comments
 (0)