From 13d3e57237eefd92a518d99367b6f8e04110e847 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Fri, 4 Aug 2023 23:54:14 +0000
Subject: [PATCH 1/4] RPITITs capture all their lifetimes

---
 compiler/rustc_ast_lowering/src/lib.rs        | 53 ++++++++-------
 compiler/rustc_resolve/src/late.rs            | 21 +++---
 .../impl-trait/in-trait/object-safety.stderr  | 13 +++-
 .../in-trait/signature-mismatch.stderr        | 65 +++----------------
 4 files changed, 60 insertions(+), 92 deletions(-)

diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 1827e42368f92..a4ba1a5c9bf48 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -236,7 +236,7 @@ enum ImplTraitContext {
     ReturnPositionOpaqueTy {
         /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
         origin: hir::OpaqueTyOrigin,
-        in_trait: bool,
+        fn_kind: FnDeclKind,
     },
     /// Impl trait in type aliases.
     TypeAliasesOpaqueTy { in_assoc_ty: bool },
@@ -312,7 +312,7 @@ impl std::fmt::Display for ImplTraitPosition {
     }
 }
 
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum FnDeclKind {
     Fn,
     Inherent,
@@ -1401,13 +1401,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             TyKind::ImplTrait(def_node_id, bounds) => {
                 let span = t.span;
                 match itctx {
-                    ImplTraitContext::ReturnPositionOpaqueTy { origin, in_trait } => self
+                    ImplTraitContext::ReturnPositionOpaqueTy { origin, fn_kind } => self
                         .lower_opaque_impl_trait(
                             span,
                             *origin,
                             *def_node_id,
                             bounds,
-                            *in_trait,
+                            Some(*fn_kind),
                             itctx,
                         ),
                     &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self
@@ -1416,7 +1416,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             hir::OpaqueTyOrigin::TyAlias { in_assoc_ty },
                             *def_node_id,
                             bounds,
-                            false,
+                            None,
                             itctx,
                         ),
                     ImplTraitContext::Universal => {
@@ -1523,7 +1523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         origin: hir::OpaqueTyOrigin,
         opaque_ty_node_id: NodeId,
         bounds: &GenericBounds,
-        in_trait: bool,
+        fn_kind: Option<FnDeclKind>,
         itctx: &ImplTraitContext,
     ) -> hir::TyKind<'hir> {
         // Make sure we know that some funky desugaring has been going on here.
@@ -1540,10 +1540,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 Vec::new()
             }
             hir::OpaqueTyOrigin::FnReturn(..) => {
-                // in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
-                // example, we only need to duplicate lifetimes that appear in the
-                // bounds, since those are the only ones that are captured by the opaque.
-                lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
+                if let FnDeclKind::Impl | FnDeclKind::Trait =
+                    fn_kind.expect("expected RPITs to be lowered with a FnKind")
+                {
+                    // return-position impl trait in trait was decided to capture all
+                    // in-scope lifetimes, which we collect for all opaques during resolution.
+                    self.resolver
+                        .take_extra_lifetime_params(opaque_ty_node_id)
+                        .into_iter()
+                        .map(|(ident, id, _)| Lifetime { id, ident })
+                        .collect()
+                } else {
+                    // in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
+                    // example, we only need to duplicate lifetimes that appear in the
+                    // bounds, since those are the only ones that are captured by the opaque.
+                    lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
+                }
             }
             hir::OpaqueTyOrigin::AsyncFn(..) => {
                 unreachable!("should be using `lower_async_fn_ret_ty`")
@@ -1554,7 +1566,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.lower_opaque_inner(
             opaque_ty_node_id,
             origin,
-            in_trait,
+            matches!(fn_kind, Some(FnDeclKind::Trait)),
             captured_lifetimes_to_duplicate,
             span,
             opaque_ty_span,
@@ -1802,12 +1814,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
 
             let fn_def_id = self.local_def_id(fn_node_id);
-            self.lower_async_fn_ret_ty(
-                &decl.output,
-                fn_def_id,
-                ret_id,
-                matches!(kind, FnDeclKind::Trait),
-            )
+            self.lower_async_fn_ret_ty(&decl.output, fn_def_id, ret_id, kind)
         } else {
             match &decl.output {
                 FnRetTy::Ty(ty) => {
@@ -1815,7 +1822,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         let fn_def_id = self.local_def_id(fn_node_id);
                         ImplTraitContext::ReturnPositionOpaqueTy {
                             origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
-                            in_trait: matches!(kind, FnDeclKind::Trait),
+                            fn_kind: kind,
                         }
                     } else {
                         let position = match kind {
@@ -1883,7 +1890,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         output: &FnRetTy,
         fn_def_id: LocalDefId,
         opaque_ty_node_id: NodeId,
-        in_trait: bool,
+        fn_kind: FnDeclKind,
     ) -> hir::FnRetTy<'hir> {
         let span = self.lower_span(output.span());
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
@@ -1898,7 +1905,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let opaque_ty_ref = self.lower_opaque_inner(
             opaque_ty_node_id,
             hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-            in_trait,
+            matches!(fn_kind, FnDeclKind::Trait),
             captured_lifetimes,
             span,
             opaque_ty_span,
@@ -1906,7 +1913,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let future_bound = this.lower_async_fn_output_type_to_future_bound(
                     output,
                     span,
-                    if in_trait && !this.tcx.features().return_position_impl_trait_in_trait {
+                    if let FnDeclKind::Trait = fn_kind
+                        && !this.tcx.features().return_position_impl_trait_in_trait
+                    {
                         ImplTraitContext::FeatureGated(
                             ImplTraitPosition::TraitReturn,
                             sym::return_position_impl_trait_in_trait,
@@ -1914,7 +1923,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     } else {
                         ImplTraitContext::ReturnPositionOpaqueTy {
                             origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
-                            in_trait,
+                            fn_kind,
                         }
                     },
                 );
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 22d084c8e0b5c..500004269c927 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -772,9 +772,10 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                 self.r.record_partial_res(ty.id, PartialRes::new(res));
                 visit::walk_ty(self, ty)
             }
-            TyKind::ImplTrait(..) => {
+            TyKind::ImplTrait(node_id, _) => {
                 let candidates = self.lifetime_elision_candidates.take();
                 visit::walk_ty(self, ty);
+                self.record_lifetime_params_for_impl_trait(*node_id);
                 self.lifetime_elision_candidates = candidates;
             }
             TyKind::TraitObject(bounds, ..) => {
@@ -909,8 +910,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                             &sig.decl.output,
                         );
 
-                        if let Some((async_node_id, span)) = sig.header.asyncness.opt_return_id() {
-                            this.record_lifetime_params_for_impl_trait(async_node_id, span);
+                        if let Some((async_node_id, _)) = sig.header.asyncness.opt_return_id() {
+                            this.record_lifetime_params_for_impl_trait(async_node_id);
                         }
                     },
                 );
@@ -951,8 +952,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                                     &declaration.output,
                                 );
 
-                                if let Some((async_node_id, span)) = async_node_id {
-                                    this.record_lifetime_params_for_impl_trait(async_node_id, span);
+                                if let Some((async_node_id, _)) = async_node_id {
+                                    this.record_lifetime_params_for_impl_trait(async_node_id);
                                 }
                             },
                         );
@@ -4367,7 +4368,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     /// We include all lifetime parameters, either named or "Fresh".
     /// The order of those parameters does not matter, as long as it is
     /// deterministic.
-    fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId, span: Span) {
+    fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId) {
         let mut extra_lifetime_params = vec![];
 
         for rib in self.lifetime_ribs.iter().rev() {
@@ -4380,14 +4381,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                         extra_lifetime_params.extend(earlier_fresh);
                     }
                 }
-                LifetimeRibKind::Generics { .. } => {}
-                _ => {
-                    // We are in a function definition. We should only find `Generics`
-                    // and `AnonymousCreateParameter` inside the innermost `Item`.
-                    span_bug!(span, "unexpected rib kind: {:?}", rib.kind)
-                }
+                _ => {}
             }
         }
+
         self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params);
     }
 
diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/object-safety.stderr
index 4a3b3b11465a1..1eb063a5fc2e7 100644
--- a/tests/ui/impl-trait/in-trait/object-safety.stderr
+++ b/tests/ui/impl-trait/in-trait/object-safety.stderr
@@ -13,6 +13,14 @@ LL |     fn baz(&self) -> impl Debug;
    |                      ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
    = help: consider moving `baz` to another trait
 
+error[E0277]: the trait bound `dyn Foo: Foo` is not satisfied
+  --> $DIR/object-safety.rs:20:15
+   |
+LL |     let s = i.baz();
+   |               ^^^ the trait `Foo` is not implemented for `dyn Foo`
+   |
+   = help: the trait `Foo` is implemented for `u32`
+
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/object-safety.rs:20:13
    |
@@ -44,6 +52,7 @@ LL |     fn baz(&self) -> impl Debug;
    = help: consider moving `baz` to another trait
    = note: required for the cast from `Box<u32>` to `Box<dyn Foo>`
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0038`.
+Some errors have detailed explanations: E0038, E0277.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.stderr b/tests/ui/impl-trait/in-trait/signature-mismatch.stderr
index 616f1ac35a953..05b5d3f11489f 100644
--- a/tests/ui/impl-trait/in-trait/signature-mismatch.stderr
+++ b/tests/ui/impl-trait/in-trait/signature-mismatch.stderr
@@ -1,61 +1,14 @@
-error: return type captures more lifetimes than trait definition
-  --> $DIR/signature-mismatch.rs:34:47
-   |
-LL |     fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
-   |                 -- this lifetime was captured ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: hidden type must only reference lifetimes captured by this impl trait
-  --> $DIR/signature-mismatch.rs:15:40
-   |
-LL |     fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>;
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: hidden type inferred to be `impl Future<Output = Vec<u8>> + 'a`
-
-error: return type captures more lifetimes than trait definition
-  --> $DIR/signature-mismatch.rs:39:57
-   |
-LL |     fn async_fn_early<'a: 'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
-   |                       -- this lifetime was captured     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: hidden type must only reference lifetimes captured by this impl trait
-  --> $DIR/signature-mismatch.rs:16:57
-   |
-LL |     fn async_fn_early<'a: 'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>>;
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: hidden type inferred to be `impl Future<Output = Vec<u8>> + 'a`
-
-error: return type captures more lifetimes than trait definition
-  --> $DIR/signature-mismatch.rs:47:10
-   |
-LL |     fn async_fn_multiple<'a, 'b>(
-   |                              -- this lifetime was captured
-...
-LL |     ) -> impl Future<Output = Vec<u8>> + Captures2<'a, 'b> {
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: hidden type must only reference lifetimes captured by this impl trait
-  --> $DIR/signature-mismatch.rs:18:12
-   |
-LL |         -> impl Future<Output = Vec<u8>> + Captures<'a>;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: hidden type inferred to be `impl Future<Output = Vec<u8>> + Captures2<'a, 'b>`
-
-error[E0309]: the parameter type `T` may not live long enough
+error[E0623]: lifetime mismatch
   --> $DIR/signature-mismatch.rs:56:10
    |
+LL |         &'a self,
+   |         -------- this parameter and the return type are declared with different lifetimes...
+...
 LL |     ) -> impl Future<Output = Vec<u8>> {
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `impl Future<Output = Vec<u8>>` will meet its required lifetime bounds...
-   |
-note: ...that is required by this bound
-  --> $DIR/signature-mismatch.rs:23:42
-   |
-LL |     ) -> impl Future<Output = Vec<u8>> + 'a;
-   |                                          ^^
-help: consider adding an explicit lifetime bound...
-   |
-LL |     fn async_fn_reduce_outlive<'a, 'b, T: 'a>(
-   |                                         ++++
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |          |
+   |          ...but data from `buff` is returned here
 
-error: aborting due to 4 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0309`.
+For more information about this error, try `rustc --explain E0623`.

From 32a9565223c05e6f7e60d783ad25e1864cd51d70 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 8 Aug 2023 19:37:35 +0000
Subject: [PATCH 2/4] Bless tests

---
 tests/ui/impl-trait/in-trait/object-safety.rs |  1 +
 ...derr => signature-mismatch.failure.stderr} |  2 +-
 .../impl-trait/in-trait/signature-mismatch.rs | 38 +++++++++++++++----
 3 files changed, 32 insertions(+), 9 deletions(-)
 rename tests/ui/impl-trait/in-trait/{signature-mismatch.stderr => signature-mismatch.failure.stderr} (91%)

diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs
index dd35b9a2d8a75..6e02934363d56 100644
--- a/tests/ui/impl-trait/in-trait/object-safety.rs
+++ b/tests/ui/impl-trait/in-trait/object-safety.rs
@@ -19,4 +19,5 @@ fn main() {
     //~| ERROR the trait `Foo` cannot be made into an object
     let s = i.baz();
     //~^ ERROR the trait `Foo` cannot be made into an object
+    //~| ERROR the trait bound `dyn Foo: Foo`
 }
diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.stderr b/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr
similarity index 91%
rename from tests/ui/impl-trait/in-trait/signature-mismatch.stderr
rename to tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr
index 05b5d3f11489f..186580f57566d 100644
--- a/tests/ui/impl-trait/in-trait/signature-mismatch.stderr
+++ b/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr
@@ -1,5 +1,5 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/signature-mismatch.rs:56:10
+  --> $DIR/signature-mismatch.rs:77:10
    |
 LL |         &'a self,
    |         -------- this parameter and the return type are declared with different lifetimes...
diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.rs b/tests/ui/impl-trait/in-trait/signature-mismatch.rs
index 1d63a6f3ce200..c84a3b8f46b5e 100644
--- a/tests/ui/impl-trait/in-trait/signature-mismatch.rs
+++ b/tests/ui/impl-trait/in-trait/signature-mismatch.rs
@@ -1,4 +1,6 @@
 // edition:2021
+// revisions: success failure
+//[success] check-pass
 
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
@@ -11,16 +13,25 @@ impl<T> Captures<'_> for T {}
 trait Captures2<'a, 'b> {}
 impl<T> Captures2<'_, '_> for T {}
 
-pub trait AsyncTrait {
+trait AsyncTrait {
+    #[cfg(success)]
     fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>;
+
+    #[cfg(success)]
     fn async_fn_early<'a: 'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>>;
+
+    #[cfg(success)]
     fn async_fn_multiple<'a>(&'a self, buff: &[u8])
-        -> impl Future<Output = Vec<u8>> + Captures<'a>;
+    -> impl Future<Output = Vec<u8>> + Captures<'a>;
+
+    #[cfg(failure)]
     fn async_fn_reduce_outlive<'a, T>(
         &'a self,
         buff: &[u8],
         t: T,
     ) -> impl Future<Output = Vec<u8>> + 'a;
+
+    #[cfg(success)]
     fn async_fn_reduce<'a, T>(
         &'a self,
         buff: &[u8],
@@ -31,38 +42,49 @@ pub trait AsyncTrait {
 pub struct Struct;
 
 impl AsyncTrait for Struct {
+    // Does not capture more lifetimes that trait def'n, since trait def'n
+    // implicitly captures all in-scope lifetimes.
+    #[cfg(success)]
     fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
-        //~^ ERROR return type captures more lifetimes than trait definition
         async move { buff.to_vec() }
     }
 
+    // Does not capture more lifetimes that trait def'n, since trait def'n
+    // implicitly captures all in-scope lifetimes.
+    #[cfg(success)]
     fn async_fn_early<'a: 'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
-        //~^ ERROR return type captures more lifetimes than trait definition
         async move { buff.to_vec() }
     }
 
+    // Does not capture more lifetimes that trait def'n, since trait def'n
+    // implicitly captures all in-scope lifetimes.
+    #[cfg(success)]
     fn async_fn_multiple<'a, 'b>(
         &'a self,
         buff: &'b [u8],
     ) -> impl Future<Output = Vec<u8>> + Captures2<'a, 'b> {
-        //~^ ERROR return type captures more lifetimes than trait definition
         async move { buff.to_vec() }
     }
 
+    // This error message is awkward, but `impl Future<Output = Vec<u8>>`
+    // cannot outlive `'a` (from the trait signature) because it captures
+    // both `T` and `'b`.
+    #[cfg(failure)]
     fn async_fn_reduce_outlive<'a, 'b, T>(
         &'a self,
         buff: &'b [u8],
         t: T,
     ) -> impl Future<Output = Vec<u8>> {
-        //~^ ERROR the parameter type `T` may not live long enough
+        //[failure]~^ ERROR lifetime mismatch
         async move {
             let _t = t;
             vec![]
         }
     }
 
-    // OK: We remove the `Captures<'a>`, providing a guarantee that we don't capture `'a`,
-    // but we still fulfill the `Captures<'a>` trait bound.
+    // Does not capture fewer lifetimes that trait def'n (not that it matters),
+    // since impl also captures all in-scope lifetimes.
+    #[cfg(success)]
     fn async_fn_reduce<'a, 'b, T>(&'a self, buff: &'b [u8], t: T) -> impl Future<Output = Vec<u8>> {
         async move {
             let _t = t;

From 690bcc6619aad74d8c32a52c104d4f79fa2f6bf4 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 8 Aug 2023 19:59:44 +0000
Subject: [PATCH 3/4] Test variances of opaque captures

---
 compiler/rustc_feature/src/builtin_attrs.rs   |  1 +
 .../rustc_hir_analysis/src/variance/test.rs   | 15 +++++++++++
 compiler/rustc_span/src/symbol.rs             |  1 +
 tests/ui/impl-trait/in-trait/variance.rs      | 20 ++++++++++++++
 tests/ui/impl-trait/in-trait/variance.stderr  | 26 +++++++++++++++++++
 tests/ui/impl-trait/variance.rs               | 16 ++++++++++++
 tests/ui/impl-trait/variance.stderr           | 26 +++++++++++++++++++
 7 files changed, 105 insertions(+)
 create mode 100644 tests/ui/impl-trait/in-trait/variance.rs
 create mode 100644 tests/ui/impl-trait/in-trait/variance.stderr
 create mode 100644 tests/ui/impl-trait/variance.rs
 create mode 100644 tests/ui/impl-trait/variance.stderr

diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 168cc16bb367e..e745ef1ec07ed 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -813,6 +813,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_variance_of_opaques, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
     rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
     rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs
index d57d05d7605db..d98dc0e6b83ef 100644
--- a/compiler/rustc_hir_analysis/src/variance/test.rs
+++ b/compiler/rustc_hir_analysis/src/variance/test.rs
@@ -1,9 +1,24 @@
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 
 use crate::errors;
 
 pub fn test_variance(tcx: TyCtxt<'_>) {
+    if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
+        for id in tcx.hir().items() {
+            if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
+                let variances_of = tcx.variances_of(id.owner_id);
+
+                tcx.sess.emit_err(errors::VariancesOf {
+                    span: tcx.def_span(id.owner_id),
+                    variances_of: format!("{variances_of:?}"),
+                });
+            }
+        }
+    }
+
     // For unit testing: check for a special "rustc_variance"
     // attribute and report an error with various results if found.
     for id in tcx.hir().items() {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9d4f49f9453dd..656deebb5d06b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1366,6 +1366,7 @@ symbols! {
         rustc_trivial_field_reads,
         rustc_unsafe_specialization_marker,
         rustc_variance,
+        rustc_variance_of_opaques,
         rustdoc,
         rustdoc_internals,
         rustdoc_missing_doc_code_examples,
diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs
new file mode 100644
index 0000000000000..f8e4ab88c19ae
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/variance.rs
@@ -0,0 +1,20 @@
+#![feature(rustc_attrs, return_position_impl_trait_in_trait)]
+#![allow(internal_features)]
+#![rustc_variance_of_opaques]
+
+trait Captures<'a> {}
+impl<T> Captures<'_> for T {}
+
+trait Foo<'i> {
+    fn implicit_capture_early<'a: 'a>() -> impl Sized {}
+    //~^ [o, *, *, o, o]
+    // Self, 'i, 'a, 'i_duplicated, 'a_duplicated
+
+    fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ [o, *, *, o, o]
+
+    fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} //~ [o, *, o, o]
+
+    fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ [o, *, o, o]
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/variance.stderr b/tests/ui/impl-trait/in-trait/variance.stderr
new file mode 100644
index 0000000000000..8cae5a92f0dd5
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/variance.stderr
@@ -0,0 +1,26 @@
+error: [o, *, *, o, o]
+  --> $DIR/variance.rs:9:44
+   |
+LL |     fn implicit_capture_early<'a: 'a>() -> impl Sized {}
+   |                                            ^^^^^^^^^^
+
+error: [o, *, *, o, o]
+  --> $DIR/variance.rs:13:44
+   |
+LL |     fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {}
+   |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: [o, *, o, o]
+  --> $DIR/variance.rs:15:48
+   |
+LL |     fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {}
+   |                                                ^^^^^^^^^^
+
+error: [o, *, o, o]
+  --> $DIR/variance.rs:17:48
+   |
+LL |     fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
+   |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/impl-trait/variance.rs b/tests/ui/impl-trait/variance.rs
new file mode 100644
index 0000000000000..d6212f8f39372
--- /dev/null
+++ b/tests/ui/impl-trait/variance.rs
@@ -0,0 +1,16 @@
+#![feature(rustc_attrs)]
+#![allow(internal_features)]
+#![rustc_variance_of_opaques]
+
+trait Captures<'a> {}
+impl<T> Captures<'_> for T {}
+
+fn not_captured_early<'a: 'a>() -> impl Sized {} //~ [*]
+
+fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ [*, o]
+
+fn not_captured_late<'a>(_: &'a ()) -> impl Sized {} //~ []
+
+fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ [o]
+
+fn main() {}
diff --git a/tests/ui/impl-trait/variance.stderr b/tests/ui/impl-trait/variance.stderr
new file mode 100644
index 0000000000000..6447367541097
--- /dev/null
+++ b/tests/ui/impl-trait/variance.stderr
@@ -0,0 +1,26 @@
+error: [*]
+  --> $DIR/variance.rs:8:36
+   |
+LL | fn not_captured_early<'a: 'a>() -> impl Sized {}
+   |                                    ^^^^^^^^^^
+
+error: [*, o]
+  --> $DIR/variance.rs:10:32
+   |
+LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {}
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: []
+  --> $DIR/variance.rs:12:40
+   |
+LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
+   |                                        ^^^^^^^^^^
+
+error: [o]
+  --> $DIR/variance.rs:14:36
+   |
+LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+

From f8e0dcbf5627d3e1a70a4d1d6bd1101d5b24f1e3 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 8 Aug 2023 20:13:57 +0000
Subject: [PATCH 4/4] Better error message for object type with GAT

---
 .../src/traits/select/confirmation.rs            |  2 +-
 tests/ui/impl-trait/in-trait/object-safety.rs    |  2 +-
 .../ui/impl-trait/in-trait/object-safety.stderr  | 16 +++++++++++-----
 3 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 88d0300330917..8a24f96743a6a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -548,7 +548,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     obligation.cause.span,
                     "GATs in trait object shouldn't have been considered",
                 );
-                return Err(SelectionError::Unimplemented);
+                return Err(SelectionError::TraitNotObjectSafe(trait_predicate.trait_ref.def_id));
             }
 
             // This maybe belongs in wf, but that can't (doesn't) handle
diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs
index 6e02934363d56..9a231e59b09bf 100644
--- a/tests/ui/impl-trait/in-trait/object-safety.rs
+++ b/tests/ui/impl-trait/in-trait/object-safety.rs
@@ -19,5 +19,5 @@ fn main() {
     //~| ERROR the trait `Foo` cannot be made into an object
     let s = i.baz();
     //~^ ERROR the trait `Foo` cannot be made into an object
-    //~| ERROR the trait bound `dyn Foo: Foo`
+    //~| ERROR the trait `Foo` cannot be made into an object
 }
diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/object-safety.stderr
index 1eb063a5fc2e7..0170dc5d0fc85 100644
--- a/tests/ui/impl-trait/in-trait/object-safety.stderr
+++ b/tests/ui/impl-trait/in-trait/object-safety.stderr
@@ -13,13 +13,20 @@ LL |     fn baz(&self) -> impl Debug;
    |                      ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
    = help: consider moving `baz` to another trait
 
-error[E0277]: the trait bound `dyn Foo: Foo` is not satisfied
+error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/object-safety.rs:20:15
    |
 LL |     let s = i.baz();
-   |               ^^^ the trait `Foo` is not implemented for `dyn Foo`
+   |               ^^^ `Foo` cannot be made into an object
    |
-   = help: the trait `Foo` is implemented for `u32`
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety.rs:7:22
+   |
+LL | trait Foo {
+   |       --- this trait cannot be made into an object...
+LL |     fn baz(&self) -> impl Debug;
+   |                      ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
+   = help: consider moving `baz` to another trait
 
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/object-safety.rs:20:13
@@ -54,5 +61,4 @@ LL |     fn baz(&self) -> impl Debug;
 
 error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0038, E0277.
-For more information about an error, try `rustc --explain E0038`.
+For more information about this error, try `rustc --explain E0038`.