aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/mbe/src/expander/matcher.rs1
-rw-r--r--crates/mbe/src/parser.rs12
-rw-r--r--crates/mbe/src/subtree_source.rs1
-rw-r--r--crates/mbe/src/syntax_bridge.rs7
-rw-r--r--crates/mbe/src/tests/expand.rs6
-rw-r--r--crates/proc_macro_srv/src/rustc_server.rs9
6 files changed, 24 insertions, 12 deletions
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index b6782b4ba..3c53960ce 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -710,6 +710,7 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
710 let tt_result = match kind { 710 let tt_result = match kind {
711 "ident" => input 711 "ident" => input
712 .expect_ident() 712 .expect_ident()
713 .and_then(|ident| if ident.text == "_" { Err(()) } else { Ok(ident) })
713 .map(|ident| Some(tt::Leaf::from(ident.clone()).into())) 714 .map(|ident| Some(tt::Leaf::from(ident.clone()).into()))
714 .map_err(|()| err!("expected ident")), 715 .map_err(|()| err!("expected ident")),
715 "tt" => input.expect_tt().map(Some).map_err(|()| err!()), 716 "tt" => input.expect_tt().map(Some).map_err(|()| err!()),
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index 7b5b8ec16..c88387653 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -177,16 +177,8 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
177 Op::Repeat { tokens: MetaTemplate(tokens), separator, kind } 177 Op::Repeat { tokens: MetaTemplate(tokens), separator, kind }
178 } 178 }
179 tt::TokenTree::Leaf(leaf) => match leaf { 179 tt::TokenTree::Leaf(leaf) => match leaf {
180 tt::Leaf::Punct(punct) => { 180 tt::Leaf::Punct(_) => {
181 static UNDERSCORE: SmolStr = SmolStr::new_inline("_"); 181 return Err(ParseError::Expected("ident".to_string()));
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 }
190 } 182 }
191 tt::Leaf::Ident(ident) if ident.text == "crate" => { 183 tt::Leaf::Ident(ident) if ident.text == "crate" => {
192 // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. 184 // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path.
diff --git a/crates/mbe/src/subtree_source.rs b/crates/mbe/src/subtree_source.rs
index d7433bd35..a05cab0f3 100644
--- a/crates/mbe/src/subtree_source.rs
+++ b/crates/mbe/src/subtree_source.rs
@@ -150,6 +150,7 @@ fn convert_ident(ident: &tt::Ident) -> TtToken {
150 let kind = match ident.text.as_ref() { 150 let kind = match ident.text.as_ref() {
151 "true" => T![true], 151 "true" => T![true],
152 "false" => T![false], 152 "false" => T![false],
153 "_" => UNDERSCORE,
153 i if i.starts_with('\'') => LIFETIME_IDENT, 154 i if i.starts_with('\'') => LIFETIME_IDENT,
154 _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT), 155 _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT),
155 }; 156 };
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 85163c4b3..8bba3d3d5 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -350,7 +350,7 @@ trait TokenConvertor {
350 return; 350 return;
351 } 351 }
352 352
353 result.push(if k.is_punct() { 353 result.push(if k.is_punct() && k != UNDERSCORE {
354 assert_eq!(range.len(), TextSize::of('.')); 354 assert_eq!(range.len(), TextSize::of('.'));
355 let delim = match k { 355 let delim = match k {
356 T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])), 356 T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])),
@@ -395,7 +395,9 @@ trait TokenConvertor {
395 { 395 {
396 tt::Spacing::Alone 396 tt::Spacing::Alone
397 } 397 }
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 }
399 _ => tt::Spacing::Alone, 401 _ => tt::Spacing::Alone,
400 }; 402 };
401 let char = match token.to_char() { 403 let char = match token.to_char() {
@@ -415,6 +417,7 @@ trait TokenConvertor {
415 let leaf: tt::Leaf = match k { 417 let leaf: tt::Leaf = match k {
416 T![true] | T![false] => make_leaf!(Ident), 418 T![true] | T![false] => make_leaf!(Ident),
417 IDENT => make_leaf!(Ident), 419 IDENT => make_leaf!(Ident),
420 UNDERSCORE => make_leaf!(Ident),
418 k if k.is_keyword() => make_leaf!(Ident), 421 k if k.is_keyword() => make_leaf!(Ident),
419 k if k.is_literal() => make_leaf!(Literal), 422 k if k.is_literal() => make_leaf!(Literal),
420 LIFETIME_IDENT => { 423 LIFETIME_IDENT => {
diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs
index 9dd8ff75b..2cce62781 100644
--- a/crates/mbe/src/tests/expand.rs
+++ b/crates/mbe/src/tests/expand.rs
@@ -1080,6 +1080,12 @@ macro_rules! q {
1080} 1080}
1081 1081
1082#[test] 1082#[test]
1083fn test_underscore_lifetime() {
1084 parse_macro(r#"macro_rules! q { ($a:lifetime) => {0}; }"#)
1085 .assert_expand_items(r#"q!['_]"#, r#"0"#);
1086}
1087
1088#[test]
1083fn test_vertical_bar_with_pat() { 1089fn test_vertical_bar_with_pat() {
1084 parse_macro( 1090 parse_macro(
1085 r#" 1091 r#"
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs
index ceefd187d..c147484c0 100644
--- a/crates/proc_macro_srv/src/rustc_server.rs
+++ b/crates/proc_macro_srv/src/rustc_server.rs
@@ -805,5 +805,14 @@ mod tests {
805 let t2 = TokenStream::from_str("(a);").unwrap(); 805 let t2 = TokenStream::from_str("(a);").unwrap();
806 assert_eq!(t2.token_trees.len(), 2); 806 assert_eq!(t2.token_trees.len(), 2);
807 assert_eq!(t2.token_trees[0], subtree_paren_a); 807 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 );
808 } 817 }
809} 818}