diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index 3fc6444168e..be5d322ba16 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -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, diff --git a/src/librustc_ast/util/literal.rs b/src/librustc_ast/util/literal.rs index d1757394f3a..1b17f343a6d 100644 --- a/src/librustc_ast/util/literal.rs +++ b/src/librustc_ast/util/literal.rs @@ -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 { let lit = match token.uninterpolate().kind { token::Ident(name, false) if name.is_bool_lit() => { diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index 3b9158f4445..0d777d88cad 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -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, diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index c65e99842c5..58ebc6b5637 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -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> { maybe_whole_expr!(self); diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 9d70f606f3e..7ccf31d8b4f 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -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)) } diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs index 4585941943b..5aab0580997 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/src/librustc_parse/parser/pat.rs @@ -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() }) } diff --git a/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs b/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs index cb23f2c808c..4ecb21d26ab 100644 --- a/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs +++ b/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs @@ -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"); +} diff --git a/src/test/ui/parser/issue-70050-ntliteral-accepts-negated-lit.rs b/src/test/ui/parser/issue-70050-ntliteral-accepts-negated-lit.rs new file mode 100644 index 00000000000..aca9d9eb0a5 --- /dev/null +++ b/src/test/ui/parser/issue-70050-ntliteral-accepts-negated-lit.rs @@ -0,0 +1,16 @@ +// check-pass + +macro_rules! foo { + ($a:literal) => { + bar!($a) + }; +} + +macro_rules! bar { + ($b:literal) => {}; +} + +fn main() { + foo!(-2); + bar!(-2); +}