about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs22
-rw-r--r--src/test/ui/parser/kw-in-trait-bounds.rs47
-rw-r--r--src/test/ui/parser/kw-in-trait-bounds.stderr171
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/without-tilde.stderr6
5 files changed, 244 insertions, 4 deletions
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 76b710095d7..4a2cf74905b 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -640,7 +640,13 @@ impl<'a> Parser<'a> {
         let mut bounds = Vec::new();
         let mut negative_bounds = Vec::new();
 
-        while self.can_begin_bound() || self.token.is_keyword(kw::Dyn) {
+        while self.can_begin_bound()
+            // Continue even if we find a keyword.
+            // This is necessary for error recover on, for example, `impl fn()`.
+            //
+            // The only keyword that can go after generic bounds is `where`, so stop if it's it.
+            || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where))
+        {
             if self.token.is_keyword(kw::Dyn) {
                 // Account for `&dyn Trait + dyn Other`.
                 self.struct_span_err(self.token.span, "invalid `dyn` keyword")
@@ -804,6 +810,20 @@ impl<'a> Parser<'a> {
             let span = tilde.to(self.prev_token.span);
             self.sess.gated_spans.gate(sym::const_trait_impl, span);
             Some(span)
+        } else if self.eat_keyword(kw::Const) {
+            let span = self.prev_token.span;
+            self.sess.gated_spans.gate(sym::const_trait_impl, span);
+
+            self.struct_span_err(span, "const bounds must start with `~`")
+                .span_suggestion(
+                    span.shrink_to_lo(),
+                    "add `~`",
+                    "~",
+                    Applicability::MachineApplicable,
+                )
+                .emit();
+
+            Some(span)
         } else {
             None
         };
diff --git a/src/test/ui/parser/kw-in-trait-bounds.rs b/src/test/ui/parser/kw-in-trait-bounds.rs
new file mode 100644
index 00000000000..fa037e5937d
--- /dev/null
+++ b/src/test/ui/parser/kw-in-trait-bounds.rs
@@ -0,0 +1,47 @@
+// edition:2018
+
+fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
+//~^ ERROR expected identifier, found keyword `fn`
+//~| ERROR expected identifier, found keyword `fn`
+//~| ERROR expected identifier, found keyword `fn`
+//~| ERROR cannot find trait `r#fn` in this scope
+//~| ERROR cannot find trait `r#fn` in this scope
+//~| ERROR cannot find trait `r#fn` in this scope
+//~| HELP  a trait with a similar name exists
+//~| HELP  a trait with a similar name exists
+//~| HELP  a trait with a similar name exists
+//~| HELP  escape `fn` to use it as an identifier
+//~| HELP  escape `fn` to use it as an identifier
+//~| HELP  escape `fn` to use it as an identifier
+where
+G: fn(),
+    //~^ ERROR expected identifier, found keyword `fn`
+    //~| ERROR cannot find trait `r#fn` in this scope
+    //~| HELP  a trait with a similar name exists
+    //~| HELP  escape `fn` to use it as an identifier
+{}
+
+fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
+//~^ ERROR expected identifier, found keyword `struct`
+//~| ERROR expected identifier, found keyword `struct`
+//~| ERROR expected identifier, found keyword `struct`
+//~| ERROR cannot find trait `r#struct` in this scope
+//~| ERROR cannot find trait `r#struct` in this scope
+//~| ERROR cannot find trait `r#struct` in this scope
+//~| HELP  a trait with a similar name exists
+//~| HELP  a trait with a similar name exists
+//~| HELP  a trait with a similar name exists
+//~| HELP  escape `struct` to use it as an identifier
+//~| HELP  escape `struct` to use it as an identifier
+//~| HELP  escape `struct` to use it as an identifier
+where
+    B: struct,
+    //~^ ERROR expected identifier, found keyword `struct`
+    //~| ERROR cannot find trait `r#struct` in this scope
+    //~| HELP  a trait with a similar name exists
+    //~| HELP  escape `struct` to use it as an identifier
+{}
+
+trait Struct {}
+
+fn main() {}
diff --git a/src/test/ui/parser/kw-in-trait-bounds.stderr b/src/test/ui/parser/kw-in-trait-bounds.stderr
new file mode 100644
index 00000000000..28196c7ce2d
--- /dev/null
+++ b/src/test/ui/parser/kw-in-trait-bounds.stderr
@@ -0,0 +1,171 @@
+error: expected identifier, found keyword `fn`
+  --> $DIR/kw-in-trait-bounds.rs:3:10
+   |
+LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
+   |          ^^ expected identifier, found keyword
+   |
+help: escape `fn` to use it as an identifier
+   |
+LL | fn _f<F: r#fn(), G>(_: impl fn(), _: &dyn fn())
+   |          ++
+
+error: expected identifier, found keyword `fn`
+  --> $DIR/kw-in-trait-bounds.rs:3:27
+   |
+LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
+   |                           ^^ expected identifier, found keyword
+   |
+help: escape `fn` to use it as an identifier
+   |
+LL | fn _f<F: fn(), G>(_: impl r#fn(), _: &dyn fn())
+   |                           ++
+
+error: expected identifier, found keyword `fn`
+  --> $DIR/kw-in-trait-bounds.rs:3:41
+   |
+LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
+   |                                         ^^ expected identifier, found keyword
+   |
+help: escape `fn` to use it as an identifier
+   |
+LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn r#fn())
+   |                                         ++
+
+error: expected identifier, found keyword `fn`
+  --> $DIR/kw-in-trait-bounds.rs:17:4
+   |
+LL | G: fn(),
+   |    ^^ expected identifier, found keyword
+   |
+help: escape `fn` to use it as an identifier
+   |
+LL | G: r#fn(),
+   |    ++
+
+error: expected identifier, found keyword `struct`
+  --> $DIR/kw-in-trait-bounds.rs:24:10
+   |
+LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
+   |          ^^^^^^ expected identifier, found keyword
+   |
+help: escape `struct` to use it as an identifier
+   |
+LL | fn _g<A: r#struct, B>(_: impl struct, _: &dyn struct)
+   |          ++
+
+error: expected identifier, found keyword `struct`
+  --> $DIR/kw-in-trait-bounds.rs:24:29
+   |
+LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
+   |                             ^^^^^^ expected identifier, found keyword
+   |
+help: escape `struct` to use it as an identifier
+   |
+LL | fn _g<A: struct, B>(_: impl r#struct, _: &dyn struct)
+   |                             ++
+
+error: expected identifier, found keyword `struct`
+  --> $DIR/kw-in-trait-bounds.rs:24:45
+   |
+LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
+   |                                             ^^^^^^ expected identifier, found keyword
+   |
+help: escape `struct` to use it as an identifier
+   |
+LL | fn _g<A: struct, B>(_: impl struct, _: &dyn r#struct)
+   |                                             ++
+
+error: expected identifier, found keyword `struct`
+  --> $DIR/kw-in-trait-bounds.rs:38:8
+   |
+LL |     B: struct,
+   |        ^^^^^^ expected identifier, found keyword
+   |
+help: escape `struct` to use it as an identifier
+   |
+LL |     B: r#struct,
+   |        ++
+
+error[E0405]: cannot find trait `r#fn` in this scope
+  --> $DIR/kw-in-trait-bounds.rs:3:10
+   |
+LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
+   |          ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
+   |
+  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL | pub trait Fn<Args>: FnMut<Args> {
+   | ------------------------------- similarly named trait `Fn` defined here
+
+error[E0405]: cannot find trait `r#fn` in this scope
+  --> $DIR/kw-in-trait-bounds.rs:17:4
+   |
+LL | G: fn(),
+   |    ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
+   |
+  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL | pub trait Fn<Args>: FnMut<Args> {
+   | ------------------------------- similarly named trait `Fn` defined here
+
+error[E0405]: cannot find trait `r#fn` in this scope
+  --> $DIR/kw-in-trait-bounds.rs:3:27
+   |
+LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
+   |                           ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
+   |
+  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL | pub trait Fn<Args>: FnMut<Args> {
+   | ------------------------------- similarly named trait `Fn` defined here
+
+error[E0405]: cannot find trait `r#fn` in this scope
+  --> $DIR/kw-in-trait-bounds.rs:3:41
+   |
+LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
+   |                                         ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
+   |
+  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL | pub trait Fn<Args>: FnMut<Args> {
+   | ------------------------------- similarly named trait `Fn` defined here
+
+error[E0405]: cannot find trait `r#struct` in this scope
+  --> $DIR/kw-in-trait-bounds.rs:24:10
+   |
+LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
+   |          ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
+...
+LL | trait Struct {}
+   | ------------ similarly named trait `Struct` defined here
+
+error[E0405]: cannot find trait `r#struct` in this scope
+  --> $DIR/kw-in-trait-bounds.rs:38:8
+   |
+LL |     B: struct,
+   |        ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
+...
+LL | trait Struct {}
+   | ------------ similarly named trait `Struct` defined here
+
+error[E0405]: cannot find trait `r#struct` in this scope
+  --> $DIR/kw-in-trait-bounds.rs:24:29
+   |
+LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
+   |                             ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
+...
+LL | trait Struct {}
+   | ------------ similarly named trait `Struct` defined here
+
+error[E0405]: cannot find trait `r#struct` in this scope
+  --> $DIR/kw-in-trait-bounds.rs:24:45
+   |
+LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
+   |                                             ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
+...
+LL | trait Struct {}
+   | ------------ similarly named trait `Struct` defined here
+
+error: aborting due to 16 previous errors
+
+For more information about this error, try `rustc --explain E0405`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs b/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs
index e8b26154549..d63381b5f2c 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs
@@ -3,4 +3,4 @@
 #![feature(const_trait_impl)]
 
 struct S<T: const Tr>;
-//~^ ERROR expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, `~`, lifetime, or path
+//~^ ERROR const bounds must start with `~`
diff --git a/src/test/ui/rfc-2632-const-trait-impl/without-tilde.stderr b/src/test/ui/rfc-2632-const-trait-impl/without-tilde.stderr
index b6b77ac4a2f..31300354a57 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/without-tilde.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/without-tilde.stderr
@@ -1,8 +1,10 @@
-error: expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, `~`, lifetime, or path, found keyword `const`
+error: const bounds must start with `~`
   --> $DIR/without-tilde.rs:5:13
    |
 LL | struct S<T: const Tr>;
-   |             ^^^^^ expected one of 10 possible tokens
+   |             -^^^^
+   |             |
+   |             help: add `~`: `~`
 
 error: aborting due to previous error