about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_ast/token.rs17
-rw-r--r--src/librustc_ast/util/literal.rs2
-rw-r--r--src/librustc_expand/mbe/macro_parser.rs2
-rw-r--r--src/librustc_parse/parser/expr.rs1
-rw-r--r--src/librustc_parse/parser/item.rs2
-rw-r--r--src/librustc_parse/parser/pat.rs2
-rw-r--r--src/test/ui/parser/extern-abi-from-mac-literal-frag.rs22
-rw-r--r--src/test/ui/parser/issue-70050-ntliteral-accepts-negated-lit.rs16
8 files changed, 55 insertions, 9 deletions
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<Lit, LitError> {
         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<Expr>> {
         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);
+}