From c018ead64ea14ab96f6baa55064f2a46c27fec68 Mon Sep 17 00:00:00 2001
From: Jack Huey <31162821+jackh726@users.noreply.github.com>
Date: Mon, 13 Dec 2021 02:07:31 -0500
Subject: [PATCH 1/2] Warn when gats are enabled and we trigger the outlives
 lint

---
 compiler/rustc_typeck/src/check/wfcheck.rs    | 24 ++++++++-----
 .../self-outlives-lint.rs                     | 14 ++++++--
 .../self-outlives-lint.stderr                 | 36 +++++++++++++++----
 3 files changed, 57 insertions(+), 17 deletions(-)

diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 1404bc271673e..36a7b319269ff 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -287,7 +287,7 @@ fn check_gat_where_clauses(
     let generics: &ty::Generics = tcx.generics_of(trait_item.def_id);
     // If the current associated type doesn't have any (own) params, it's not a GAT
     // FIXME(jackh726): we can also warn in the more general case
-    if generics.params.len() == 0 {
+    if generics.params.len() == 0 && !tcx.features().generic_associated_types {
         return;
     }
     let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id);
@@ -465,10 +465,18 @@ fn check_gat_where_clauses(
 
         if !clauses.is_empty() {
             let plural = if clauses.len() > 1 { "s" } else { "" };
-            let mut err = tcx.sess.struct_span_err(
-                trait_item.span,
-                &format!("missing required bound{} on `{}`", plural, trait_item.ident),
-            );
+            let severity = if generics.params.len() == 0 { "recommended" } else { "required" };
+            let mut err = if generics.params.len() == 0 {
+                tcx.sess.struct_span_warn(
+                    trait_item.span,
+                    &format!("missing {} bound{} on `{}`", severity, plural, trait_item.ident),
+                )
+            } else {
+                tcx.sess.struct_span_err(
+                    trait_item.span,
+                    &format!("missing {} bound{} on `{}`", severity, plural, trait_item.ident),
+                )
+            };
 
             let suggestion = format!(
                 "{} {}",
@@ -481,15 +489,15 @@ fn check_gat_where_clauses(
             );
             err.span_suggestion(
                 trait_item.generics.where_clause.tail_span_for_suggestion(),
-                &format!("add the required where clause{}", plural),
+                &format!("add the {} where clause{}", severity, plural),
                 suggestion,
                 Applicability::MachineApplicable,
             );
 
             let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" };
             err.note(&format!(
-                "{} currently required to ensure that impls have maximum flexibility",
-                bound
+                "{} currently {} to ensure that impls have maximum flexibility",
+                bound, severity,
             ));
             err.note(
                 "we are soliciting feedback, see issue #87479 \
diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.rs b/src/test/ui/generic-associated-types/self-outlives-lint.rs
index 37b3a6155d5ae..dd6519961d968 100644
--- a/src/test/ui/generic-associated-types/self-outlives-lint.rs
+++ b/src/test/ui/generic-associated-types/self-outlives-lint.rs
@@ -102,12 +102,22 @@ impl Des3 for () {
 }
 */
 
-// Similar case to before, except with GAT.
+// Similar case to before, except without GAT.
 trait NoGat<'a> {
     type Bar;
+    //~^ missing recommended
     fn method(&'a self) -> Self::Bar;
 }
 
+
+// Same as above, except explicit
+trait NoGatWarning<'a> {
+    type Output;
+    //~^ missing recommended
+
+    fn method(&'a self) -> <Self as NoGatWarning<'a>>::Output;
+}
+
 // Lifetime is not on function; except `Self: 'a`
 // FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one
 trait TraitLifetime<'a> {
@@ -184,7 +194,7 @@ trait MultipleMethods {
 
 // We would normally require `Self: 'a`, but we can prove that `Self: 'static`
 // because of the the bounds on the trait, so the bound is proven
-trait Trait: 'static {
+trait StaticTrait: 'static {
     type Assoc<'a>;
     fn make_assoc(_: &u32) -> Self::Assoc<'_>;
 }
diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.stderr b/src/test/ui/generic-associated-types/self-outlives-lint.stderr
index 3b9146ad875a3..b87ef8f2360ec 100644
--- a/src/test/ui/generic-associated-types/self-outlives-lint.stderr
+++ b/src/test/ui/generic-associated-types/self-outlives-lint.stderr
@@ -75,8 +75,30 @@ LL |     type Out<'x, D>;
    = note: this bound is currently required to ensure that impls have maximum flexibility
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
+warning: missing recommended bound on `Bar`
+  --> $DIR/self-outlives-lint.rs:107:5
+   |
+LL |     type Bar;
+   |     ^^^^^^^^-
+   |             |
+   |             help: add the recommended where clause: `where Self: 'a`
+   |
+   = note: this bound is currently recommended to ensure that impls have maximum flexibility
+   = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
+
+warning: missing recommended bound on `Output`
+  --> $DIR/self-outlives-lint.rs:115:5
+   |
+LL |     type Output;
+   |     ^^^^^^^^^^^-
+   |                |
+   |                help: add the recommended where clause: `where Self: 'a`
+   |
+   = note: this bound is currently recommended to ensure that impls have maximum flexibility
+   = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
+
 error: missing required bounds on `Bar`
-  --> $DIR/self-outlives-lint.rs:114:5
+  --> $DIR/self-outlives-lint.rs:124:5
    |
 LL |     type Bar<'b>;
    |     ^^^^^^^^^^^^-
@@ -87,7 +109,7 @@ LL |     type Bar<'b>;
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
 error: missing required bound on `Bar`
-  --> $DIR/self-outlives-lint.rs:122:5
+  --> $DIR/self-outlives-lint.rs:132:5
    |
 LL |     type Bar<'b>;
    |     ^^^^^^^^^^^^-
@@ -98,7 +120,7 @@ LL |     type Bar<'b>;
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
 error: missing required bound on `Bar`
-  --> $DIR/self-outlives-lint.rs:129:5
+  --> $DIR/self-outlives-lint.rs:139:5
    |
 LL |     type Bar<'b>;
    |     ^^^^^^^^^^^^-
@@ -109,7 +131,7 @@ LL |     type Bar<'b>;
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
 error: missing required bound on `Iterator`
-  --> $DIR/self-outlives-lint.rs:143:5
+  --> $DIR/self-outlives-lint.rs:153:5
    |
 LL |     type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -120,7 +142,7 @@ LL |     type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
 error: missing required bound on `Bar`
-  --> $DIR/self-outlives-lint.rs:151:5
+  --> $DIR/self-outlives-lint.rs:161:5
    |
 LL |     type Bar<'a, 'b>;
    |     ^^^^^^^^^^^^^^^^-
@@ -131,7 +153,7 @@ LL |     type Bar<'a, 'b>;
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
 error: missing required bound on `Fut`
-  --> $DIR/self-outlives-lint.rs:167:5
+  --> $DIR/self-outlives-lint.rs:177:5
    |
 LL |     type Fut<'out>;
    |     ^^^^^^^^^^^^^^-
@@ -141,5 +163,5 @@ LL |     type Fut<'out>;
    = note: this bound is currently required to ensure that impls have maximum flexibility
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
-error: aborting due to 13 previous errors
+error: aborting due to 13 previous errors; 2 warnings emitted
 

From cc51c4edd58b93906dc6791616cb6ed36b89d476 Mon Sep 17 00:00:00 2001
From: Jack Huey <31162821+jackh726@users.noreply.github.com>
Date: Mon, 7 Feb 2022 14:20:57 -0500
Subject: [PATCH 2/2] Change to error for crater

---
 compiler/rustc_typeck/src/check/wfcheck.rs | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 36a7b319269ff..e6e4ffc92726f 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -285,11 +285,6 @@ fn check_gat_where_clauses(
         return;
     }
     let generics: &ty::Generics = tcx.generics_of(trait_item.def_id);
-    // If the current associated type doesn't have any (own) params, it's not a GAT
-    // FIXME(jackh726): we can also warn in the more general case
-    if generics.params.len() == 0 && !tcx.features().generic_associated_types {
-        return;
-    }
     let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id);
     let mut clauses: Option<FxHashSet<ty::Predicate<'_>>> = None;
     // For every function in this trait...
@@ -466,17 +461,11 @@ fn check_gat_where_clauses(
         if !clauses.is_empty() {
             let plural = if clauses.len() > 1 { "s" } else { "" };
             let severity = if generics.params.len() == 0 { "recommended" } else { "required" };
-            let mut err = if generics.params.len() == 0 {
-                tcx.sess.struct_span_warn(
-                    trait_item.span,
-                    &format!("missing {} bound{} on `{}`", severity, plural, trait_item.ident),
-                )
-            } else {
+            let mut err = 
                 tcx.sess.struct_span_err(
                     trait_item.span,
                     &format!("missing {} bound{} on `{}`", severity, plural, trait_item.ident),
-                )
-            };
+                );
 
             let suggestion = format!(
                 "{} {}",