7059: Special case $_ in meta var instead of treat it as ident in mbe  r=lnicola a=edwin0cheng

In #6929, we treat '_' as an ident but rustc is only allow it in some special places (e.g. meta var in mbe , type, pat etc). 

This PR rollback that and we only make '$_' works in meta var matching. 

Fixes #7056 

Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
bors[bot] 2020-12-28 12:26:55 +00:00 committed by GitHub
commit 99ec2f623d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 4 deletions

View File

@ -101,8 +101,15 @@ fn next_op<'a>(
Op::Repeat { subtree, separator, kind }
}
tt::TokenTree::Leaf(leaf) => match leaf {
tt::Leaf::Punct(_) => {
return Err(ExpandError::UnexpectedToken);
tt::Leaf::Punct(punct) => {
static UNDERSCORE: SmolStr = SmolStr::new_inline("_");
if punct.char != '_' {
return Err(ExpandError::UnexpectedToken);
}
let name = &UNDERSCORE;
let kind = eat_fragment_kind(src, mode)?;
Op::Var { name, kind }
}
tt::Leaf::Ident(ident) => {
let name = &ident.text;

View File

@ -313,7 +313,7 @@ fn collect_leaf(&mut self, result: &mut Vec<tt::TokenTree>) {
return;
}
result.push(if k.is_punct() && k != UNDERSCORE {
result.push(if k.is_punct() {
assert_eq!(range.len(), TextSize::of('.'));
let delim = match k {
T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])),
@ -378,7 +378,6 @@ 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 => {

View File

@ -1019,6 +1019,42 @@ macro_rules! foo {
.assert_expand_items(r#"foo! { => }"#, r#"0"#);
}
#[test]
fn test_underscore_not_greedily() {
parse_macro(
r#"
macro_rules! q {
($($a:ident)* _) => {0};
}
"#,
)
// `_` overlaps with `$a:ident` but rustc matches it under the `_` token
.assert_expand_items(r#"q![a b c d _]"#, r#"0"#);
parse_macro(
r#"
macro_rules! q {
($($a:expr => $b:ident)* _ => $c:expr) => {0};
}
"#,
)
// `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr`
.assert_expand_items(r#"q![a => b c => d _ => ou]"#, r#"0"#);
}
#[test]
fn test_underscore_as_type() {
parse_macro(
r#"
macro_rules! q {
($a:ty) => {0};
}
"#,
)
// Underscore is a type
.assert_expand_items(r#"q![_]"#, r#"0"#);
}
#[test]
fn test_vertical_bar_with_pat() {
parse_macro(