aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/mbe/src/expander/matcher.rs4
-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/mbe/src/tests/rule.rs4
-rw-r--r--crates/mbe/src/tt_iter.rs7
-rw-r--r--crates/proc_macro_srv/src/rustc_server.rs9
8 files changed, 36 insertions, 14 deletions
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index b6782b4ba..1682b21b0 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -762,7 +762,7 @@ impl<'a> TtIter<'a> {
762 fn expect_separator(&mut self, separator: &Separator, idx: usize) -> bool { 762 fn expect_separator(&mut self, separator: &Separator, idx: usize) -> bool {
763 let mut fork = self.clone(); 763 let mut fork = self.clone();
764 let ok = match separator { 764 let ok = match separator {
765 Separator::Ident(lhs) if idx == 0 => match fork.expect_ident() { 765 Separator::Ident(lhs) if idx == 0 => match fork.expect_ident_or_underscore() {
766 Ok(rhs) => rhs.text == lhs.text, 766 Ok(rhs) => rhs.text == lhs.text,
767 _ => false, 767 _ => false,
768 }, 768 },
@@ -852,7 +852,7 @@ impl<'a> TtIter<'a> {
852 if punct.char != '\'' { 852 if punct.char != '\'' {
853 return Err(()); 853 return Err(());
854 } 854 }
855 let ident = self.expect_ident()?; 855 let ident = self.expect_ident_or_underscore()?;
856 856
857 Ok(tt::Subtree { 857 Ok(tt::Subtree {
858 delimiter: None, 858 delimiter: None,
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/mbe/src/tests/rule.rs b/crates/mbe/src/tests/rule.rs
index 07277966d..bf48112b3 100644
--- a/crates/mbe/src/tests/rule.rs
+++ b/crates/mbe/src/tests/rule.rs
@@ -12,6 +12,9 @@ fn test_valid_arms() {
12 } 12 }
13 13
14 check("($i:ident) => ()"); 14 check("($i:ident) => ()");
15 check("($(x),*) => ()");
16 check("($(x)_*) => ()");
17 check("($(x)i*) => ()");
15 check("($($i:ident)*) => ($_)"); 18 check("($($i:ident)*) => ($_)");
16 check("($($true:ident)*) => ($true)"); 19 check("($($true:ident)*) => ($true)");
17 check("($($false:ident)*) => ($false)"); 20 check("($($false:ident)*) => ($false)");
@@ -32,6 +35,7 @@ fn test_invalid_arms() {
32 35
33 check("($i) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into())); 36 check("($i) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
34 check("($i:) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into())); 37 check("($i:) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
38 check("($i:_) => ()", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
35} 39}
36 40
37fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError> { 41fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError> {
diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs
index a362d31fc..319a40f2a 100644
--- a/crates/mbe/src/tt_iter.rs
+++ b/crates/mbe/src/tt_iter.rs
@@ -50,6 +50,13 @@ impl<'a> TtIter<'a> {
50 50
51 pub(crate) fn expect_ident(&mut self) -> Result<&'a tt::Ident, ()> { 51 pub(crate) fn expect_ident(&mut self) -> Result<&'a tt::Ident, ()> {
52 match self.expect_leaf()? { 52 match self.expect_leaf()? {
53 tt::Leaf::Ident(it) if it.text != "_" => Ok(it),
54 _ => Err(()),
55 }
56 }
57
58 pub(crate) fn expect_ident_or_underscore(&mut self) -> Result<&'a tt::Ident, ()> {
59 match self.expect_leaf()? {
53 tt::Leaf::Ident(it) => Ok(it), 60 tt::Leaf::Ident(it) => Ok(it),
54 _ => Err(()), 61 _ => Err(()),
55 } 62 }
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}