Rollup merge of #70058 - Centril:fix-70050, r=petrochenkov

can_begin_literal_maybe_minus: `true` on `"-"? lit` NTs.

Make `can_begin_literal_or_bool` (renamed to `can_begin_literal_maybe_minus`) accept `NtLiteral(e) | NtExpr(e)` where `e` is either a literal or a negated literal.

Fixes https://github.com/rust-lang/rust/issues/70050.

r? @petrochenkov
This commit is contained in:
Mazdak Farrokhzad 2020-03-21 05:33:20 +01:00 committed by GitHub
commit 67e418ce75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 55 additions and 9 deletions

View File

@ -424,7 +424,7 @@ impl Token {
NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
_ => false,
},
_ => self.can_begin_literal_or_bool(),
_ => self.can_begin_literal_maybe_minus(),
}
}
@ -448,13 +448,22 @@ impl Token {
/// Returns `true` if the token is any literal, a minus (which can prefix a literal,
/// for example a '-42', or one of the boolean idents).
///
/// Keep this in sync with `Lit::from_token`.
pub fn can_begin_literal_or_bool(&self) -> bool {
/// In other words, would this token be a valid start of `parse_literal_maybe_minus`?
///
/// Keep this in sync with and `Lit::from_token`, excluding unary negation.
pub fn can_begin_literal_maybe_minus(&self) -> bool {
match self.uninterpolate().kind {
Literal(..) | BinOp(Minus) => true,
Ident(name, false) if name.is_bool_lit() => true,
Interpolated(ref nt) => match &**nt {
NtExpr(e) | NtLiteral(e) => matches!(e.kind, ast::ExprKind::Lit(_)),
NtLiteral(_) => true,
NtExpr(e) => match &e.kind {
ast::ExprKind::Lit(_) => true,
ast::ExprKind::Unary(ast::UnOp::Neg, e) => {
matches!(&e.kind, ast::ExprKind::Lit(_))
}
_ => false,
},
_ => false,
},
_ => false,

View File

@ -189,7 +189,7 @@ impl Lit {
/// Converts arbitrary token into an AST literal.
///
/// Keep this in sync with `Token::can_begin_literal_or_bool`.
/// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
pub fn from_token(token: &Token) -> Result<Lit, LitError> {
let lit = match token.uninterpolate().kind {
token::Ident(name, false) if name.is_bool_lit() => {

View File

@ -778,7 +778,7 @@ fn may_begin_with(token: &Token, name: Name) -> bool {
}
sym::ty => token.can_begin_type(),
sym::ident => get_macro_ident(token).is_some(),
sym::literal => token.can_begin_literal_or_bool(),
sym::literal => token.can_begin_literal_maybe_minus(),
sym::vis => match token.kind {
// The follow-set of :vis + "priv" keyword + interpolated
token::Comma | token::Ident(..) | token::Interpolated(_) => true,

View File

@ -1374,6 +1374,7 @@ impl<'a> Parser<'a> {
}
/// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
/// Keep this in sync with `Token::can_begin_literal_maybe_minus`.
pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
maybe_whole_expr!(self);

View File

@ -1509,7 +1509,7 @@ impl<'a> Parser<'a> {
})
// `extern ABI fn`
|| self.check_keyword(kw::Extern)
&& self.look_ahead(1, |t| t.can_begin_literal_or_bool())
&& self.look_ahead(1, |t| t.can_begin_literal_maybe_minus())
&& self.look_ahead(2, |t| t.is_keyword(kw::Fn))
}

View File

@ -696,7 +696,7 @@ impl<'a> Parser<'a> {
self.look_ahead(dist, |t| {
t.is_path_start() // e.g. `MY_CONST`;
|| t.kind == token::Dot // e.g. `.5` for recovery;
|| t.can_begin_literal_or_bool() // e.g. `42`.
|| t.can_begin_literal_maybe_minus() // e.g. `42`.
|| t.is_whole_expr()
})
}

View File

@ -1,7 +1,7 @@
// check-pass
// In this test we check that the parser accepts an ABI string when it
// comes from a macro `literal` fragment as opposed to a hardcoded string.
// comes from a macro `literal` or `expr` fragment as opposed to a hardcoded string.
fn main() {}
@ -17,6 +17,18 @@ macro_rules! abi_from_lit_frag {
}
}
macro_rules! abi_from_expr_frag {
($abi:expr) => {
extern $abi {
fn _import();
}
extern $abi fn _export() {}
type _PTR = extern $abi fn();
};
}
mod rust {
abi_from_lit_frag!("Rust");
}
@ -24,3 +36,11 @@ mod rust {
mod c {
abi_from_lit_frag!("C");
}
mod rust_expr {
abi_from_expr_frag!("Rust");
}
mod c_expr {
abi_from_expr_frag!("C");
}

View File

@ -0,0 +1,16 @@
// check-pass
macro_rules! foo {
($a:literal) => {
bar!($a)
};
}
macro_rules! bar {
($b:literal) => {};
}
fn main() {
foo!(-2);
bar!(-2);
}