about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-10-28 00:29:23 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2019-11-07 05:25:31 +0100
commit1db4d607e7621a7d813743e83125859a47970f79 (patch)
treecde776509b2b3fbfb57b2a8bb9c4d33ef3856978
parent49def0769c51d182bf6c321eefdcda288e3ad218 (diff)
downloadrust-1db4d607e7621a7d813743e83125859a47970f79.tar.gz
rust-1db4d607e7621a7d813743e83125859a47970f79.zip
parser: allow ABIs from literal macro fragments
-rw-r--r--src/libsyntax/parse/parser.rs40
-rw-r--r--src/libsyntax/parse/parser/expr.rs6
-rw-r--r--src/libsyntax/parse/parser/item.rs2
-rw-r--r--src/libsyntax/parse/token.rs7
-rw-r--r--src/test/ui/parser/bad-lit-suffixes.rs4
-rw-r--r--src/test/ui/parser/bad-lit-suffixes.stderr4
-rw-r--r--src/test/ui/parser/extern-abi-from-mac-literal-frag.rs26
7 files changed, 63 insertions, 26 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 382c1a517aa..0c358b1caaf 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1205,27 +1205,41 @@ impl<'a> Parser<'a> {
         Ok(())
     }
 
-    /// Parses `extern` followed by an optional ABI string, or nothing.
+    /// Parses `extern string_literal?`.
+    /// If `extern` is not found, the Rust ABI is used.
+    /// If `extern` is found and a `string_literal` does not follow, the C ABI is used.
     fn parse_extern_abi(&mut self) -> PResult<'a, Abi> {
         Ok(if self.eat_keyword(kw::Extern) {
-            let ext_sp = self.prev_span;
-            self.parse_opt_abi()?.unwrap_or_else(|| Abi::new(sym::C, ext_sp))
+            self.parse_opt_abi()?
         } else {
             Abi::default()
         })
     }
 
-    /// Parses a string as an ABI spec on an extern type or module.
-    fn parse_opt_abi(&mut self) -> PResult<'a, Option<Abi>> {
-        match self.token.kind {
-            token::Literal(token::Lit { kind: token::Str, symbol, suffix }) |
-            token::Literal(token::Lit { kind: token::StrRaw(..), symbol, suffix }) => {
-                self.expect_no_suffix(self.token.span, "an ABI spec", suffix);
-                self.bump();
-                Ok(Some(Abi::new(symbol, self.prev_span)))
+    /// Parses a string literal as an ABI spec.
+    /// If one is not found, the "C" ABI is used.
+    fn parse_opt_abi(&mut self) -> PResult<'a, Abi> {
+        let span = if self.token.can_begin_literal_or_bool() {
+            let ast::Lit { span, kind, .. } = self.parse_lit()?;
+            match kind {
+                ast::LitKind::Str(symbol, _) => return Ok(Abi::new(symbol, span)),
+                ast::LitKind::Err(_) => {}
+                _ => {
+                    self.struct_span_err(span, "non-string ABI literal")
+                        .span_suggestion(
+                            span,
+                            "specify the ABI with a string literal",
+                            "\"C\"".to_string(),
+                            Applicability::MaybeIncorrect,
+                        )
+                        .emit();
+                }
             }
-            _ => Ok(None),
-        }
+            span
+        } else {
+            self.prev_span
+        };
+        Ok(Abi::new(sym::C, span))
     }
 
     /// We are parsing `async fn`. If we are on Rust 2015, emit an error.
diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs
index 97b1092452a..80ea8f380fb 100644
--- a/src/libsyntax/parse/parser/expr.rs
+++ b/src/libsyntax/parse/parser/expr.rs
@@ -1116,7 +1116,11 @@ impl<'a> Parser<'a> {
                 Err(self.span_fatal(token.span, &msg))
             }
             Err(err) => {
-                let (lit, span) = (token.expect_lit(), token.span);
+                let span = token.span;
+                let lit = match token.kind {
+                    token::Literal(lit) => lit,
+                    _ => unreachable!(),
+                };
                 self.bump();
                 self.error_literal_from_token(err, lit, span);
                 // Pack possible quotes and prefixes from the original literal into
diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs
index 76411e7cf13..ebb1cf12996 100644
--- a/src/libsyntax/parse/parser/item.rs
+++ b/src/libsyntax/parse/parser/item.rs
@@ -110,7 +110,7 @@ impl<'a> Parser<'a> {
                 return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?));
             }
 
-            let abi = self.parse_opt_abi()?.unwrap_or_else(|| Abi::new(sym::C, extern_sp));
+            let abi = self.parse_opt_abi()?;
 
             if self.eat_keyword(kw::Fn) {
                 // EXTERN FUNCTION ITEM
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index ea82aad0eae..6f3da344ccf 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -402,13 +402,6 @@ impl Token {
         }
     }
 
-    crate fn expect_lit(&self) -> Lit {
-        match self.kind {
-            Literal(lit) => lit,
-            _ => panic!("`expect_lit` called on non-literal"),
-        }
-    }
-
     /// 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).
     pub fn can_begin_literal_or_bool(&self) -> bool {
diff --git a/src/test/ui/parser/bad-lit-suffixes.rs b/src/test/ui/parser/bad-lit-suffixes.rs
index 9f301db0995..7db83674efc 100644
--- a/src/test/ui/parser/bad-lit-suffixes.rs
+++ b/src/test/ui/parser/bad-lit-suffixes.rs
@@ -1,9 +1,9 @@
 extern
-    "C"suffix //~ ERROR suffixes on an ABI spec are invalid
+    "C"suffix //~ ERROR suffixes on a string literal are invalid
     fn foo() {}
 
 extern
-    "C"suffix //~ ERROR suffixes on an ABI spec are invalid
+    "C"suffix //~ ERROR suffixes on a string literal are invalid
 {}
 
 fn main() {
diff --git a/src/test/ui/parser/bad-lit-suffixes.stderr b/src/test/ui/parser/bad-lit-suffixes.stderr
index 208fcf43d91..6b0049298ff 100644
--- a/src/test/ui/parser/bad-lit-suffixes.stderr
+++ b/src/test/ui/parser/bad-lit-suffixes.stderr
@@ -1,10 +1,10 @@
-error: suffixes on an ABI spec are invalid
+error: suffixes on a string literal are invalid
   --> $DIR/bad-lit-suffixes.rs:2:5
    |
 LL |     "C"suffix
    |     ^^^^^^^^^ invalid suffix `suffix`
 
-error: suffixes on an ABI spec are invalid
+error: suffixes on a string literal are invalid
   --> $DIR/bad-lit-suffixes.rs:6:5
    |
 LL |     "C"suffix
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
new file mode 100644
index 00000000000..cb23f2c808c
--- /dev/null
+++ b/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs
@@ -0,0 +1,26 @@
+// 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.
+
+fn main() {}
+
+macro_rules! abi_from_lit_frag {
+    ($abi:literal) => {
+        extern $abi {
+            fn _import();
+        }
+
+        extern $abi fn _export() {}
+
+        type _PTR = extern $abi fn();
+    }
+}
+
+mod rust {
+    abi_from_lit_frag!("Rust");
+}
+
+mod c {
+    abi_from_lit_frag!("C");
+}