about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-03-26 09:31:29 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2020-03-26 09:44:11 +0100
commitaf1146bd23634d34d953255114b1235e131f2c80 (patch)
tree0bd12f8e2b4c42623db0e300967fb3bf106370b8 /src
parenta5fb9ae5b2ed3cb011ada9dc1e8633aa0927f279 (diff)
downloadrust-af1146bd23634d34d953255114b1235e131f2c80.tar.gz
rust-af1146bd23634d34d953255114b1235e131f2c80.zip
parse: recover on `const fn()` / `async fn()`.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_parse/parser/item.rs4
-rw-r--r--src/librustc_parse/parser/ty.rs44
-rw-r--r--src/test/ui/keyword/extern/keyword-extern-as-identifier-type.rs2
-rw-r--r--src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr6
-rw-r--r--src/test/ui/parser/issue-63116.stderr2
-rw-r--r--src/test/ui/parser/recover-const-async-fn-ptr.rs25
-rw-r--r--src/test/ui/parser/recover-const-async-fn-ptr.stderr155
7 files changed, 215 insertions, 23 deletions
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 7a4f7680415..a0e82b7ca1e 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -1494,7 +1494,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Is the current token the start of an `FnHeader` / not a valid parse?
-    fn check_fn_front_matter(&mut self) -> bool {
+    pub(super) fn check_fn_front_matter(&mut self) -> bool {
         // We use an over-approximation here.
         // `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
         const QUALS: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern];
@@ -1521,7 +1521,7 @@ impl<'a> Parser<'a> {
     /// FnQual = "const"? "async"? "unsafe"? Extern? ;
     /// FnFrontMatter = FnQual? "fn" ;
     /// ```
-    fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
+    pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
         let constness = self.parse_constness();
         let asyncness = self.parse_asyncness();
         let unsafety = self.parse_unsafety();
diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs
index c21ac8d04f1..a6015504a32 100644
--- a/src/librustc_parse/parser/ty.rs
+++ b/src/librustc_parse/parser/ty.rs
@@ -127,16 +127,16 @@ impl<'a> Parser<'a> {
         } else if self.eat_keyword(kw::Underscore) {
             // A type to be inferred `_`
             TyKind::Infer
-        } else if self.token_is_bare_fn_keyword() {
+        } else if self.check_fn_front_matter() {
             // Function pointer type
-            self.parse_ty_bare_fn(Vec::new())?
+            self.parse_ty_bare_fn(lo, Vec::new())?
         } else if self.check_keyword(kw::For) {
             // Function pointer type or bound list (trait object type) starting with a poly-trait.
             //   `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
             //   `for<'lt> Trait1<'lt> + Trait2 + 'a`
             let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
-            if self.token_is_bare_fn_keyword() {
-                self.parse_ty_bare_fn(lifetime_defs)?
+            if self.check_fn_front_matter() {
+                self.parse_ty_bare_fn(lo, lifetime_defs)?
             } else {
                 let path = self.parse_path(PathStyle::Type)?;
                 let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
@@ -291,13 +291,6 @@ impl<'a> Parser<'a> {
         Ok(TyKind::Typeof(expr))
     }
 
-    /// Is the current token one of the keywords that signals a bare function type?
-    fn token_is_bare_fn_keyword(&mut self) -> bool {
-        self.check_keyword(kw::Fn)
-            || self.check_keyword(kw::Unsafe)
-            || self.check_keyword(kw::Extern)
-    }
-
     /// Parses a function pointer type (`TyKind::BareFn`).
     /// ```
     /// [unsafe] [extern "ABI"] fn (S) -> T
@@ -306,12 +299,31 @@ impl<'a> Parser<'a> {
     ///    |               |        |   Return type
     /// Function Style    ABI  Parameter types
     /// ```
-    fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>) -> PResult<'a, TyKind> {
-        let unsafety = self.parse_unsafety();
-        let ext = self.parse_extern()?;
-        self.expect_keyword(kw::Fn)?;
+    /// We actually parse `FnHeader FnDecl`, but we error on `const` and `async` qualifiers.
+    fn parse_ty_bare_fn(&mut self, lo: Span, params: Vec<GenericParam>) -> PResult<'a, TyKind> {
+        let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?;
         let decl = self.parse_fn_decl(|_| false, AllowPlus::No)?;
-        Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params, decl })))
+        let whole_span = lo.to(self.prev_token.span);
+        if let ast::Const::Yes(span) = constness {
+            self.error_fn_ptr_bad_qualifier(whole_span, span, "const");
+        }
+        if let ast::Async::Yes { span, .. } = asyncness {
+            self.error_fn_ptr_bad_qualifier(whole_span, span, "async");
+        }
+        Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl })))
+    }
+
+    /// Emit an error for the given bad function pointer qualifier.
+    fn error_fn_ptr_bad_qualifier(&self, span: Span, qual_span: Span, qual: &str) {
+        self.struct_span_err(span, &format!("an `fn` pointer type cannot be `{}`", qual))
+            .span_label(qual_span, format!("`{}` because of this", qual))
+            .span_suggestion_short(
+                qual_span,
+                &format!("remove the `{}` qualifier", qual),
+                String::new(),
+                Applicability::MaybeIncorrect,
+            )
+            .emit();
     }
 
     /// Parses an `impl B0 + ... + Bn` type.
diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.rs b/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.rs
index 3845a9aa017..12aa059766b 100644
--- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.rs
+++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.rs
@@ -1,3 +1,3 @@
-type A = extern::foo::bar; //~ ERROR expected `fn`, found `::`
+type A = extern::foo::bar; //~ ERROR expected type, found keyword `extern`
 
 fn main() {}
diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr b/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr
index 48c2f556f1d..20ecf6bac76 100644
--- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr
+++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-type.stderr
@@ -1,8 +1,8 @@
-error: expected `fn`, found `::`
-  --> $DIR/keyword-extern-as-identifier-type.rs:1:16
+error: expected type, found keyword `extern`
+  --> $DIR/keyword-extern-as-identifier-type.rs:1:10
    |
 LL | type A = extern::foo::bar;
-   |                ^^ expected `fn`
+   |          ^^^^^^ expected type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issue-63116.stderr b/src/test/ui/parser/issue-63116.stderr
index 15cd3df860b..80a450dbd36 100644
--- a/src/test/ui/parser/issue-63116.stderr
+++ b/src/test/ui/parser/issue-63116.stderr
@@ -12,7 +12,7 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;`
 LL | impl W <s(f;Y(;]
    |            ^ expected one of 7 possible tokens
 
-error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;`
+error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `async`, `const`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;`
   --> $DIR/issue-63116.rs:3:15
    |
 LL | impl W <s(f;Y(;]
diff --git a/src/test/ui/parser/recover-const-async-fn-ptr.rs b/src/test/ui/parser/recover-const-async-fn-ptr.rs
new file mode 100644
index 00000000000..25af8772ced
--- /dev/null
+++ b/src/test/ui/parser/recover-const-async-fn-ptr.rs
@@ -0,0 +1,25 @@
+// edition:2018
+
+type T0 = const fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type T1 = const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type T2 = const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type T3 = async fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type T4 = async extern fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type T5 = async unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type T6 = const async unsafe extern "C" fn();
+//~^ ERROR an `fn` pointer type cannot be `const`
+//~| ERROR an `fn` pointer type cannot be `async`
+
+type FT0 = for<'a> const fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type FT1 = for<'a> const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type FT2 = for<'a> const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type FT3 = for<'a> async fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type FT4 = for<'a> async extern fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type FT5 = for<'a> async unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type FT6 = for<'a> const async unsafe extern "C" fn();
+//~^ ERROR an `fn` pointer type cannot be `const`
+//~| ERROR an `fn` pointer type cannot be `async`
+
+fn main() {
+    let _recovery_witness: () = 0; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/parser/recover-const-async-fn-ptr.stderr b/src/test/ui/parser/recover-const-async-fn-ptr.stderr
new file mode 100644
index 00000000000..7012096b644
--- /dev/null
+++ b/src/test/ui/parser/recover-const-async-fn-ptr.stderr
@@ -0,0 +1,155 @@
+error: an `fn` pointer type cannot be `const`
+  --> $DIR/recover-const-async-fn-ptr.rs:3:11
+   |
+LL | type T0 = const fn();
+   |           -----^^^^^
+   |           |
+   |           `const` because of this
+   |           help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `const`
+  --> $DIR/recover-const-async-fn-ptr.rs:4:11
+   |
+LL | type T1 = const extern "C" fn();
+   |           -----^^^^^^^^^^^^^^^^
+   |           |
+   |           `const` because of this
+   |           help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `const`
+  --> $DIR/recover-const-async-fn-ptr.rs:5:11
+   |
+LL | type T2 = const unsafe extern fn();
+   |           -----^^^^^^^^^^^^^^^^^^^
+   |           |
+   |           `const` because of this
+   |           help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `async`
+  --> $DIR/recover-const-async-fn-ptr.rs:6:11
+   |
+LL | type T3 = async fn();
+   |           -----^^^^^
+   |           |
+   |           `async` because of this
+   |           help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `async`
+  --> $DIR/recover-const-async-fn-ptr.rs:7:11
+   |
+LL | type T4 = async extern fn();
+   |           -----^^^^^^^^^^^^
+   |           |
+   |           `async` because of this
+   |           help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `async`
+  --> $DIR/recover-const-async-fn-ptr.rs:8:11
+   |
+LL | type T5 = async unsafe extern "C" fn();
+   |           -----^^^^^^^^^^^^^^^^^^^^^^^
+   |           |
+   |           `async` because of this
+   |           help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `const`
+  --> $DIR/recover-const-async-fn-ptr.rs:9:11
+   |
+LL | type T6 = const async unsafe extern "C" fn();
+   |           -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           |
+   |           `const` because of this
+   |           help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `async`
+  --> $DIR/recover-const-async-fn-ptr.rs:9:11
+   |
+LL | type T6 = const async unsafe extern "C" fn();
+   |           ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
+   |                 |
+   |                 `async` because of this
+   |                 help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `const`
+  --> $DIR/recover-const-async-fn-ptr.rs:13:12
+   |
+LL | type FT0 = for<'a> const fn();
+   |            ^^^^^^^^-----^^^^^
+   |                    |
+   |                    `const` because of this
+   |                    help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `const`
+  --> $DIR/recover-const-async-fn-ptr.rs:14:12
+   |
+LL | type FT1 = for<'a> const extern "C" fn();
+   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^
+   |                    |
+   |                    `const` because of this
+   |                    help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `const`
+  --> $DIR/recover-const-async-fn-ptr.rs:15:12
+   |
+LL | type FT2 = for<'a> const unsafe extern fn();
+   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^
+   |                    |
+   |                    `const` because of this
+   |                    help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `async`
+  --> $DIR/recover-const-async-fn-ptr.rs:16:12
+   |
+LL | type FT3 = for<'a> async fn();
+   |            ^^^^^^^^-----^^^^^
+   |                    |
+   |                    `async` because of this
+   |                    help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `async`
+  --> $DIR/recover-const-async-fn-ptr.rs:17:12
+   |
+LL | type FT4 = for<'a> async extern fn();
+   |            ^^^^^^^^-----^^^^^^^^^^^^
+   |                    |
+   |                    `async` because of this
+   |                    help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `async`
+  --> $DIR/recover-const-async-fn-ptr.rs:18:12
+   |
+LL | type FT5 = for<'a> async unsafe extern "C" fn();
+   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
+   |                    |
+   |                    `async` because of this
+   |                    help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `const`
+  --> $DIR/recover-const-async-fn-ptr.rs:19:12
+   |
+LL | type FT6 = for<'a> const async unsafe extern "C" fn();
+   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                    |
+   |                    `const` because of this
+   |                    help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `async`
+  --> $DIR/recover-const-async-fn-ptr.rs:19:12
+   |
+LL | type FT6 = for<'a> const async unsafe extern "C" fn();
+   |            ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
+   |                          |
+   |                          `async` because of this
+   |                          help: remove the `async` qualifier
+
+error[E0308]: mismatched types
+  --> $DIR/recover-const-async-fn-ptr.rs:24:33
+   |
+LL |     let _recovery_witness: () = 0;
+   |                            --   ^ expected `()`, found integer
+   |                            |
+   |                            expected due to this
+
+error: aborting due to 17 previous errors
+
+For more information about this error, try `rustc --explain E0308`.