diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/mbe/src/parser.rs | 11 | ||||
-rw-r--r-- | crates/mbe/src/tests.rs | 36 |
2 files changed, 45 insertions, 2 deletions
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index c3fdd4040..d681905f5 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs | |||
@@ -101,8 +101,15 @@ fn next_op<'a>( | |||
101 | Op::Repeat { subtree, separator, kind } | 101 | Op::Repeat { subtree, separator, kind } |
102 | } | 102 | } |
103 | tt::TokenTree::Leaf(leaf) => match leaf { | 103 | tt::TokenTree::Leaf(leaf) => match leaf { |
104 | tt::Leaf::Punct(_) => { | 104 | tt::Leaf::Punct(punct) => { |
105 | return Err(ExpandError::UnexpectedToken); | 105 | static UNDERSCORE: SmolStr = SmolStr::new_inline("_"); |
106 | |||
107 | if punct.char != '_' { | ||
108 | return Err(ExpandError::UnexpectedToken); | ||
109 | } | ||
110 | let name = &UNDERSCORE; | ||
111 | let kind = eat_fragment_kind(src, mode)?; | ||
112 | Op::Var { name, kind } | ||
106 | } | 113 | } |
107 | tt::Leaf::Ident(ident) => { | 114 | tt::Leaf::Ident(ident) => { |
108 | let name = &ident.text; | 115 | let name = &ident.text; |
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index 6cd0ed205..9958a33a0 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs | |||
@@ -1020,6 +1020,42 @@ fn test_underscore() { | |||
1020 | } | 1020 | } |
1021 | 1021 | ||
1022 | #[test] | 1022 | #[test] |
1023 | fn test_underscore_not_greedily() { | ||
1024 | parse_macro( | ||
1025 | r#" | ||
1026 | macro_rules! q { | ||
1027 | ($($a:ident)* _) => {0}; | ||
1028 | } | ||
1029 | "#, | ||
1030 | ) | ||
1031 | // `_` overlaps with `$a:ident` but rustc matches it under the `_` token | ||
1032 | .assert_expand_items(r#"q![a b c d _]"#, r#"0"#); | ||
1033 | |||
1034 | parse_macro( | ||
1035 | r#" | ||
1036 | macro_rules! q { | ||
1037 | ($($a:expr => $b:ident)* _ => $c:expr) => {0}; | ||
1038 | } | ||
1039 | "#, | ||
1040 | ) | ||
1041 | // `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr` | ||
1042 | .assert_expand_items(r#"q![a => b c => d _ => ou]"#, r#"0"#); | ||
1043 | } | ||
1044 | |||
1045 | #[test] | ||
1046 | fn test_underscore_as_type() { | ||
1047 | parse_macro( | ||
1048 | r#" | ||
1049 | macro_rules! q { | ||
1050 | ($a:ty) => {0}; | ||
1051 | } | ||
1052 | "#, | ||
1053 | ) | ||
1054 | // Underscore is a type | ||
1055 | .assert_expand_items(r#"q![_]"#, r#"0"#); | ||
1056 | } | ||
1057 | |||
1058 | #[test] | ||
1023 | fn test_vertical_bar_with_pat() { | 1059 | fn test_vertical_bar_with_pat() { |
1024 | parse_macro( | 1060 | parse_macro( |
1025 | r#" | 1061 | r#" |