From 52aff538123137fb395a52c4ddb6fba2ef6fed07 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sat, 2 Sep 2023 21:29:27 +0000
Subject: [PATCH 1/2] Correctly deny late-bound lifetimes from parent in anon
 consts and TAITs

---
 compiler/rustc_hir_analysis/messages.ftl      | 12 ++--
 .../rustc_hir_analysis/src/astconv/mod.rs     |  4 +-
 .../src/collect/resolve_bound_vars.rs         | 71 +++++++++++++------
 compiler/rustc_hir_analysis/src/errors.rs     | 16 ++++-
 .../late-bound-vars/in_closure.rs             | 28 +++-----
 .../late-bound-vars/in_closure.stderr         | 30 +++++---
 .../const-generics/late-bound-vars/simple.rs  | 27 +++----
 .../late-bound-vars/simple.stderr             | 29 +++++---
 tests/ui/consts/escaping-bound-var.rs         | 13 ++++
 tests/ui/consts/escaping-bound-var.stderr     | 20 ++++++
 .../capture-late-ct-in-anon.rs                |  2 +-
 .../capture-late-ct-in-anon.stderr            |  2 +-
 .../late-bound-in-anon-ct.rs                  |  2 +-
 .../late-bound-in-anon-ct.stderr              |  2 +-
 .../escaping-bound-var.rs                     | 22 ++++++
 .../escaping-bound-var.stderr                 |  8 +++
 tests/ui/type-alias-impl-trait/variance.rs    | 30 ++++----
 .../ui/type-alias-impl-trait/variance.stderr  | 62 ++++++----------
 18 files changed, 230 insertions(+), 150 deletions(-)
 create mode 100644 tests/ui/consts/escaping-bound-var.rs
 create mode 100644 tests/ui/consts/escaping-bound-var.stderr
 create mode 100644 tests/ui/type-alias-impl-trait/escaping-bound-var.rs
 create mode 100644 tests/ui/type-alias-impl-trait/escaping-bound-var.stderr

diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 597cae6ff33..d2c09168c7f 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -21,12 +21,16 @@ hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit wh
     .label = deref recursion limit reached
     .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
 
-hir_analysis_cannot_capture_late_bound_const_in_anon_const =
-    cannot capture late-bound const parameter in a constant
+hir_analysis_cannot_capture_late_bound_const =
+    cannot capture late-bound const parameter in {$what}
     .label = parameter defined here
 
-hir_analysis_cannot_capture_late_bound_ty_in_anon_const =
-    cannot capture late-bound type parameter in a constant
+hir_analysis_cannot_capture_late_bound_lifetime =
+    cannot capture late-bound lifetime in {$what}
+    .label = lifetime defined here
+
+hir_analysis_cannot_capture_late_bound_ty =
+    cannot capture late-bound type parameter in {$what}
     .label = parameter defined here
 
 hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 90f64e18632..065284e558e 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -268,9 +268,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // (*) -- not late-bound, won't change
             }
 
-            Some(rbv::ResolvedArg::Error(_)) => {
-                bug!("only ty/ct should resolve as ResolvedArg::Error")
-            }
+            Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar),
 
             None => {
                 self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| {
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 2bee2727725..6869c869603 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -158,13 +158,14 @@ enum Scope<'a> {
         s: ScopeRef<'a>,
     },
 
-    /// Disallows capturing non-lifetime binders from parent scopes.
+    /// Disallows capturing late-bound vars from parent scopes.
     ///
     /// This is necessary for something like `for<T> [(); { /* references T */ }]:`,
     /// since we don't do something more correct like replacing any captured
     /// late-bound vars with early-bound params in the const's own generics.
-    AnonConstBoundary {
+    LateBoundary {
         s: ScopeRef<'a>,
+        what: &'static str,
     },
 
     Root {
@@ -216,7 +217,9 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
                 .field("s", &"..")
                 .finish(),
             Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
-            Scope::AnonConstBoundary { s: _ } => f.debug_struct("AnonConstBoundary").finish(),
+            Scope::LateBoundary { s: _, what } => {
+                f.debug_struct("LateBoundary").field("what", what).finish()
+            }
             Scope::Root { opt_parent_item } => {
                 f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
             }
@@ -318,7 +321,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     break (vec![], BinderScopeType::Normal);
                 }
 
-                Scope::ObjectLifetimeDefault { s, .. } | Scope::AnonConstBoundary { s } => {
+                Scope::ObjectLifetimeDefault { s, .. } | Scope::LateBoundary { s, .. } => {
                     scope = s;
                 }
 
@@ -697,9 +700,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     }) => {
                         intravisit::walk_ty(self, ty);
 
-                        // Elided lifetimes are not allowed in non-return
-                        // position impl Trait
-                        let scope = Scope::TraitRefBoundary { s: self.scope };
+                        // Elided lifetimes and late-bound lifetimes (from the parent)
+                        // are not allowed in non-return position impl Trait
+                        let scope = Scope::LateBoundary {
+                            s: &Scope::TraitRefBoundary { s: self.scope },
+                            what: "type alias impl trait",
+                        };
                         self.with(scope, |this| intravisit::walk_item(this, opaque_ty));
 
                         return;
@@ -979,7 +985,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
     }
 
     fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
-        self.with(Scope::AnonConstBoundary { s: self.scope }, |this| {
+        self.with(Scope::LateBoundary { s: self.scope, what: "constant" }, |this| {
             intravisit::walk_anon_const(this, c);
         });
     }
@@ -1174,6 +1180,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         let mut late_depth = 0;
         let mut scope = self.scope;
         let mut outermost_body = None;
+        let mut crossed_late_boundary = None;
         let result = loop {
             match *scope {
                 Scope::Body { id, s } => {
@@ -1258,8 +1265,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
 
                 Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::Supertrait { s, .. }
-                | Scope::TraitRefBoundary { s, .. }
-                | Scope::AnonConstBoundary { s } => {
+                | Scope::TraitRefBoundary { s, .. } => {
+                    scope = s;
+                }
+
+                Scope::LateBoundary { s, what } => {
+                    crossed_late_boundary = Some(what);
                     scope = s;
                 }
             }
@@ -1268,6 +1279,22 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         if let Some(mut def) = result {
             if let ResolvedArg::EarlyBound(..) = def {
                 // Do not free early-bound regions, only late-bound ones.
+            } else if let ResolvedArg::LateBound(_, _, param_def_id) = def
+                && let Some(what) = crossed_late_boundary
+            {
+                let use_span = lifetime_ref.ident.span;
+                let def_span = self.tcx.def_span(param_def_id);
+                let guar = match self.tcx.def_kind(param_def_id) {
+                    DefKind::LifetimeParam => {
+                        self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Lifetime {
+                            use_span,
+                            def_span,
+                            what,
+                        })
+                    }
+                    _ => unreachable!(),
+                };
+                def = ResolvedArg::Error(guar);
             } else if let Some(body_id) = outermost_body {
                 let fn_id = self.tcx.hir().body_owner(body_id);
                 match self.tcx.hir().get(fn_id) {
@@ -1322,7 +1349,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 | Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::Supertrait { s, .. }
                 | Scope::TraitRefBoundary { s, .. }
-                | Scope::AnonConstBoundary { s } => {
+                | Scope::LateBoundary { s, .. } => {
                     scope = s;
                 }
             }
@@ -1341,7 +1368,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         // search.
         let mut late_depth = 0;
         let mut scope = self.scope;
-        let mut crossed_anon_const = false;
+        let mut crossed_late_boundary = None;
 
         let result = loop {
             match *scope {
@@ -1376,28 +1403,32 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     scope = s;
                 }
 
-                Scope::AnonConstBoundary { s } => {
-                    crossed_anon_const = true;
+                Scope::LateBoundary { s, what } => {
+                    crossed_late_boundary = Some(what);
                     scope = s;
                 }
             }
         };
 
         if let Some(def) = result {
-            if let ResolvedArg::LateBound(..) = def && crossed_anon_const {
+            if let ResolvedArg::LateBound(..) = def
+                && let Some(what) = crossed_late_boundary
+            {
                 let use_span = self.tcx.hir().span(hir_id);
                 let def_span = self.tcx.def_span(param_def_id);
                 let guar = match self.tcx.def_kind(param_def_id) {
                     DefKind::ConstParam => {
-                        self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Const {
+                        self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Const {
                             use_span,
                             def_span,
+                            what,
                         })
                     }
                     DefKind::TyParam => {
-                        self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Type {
+                        self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Type {
                             use_span,
                             def_span,
+                            what,
                         })
                     }
                     _ => unreachable!(),
@@ -1446,7 +1477,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 | Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::Supertrait { s, .. }
                 | Scope::TraitRefBoundary { s, .. }
-                | Scope::AnonConstBoundary { s } => {
+                | Scope::LateBoundary { s, .. } => {
                     scope = s;
                 }
             }
@@ -1526,7 +1557,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                         | Scope::ObjectLifetimeDefault { s, .. }
                         | Scope::Supertrait { s, .. }
                         | Scope::TraitRefBoundary { s, .. }
-                        | Scope::AnonConstBoundary { s } => {
+                        | Scope::LateBoundary { s, .. } => {
                             scope = s;
                         }
                     }
@@ -1831,7 +1862,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
 
                 Scope::Supertrait { s, .. }
                 | Scope::TraitRefBoundary { s, .. }
-                | Scope::AnonConstBoundary { s } => {
+                | Scope::LateBoundary { s, .. } => {
                     scope = s;
                 }
             }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 9471ad9ca90..55ab7133a7a 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -430,20 +430,30 @@ pub(crate) struct VariadicFunctionCompatibleConvention<'a> {
 }
 
 #[derive(Diagnostic)]
-pub(crate) enum CannotCaptureLateBoundInAnonConst {
-    #[diag(hir_analysis_cannot_capture_late_bound_ty_in_anon_const)]
+pub(crate) enum CannotCaptureLateBound {
+    #[diag(hir_analysis_cannot_capture_late_bound_ty)]
     Type {
         #[primary_span]
         use_span: Span,
         #[label]
         def_span: Span,
+        what: &'static str,
     },
-    #[diag(hir_analysis_cannot_capture_late_bound_const_in_anon_const)]
+    #[diag(hir_analysis_cannot_capture_late_bound_const)]
     Const {
         #[primary_span]
         use_span: Span,
         #[label]
         def_span: Span,
+        what: &'static str,
+    },
+    #[diag(hir_analysis_cannot_capture_late_bound_lifetime)]
+    Lifetime {
+        #[primary_span]
+        use_span: Span,
+        #[label]
+        def_span: Span,
+        what: &'static str,
     },
 }
 
diff --git a/tests/ui/const-generics/late-bound-vars/in_closure.rs b/tests/ui/const-generics/late-bound-vars/in_closure.rs
index 6549cad629b..349e82fa45a 100644
--- a/tests/ui/const-generics/late-bound-vars/in_closure.rs
+++ b/tests/ui/const-generics/late-bound-vars/in_closure.rs
@@ -1,23 +1,13 @@
-// failure-status: 1
 // known-bug: unknown
-// error-pattern:internal compiler error
-// normalize-stderr-test "internal compiler error.*" -> ""
-// normalize-stderr-test "DefId\([^)]*\)" -> "..."
-// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
-// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
-// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
-// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
-// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
-// normalize-stderr-test "thread.*panicked.*:\n.*\n" -> ""
-// normalize-stderr-test "stack backtrace:\n" -> ""
-// normalize-stderr-test "\s\d{1,}: .*\n" -> ""
-// normalize-stderr-test "\s at .*\n" -> ""
-// normalize-stderr-test ".*note: Some details.*\n" -> ""
-// normalize-stderr-test "\n[ ]*\n" -> ""
-// normalize-stderr-test "compiler/.*: projection" -> "projection"
-// normalize-stderr-test ".*omitted \d{1,} frame.*\n" -> ""
-// normalize-stderr-test "error: [\s\n]*query stack during panic:\n" -> ""
-// this should run-pass
+
+// If we want this to compile, then we'd need to do something like RPITs do,
+// where nested associated constants have early-bound versions of their captured
+// late-bound vars inserted into their generics. This gives us substitutable
+// lifetimes to actually use when borrow-checking the associated const, which is
+// lowered as a totally separate body from its parent. Since this doesn't exist,
+// so we should just error rather than resolving this late-bound var with no
+// binder to actually attach it to, or worse, as a free region that can't even be
+// substituted correctly, and ICEing. - @compiler-errors
 
 #![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/const-generics/late-bound-vars/in_closure.stderr b/tests/ui/const-generics/late-bound-vars/in_closure.stderr
index ac406bf2bb1..275dd742ebd 100644
--- a/tests/ui/const-generics/late-bound-vars/in_closure.stderr
+++ b/tests/ui/const-generics/late-bound-vars/in_closure.stderr
@@ -1,10 +1,20 @@
-#0 [mir_borrowck] borrow-checking `test::{closure#0}::{constant#1}`
-#1 [mir_drops_elaborated_and_const_checked] elaborating drops for `test::{closure#0}::{constant#1}`
-#2 [mir_for_ctfe] caching mir of `test::{closure#0}::{constant#1}` for CTFE
-#3 [eval_to_allocation_raw] const-evaluating + checking `test::{closure#0}::{constant#1}`
-#4 [eval_to_allocation_raw] const-evaluating + checking `test::{closure#0}::{constant#1}`
-#5 [eval_to_valtree] evaluating type-level constant
-#6 [typeck] type-checking `test`
-#7 [analysis] running analysis passes on this crate
-end of query stack
-error: aborting due to previous error
\ No newline at end of file
+error: cannot capture late-bound lifetime in constant
+  --> $DIR/in_closure.rs:24:29
+   |
+LL | fn test<'a>() {
+   |         -- lifetime defined here
+LL |     let _ = || {
+LL |         let _: [u8; inner::<'a>()];
+   |                             ^^
+
+error: cannot capture late-bound lifetime in constant
+  --> $DIR/in_closure.rs:25:29
+   |
+LL | fn test<'a>() {
+   |         -- lifetime defined here
+...
+LL |         let _ = [0; inner::<'a>()];
+   |                             ^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/const-generics/late-bound-vars/simple.rs b/tests/ui/const-generics/late-bound-vars/simple.rs
index 544073b5a56..c459419115a 100644
--- a/tests/ui/const-generics/late-bound-vars/simple.rs
+++ b/tests/ui/const-generics/late-bound-vars/simple.rs
@@ -1,22 +1,13 @@
-// failure-status: 101
 // known-bug: unknown
-// error-pattern:internal compiler error
-// normalize-stderr-test "internal compiler error.*" -> ""
-// normalize-stderr-test "DefId\([^)]*\)" -> "..."
-// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
-// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
-// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
-// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
-// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
-// normalize-stderr-test "thread.*panicked.*:\n.*\n" -> ""
-// normalize-stderr-test "stack backtrace:\n" -> ""
-// normalize-stderr-test "\s\d{1,}: .*\n" -> ""
-// normalize-stderr-test "\s at .*\n" -> ""
-// normalize-stderr-test ".*note: Some details.*\n" -> ""
-// normalize-stderr-test "\n\n[ ]*\n" -> ""
-// normalize-stderr-test "compiler/.*: projection" -> "projection"
-// normalize-stderr-test ".*omitted \d{1,} frame.*\n" -> ""
-// normalize-stderr-test "error: [\s\n]*query stack" -> "error: query stack"
+
+// If we want this to compile, then we'd need to do something like RPITs do,
+// where nested associated constants have early-bound versions of their captured
+// late-bound vars inserted into their generics. This gives us substitutable
+// lifetimes to actually use when borrow-checking the associated const, which is
+// lowered as a totally separate body from its parent. Since this doesn't exist,
+// so we should just error rather than resolving this late-bound var with no
+// binder to actually attach it to, or worse, as a free region that can't even be
+// substituted correctly, and ICEing. - @compiler-errors
 
 #![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/const-generics/late-bound-vars/simple.stderr b/tests/ui/const-generics/late-bound-vars/simple.stderr
index c9f2164b635..e72e373630d 100644
--- a/tests/ui/const-generics/late-bound-vars/simple.stderr
+++ b/tests/ui/const-generics/late-bound-vars/simple.stderr
@@ -1,12 +1,19 @@
-error: query stack during panic:
-#0 [mir_borrowck] borrow-checking `test::{constant#1}`
-#1 [mir_drops_elaborated_and_const_checked] elaborating drops for `test::{constant#1}`
-#2 [mir_for_ctfe] caching mir of `test::{constant#1}` for CTFE
-#3 [eval_to_allocation_raw] const-evaluating + checking `test::{constant#1}`
-#4 [eval_to_allocation_raw] const-evaluating + checking `test::{constant#1}`
-#5 [eval_to_valtree] evaluating type-level constant
-#6 [typeck] type-checking `test`
-#7 [analysis] running analysis passes on this crate
-end of query stack
-error: aborting due to previous error
+error: cannot capture late-bound lifetime in constant
+  --> $DIR/simple.rs:20:25
+   |
+LL | fn test<'a>() {
+   |         -- lifetime defined here
+LL |     let _: [u8; inner::<'a>()];
+   |                         ^^
+
+error: cannot capture late-bound lifetime in constant
+  --> $DIR/simple.rs:21:25
+   |
+LL | fn test<'a>() {
+   |         -- lifetime defined here
+LL |     let _: [u8; inner::<'a>()];
+LL |     let _ = [0; inner::<'a>()];
+   |                         ^^
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/escaping-bound-var.rs b/tests/ui/consts/escaping-bound-var.rs
new file mode 100644
index 00000000000..7c1fbd24f55
--- /dev/null
+++ b/tests/ui/consts/escaping-bound-var.rs
@@ -0,0 +1,13 @@
+#![feature(generic_const_exprs)]
+//~^ WARN the feature `generic_const_exprs` is incomplete
+
+fn test<'a>(
+    _: &'a (),
+) -> [(); {
+    let x: &'a ();
+    //~^ ERROR cannot capture late-bound lifetime in constant
+    1
+}] {
+}
+
+fn main() {}
diff --git a/tests/ui/consts/escaping-bound-var.stderr b/tests/ui/consts/escaping-bound-var.stderr
new file mode 100644
index 00000000000..d26ae2cee1c
--- /dev/null
+++ b/tests/ui/consts/escaping-bound-var.stderr
@@ -0,0 +1,20 @@
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/escaping-bound-var.rs:1:12
+   |
+LL | #![feature(generic_const_exprs)]
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: cannot capture late-bound lifetime in constant
+  --> $DIR/escaping-bound-var.rs:7:13
+   |
+LL | fn test<'a>(
+   |         -- lifetime defined here
+...
+LL |     let x: &'a ();
+   |             ^^
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.rs b/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.rs
index 91c6dfb8e0a..bbae67f0bad 100644
--- a/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.rs
+++ b/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.rs
@@ -4,7 +4,7 @@
 fn b()
 where
     for<const C: usize> [(); C]: Copy,
-    //~^ ERROR cannot capture late-bound const parameter in a constant
+    //~^ ERROR cannot capture late-bound const parameter in constant
 {
 }
 
diff --git a/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.stderr b/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.stderr
index 69bb605bf41..d65892ec6df 100644
--- a/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.stderr
+++ b/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.stderr
@@ -7,7 +7,7 @@ LL | #![feature(non_lifetime_binders)]
    = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: cannot capture late-bound const parameter in a constant
+error: cannot capture late-bound const parameter in constant
   --> $DIR/capture-late-ct-in-anon.rs:6:30
    |
 LL |     for<const C: usize> [(); C]: Copy,
diff --git a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs
index 3903bfe9bcf..64f09f823fc 100644
--- a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs
+++ b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs
@@ -5,7 +5,7 @@
 fn foo() -> usize
 where
     for<T> [i32; { let _: T = todo!(); 0 }]:,
-    //~^ ERROR cannot capture late-bound type parameter in a constant
+    //~^ ERROR cannot capture late-bound type parameter in constant
 {}
 
 fn main() {}
diff --git a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr
index fafff02dea6..dc54e1acc39 100644
--- a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr
+++ b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr
@@ -15,7 +15,7 @@ LL | #![feature(non_lifetime_binders, generic_const_exprs)]
    |
    = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
 
-error: cannot capture late-bound type parameter in a constant
+error: cannot capture late-bound type parameter in constant
   --> $DIR/late-bound-in-anon-ct.rs:7:27
    |
 LL |     for<T> [i32; { let _: T = todo!(); 0 }]:,
diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs
new file mode 100644
index 00000000000..bf27e76db2b
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs
@@ -0,0 +1,22 @@
+#![feature(type_alias_impl_trait)]
+
+pub trait Trait<'a> {
+    type Assoc;
+}
+
+trait Test<'a> {}
+
+pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>;
+//~^ ERROR cannot capture late-bound lifetime in type alias impl trait
+
+impl Trait<'_> for () {
+    type Assoc = ();
+}
+
+impl Test<'_> for () {}
+
+fn constrain() -> Foo {
+    ()
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr
new file mode 100644
index 00000000000..8205a60ccdd
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr
@@ -0,0 +1,8 @@
+error: cannot capture late-bound lifetime in type alias impl trait
+  --> $DIR/escaping-bound-var.rs:9:57
+   |
+LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>;
+   |                         -- lifetime defined here        ^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/type-alias-impl-trait/variance.rs b/tests/ui/type-alias-impl-trait/variance.rs
index eba4816003b..e92cf2513e7 100644
--- a/tests/ui/type-alias-impl-trait/variance.rs
+++ b/tests/ui/type-alias-impl-trait/variance.rs
@@ -9,42 +9,36 @@ type NotCapturedEarly<'a> = impl Sized; //~ [o]
 
 type CapturedEarly<'a> = impl Sized + Captures<'a>; //~ [o]
 
+// TAIT does *not* capture `'b`
 type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>; //~ [o]
 
-type CapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'b>>; //~ [o]
-
-type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a> + Captures<'b>>; //~ [o]
+// TAIT does *not* capture `'b`
+type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>; //~ [o]
 
 type Bar<'a, 'b: 'b, T> = impl Sized; //~ ERROR [o, o, o]
 
 trait Foo<'i> {
-    type ImplicitCapturedEarly<'a>;
+    type ImplicitCapture<'a>;
 
-    type ExplicitCaptureEarly<'a>;
+    type ExplicitCaptureFromHeader<'a>;
 
-    type ImplicitCaptureLate<'a>;
-
-    type ExplicitCaptureLate<'a>;
+    type ExplicitCaptureFromGat<'a>;
 }
 
 impl<'i> Foo<'i> for &'i () {
-    type ImplicitCapturedEarly<'a> = impl Sized; //~ [o, o]
+    type ImplicitCapture<'a> = impl Sized; //~ [o, o]
 
-    type ExplicitCaptureEarly<'a> = impl Sized + Captures<'i>; //~ [o, o]
+    type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ [o, o]
 
-    type ImplicitCaptureLate<'a> = impl Sized; //~ [o, o]
-
-    type ExplicitCaptureLate<'a> = impl Sized + Captures<'a>; //~ [o, o]
+    type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ [o, o]
 }
 
 impl<'i> Foo<'i> for () {
-    type ImplicitCapturedEarly<'a> = impl Sized; //~ [o, o]
+    type ImplicitCapture<'a> = impl Sized; //~ [o, o]
 
-    type ExplicitCaptureEarly<'a> = impl Sized + Captures<'i>; //~ [o, o]
+    type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ [o, o]
 
-    type ImplicitCaptureLate<'a> = impl Sized; //~ [o, o]
-
-    type ExplicitCaptureLate<'a> = impl Sized + Captures<'a>; //~ [o, o]
+    type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ [o, o]
 }
 
 fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/variance.stderr b/tests/ui/type-alias-impl-trait/variance.stderr
index f73cf617a4c..1794447c89a 100644
--- a/tests/ui/type-alias-impl-trait/variance.stderr
+++ b/tests/ui/type-alias-impl-trait/variance.stderr
@@ -11,22 +11,16 @@ LL | type CapturedEarly<'a> = impl Sized + Captures<'a>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: [o]
-  --> $DIR/variance.rs:12:56
+  --> $DIR/variance.rs:13:56
    |
 LL | type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>;
    |                                                        ^^^^^^^^^^
 
-error: [o]
-  --> $DIR/variance.rs:14:53
-   |
-LL | type CapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'b>>;
-   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: [o]
   --> $DIR/variance.rs:16:49
    |
-LL | type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a> + Captures<'b>>;
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>;
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: [o, o, o]
   --> $DIR/variance.rs:18:27
@@ -35,52 +29,40 @@ LL | type Bar<'a, 'b: 'b, T> = impl Sized;
    |                           ^^^^^^^^^^
 
 error: [o, o]
-  --> $DIR/variance.rs:31:38
+  --> $DIR/variance.rs:29:32
    |
-LL |     type ImplicitCapturedEarly<'a> = impl Sized;
-   |                                      ^^^^^^^^^^
+LL |     type ImplicitCapture<'a> = impl Sized;
+   |                                ^^^^^^^^^^
 
 error: [o, o]
-  --> $DIR/variance.rs:33:37
+  --> $DIR/variance.rs:31:42
    |
-LL |     type ExplicitCaptureEarly<'a> = impl Sized + Captures<'i>;
-   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>;
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: [o, o]
-  --> $DIR/variance.rs:35:36
+  --> $DIR/variance.rs:33:39
    |
-LL |     type ImplicitCaptureLate<'a> = impl Sized;
-   |                                    ^^^^^^^^^^
+LL |     type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>;
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: [o, o]
-  --> $DIR/variance.rs:37:36
+  --> $DIR/variance.rs:37:32
    |
-LL |     type ExplicitCaptureLate<'a> = impl Sized + Captures<'a>;
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     type ImplicitCapture<'a> = impl Sized;
+   |                                ^^^^^^^^^^
 
 error: [o, o]
-  --> $DIR/variance.rs:41:38
+  --> $DIR/variance.rs:39:42
    |
-LL |     type ImplicitCapturedEarly<'a> = impl Sized;
-   |                                      ^^^^^^^^^^
+LL |     type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>;
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: [o, o]
-  --> $DIR/variance.rs:43:37
+  --> $DIR/variance.rs:41:39
    |
-LL |     type ExplicitCaptureEarly<'a> = impl Sized + Captures<'i>;
-   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>;
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [o, o]
-  --> $DIR/variance.rs:45:36
-   |
-LL |     type ImplicitCaptureLate<'a> = impl Sized;
-   |                                    ^^^^^^^^^^
-
-error: [o, o]
-  --> $DIR/variance.rs:47:36
-   |
-LL |     type ExplicitCaptureLate<'a> = impl Sized + Captures<'a>;
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 14 previous errors
+error: aborting due to 11 previous errors
 

From f479a7aa8d17dd3abab4f84fe9fe3e248e362eaf Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sat, 2 Sep 2023 22:53:59 +0000
Subject: [PATCH 2/2] Restore some removed tests

---
 .../const-generics/late-bound-vars/in_closure.rs  | 10 +---------
 .../late-bound-vars/in_closure.stderr             |  4 ++--
 .../late-bound-in-return-issue-77357.rs           | 13 +++++++++++++
 .../late-bound-in-return-issue-77357.stderr       |  8 ++++++++
 .../late-bound-in-where-issue-83993.rs            | 15 +++++++++++++++
 .../late-bound-in-where-issue-83993.stderr        | 10 ++++++++++
 tests/ui/const-generics/late-bound-vars/simple.rs |  2 +-
 7 files changed, 50 insertions(+), 12 deletions(-)
 create mode 100644 tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.rs
 create mode 100644 tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr
 create mode 100644 tests/ui/const-generics/late-bound-vars/late-bound-in-where-issue-83993.rs
 create mode 100644 tests/ui/const-generics/late-bound-vars/late-bound-in-where-issue-83993.stderr

diff --git a/tests/ui/const-generics/late-bound-vars/in_closure.rs b/tests/ui/const-generics/late-bound-vars/in_closure.rs
index 349e82fa45a..443c755c601 100644
--- a/tests/ui/const-generics/late-bound-vars/in_closure.rs
+++ b/tests/ui/const-generics/late-bound-vars/in_closure.rs
@@ -1,13 +1,5 @@
 // known-bug: unknown
-
-// If we want this to compile, then we'd need to do something like RPITs do,
-// where nested associated constants have early-bound versions of their captured
-// late-bound vars inserted into their generics. This gives us substitutable
-// lifetimes to actually use when borrow-checking the associated const, which is
-// lowered as a totally separate body from its parent. Since this doesn't exist,
-// so we should just error rather than resolving this late-bound var with no
-// binder to actually attach it to, or worse, as a free region that can't even be
-// substituted correctly, and ICEing. - @compiler-errors
+// see comment on `tests/ui/const-generics/late-bound-vars/simple.rs`
 
 #![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/const-generics/late-bound-vars/in_closure.stderr b/tests/ui/const-generics/late-bound-vars/in_closure.stderr
index 275dd742ebd..e15496454a0 100644
--- a/tests/ui/const-generics/late-bound-vars/in_closure.stderr
+++ b/tests/ui/const-generics/late-bound-vars/in_closure.stderr
@@ -1,5 +1,5 @@
 error: cannot capture late-bound lifetime in constant
-  --> $DIR/in_closure.rs:24:29
+  --> $DIR/in_closure.rs:16:29
    |
 LL | fn test<'a>() {
    |         -- lifetime defined here
@@ -8,7 +8,7 @@ LL |         let _: [u8; inner::<'a>()];
    |                             ^^
 
 error: cannot capture late-bound lifetime in constant
-  --> $DIR/in_closure.rs:25:29
+  --> $DIR/in_closure.rs:17:29
    |
 LL | fn test<'a>() {
    |         -- lifetime defined here
diff --git a/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.rs b/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.rs
new file mode 100644
index 00000000000..b81aa50d9a9
--- /dev/null
+++ b/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.rs
@@ -0,0 +1,13 @@
+// known-bug: unknown
+// see comment on `tests/ui/const-generics/late-bound-vars/simple.rs`
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait MyTrait<T> {}
+
+fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
+    todo!()
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr b/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr
new file mode 100644
index 00000000000..21c8fe6865c
--- /dev/null
+++ b/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr
@@ -0,0 +1,8 @@
+error: cannot capture late-bound lifetime in constant
+  --> $DIR/late-bound-in-return-issue-77357.rs:9:53
+   |
+LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
+   |        -- lifetime defined here                     ^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/const-generics/late-bound-vars/late-bound-in-where-issue-83993.rs b/tests/ui/const-generics/late-bound-vars/late-bound-in-where-issue-83993.rs
new file mode 100644
index 00000000000..89f01748fc9
--- /dev/null
+++ b/tests/ui/const-generics/late-bound-vars/late-bound-in-where-issue-83993.rs
@@ -0,0 +1,15 @@
+// known-bug: unknown
+// see comment on `tests/ui/const-generics/late-bound-vars/simple.rs`
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn bug<'a>()
+where
+    for<'b> [(); {
+        let x: &'b ();
+        0
+    }]:
+{}
+
+fn main() {}
diff --git a/tests/ui/const-generics/late-bound-vars/late-bound-in-where-issue-83993.stderr b/tests/ui/const-generics/late-bound-vars/late-bound-in-where-issue-83993.stderr
new file mode 100644
index 00000000000..a66dc8db914
--- /dev/null
+++ b/tests/ui/const-generics/late-bound-vars/late-bound-in-where-issue-83993.stderr
@@ -0,0 +1,10 @@
+error: cannot capture late-bound lifetime in constant
+  --> $DIR/late-bound-in-where-issue-83993.rs:10:17
+   |
+LL |     for<'b> [(); {
+   |         -- lifetime defined here
+LL |         let x: &'b ();
+   |                 ^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/const-generics/late-bound-vars/simple.rs b/tests/ui/const-generics/late-bound-vars/simple.rs
index c459419115a..a562bd8cb41 100644
--- a/tests/ui/const-generics/late-bound-vars/simple.rs
+++ b/tests/ui/const-generics/late-bound-vars/simple.rs
@@ -5,7 +5,7 @@
 // late-bound vars inserted into their generics. This gives us substitutable
 // lifetimes to actually use when borrow-checking the associated const, which is
 // lowered as a totally separate body from its parent. Since this doesn't exist,
-// so we should just error rather than resolving this late-bound var with no
+// we should just error rather than resolving this late-bound var with no
 // binder to actually attach it to, or worse, as a free region that can't even be
 // substituted correctly, and ICEing. - @compiler-errors