]> git.lizzy.rs Git - rust.git/commitdiff
can_begin_literal_maybe_minus: `true` on `"-"? lit` NTs.
authorMazdak Farrokhzad <twingoow@gmail.com>
Mon, 16 Mar 2020 22:36:14 +0000 (23:36 +0100)
committerMazdak Farrokhzad <twingoow@gmail.com>
Fri, 20 Mar 2020 15:42:53 +0000 (16:42 +0100)
src/librustc_ast/token.rs
src/librustc_ast/util/literal.rs
src/librustc_expand/mbe/macro_parser.rs
src/librustc_parse/parser/expr.rs
src/librustc_parse/parser/item.rs
src/librustc_parse/parser/pat.rs
src/test/ui/parser/extern-abi-from-mac-literal-frag.rs
src/test/ui/parser/issue-70050-ntliteral-accepts-negated-lit.rs [new file with mode: 0644]

index 3fc6444168e24297b8e1118ad9e1b384d9100a60..be5d322ba1677dd4d984367ff430601babe40ec5 100644 (file)
@@ -424,7 +424,7 @@ pub fn can_begin_const_arg(&self) -> bool {
                 NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
                 _ => false,
             },
-            _ => self.can_begin_literal_or_bool(),
+            _ => self.can_begin_literal_maybe_minus(),
         }
     }
 
@@ -448,13 +448,22 @@ pub fn is_lit(&self) -> bool {
     /// 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,
index d1757394f3a1dee633881c5720e6695022c9727c..1b17f343a6d67deb74f0e7027199c9985d65438f 100644 (file)
@@ -189,7 +189,7 @@ pub fn from_lit_token(token: token::Lit, span: Span) -> Result<Lit, LitError> {
 
     /// 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() => {
index 3b9158f444519f1cc64c80244b9c874789242444..0d777d88cad3a6b1e7ca080ae5260005b355686d 100644 (file)
@@ -778,7 +778,7 @@ fn may_be_ident(nt: &token::Nonterminal) -> 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,
index c65e99842c5ddf3c63353bed158521c57f6ef081..58ebc6b5637072f7681875c769d495f9f1a1bd05 100644 (file)
@@ -1374,6 +1374,7 @@ pub(super) fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<Symbo
     }
 
     /// 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);
 
index 9d70f606f3ef4339e80e6c619cd1048282bbd8d6..7ccf31d8b4faa64943c59560e0039ea42a13f9bc 100644 (file)
@@ -1509,7 +1509,7 @@ fn check_fn_front_matter(&mut self) -> bool {
                 })
             // `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))
     }
 
index 4585941943b74a001a64c10a85ae14c2370e55d4..5aab0580997c0b9b30e4b77d27f8cc123ea447bc 100644 (file)
@@ -696,7 +696,7 @@ fn is_pat_range_end_start(&self, dist: usize) -> bool {
         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()
         })
     }
index cb23f2c808c3478515e6366ce7d66d565062f2d7..4ecb21d26ab9b7fe6f99cec1d1122b8acec0b45b 100644 (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");
+}
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 (file)
index 0000000..aca9d9e
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+macro_rules! foo {
+    ($a:literal) => {
+        bar!($a)
+    };
+}
+
+macro_rules! bar {
+    ($b:literal) => {};
+}
+
+fn main() {
+    foo!(-2);
+    bar!(-2);
+}