]> git.lizzy.rs Git - rust.git/commitdiff
Make bare underscore token an Ident rather than Punct in proc-macro
authorKevin Mehall <km@kevinmehall.net>
Sat, 20 Mar 2021 18:18:57 +0000 (12:18 -0600)
committerKevin Mehall <km@kevinmehall.net>
Sat, 20 Mar 2021 18:28:44 +0000 (12:28 -0600)
crates/mbe/src/expander/matcher.rs
crates/mbe/src/parser.rs
crates/mbe/src/subtree_source.rs
crates/mbe/src/syntax_bridge.rs
crates/mbe/src/tests/expand.rs
crates/proc_macro_srv/src/rustc_server.rs

index b6782b4ba8c7c537e33a92c438eff65c92f5de9f..3c53960cedc4c47b932b0750615d227ae2bf881a 100644 (file)
@@ -710,6 +710,7 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
             let tt_result = match kind {
                 "ident" => input
                     .expect_ident()
+                    .and_then(|ident| if ident.text == "_" { Err(()) } else { Ok(ident) })
                     .map(|ident| Some(tt::Leaf::from(ident.clone()).into()))
                     .map_err(|()| err!("expected ident")),
                 "tt" => input.expect_tt().map(Some).map_err(|()| err!()),
index 7b5b8ec16495f77aaa7d8905ef882a8b46160b99..c88387653dd25bbf8f250b83c69600c2c1ada9d2 100644 (file)
@@ -177,16 +177,8 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
                     Op::Repeat { tokens: MetaTemplate(tokens), separator, kind }
                 }
                 tt::TokenTree::Leaf(leaf) => match leaf {
-                    tt::Leaf::Punct(punct) => {
-                        static UNDERSCORE: SmolStr = SmolStr::new_inline("_");
-
-                        if punct.char != '_' {
-                            return Err(ParseError::Expected("_".to_string()));
-                        }
-                        let name = UNDERSCORE.clone();
-                        let kind = eat_fragment_kind(src, mode)?;
-                        let id = punct.id;
-                        Op::Var { name, kind, id }
+                    tt::Leaf::Punct(_) => {
+                        return Err(ParseError::Expected("ident".to_string()));
                     }
                     tt::Leaf::Ident(ident) if ident.text == "crate" => {
                         // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path.
index d7433bd353c7ea37aa3f979baafbd0aacbf736fc..a05cab0f373de92a6342d346df3eab19789cd1f8 100644 (file)
@@ -150,6 +150,7 @@ fn convert_ident(ident: &tt::Ident) -> TtToken {
     let kind = match ident.text.as_ref() {
         "true" => T![true],
         "false" => T![false],
+        "_" => UNDERSCORE,
         i if i.starts_with('\'') => LIFETIME_IDENT,
         _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT),
     };
index 85163c4b32b0df10b3916f8ee12029382cffeeca..8bba3d3d5288d7ba84c463e34ee6c48a23174cb1 100644 (file)
@@ -350,7 +350,7 @@ fn collect_leaf(&mut self, result: &mut Vec<tt::TokenTree>) {
             return;
         }
 
-        result.push(if k.is_punct() {
+        result.push(if k.is_punct() && k != UNDERSCORE {
             assert_eq!(range.len(), TextSize::of('.'));
             let delim = match k {
                 T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])),
@@ -395,7 +395,9 @@ fn collect_leaf(&mut self, result: &mut Vec<tt::TokenTree>) {
                     {
                         tt::Spacing::Alone
                     }
-                    Some(next) if next.kind().is_punct() => tt::Spacing::Joint,
+                    Some(next) if next.kind().is_punct() && next.kind() != UNDERSCORE => {
+                        tt::Spacing::Joint
+                    }
                     _ => tt::Spacing::Alone,
                 };
                 let char = match token.to_char() {
@@ -415,6 +417,7 @@ macro_rules! make_leaf {
             let leaf: tt::Leaf = match k {
                 T![true] | T![false] => make_leaf!(Ident),
                 IDENT => make_leaf!(Ident),
+                UNDERSCORE => make_leaf!(Ident),
                 k if k.is_keyword() => make_leaf!(Ident),
                 k if k.is_literal() => make_leaf!(Literal),
                 LIFETIME_IDENT => {
index 9dd8ff75bcad72ed207293ba7c0361a91e13fe20..2cce62781a41f3aee6dfef8e3679822aa492dd89 100644 (file)
@@ -1079,6 +1079,12 @@ macro_rules! q {
     .assert_expand_items(r#"q![_]"#, r#"0"#);
 }
 
+#[test]
+fn test_underscore_lifetime() {
+    parse_macro(r#"macro_rules! q { ($a:lifetime) => {0}; }"#)
+        .assert_expand_items(r#"q!['_]"#, r#"0"#);
+}
+
 #[test]
 fn test_vertical_bar_with_pat() {
     parse_macro(
index ceefd187d257f2e0c1f156a57a6082801b161125..c147484c0e0f65518b54e427fdc03203a2c1482a 100644 (file)
@@ -805,5 +805,14 @@ fn test_rustc_server_from_str() {
         let t2 = TokenStream::from_str("(a);").unwrap();
         assert_eq!(t2.token_trees.len(), 2);
         assert_eq!(t2.token_trees[0], subtree_paren_a);
+
+        let underscore = TokenStream::from_str("_").unwrap();
+        assert_eq!(
+            underscore.token_trees[0],
+            tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
+                text: "_".into(),
+                id: tt::TokenId::unspecified(),
+            }))
+        );
     }
 }