From a72dd4a5b973a3d94876ebea66e428fabaff00b0 Mon Sep 17 00:00:00 2001
From: Hirochika Matsumoto <git@hkmatsumoto.com>
Date: Tue, 19 Oct 2021 01:31:23 +0900
Subject: [PATCH] Explain why `Self` is invalid in generic parameters

---
 compiler/rustc_parse/src/parser/generics.rs   | 13 +++++++++
 .../ui/keyword/keyword-self-as-type-param.rs  |  6 ++--
 .../keyword/keyword-self-as-type-param.stderr | 29 ++++++++++++-------
 3 files changed, 35 insertions(+), 13 deletions(-)

diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index f175c5b50b397..ec7e376656618 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -89,6 +89,19 @@ impl<'a> Parser<'a> {
             let attrs = self.parse_outer_attributes()?;
             let param =
                 self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+                    if this.eat_keyword_noexpect(kw::SelfUpper) {
+                        // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
+                        // as if `Self` never existed.
+                        this.struct_span_err(
+                            this.prev_token.span,
+                            "unexpected keyword `Self` in generic parameters",
+                        )
+                        .note("you cannot use `Self` as a generic parameter because it is reserved for associated items")
+                        .emit();
+
+                        this.eat(&token::Comma);
+                    }
+
                     let param = if this.check_lifetime() {
                         let lifetime = this.expect_lifetime();
                         // Parse lifetime parameter.
diff --git a/src/test/ui/keyword/keyword-self-as-type-param.rs b/src/test/ui/keyword/keyword-self-as-type-param.rs
index 785d64ec8ea22..55c7ac128ffde 100644
--- a/src/test/ui/keyword/keyword-self-as-type-param.rs
+++ b/src/test/ui/keyword/keyword-self-as-type-param.rs
@@ -1,10 +1,10 @@
 // Regression test of #36638.
 
 struct Foo<Self>(Self);
-//~^ ERROR expected identifier, found keyword `Self`
-//~^^ ERROR E0392
+//~^ ERROR unexpected keyword `Self` in generic parameters
+//~| ERROR recursive type `Foo` has infinite size
 
 trait Bar<Self> {}
-//~^ ERROR expected identifier, found keyword `Self`
+//~^ ERROR unexpected keyword `Self` in generic parameters
 
 fn main() {}
diff --git a/src/test/ui/keyword/keyword-self-as-type-param.stderr b/src/test/ui/keyword/keyword-self-as-type-param.stderr
index cc3df2e36f7f5..fd101b32b4c9c 100644
--- a/src/test/ui/keyword/keyword-self-as-type-param.stderr
+++ b/src/test/ui/keyword/keyword-self-as-type-param.stderr
@@ -1,24 +1,33 @@
-error: expected identifier, found keyword `Self`
+error: unexpected keyword `Self` in generic parameters
   --> $DIR/keyword-self-as-type-param.rs:3:12
    |
 LL | struct Foo<Self>(Self);
-   |            ^^^^ expected identifier, found keyword
+   |            ^^^^
+   |
+   = note: you cannot use `Self` as a generic parameter because it is reserved for associated items
 
-error: expected identifier, found keyword `Self`
+error: unexpected keyword `Self` in generic parameters
   --> $DIR/keyword-self-as-type-param.rs:7:11
    |
 LL | trait Bar<Self> {}
-   |           ^^^^ expected identifier, found keyword
+   |           ^^^^
+   |
+   = note: you cannot use `Self` as a generic parameter because it is reserved for associated items
 
-error[E0392]: parameter `Self` is never used
-  --> $DIR/keyword-self-as-type-param.rs:3:12
+error[E0072]: recursive type `Foo` has infinite size
+  --> $DIR/keyword-self-as-type-param.rs:3:1
    |
 LL | struct Foo<Self>(Self);
-   |            ^^^^ unused parameter
+   | ^^^^^^^^^^^^^^^^^----^^
+   | |                |
+   | |                recursive without indirection
+   | recursive type has infinite size
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
    |
-   = help: consider removing `Self`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `Self` to be a const parameter, use `const Self: usize` instead
+LL | struct Foo<Self>(Box<Self>);
+   |                  ++++    +
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0392`.
+For more information about this error, try `rustc --explain E0072`.