about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-06-05 16:18:52 -0400
committerMichael Goulet <michael@errs.io>2024-06-17 22:35:25 -0400
commitb1efe1ab5d10c5dc0462445273ca4e42dea3c5e3 (patch)
tree88d5d68eaba69cf8e65e87f38b6dcd04bd9c3f46
parent68bd001c00e37a6c6854482138d27a76428efdff (diff)
downloadrust-b1efe1ab5d10c5dc0462445273ca4e42dea3c5e3.tar.gz
rust-b1efe1ab5d10c5dc0462445273ca4e42dea3c5e3.zip
Rework precise capturing syntax
-rw-r--r--compiler/rustc_ast/src/ast.rs5
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs12
-rw-r--r--compiler/rustc_ast/src/util/classify.rs6
-rw-r--r--compiler/rustc_ast/src/visit.rs21
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs132
-rw-r--r--compiler/rustc_ast_passes/messages.ftl2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs180
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs8
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs20
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs4
-rw-r--r--compiler/rustc_hir/src/intravisit.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs3
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs16
-rw-r--r--compiler/rustc_lint/src/impl_trait_overcaptures.rs18
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs2
-rw-r--r--compiler/rustc_parse/src/parser/item.rs2
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs27
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs4
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-precise-capturing.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-precise-capturing.stderr6
-rw-r--r--tests/ui/impl-trait/precise-capturing/apit.rs2
-rw-r--r--tests/ui/impl-trait/precise-capturing/apit.stderr6
-rw-r--r--tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs6
-rw-r--r--tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr28
-rw-r--r--tests/ui/impl-trait/precise-capturing/bad-params.rs8
-rw-r--r--tests/ui/impl-trait/precise-capturing/bad-params.stderr26
-rw-r--r--tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs8
-rw-r--r--tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr10
-rw-r--r--tests/ui/impl-trait/precise-capturing/elided.rs2
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs2
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr4
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs4
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr16
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs4
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr8
-rw-r--r--tests/ui/impl-trait/precise-capturing/higher-ranked.rs2
-rw-r--r--tests/ui/impl-trait/precise-capturing/ordering.rs8
-rw-r--r--tests/ui/impl-trait/precise-capturing/ordering.stderr28
-rw-r--r--tests/ui/impl-trait/precise-capturing/outlives.rs2
-rw-r--r--tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed8
-rw-r--r--tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr16
-rw-r--r--tests/ui/impl-trait/precise-capturing/redundant.rs8
-rw-r--r--tests/ui/impl-trait/precise-capturing/redundant.stderr32
-rw-r--r--tests/ui/impl-trait/precise-capturing/self-capture.rs2
-rw-r--r--tests/ui/impl-trait/precise-capturing/unexpected-token.rs2
-rw-r--r--tests/ui/impl-trait/precise-capturing/unexpected-token.stderr6
-rw-r--r--tests/ui/parser/trait-object-delimiters.rs2
-rw-r--r--tests/ui/parser/trait-object-delimiters.stderr4
54 files changed, 405 insertions, 349 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 9cb193b4a67..fe888d2004f 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -307,6 +307,8 @@ impl TraitBoundModifiers {
 pub enum GenericBound {
     Trait(PolyTraitRef, TraitBoundModifiers),
     Outlives(Lifetime),
+    /// Precise capturing syntax: `impl Sized + use<'a>`
+    Use(ThinVec<PreciseCapturingArg>, Span),
 }
 
 impl GenericBound {
@@ -314,6 +316,7 @@ impl GenericBound {
         match self {
             GenericBound::Trait(t, ..) => t.span,
             GenericBound::Outlives(l) => l.ident.span,
+            GenericBound::Use(_, span) => *span,
         }
     }
 }
@@ -2162,7 +2165,7 @@ pub enum TyKind {
     /// The `NodeId` exists to prevent lowering from having to
     /// generate `NodeId`s on the fly, which would complicate
     /// the generation of opaque `type Foo = impl Trait` items significantly.
-    ImplTrait(NodeId, GenericBounds, Option<P<(ThinVec<PreciseCapturingArg>, Span)>>),
+    ImplTrait(NodeId, GenericBounds),
     /// No-op; kept solely so that we can pretty-print faithfully.
     Paren(P<Ty>),
     /// Unused for now.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index cc33ce2cb56..182ad7359af 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -523,14 +523,9 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
         TyKind::TraitObject(bounds, _syntax) => {
             visit_vec(bounds, |bound| vis.visit_param_bound(bound))
         }
-        TyKind::ImplTrait(id, bounds, precise_capturing) => {
+        TyKind::ImplTrait(id, bounds) => {
             vis.visit_id(id);
             visit_vec(bounds, |bound| vis.visit_param_bound(bound));
-            if let Some((precise_capturing, _span)) = precise_capturing.as_deref_mut() {
-                for arg in precise_capturing {
-                    vis.visit_precise_capturing_arg(arg);
-                }
-            }
         }
         TyKind::MacCall(mac) => vis.visit_mac_call(mac),
         TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
@@ -923,6 +918,11 @@ fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T) {
     match pb {
         GenericBound::Trait(ty, _modifier) => vis.visit_poly_trait_ref(ty),
         GenericBound::Outlives(lifetime) => noop_visit_lifetime(lifetime, vis),
+        GenericBound::Use(args, _) => {
+            for arg in args {
+                vis.visit_precise_capturing_arg(arg);
+            }
+        }
     }
 }
 
diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs
index 382c903625f..4b2544ac47e 100644
--- a/compiler/rustc_ast/src/util/classify.rs
+++ b/compiler/rustc_ast/src/util/classify.rs
@@ -184,7 +184,7 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
                 None => break None,
             },
 
-            ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds, _) => {
+            ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => {
                 match bounds.last() {
                     Some(ast::GenericBound::Trait(bound, _)) => {
                         match path_return_type(&bound.trait_ref.path) {
@@ -192,7 +192,9 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
                             None => break None,
                         }
                     }
-                    Some(ast::GenericBound::Outlives(_)) | None => break None,
+                    Some(ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..)) | None => {
+                        break None;
+                    }
                 }
             }
 
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index fa97c8db326..104a401cd53 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -52,6 +52,16 @@ pub enum BoundKind {
     /// E.g., `trait A: B`
     SuperTraits,
 }
+impl BoundKind {
+    pub fn descr(self) -> &'static str {
+        match self {
+            BoundKind::Bound => "bounds",
+            BoundKind::Impl => "`impl Trait`",
+            BoundKind::TraitObject => "`dyn` trait object bounds",
+            BoundKind::SuperTraits => "supertrait bounds",
+        }
+    }
+}
 
 #[derive(Copy, Clone, Debug)]
 pub enum FnKind<'a> {
@@ -497,13 +507,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
         TyKind::TraitObject(bounds, ..) => {
             walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject);
         }
-        TyKind::ImplTrait(_, bounds, precise_capturing) => {
+        TyKind::ImplTrait(_, bounds) => {
             walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl);
-            if let Some((precise_capturing, _span)) = precise_capturing.as_deref() {
-                for arg in precise_capturing {
-                    try_visit!(visitor.visit_precise_capturing_arg(arg));
-                }
-            }
         }
         TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)),
         TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {}
@@ -688,6 +693,10 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB
     match bound {
         GenericBound::Trait(typ, _modifier) => visitor.visit_poly_trait_ref(typ),
         GenericBound::Outlives(lifetime) => visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound),
+        GenericBound::Use(args, _) => {
+            walk_list!(visitor, visit_precise_capturing_arg, args);
+            V::Result::output()
+        }
     }
 }
 
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 88f6e6c3b78..1fc6a969915 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -51,9 +51,9 @@ use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{DiagArgFromDisplay, DiagCtxt, StashKey};
-use rustc_hir as hir;
 use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::{self as hir};
 use rustc_hir::{
     ConstArg, GenericArg, HirId, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate,
 };
@@ -1384,6 +1384,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 }
                                 None
                             }
+                            // Ignore `use` syntax since that is not valid in objects.
+                            GenericBound::Use(..) => None,
                         }));
                     let lifetime_bound =
                         lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
@@ -1391,7 +1393,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 });
                 hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
             }
-            TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => {
+            TyKind::ImplTrait(def_node_id, bounds) => {
                 let span = t.span;
                 match itctx {
                     ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
@@ -1401,12 +1403,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         bounds,
                         fn_kind,
                         itctx,
-                        precise_capturing.as_deref().map(|(args, span)| (args.as_slice(), *span)),
                     ),
                     ImplTraitContext::Universal => {
-                        if let Some(&(_, span)) = precise_capturing.as_deref() {
+                        if let Some(span) = bounds.iter().find_map(|bound| match *bound {
+                            ast::GenericBound::Use(_, span) => Some(span),
+                            _ => None,
+                        }) {
                             self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span });
-                        };
+                        }
+
                         let span = t.span;
 
                         // HACK: pprust breaks strings with newlines when the type
@@ -1517,7 +1522,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         bounds: &GenericBounds,
         fn_kind: Option<FnDeclKind>,
         itctx: ImplTraitContext,
-        precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>,
     ) -> hir::TyKind<'hir> {
         // Make sure we know that some funky desugaring has been going on here.
         // This is a first: there is code in other places like for loop
@@ -1526,59 +1530,61 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // frequently opened issues show.
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
-        let captured_lifetimes_to_duplicate =
-            if let Some((precise_capturing, _)) = precise_capturing_args {
-                // We'll actually validate these later on; all we need is the list of
-                // lifetimes to duplicate during this portion of lowering.
-                precise_capturing
-                    .iter()
-                    .filter_map(|arg| match arg {
-                        PreciseCapturingArg::Lifetime(lt) => Some(*lt),
-                        PreciseCapturingArg::Arg(..) => None,
-                    })
-                    // Add in all the lifetimes mentioned in the bounds. We will error
-                    // them out later, but capturing them here is important to make sure
-                    // they actually get resolved in resolve_bound_vars.
-                    .chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds))
-                    .collect()
-            } else {
-                match origin {
-                    hir::OpaqueTyOrigin::TyAlias { .. } => {
-                        // type alias impl trait and associated type position impl trait were
-                        // decided to capture all in-scope lifetimes, which we collect for
-                        // all opaques during resolution.
+        let captured_lifetimes_to_duplicate = if let Some(args) =
+            bounds.iter().find_map(|bound| match bound {
+                ast::GenericBound::Use(a, _) => Some(a),
+                _ => None,
+            }) {
+            // We'll actually validate these later on; all we need is the list of
+            // lifetimes to duplicate during this portion of lowering.
+            args.iter()
+                .filter_map(|arg| match arg {
+                    PreciseCapturingArg::Lifetime(lt) => Some(*lt),
+                    PreciseCapturingArg::Arg(..) => None,
+                })
+                // Add in all the lifetimes mentioned in the bounds. We will error
+                // them out later, but capturing them here is important to make sure
+                // they actually get resolved in resolve_bound_vars.
+                .chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds))
+                .collect()
+        } else {
+            match origin {
+                hir::OpaqueTyOrigin::TyAlias { .. } => {
+                    // type alias impl trait and associated type position impl trait were
+                    // 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()
+                }
+                hir::OpaqueTyOrigin::FnReturn(..) => {
+                    if matches!(
+                        fn_kind.expect("expected RPITs to be lowered with a FnKind"),
+                        FnDeclKind::Impl | FnDeclKind::Trait
+                    ) || self.tcx.features().lifetime_capture_rules_2024
+                        || span.at_least_rust_2024()
+                    {
+                        // 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()
-                    }
-                    hir::OpaqueTyOrigin::FnReturn(..) => {
-                        if matches!(
-                            fn_kind.expect("expected RPITs to be lowered with a FnKind"),
-                            FnDeclKind::Impl | FnDeclKind::Trait
-                        ) || self.tcx.features().lifetime_capture_rules_2024
-                            || span.at_least_rust_2024()
-                        {
-                            // 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`")
+                    } 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`")
+                }
+            }
+        };
         debug!(?captured_lifetimes_to_duplicate);
 
         self.lower_opaque_inner(
@@ -1588,7 +1594,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             captured_lifetimes_to_duplicate,
             span,
             opaque_ty_span,
-            precise_capturing_args,
             |this| this.lower_param_bounds(bounds, itctx),
         )
     }
@@ -1601,7 +1606,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>,
         span: Span,
         opaque_ty_span: Span,
-        precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>,
         lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
     ) -> hir::TyKind<'hir> {
         let opaque_ty_def_id = self.create_def(
@@ -1688,18 +1692,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // Install the remapping from old to new (if any). This makes sure that
             // any lifetimes that would have resolved to the def-id of captured
             // lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
-            let (bounds, precise_capturing_args) =
-                this.with_remapping(captured_to_synthesized_mapping, |this| {
-                    (
-                        lower_item_bounds(this),
-                        precise_capturing_args.map(|(precise_capturing, span)| {
-                            (
-                                this.lower_precise_capturing_args(precise_capturing),
-                                this.lower_span(span),
-                            )
-                        }),
-                    )
-                });
+            let bounds = this
+                .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this));
 
             let generic_params =
                 this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map(
@@ -1744,7 +1738,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 origin,
                 lifetime_mapping,
                 in_trait,
-                precise_capturing_args,
             };
 
             // Generate an `type Foo = impl Trait;` declaration.
@@ -1955,7 +1948,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             captured_lifetimes,
             span,
             opaque_ty_span,
-            None,
             |this| {
                 let bound = this.lower_coroutine_fn_output_type_to_bound(
                     output,
@@ -2038,6 +2030,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             GenericBound::Outlives(lifetime) => {
                 hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
             }
+            GenericBound::Use(args, span) => hir::GenericBound::Use(
+                self.lower_precise_capturing_args(args),
+                self.lower_span(*span),
+            ),
         }
     }
 
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 9a8689e27c0..af27429b508 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -14,6 +14,8 @@ ast_passes_assoc_type_without_body =
     associated type in `impl` without body
     .suggestion = provide a definition for the type
 
+ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax is not allowed in {$loc}
+
 ast_passes_at_least_one_trait = at least one trait must be specified
 
 ast_passes_auto_generic = auto traits cannot have generic parameters
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 0fbb288cc96..04c06e76e9c 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -751,7 +751,7 @@ impl<'a> AstValidator<'a> {
                     }
                 }
             }
-            TyKind::ImplTrait(_, bounds, _) => {
+            TyKind::ImplTrait(_, bounds) => {
                 if self.is_impl_trait_banned {
                     self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
                 }
@@ -1304,6 +1304,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                                     }
                                 }
                                 GenericBound::Outlives(_) => {}
+                                GenericBound::Use(..) => {}
                             }
                         }
                     }
@@ -1322,95 +1323,110 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     }
 
     fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
-        if let GenericBound::Trait(poly, modifiers) = bound {
-            match (ctxt, modifiers.constness, modifiers.polarity) {
-                (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
-                    self.dcx().emit_err(errors::OptionalTraitSupertrait {
-                        span: poly.span,
-                        path_str: pprust::path_to_string(&poly.trait_ref.path),
-                    });
-                }
-                (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
-                    self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
-                }
-                (BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => {
-                    self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span });
+        match bound {
+            GenericBound::Trait(trait_ref, modifiers) => {
+                match (ctxt, modifiers.constness, modifiers.polarity) {
+                    (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
+                        self.dcx().emit_err(errors::OptionalTraitSupertrait {
+                            span: trait_ref.span,
+                            path_str: pprust::path_to_string(&trait_ref.trait_ref.path),
+                        });
+                    }
+                    (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
+                        self.dcx().emit_err(errors::OptionalTraitObject { span: trait_ref.span });
+                    }
+                    (
+                        BoundKind::TraitObject,
+                        BoundConstness::Always(_),
+                        BoundPolarity::Positive,
+                    ) => {
+                        self.dcx().emit_err(errors::ConstBoundTraitObject { span: trait_ref.span });
+                    }
+                    (_, BoundConstness::Maybe(span), BoundPolarity::Positive)
+                        if let Some(reason) = &self.disallow_tilde_const =>
+                    {
+                        let reason = match reason {
+                            DisallowTildeConstContext::Fn(FnKind::Closure(..)) => {
+                                errors::TildeConstReason::Closure
+                            }
+                            DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => {
+                                errors::TildeConstReason::Function { ident: ident.span }
+                            }
+                            &DisallowTildeConstContext::Trait(span) => {
+                                errors::TildeConstReason::Trait { span }
+                            }
+                            &DisallowTildeConstContext::TraitImpl(span) => {
+                                errors::TildeConstReason::TraitImpl { span }
+                            }
+                            &DisallowTildeConstContext::Impl(span) => {
+                                // FIXME(effects): Consider providing a help message or even a structured
+                                // suggestion for moving such bounds to the assoc const fns if available.
+                                errors::TildeConstReason::Impl { span }
+                            }
+                            &DisallowTildeConstContext::TraitAssocTy(span) => {
+                                errors::TildeConstReason::TraitAssocTy { span }
+                            }
+                            &DisallowTildeConstContext::TraitImplAssocTy(span) => {
+                                errors::TildeConstReason::TraitImplAssocTy { span }
+                            }
+                            &DisallowTildeConstContext::InherentAssocTy(span) => {
+                                errors::TildeConstReason::InherentAssocTy { span }
+                            }
+                            DisallowTildeConstContext::TraitObject => {
+                                errors::TildeConstReason::TraitObject
+                            }
+                            DisallowTildeConstContext::Item => errors::TildeConstReason::Item,
+                        };
+                        self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
+                    }
+                    (
+                        _,
+                        BoundConstness::Always(_) | BoundConstness::Maybe(_),
+                        BoundPolarity::Negative(_) | BoundPolarity::Maybe(_),
+                    ) => {
+                        self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
+                            span: bound.span(),
+                            left: modifiers.constness.as_str(),
+                            right: modifiers.polarity.as_str(),
+                        });
+                    }
+                    _ => {}
                 }
-                (_, BoundConstness::Maybe(span), BoundPolarity::Positive)
-                    if let Some(reason) = &self.disallow_tilde_const =>
+
+                // Negative trait bounds are not allowed to have associated constraints
+                if let BoundPolarity::Negative(_) = modifiers.polarity
+                    && let Some(segment) = trait_ref.trait_ref.path.segments.last()
                 {
-                    let reason = match reason {
-                        DisallowTildeConstContext::Fn(FnKind::Closure(..)) => {
-                            errors::TildeConstReason::Closure
-                        }
-                        DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => {
-                            errors::TildeConstReason::Function { ident: ident.span }
-                        }
-                        &DisallowTildeConstContext::Trait(span) => {
-                            errors::TildeConstReason::Trait { span }
-                        }
-                        &DisallowTildeConstContext::TraitImpl(span) => {
-                            errors::TildeConstReason::TraitImpl { span }
-                        }
-                        &DisallowTildeConstContext::Impl(span) => {
-                            // FIXME(effects): Consider providing a help message or even a structured
-                            // suggestion for moving such bounds to the assoc const fns if available.
-                            errors::TildeConstReason::Impl { span }
-                        }
-                        &DisallowTildeConstContext::TraitAssocTy(span) => {
-                            errors::TildeConstReason::TraitAssocTy { span }
-                        }
-                        &DisallowTildeConstContext::TraitImplAssocTy(span) => {
-                            errors::TildeConstReason::TraitImplAssocTy { span }
-                        }
-                        &DisallowTildeConstContext::InherentAssocTy(span) => {
-                            errors::TildeConstReason::InherentAssocTy { span }
-                        }
-                        DisallowTildeConstContext::TraitObject => {
-                            errors::TildeConstReason::TraitObject
+                    match segment.args.as_deref() {
+                        Some(ast::GenericArgs::AngleBracketed(args)) => {
+                            for arg in &args.args {
+                                if let ast::AngleBracketedArg::Constraint(constraint) = arg {
+                                    self.dcx().emit_err(errors::ConstraintOnNegativeBound {
+                                        span: constraint.span,
+                                    });
+                                }
+                            }
                         }
-                        DisallowTildeConstContext::Item => errors::TildeConstReason::Item,
-                    };
-                    self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
-                }
-                (
-                    _,
-                    BoundConstness::Always(_) | BoundConstness::Maybe(_),
-                    BoundPolarity::Negative(_) | BoundPolarity::Maybe(_),
-                ) => {
-                    self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
-                        span: bound.span(),
-                        left: modifiers.constness.as_str(),
-                        right: modifiers.polarity.as_str(),
-                    });
-                }
-                _ => {}
-            }
-        }
-
-        // Negative trait bounds are not allowed to have associated constraints
-        if let GenericBound::Trait(trait_ref, modifiers) = bound
-            && let BoundPolarity::Negative(_) = modifiers.polarity
-            && let Some(segment) = trait_ref.trait_ref.path.segments.last()
-        {
-            match segment.args.as_deref() {
-                Some(ast::GenericArgs::AngleBracketed(args)) => {
-                    for arg in &args.args {
-                        if let ast::AngleBracketedArg::Constraint(constraint) = arg {
-                            self.dcx().emit_err(errors::ConstraintOnNegativeBound {
-                                span: constraint.span,
+                        // The lowered form of parenthesized generic args contains an associated type binding.
+                        Some(ast::GenericArgs::Parenthesized(args)) => {
+                            self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation {
+                                span: args.span,
                             });
                         }
+                        None => {}
                     }
                 }
-                // The lowered form of parenthesized generic args contains an associated type binding.
-                Some(ast::GenericArgs::Parenthesized(args)) => {
-                    self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation {
-                        span: args.span,
-                    });
-                }
-                None => {}
             }
+            GenericBound::Outlives(_) => {}
+            GenericBound::Use(_, span) => match ctxt {
+                BoundKind::Impl => {}
+                BoundKind::Bound | BoundKind::TraitObject | BoundKind::SuperTraits => {
+                    self.dcx().emit_err(errors::PreciseCapturingNotAllowedHere {
+                        loc: ctxt.descr(),
+                        span: *span,
+                    })
+                }
+            },
         }
 
         visit::walk_param_bound(self, bound)
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 260c182bd9e..cb95b7bce91 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -844,3 +844,11 @@ pub struct MatchArmWithNoBody {
     #[suggestion(code = " => todo!(),", applicability = "has-placeholders")]
     pub suggestion: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_precise_capturing_not_allowed_here)]
+pub struct PreciseCapturingNotAllowedHere {
+    #[primary_span]
+    pub span: Span,
+    pub loc: &'static str,
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 4eb2a103fd8..0225c95dca8 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1187,17 +1187,8 @@ impl<'a> State<'a> {
                 }
                 self.print_type_bounds(bounds);
             }
-            ast::TyKind::ImplTrait(_, bounds, precise_capturing_args) => {
+            ast::TyKind::ImplTrait(_, bounds) => {
                 self.word_nbsp("impl");
-                if let Some((precise_capturing_args, ..)) = precise_capturing_args.as_deref() {
-                    self.word("use");
-                    self.word("<");
-                    self.commasep(Inconsistent, precise_capturing_args, |s, arg| match arg {
-                        ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0),
-                        ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt),
-                    });
-                    self.word(">")
-                }
                 self.print_type_bounds(bounds);
             }
             ast::TyKind::Array(ty, length) => {
@@ -1800,6 +1791,15 @@ impl<'a> State<'a> {
                     self.print_poly_trait_ref(tref);
                 }
                 GenericBound::Outlives(lt) => self.print_lifetime(*lt),
+                GenericBound::Use(args, _) => {
+                    self.word("use");
+                    self.word("<");
+                    self.commasep(Inconsistent, args, |s, arg| match arg {
+                        ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0),
+                        ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt),
+                    });
+                    self.word(">")
+                }
             }
         }
     }
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 58832cb1087..5cb72a2ba38 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -567,7 +567,7 @@ declare_features! (
     (unstable, optimize_attribute, "1.34.0", Some(54882)),
     /// Allows postfix match `expr.match { ... }`
     (unstable, postfix_match, "1.79.0", Some(121618)),
-    /// Allows `use<'a, 'b, A, B>` in `impl use<...> Trait` for precise capture of generic args.
+    /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.
     (incomplete, precise_capturing, "1.79.0", Some(123432)),
     /// Allows macro attributes on expressions, statements and non-inline modules.
     (unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index d4a22c4c31f..22a6c06bba3 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -463,6 +463,7 @@ pub enum TraitBoundModifier {
 pub enum GenericBound<'hir> {
     Trait(PolyTraitRef<'hir>, TraitBoundModifier),
     Outlives(&'hir Lifetime),
+    Use(&'hir [PreciseCapturingArg<'hir>], Span),
 }
 
 impl GenericBound<'_> {
@@ -477,6 +478,7 @@ impl GenericBound<'_> {
         match self {
             GenericBound::Trait(t, ..) => t.span,
             GenericBound::Outlives(l) => l.ident.span,
+            GenericBound::Use(_, span) => *span,
         }
     }
 }
@@ -2689,8 +2691,6 @@ pub struct OpaqueTy<'hir> {
     /// originating from a trait method. This makes it so that the opaque is
     /// lowered as an associated type.
     pub in_trait: bool,
-    /// List of arguments captured via `impl use<'a, P, ...> Trait` syntax.
-    pub precise_capturing_args: Option<(&'hir [PreciseCapturingArg<'hir>], Span)>,
 }
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 5a16f266dab..065ecc5d7b7 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -532,15 +532,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_ty(ty));
             try_visit!(visitor.visit_generics(generics));
         }
-        ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, precise_capturing_args, .. }) => {
+        ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => {
             try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(walk_generics(visitor, generics));
             walk_list!(visitor, visit_param_bound, bounds);
-            if let Some((precise_capturing_args, _)) = precise_capturing_args {
-                for arg in precise_capturing_args {
-                    try_visit!(visitor.visit_precise_capturing_arg(arg));
-                }
-            }
         }
         ItemKind::Enum(ref enum_definition, ref generics) => {
             try_visit!(visitor.visit_generics(generics));
@@ -1147,6 +1142,10 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(
     match *bound {
         GenericBound::Trait(ref typ, _modifier) => visitor.visit_poly_trait_ref(typ),
         GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
+        GenericBound::Use(args, _) => {
+            walk_list!(visitor, visit_precise_capturing_arg, args);
+            V::Result::output()
+        }
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 72e5995e892..3b53c253195 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -481,9 +481,12 @@ fn sanity_check_found_hidden_type<'tcx>(
 /// 2. Checking that all lifetimes that are implicitly captured are mentioned.
 /// 3. Asserting that all parameters mentioned in the captures list are invariant.
 fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {
-    let hir::OpaqueTy { precise_capturing_args, .. } =
+    let hir::OpaqueTy { bounds, .. } =
         *tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
-    let Some((precise_capturing_args, _)) = precise_capturing_args else {
+    let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound {
+        hir::GenericBound::Use(bounds, ..) => Some(bounds),
+        _ => None,
+    }) else {
         // No precise capturing args; nothing to validate
         return;
     };
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 9a6bc8a7b72..c7699b0b310 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -178,6 +178,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         lifetime.ident.span,
                     );
                 }
+                hir::GenericBound::Use(..) => {
+                    // We don't actually lower `use` into the type layer.
+                }
             }
         }
     }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index d32d0183c4e..b21f1eadfb7 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -13,7 +13,7 @@ use rustc_ast_pretty::pprust::{Comments, PrintState};
 use rustc_hir as hir;
 use rustc_hir::{
     BindingMode, ByRef, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId,
-    LifetimeParamKind, Node, PatKind, RangeEnd, Term, TraitBoundModifier,
+    LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TraitBoundModifier,
 };
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, Ident, Symbol};
@@ -2100,10 +2100,24 @@ impl<'a> State<'a> {
                 GenericBound::Outlives(lt) => {
                     self.print_lifetime(lt);
                 }
+                GenericBound::Use(args, _) => {
+                    self.word("use <");
+
+                    self.commasep(Inconsistent, args, |s, arg| s.print_precise_capturing_arg(*arg));
+
+                    self.word(">");
+                }
             }
         }
     }
 
+    fn print_precise_capturing_arg(&mut self, arg: PreciseCapturingArg<'_>) {
+        match arg {
+            PreciseCapturingArg::Lifetime(lt) => self.print_lifetime(lt),
+            PreciseCapturingArg::Param(arg) => self.print_ident(arg.ident),
+        }
+    }
+
     fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) {
         if !generic_params.is_empty() {
             self.word("<");
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index a311c274a6b..d4f6d388d9f 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
 use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::{sym, BytePos, Span};
+use rustc_span::{sym, Span};
 
 use crate::fluent_generated as fluent;
 use crate::{LateContext, LateLintPass};
@@ -53,7 +53,7 @@ declare_lint! {
     /// while the `impl Display` is live.
     ///
     /// To fix this, we can explicitly state that the `impl Display` doesn't
-    /// capture any lifetimes, using `impl use<> Display`.
+    /// capture any lifetimes, using `impl Display + use<>`.
     pub IMPL_TRAIT_OVERCAPTURES,
     Allow,
     "`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
@@ -79,7 +79,7 @@ declare_lint! {
     /// # #![feature(precise_capturing, lifetime_capture_rules_2024)]
     /// # #![allow(incomplete_features)]
     /// # #![deny(impl_trait_redundant_captures)]
-    /// fn test<'a>(x: &'a i32) -> impl use<'a> Sized { x }
+    /// fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x }
     /// ```
     ///
     /// {{produces}}
@@ -249,7 +249,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
             // If we have uncaptured args, and if the opaque doesn't already have
             // `use<>` syntax on it, and we're < edition 2024, then warn the user.
             if !new_capture_rules
-                && opaque.precise_capturing_args.is_none()
+                && !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..)))
                 && !uncaptured_spans.is_empty()
             {
                 let suggestion = if let Ok(snippet) =
@@ -268,8 +268,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
                     // Make sure that we're not trying to name any APITs
                     if generics.iter().all(|name| !name.starts_with("impl ")) {
                         Some((
-                            format!(" use<{}>", generics.join(", ")),
-                            opaque_span.with_lo(opaque_span.lo() + BytePos(4)).shrink_to_lo(),
+                            format!(" + use<{}>", generics.join(", ")),
+                            opaque_span.shrink_to_hi(),
                         ))
                     } else {
                         None
@@ -294,7 +294,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
             // have no uncaptured args, then we should warn to the user that
             // it's redundant to capture all args explicitly.
             else if new_capture_rules
-                && let Some((captured_args, capturing_span)) = opaque.precise_capturing_args
+                && let Some((captured_args, capturing_span)) =
+                    opaque.bounds.iter().find_map(|bound| match *bound {
+                        hir::GenericBound::Use(a, s) => Some((a, s)),
+                        _ => None,
+                    })
             {
                 let mut explicitly_captured = UnordSet::default();
                 for arg in captured_args {
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 7a1aa4043be..195a0f72475 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1268,7 +1268,7 @@ impl EarlyLintPass for UnusedParens {
                     ast::TyKind::TraitObject(..) => {}
                     ast::TyKind::BareFn(b)
                         if self.with_self_ty_parens && b.generic_params.len() > 0 => {}
-                    ast::TyKind::ImplTrait(_, bounds, _) if bounds.len() > 1 => {}
+                    ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
                     _ => {
                         let spans = if !ty.span.from_expansion() {
                             r.span
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 93a15c938ec..fde16ac957d 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -62,7 +62,7 @@ impl<'a> Parser<'a> {
                 let snapshot = self.create_snapshot_for_diagnostic();
                 match self.parse_ty() {
                     Ok(p) => {
-                        if let TyKind::ImplTrait(_, bounds, None) = &p.kind {
+                        if let TyKind::ImplTrait(_, bounds) = &p.kind {
                             let span = impl_span.to(self.token.span.shrink_to_lo());
                             let mut err = self.dcx().struct_span_err(
                                 span,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 3f5a4afdad8..3d2eee247b8 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -633,7 +633,7 @@ impl<'a> Parser<'a> {
                     // This notably includes paths passed through `ty` macro fragments (#46438).
                     TyKind::Path(None, path) => path,
                     other => {
-                        if let TyKind::ImplTrait(_, bounds, None) = other
+                        if let TyKind::ImplTrait(_, bounds) = other
                             && let [bound] = bounds.as_slice()
                         {
                             // Suggest removing extra `impl` keyword:
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index bdb08709f27..fcd623b477f 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -316,7 +316,7 @@ impl<'a> Parser<'a> {
                             TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
                         }
                         (TyKind::TraitObject(bounds, _), kw::Impl) => {
-                            TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, None)
+                            TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)
                         }
                         _ => return Err(err),
                     };
@@ -670,24 +670,12 @@ impl<'a> Parser<'a> {
             })
         }
 
-        // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of
-        // lifetimes and ident params (including SelfUpper). These are validated later
-        // for order, duplication, and whether they actually reference params.
-        let precise_capturing = if self.eat_keyword(kw::Use) {
-            let use_span = self.prev_token.span;
-            self.psess.gated_spans.gate(sym::precise_capturing, use_span);
-            let (args, args_span) = self.parse_precise_capturing_args()?;
-            Some(P((args, use_span.to(args_span))))
-        } else {
-            None
-        };
-
         // Always parse bounds greedily for better error recovery.
         let bounds = self.parse_generic_bounds()?;
 
         *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
 
-        Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, precise_capturing))
+        Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
     }
 
     fn parse_precise_capturing_args(
@@ -834,6 +822,7 @@ impl<'a> Parser<'a> {
             || self.check(&token::OpenDelim(Delimiter::Parenthesis))
             || self.check_keyword(kw::Const)
             || self.check_keyword(kw::Async)
+            || self.check_keyword(kw::Use)
     }
 
     /// Parses a bound according to the grammar:
@@ -850,6 +839,14 @@ impl<'a> Parser<'a> {
         let bound = if self.token.is_lifetime() {
             self.error_lt_bound_with_modifiers(modifiers);
             self.parse_generic_lt_bound(lo, inner_lo, has_parens)?
+        } else if self.eat_keyword(kw::Use) {
+            // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of
+            // lifetimes and ident params (including SelfUpper). These are validated later
+            // for order, duplication, and whether they actually reference params.
+            let use_span = self.prev_token.span;
+            self.psess.gated_spans.gate(sym::precise_capturing, use_span);
+            let (args, args_span) = self.parse_precise_capturing_args()?;
+            GenericBound::Use(args, use_span.to(args_span))
         } else {
             self.parse_generic_ty_bound(lo, has_parens, modifiers, &leading_token)?
         };
@@ -1009,7 +1006,7 @@ impl<'a> Parser<'a> {
                             Applicability::MaybeIncorrect,
                         )
                     }
-                    TyKind::ImplTrait(_, bounds, None)
+                    TyKind::ImplTrait(_, bounds)
                         if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() =>
                     {
                         (
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index d49298781a2..0ba61f8e8b4 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -429,7 +429,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
     fn visit_param_bound(&mut self, b: &'v hir::GenericBound<'v>) {
         record_variants!(
             (self, b, b, Id::None, hir, GenericBound, GenericBound),
-            [Trait, Outlives]
+            [Trait, Outlives, Use]
         );
         hir_visit::walk_param_bound(self, b)
     }
@@ -659,7 +659,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
     fn visit_param_bound(&mut self, b: &'v ast::GenericBound, _ctxt: BoundKind) {
         record_variants!(
             (self, b, b, Id::None, ast, GenericBound, GenericBound),
-            [Trait, Outlives]
+            [Trait, Outlives, Use]
         );
         ast_visit::walk_param_bound(self, b)
     }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index c1e83c59f98..5ab6ba23a7d 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -799,7 +799,7 @@ 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(node_id, _, _) => {
+            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);
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index be24755d4c5..75a1aff4fc5 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -829,7 +829,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         auto-traits; structs and enums can't be bound in that way",
                 );
                 if bounds.iter().all(|bound| match bound {
-                    ast::GenericBound::Outlives(_) => true,
+                    ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..) => true,
                     ast::GenericBound::Trait(tr, _) => tr.span == base_error.span,
                 }) {
                     let mut sugg = vec![];
@@ -3210,7 +3210,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                                 .inputs
                                 .iter()
                                 .filter_map(|param| match &param.ty.kind {
-                                    TyKind::ImplTrait(_, bounds, _) => Some(bounds),
+                                    TyKind::ImplTrait(_, bounds) => Some(bounds),
                                     _ => None,
                                 })
                                 .flat_map(|bounds| bounds.into_iter())
diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
index 06ae1723a03..4922c87b206 100644
--- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
@@ -73,7 +73,7 @@ fn type_param_bounds<'tcx>(generics: &'tcx Generics<'tcx>) -> impl Iterator<Item
                             predicate_pos,
                             bound_pos,
                         }),
-                        GenericBound::Outlives(_) => None,
+                        GenericBound::Outlives(_) | GenericBound::Use(..) => None,
                     })
                     .filter(|bound| !bound.trait_bound.span.from_expansion()),
             )
diff --git a/tests/ui/feature-gates/feature-gate-precise-capturing.rs b/tests/ui/feature-gates/feature-gate-precise-capturing.rs
index 0c3b4977623..47a21539d37 100644
--- a/tests/ui/feature-gates/feature-gate-precise-capturing.rs
+++ b/tests/ui/feature-gates/feature-gate-precise-capturing.rs
@@ -1,4 +1,4 @@
-fn hello() -> impl use<> Sized {}
+fn hello() -> impl Sized + use<> {}
 //~^ ERROR precise captures on `impl Trait` are experimental
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-precise-capturing.stderr b/tests/ui/feature-gates/feature-gate-precise-capturing.stderr
index 102b39148f9..04365408880 100644
--- a/tests/ui/feature-gates/feature-gate-precise-capturing.stderr
+++ b/tests/ui/feature-gates/feature-gate-precise-capturing.stderr
@@ -1,8 +1,8 @@
 error[E0658]: precise captures on `impl Trait` are experimental
-  --> $DIR/feature-gate-precise-capturing.rs:1:20
+  --> $DIR/feature-gate-precise-capturing.rs:1:28
    |
-LL | fn hello() -> impl use<> Sized {}
-   |                    ^^^
+LL | fn hello() -> impl Sized + use<> {}
+   |                            ^^^
    |
    = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
    = help: add `#![feature(precise_capturing)]` to the crate attributes to enable
diff --git a/tests/ui/impl-trait/precise-capturing/apit.rs b/tests/ui/impl-trait/precise-capturing/apit.rs
index efcac9ebb0b..98e7da4e34a 100644
--- a/tests/ui/impl-trait/precise-capturing/apit.rs
+++ b/tests/ui/impl-trait/precise-capturing/apit.rs
@@ -1,7 +1,7 @@
 #![feature(precise_capturing)]
 //~^ WARN the feature `precise_capturing` is incomplete
 
-fn hello(_: impl use<> Sized) {}
+fn hello(_: impl Sized + use<>) {}
 //~^ ERROR `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/apit.stderr b/tests/ui/impl-trait/precise-capturing/apit.stderr
index 96548f5732f..b676ed260cb 100644
--- a/tests/ui/impl-trait/precise-capturing/apit.stderr
+++ b/tests/ui/impl-trait/precise-capturing/apit.stderr
@@ -8,10 +8,10 @@ LL | #![feature(precise_capturing)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error: `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
-  --> $DIR/apit.rs:4:18
+  --> $DIR/apit.rs:4:26
    |
-LL | fn hello(_: impl use<> Sized) {}
-   |                  ^^^^^
+LL | fn hello(_: impl Sized + use<>) {}
+   |                          ^^^^^
 
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs
index 623063a8f50..d9ea20b1e30 100644
--- a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs
+++ b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs
@@ -1,14 +1,14 @@
 #![feature(precise_capturing)]
 //~^ WARN the feature `precise_capturing` is incomplete
 
-fn no_elided_lt() -> impl use<'_> Sized {}
+fn no_elided_lt() -> impl Sized + use<'_> {}
 //~^ ERROR missing lifetime specifier
 //~| ERROR expected lifetime parameter in `use<...>` precise captures list, found `'_`
 
-fn static_lt() -> impl use<'static> Sized {}
+fn static_lt() -> impl Sized + use<'static> {}
 //~^ ERROR expected lifetime parameter in `use<...>` precise captures list, found `'static`
 
-fn missing_lt() -> impl use<'missing> Sized {}
+fn missing_lt() -> impl Sized + use<'missing> {}
 //~^ ERROR use of undeclared lifetime name `'missing`
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr
index a926362c50c..ac8ec34e341 100644
--- a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr
+++ b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr
@@ -1,20 +1,20 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/bad-lifetimes.rs:4:31
+  --> $DIR/bad-lifetimes.rs:4:39
    |
-LL | fn no_elided_lt() -> impl use<'_> Sized {}
-   |                               ^^ expected named lifetime parameter
+LL | fn no_elided_lt() -> impl Sized + use<'_> {}
+   |                                       ^^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
    |
-LL | fn no_elided_lt() -> impl use<'static> Sized {}
-   |                               ~~~~~~~
+LL | fn no_elided_lt() -> impl Sized + use<'static> {}
+   |                                       ~~~~~~~
 
 error[E0261]: use of undeclared lifetime name `'missing`
-  --> $DIR/bad-lifetimes.rs:11:29
+  --> $DIR/bad-lifetimes.rs:11:37
    |
-LL | fn missing_lt() -> impl use<'missing> Sized {}
-   |              -              ^^^^^^^^ undeclared lifetime
+LL | fn missing_lt() -> impl Sized + use<'missing> {}
+   |              -                      ^^^^^^^^ undeclared lifetime
    |              |
    |              help: consider introducing lifetime `'missing` here: `<'missing>`
 
@@ -28,16 +28,16 @@ LL | #![feature(precise_capturing)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error: expected lifetime parameter in `use<...>` precise captures list, found `'_`
-  --> $DIR/bad-lifetimes.rs:4:31
+  --> $DIR/bad-lifetimes.rs:4:39
    |
-LL | fn no_elided_lt() -> impl use<'_> Sized {}
-   |                               ^^
+LL | fn no_elided_lt() -> impl Sized + use<'_> {}
+   |                                       ^^
 
 error: expected lifetime parameter in `use<...>` precise captures list, found `'static`
-  --> $DIR/bad-lifetimes.rs:8:28
+  --> $DIR/bad-lifetimes.rs:8:36
    |
-LL | fn static_lt() -> impl use<'static> Sized {}
-   |                            ^^^^^^^
+LL | fn static_lt() -> impl Sized + use<'static> {}
+   |                                    ^^^^^^^
 
 error: aborting due to 4 previous errors; 1 warning emitted
 
diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.rs b/tests/ui/impl-trait/precise-capturing/bad-params.rs
index 7970d49bf7c..4d9392f76f2 100644
--- a/tests/ui/impl-trait/precise-capturing/bad-params.rs
+++ b/tests/ui/impl-trait/precise-capturing/bad-params.rs
@@ -1,19 +1,19 @@
 #![feature(precise_capturing)]
 //~^ WARN the feature `precise_capturing` is incomplete
 
-fn missing() -> impl use<T> Sized {}
+fn missing() -> impl Sized + use<T> {}
 //~^ ERROR cannot find type `T` in this scope
 
-fn missing_self() -> impl use<Self> Sized {}
+fn missing_self() -> impl Sized + use<Self> {}
 //~^ ERROR cannot find type `Self` in this scope
 
 struct MyType;
 impl MyType {
-    fn self_is_not_param() -> impl use<Self> Sized {}
+    fn self_is_not_param() -> impl Sized + use<Self> {}
     //~^ ERROR `Self` can't be captured in `use<...>` precise captures list, since it is an alias
 }
 
-fn hello() -> impl use<hello> Sized {}
+fn hello() -> impl Sized + use<hello> {}
 //~^ ERROR expected type or const parameter in `use<...>` precise captures list, found function
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.stderr b/tests/ui/impl-trait/precise-capturing/bad-params.stderr
index 27bf05302f9..309a8128fe4 100644
--- a/tests/ui/impl-trait/precise-capturing/bad-params.stderr
+++ b/tests/ui/impl-trait/precise-capturing/bad-params.stderr
@@ -1,19 +1,19 @@
 error[E0412]: cannot find type `T` in this scope
-  --> $DIR/bad-params.rs:4:26
+  --> $DIR/bad-params.rs:4:34
    |
-LL | fn missing() -> impl use<T> Sized {}
-   |                          ^ not found in this scope
+LL | fn missing() -> impl Sized + use<T> {}
+   |                                  ^ not found in this scope
    |
 help: you might be missing a type parameter
    |
-LL | fn missing<T>() -> impl use<T> Sized {}
+LL | fn missing<T>() -> impl Sized + use<T> {}
    |           +++
 
 error[E0411]: cannot find type `Self` in this scope
-  --> $DIR/bad-params.rs:7:31
+  --> $DIR/bad-params.rs:7:39
    |
-LL | fn missing_self() -> impl use<Self> Sized {}
-   |    ------------               ^^^^ `Self` is only available in impls, traits, and type definitions
+LL | fn missing_self() -> impl Sized + use<Self> {}
+   |    ------------                       ^^^^ `Self` is only available in impls, traits, and type definitions
    |    |
    |    `Self` not allowed in a function
 
@@ -27,18 +27,18 @@ LL | #![feature(precise_capturing)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error: `Self` can't be captured in `use<...>` precise captures list, since it is an alias
-  --> $DIR/bad-params.rs:12:40
+  --> $DIR/bad-params.rs:12:48
    |
 LL | impl MyType {
    | ----------- `Self` is not a generic argument, but an alias to the type of the implementation
-LL |     fn self_is_not_param() -> impl use<Self> Sized {}
-   |                                        ^^^^
+LL |     fn self_is_not_param() -> impl Sized + use<Self> {}
+   |                                                ^^^^
 
 error: expected type or const parameter in `use<...>` precise captures list, found function
-  --> $DIR/bad-params.rs:16:24
+  --> $DIR/bad-params.rs:16:32
    |
-LL | fn hello() -> impl use<hello> Sized {}
-   |                        ^^^^^
+LL | fn hello() -> impl Sized + use<hello> {}
+   |                                ^^^^^
 
 error: aborting due to 4 previous errors; 1 warning emitted
 
diff --git a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs
index 35b28d0e6fb..f4acc4db269 100644
--- a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs
+++ b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs
@@ -13,25 +13,25 @@ impl Tr for W<'_> {
 
 // The normal way of capturing `'a`...
 impl<'a> W<'a> {
-    fn good1() -> impl use<'a> Into<<W<'a> as Tr>::Assoc> {}
+    fn good1() -> impl Into<<W<'a> as Tr>::Assoc> + use<'a> {}
 }
 
 // This ensures that we don't error when we capture the *parent* copy of `'a`,
 // since the opaque captures that rather than the duplicated `'a` lifetime
 // synthesized from mentioning `'a` directly in the bounds.
 impl<'a> W<'a> {
-    fn good2() -> impl use<'a> Into<<Self as Tr>::Assoc> {}
+    fn good2() -> impl Into<<Self as Tr>::Assoc> + use<'a> {}
 }
 
 // The normal way of capturing `'a`... but not mentioned in the bounds.
 impl<'a> W<'a> {
-    fn bad1() -> impl use<> Into<<W<'a> as Tr>::Assoc> {}
+    fn bad1() -> impl Into<<W<'a> as Tr>::Assoc> + use<> {}
     //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
 }
 
 // But also make sure that we error here...
 impl<'a> W<'a> {
-    fn bad2() -> impl use<> Into<<Self as Tr>::Assoc> {}
+    fn bad2() -> impl Into<<Self as Tr>::Assoc> + use<> {}
     //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
 }
 
diff --git a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr
index 13aaa999707..447f74dca2b 100644
--- a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr
+++ b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr
@@ -8,20 +8,20 @@ LL | #![feature(precise_capturing)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
-  --> $DIR/capture-parent-arg.rs:28:37
+  --> $DIR/capture-parent-arg.rs:28:31
    |
 LL | impl<'a> W<'a> {
    |      -- this lifetime parameter is captured
-LL |     fn bad1() -> impl use<> Into<<W<'a> as Tr>::Assoc> {}
-   |                  -------------------^^---------------- lifetime captured due to being mentioned in the bounds of the `impl Trait`
+LL |     fn bad1() -> impl Into<<W<'a> as Tr>::Assoc> + use<> {}
+   |                  -------------^^------------------------ lifetime captured due to being mentioned in the bounds of the `impl Trait`
 
 error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
   --> $DIR/capture-parent-arg.rs:34:18
    |
 LL | impl<'a> W<'a> {
    |      -- this lifetime parameter is captured
-LL |     fn bad2() -> impl use<> Into<<Self as Tr>::Assoc> {}
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait`
+LL |     fn bad2() -> impl Into<<Self as Tr>::Assoc> + use<> {}
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait`
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/tests/ui/impl-trait/precise-capturing/elided.rs b/tests/ui/impl-trait/precise-capturing/elided.rs
index de80e8a5d58..71e269e03a3 100644
--- a/tests/ui/impl-trait/precise-capturing/elided.rs
+++ b/tests/ui/impl-trait/precise-capturing/elided.rs
@@ -3,6 +3,6 @@
 #![feature(precise_capturing)]
 //~^ WARN the feature `precise_capturing` is incomplete
 
-fn elided(x: &()) -> impl use<'_> Sized { x }
+fn elided(x: &()) -> impl Sized + use<'_> { x }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs
index 1b604e6c358..49466585c52 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs
@@ -1,7 +1,7 @@
 #![feature(precise_capturing)]
 //~^ WARN the feature `precise_capturing` is incomplete
 
-fn constant<const C: usize>() -> impl use<> Sized {}
+fn constant<const C: usize>() -> impl Sized + use<> {}
 //~^ ERROR `impl Trait` must mention all const parameters in scope
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr
index 3f78e7c56b6..ce27f79a9d6 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr
@@ -10,8 +10,8 @@ LL | #![feature(precise_capturing)]
 error: `impl Trait` must mention all const parameters in scope in `use<...>`
   --> $DIR/forgot-to-capture-const.rs:4:34
    |
-LL | fn constant<const C: usize>() -> impl use<> Sized {}
-   |             --------------       ^^^^^^^^^^^^^^^^
+LL | fn constant<const C: usize>() -> impl Sized + use<> {}
+   |             --------------       ^^^^^^^^^^^^^^^^^^
    |             |
    |             const parameter is implicitly captured by this `impl Trait`
    |
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs
index cc86bf83107..9af36817847 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs
@@ -1,10 +1,10 @@
 #![feature(precise_capturing)]
 //~^ WARN the feature `precise_capturing` is incomplete
 
-fn lifetime_in_bounds<'a>(x: &'a ()) -> impl use<> Into<&'a ()> { x }
+fn lifetime_in_bounds<'a>(x: &'a ()) -> impl Into<&'a ()> + use<> { x }
 //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
 
-fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized { x }
+fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x }
 //~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr
index e472c898050..c884b6b0d91 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr
@@ -8,27 +8,27 @@ LL | #![feature(precise_capturing)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
-  --> $DIR/forgot-to-capture-lifetime.rs:4:58
+  --> $DIR/forgot-to-capture-lifetime.rs:4:52
    |
-LL | fn lifetime_in_bounds<'a>(x: &'a ()) -> impl use<> Into<&'a ()> { x }
-   |                       --                -----------------^^----
+LL | fn lifetime_in_bounds<'a>(x: &'a ()) -> impl Into<&'a ()> + use<> { x }
+   |                       --                -----------^^------------
    |                       |                 |
    |                       |                 lifetime captured due to being mentioned in the bounds of the `impl Trait`
    |                       this lifetime parameter is captured
 
 error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
-  --> $DIR/forgot-to-capture-lifetime.rs:7:60
+  --> $DIR/forgot-to-capture-lifetime.rs:7:62
    |
-LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized { x }
-   |                       --                ----------------   ^
+LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x }
+   |                       --                ------------------   ^
    |                       |                 |
    |                       |                 opaque type defined here
    |                       hidden type `&'a ()` captures the lifetime `'a` as defined here
    |
 help: to declare that `impl Sized` captures `'a`, you can add an explicit `'a` lifetime bound
    |
-LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized + 'a { x }
-   |                                                          ++++
+LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> + 'a { x }
+   |                                                            ++++
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs
index d359ea5e26d..bfb0745805a 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs
@@ -1,11 +1,11 @@
 #![feature(precise_capturing)]
 //~^ WARN the feature `precise_capturing` is incomplete
 
-fn type_param<T>() -> impl use<> Sized {}
+fn type_param<T>() -> impl Sized + use<> {}
 //~^ ERROR `impl Trait` must mention all type parameters in scope
 
 trait Foo {
-    fn bar() -> impl use<> Sized;
+    fn bar() -> impl Sized + use<>;
     //~^ ERROR `impl Trait` must mention the `Self` type of the trait
 }
 
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr
index 26994d0bdbf..91e7e79564d 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr
@@ -10,8 +10,8 @@ LL | #![feature(precise_capturing)]
 error: `impl Trait` must mention all type parameters in scope in `use<...>`
   --> $DIR/forgot-to-capture-type.rs:4:23
    |
-LL | fn type_param<T>() -> impl use<> Sized {}
-   |               -       ^^^^^^^^^^^^^^^^
+LL | fn type_param<T>() -> impl Sized + use<> {}
+   |               -       ^^^^^^^^^^^^^^^^^^
    |               |
    |               type parameter is implicitly captured by this `impl Trait`
    |
@@ -22,8 +22,8 @@ error: `impl Trait` must mention the `Self` type of the trait in `use<...>`
    |
 LL | trait Foo {
    | --------- `Self` type parameter is implicitly captured by this `impl Trait`
-LL |     fn bar() -> impl use<> Sized;
-   |                 ^^^^^^^^^^^^^^^^
+LL |     fn bar() -> impl Sized + use<>;
+   |                 ^^^^^^^^^^^^^^^^^^
    |
    = note: currently, all type parameters are required to be mentioned in the precise captures list
 
diff --git a/tests/ui/impl-trait/precise-capturing/higher-ranked.rs b/tests/ui/impl-trait/precise-capturing/higher-ranked.rs
index 28fb1fa4b9e..7c8038600d1 100644
--- a/tests/ui/impl-trait/precise-capturing/higher-ranked.rs
+++ b/tests/ui/impl-trait/precise-capturing/higher-ranked.rs
@@ -13,6 +13,6 @@ impl Trait<'_> for () {
     type Item = Vec<()>;
 }
 
-fn hello() -> impl for<'a> Trait<'a, Item = impl use<> IntoIterator> {}
+fn hello() -> impl for<'a> Trait<'a, Item = impl IntoIterator + use<>> {}
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/ordering.rs b/tests/ui/impl-trait/precise-capturing/ordering.rs
index 2bace798c57..ff326ae6d02 100644
--- a/tests/ui/impl-trait/precise-capturing/ordering.rs
+++ b/tests/ui/impl-trait/precise-capturing/ordering.rs
@@ -1,16 +1,16 @@
 #![feature(precise_capturing)]
 //~^ WARN the feature `precise_capturing` is incomplete
 
-fn lt<'a>() -> impl use<'a, 'a> Sized {}
+fn lt<'a>() -> impl Sized + use<'a, 'a> {}
 //~^ ERROR cannot capture parameter `'a` twice
 
-fn ty<T>() -> impl use<T, T> Sized {}
+fn ty<T>() -> impl Sized + use<T, T> {}
 //~^ ERROR cannot capture parameter `T` twice
 
-fn ct<const N: usize>() -> impl use<N, N> Sized {}
+fn ct<const N: usize>() -> impl Sized + use<N, N> {}
 //~^ ERROR cannot capture parameter `N` twice
 
-fn ordering<'a, T>() -> impl use<T, 'a> Sized {}
+fn ordering<'a, T>() -> impl Sized + use<T, 'a> {}
 //~^ ERROR lifetime parameter `'a` must be listed before non-lifetime parameters
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/ordering.stderr b/tests/ui/impl-trait/precise-capturing/ordering.stderr
index 3f545108df5..65059b854b3 100644
--- a/tests/ui/impl-trait/precise-capturing/ordering.stderr
+++ b/tests/ui/impl-trait/precise-capturing/ordering.stderr
@@ -8,30 +8,30 @@ LL | #![feature(precise_capturing)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error: cannot capture parameter `'a` twice
-  --> $DIR/ordering.rs:4:25
+  --> $DIR/ordering.rs:4:33
    |
-LL | fn lt<'a>() -> impl use<'a, 'a> Sized {}
-   |                         ^^  -- parameter captured again here
+LL | fn lt<'a>() -> impl Sized + use<'a, 'a> {}
+   |                                 ^^  -- parameter captured again here
 
 error: cannot capture parameter `T` twice
-  --> $DIR/ordering.rs:7:24
+  --> $DIR/ordering.rs:7:32
    |
-LL | fn ty<T>() -> impl use<T, T> Sized {}
-   |                        ^  - parameter captured again here
+LL | fn ty<T>() -> impl Sized + use<T, T> {}
+   |                                ^  - parameter captured again here
 
 error: cannot capture parameter `N` twice
-  --> $DIR/ordering.rs:10:37
+  --> $DIR/ordering.rs:10:45
    |
-LL | fn ct<const N: usize>() -> impl use<N, N> Sized {}
-   |                                     ^  - parameter captured again here
+LL | fn ct<const N: usize>() -> impl Sized + use<N, N> {}
+   |                                             ^  - parameter captured again here
 
 error: lifetime parameter `'a` must be listed before non-lifetime parameters
-  --> $DIR/ordering.rs:13:37
+  --> $DIR/ordering.rs:13:45
    |
-LL | fn ordering<'a, T>() -> impl use<T, 'a> Sized {}
-   |                                  -  ^^
-   |                                  |
-   |                                  move the lifetime before this parameter
+LL | fn ordering<'a, T>() -> impl Sized + use<T, 'a> {}
+   |                                          -  ^^
+   |                                          |
+   |                                          move the lifetime before this parameter
 
 error: aborting due to 4 previous errors; 1 warning emitted
 
diff --git a/tests/ui/impl-trait/precise-capturing/outlives.rs b/tests/ui/impl-trait/precise-capturing/outlives.rs
index 71e6333934e..c316a869ec5 100644
--- a/tests/ui/impl-trait/precise-capturing/outlives.rs
+++ b/tests/ui/impl-trait/precise-capturing/outlives.rs
@@ -5,7 +5,7 @@
 #![feature(lifetime_capture_rules_2024, precise_capturing)]
 //~^ WARN the feature `precise_capturing` is incomplete
 
-fn hello<'a: 'a, 'b: 'b>() -> impl use<'a> Sized { }
+fn hello<'a: 'a, 'b: 'b>() -> impl Sized + use<'a> { }
 
 fn outlives<'a, T: 'a>(_: T) {}
 
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed
index 014ab23e4eb..5ac296a9cbd 100644
--- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed
@@ -4,15 +4,15 @@
 #![allow(unused, incomplete_features)]
 #![deny(impl_trait_overcaptures)]
 
-fn named<'a>(x: &'a i32) -> impl use<> Sized { *x }
+fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x }
 //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
 
-fn implicit(x: &i32) -> impl use<> Sized { *x }
+fn implicit(x: &i32) -> impl Sized + use<> { *x }
 //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
 
 struct W;
 impl W {
-    fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self }
+    fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self }
     //~^ ERROR `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
 }
 
@@ -23,7 +23,7 @@ impl Higher<'_> for () {
     type Output = ();
 }
 
-fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {}
+fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {}
 //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
index 16cb8b7e94b..f8bb7f099af 100644
--- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
@@ -17,8 +17,8 @@ LL | #![deny(impl_trait_overcaptures)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 help: use the precise capturing `use<...>` syntax to make the captures explicit
    |
-LL | fn named<'a>(x: &'a i32) -> impl use<> Sized { *x }
-   |                                  +++++
+LL | fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x }
+   |                                        +++++++
 
 error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
   --> $DIR/overcaptures-2024.rs:10:25
@@ -34,8 +34,8 @@ LL | fn implicit(x: &i32) -> impl Sized { *x }
    = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
 help: use the precise capturing `use<...>` syntax to make the captures explicit
    |
-LL | fn implicit(x: &i32) -> impl use<> Sized { *x }
-   |                              +++++
+LL | fn implicit(x: &i32) -> impl Sized + use<> { *x }
+   |                                    +++++++
 
 error: `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
   --> $DIR/overcaptures-2024.rs:15:33
@@ -51,8 +51,8 @@ LL |     fn hello(&self, x: &i32) -> impl Sized + '_ { self }
    = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
 help: use the precise capturing `use<...>` syntax to make the captures explicit
    |
-LL |     fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self }
-   |                                      +++++++
+LL |     fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self }
+   |                                                 +++++++++
 
 error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
   --> $DIR/overcaptures-2024.rs:26:47
@@ -68,8 +68,8 @@ LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
    = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
 help: use the precise capturing `use<...>` syntax to make the captures explicit
    |
-LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {}
-   |                                                    +++++
+LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {}
+   |                                                          +++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs
index 108a4cb64aa..30acfe77e2e 100644
--- a/tests/ui/impl-trait/precise-capturing/redundant.rs
+++ b/tests/ui/impl-trait/precise-capturing/redundant.rs
@@ -4,21 +4,21 @@
 #![feature(precise_capturing)]
 //~^ WARN the feature `precise_capturing` is incomplete
 
-fn hello<'a>() -> impl use<'a> Sized {}
+fn hello<'a>() -> impl Sized + use<'a> {}
 //~^ WARN all possible in-scope parameters are already captured
 
 struct Inherent;
 impl Inherent {
-    fn inherent(&self) -> impl use<'_> Sized {}
+    fn inherent(&self) -> impl Sized + use<'_> {}
     //~^ WARN all possible in-scope parameters are already captured
 }
 
 trait Test<'a> {
-    fn in_trait() -> impl use<'a, Self> Sized;
+    fn in_trait() -> impl Sized + use<'a, Self>;
     //~^ WARN all possible in-scope parameters are already captured
 }
 impl<'a> Test<'a> for () {
-    fn in_trait() -> impl use<'a> Sized {}
+    fn in_trait() -> impl Sized + use<'a> {}
     //~^ WARN all possible in-scope parameters are already captured
 }
 
diff --git a/tests/ui/impl-trait/precise-capturing/redundant.stderr b/tests/ui/impl-trait/precise-capturing/redundant.stderr
index 325f04d3536..d100fd02053 100644
--- a/tests/ui/impl-trait/precise-capturing/redundant.stderr
+++ b/tests/ui/impl-trait/precise-capturing/redundant.stderr
@@ -10,36 +10,36 @@ LL | #![feature(precise_capturing)]
 warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
   --> $DIR/redundant.rs:7:19
    |
-LL | fn hello<'a>() -> impl use<'a> Sized {}
-   |                   ^^^^^-------^^^^^^
-   |                        |
-   |                        help: remove the `use<...>` syntax
+LL | fn hello<'a>() -> impl Sized + use<'a> {}
+   |                   ^^^^^^^^^^^^^-------
+   |                                |
+   |                                help: remove the `use<...>` syntax
    |
    = note: `#[warn(impl_trait_redundant_captures)]` on by default
 
 warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
   --> $DIR/redundant.rs:12:27
    |
-LL |     fn inherent(&self) -> impl use<'_> Sized {}
-   |                           ^^^^^-------^^^^^^
-   |                                |
-   |                                help: remove the `use<...>` syntax
+LL |     fn inherent(&self) -> impl Sized + use<'_> {}
+   |                           ^^^^^^^^^^^^^-------
+   |                                        |
+   |                                        help: remove the `use<...>` syntax
 
 warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
   --> $DIR/redundant.rs:17:22
    |
-LL |     fn in_trait() -> impl use<'a, Self> Sized;
-   |                      ^^^^^-------------^^^^^^
-   |                           |
-   |                           help: remove the `use<...>` syntax
+LL |     fn in_trait() -> impl Sized + use<'a, Self>;
+   |                      ^^^^^^^^^^^^^-------------
+   |                                   |
+   |                                   help: remove the `use<...>` syntax
 
 warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
   --> $DIR/redundant.rs:21:22
    |
-LL |     fn in_trait() -> impl use<'a> Sized {}
-   |                      ^^^^^-------^^^^^^
-   |                           |
-   |                           help: remove the `use<...>` syntax
+LL |     fn in_trait() -> impl Sized + use<'a> {}
+   |                      ^^^^^^^^^^^^^-------
+   |                                   |
+   |                                   help: remove the `use<...>` syntax
 
 warning: 5 warnings emitted
 
diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.rs b/tests/ui/impl-trait/precise-capturing/self-capture.rs
index ecbc388e27b..1dbbcadff6d 100644
--- a/tests/ui/impl-trait/precise-capturing/self-capture.rs
+++ b/tests/ui/impl-trait/precise-capturing/self-capture.rs
@@ -4,7 +4,7 @@
 //~^ WARN the feature `precise_capturing` is incomplete
 
 trait Foo {
-    fn bar<'a>() -> impl use<Self> Sized;
+    fn bar<'a>() -> impl Sized + use<Self>;
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/unexpected-token.rs b/tests/ui/impl-trait/precise-capturing/unexpected-token.rs
index 2a7ccbe1e60..a1089fd7bfc 100644
--- a/tests/ui/impl-trait/precise-capturing/unexpected-token.rs
+++ b/tests/ui/impl-trait/precise-capturing/unexpected-token.rs
@@ -2,7 +2,7 @@
 // token due to a strange interaction between the sequence parsing code and the
 // param/lifetime parsing code.
 
-fn hello() -> impl use<'a {}> Sized {}
+fn hello() -> impl Sized + use<'a {}> {}
 //~^ ERROR expected one of `,` or `>`, found `{`
 
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr b/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr
index 1f8e1d0ec32..51e4f0f6775 100644
--- a/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr
+++ b/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr
@@ -1,8 +1,8 @@
 error: expected one of `,` or `>`, found `{`
-  --> $DIR/unexpected-token.rs:5:27
+  --> $DIR/unexpected-token.rs:5:35
    |
-LL | fn hello() -> impl use<'a {}> Sized {}
-   |                           ^ expected one of `,` or `>`
+LL | fn hello() -> impl Sized + use<'a {}> {}
+   |                                   ^ expected one of `,` or `>`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/trait-object-delimiters.rs b/tests/ui/parser/trait-object-delimiters.rs
index d6bc629aa11..8f6221c1b94 100644
--- a/tests/ui/parser/trait-object-delimiters.rs
+++ b/tests/ui/parser/trait-object-delimiters.rs
@@ -8,7 +8,7 @@ fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around t
 fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around trait bounds
 
 fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
-//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `~`, lifetime, or path, found `{`
+//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{`
 //~| ERROR at least one trait is required for an object type
 
 fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`
diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr
index 2b1f8df991f..5f175e86545 100644
--- a/tests/ui/parser/trait-object-delimiters.stderr
+++ b/tests/ui/parser/trait-object-delimiters.stderr
@@ -34,11 +34,11 @@ error: expected parameter name, found `{`
 LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
    |                 ^ expected parameter name
 
-error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `~`, lifetime, or path, found `{`
+error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{`
   --> $DIR/trait-object-delimiters.rs:10:17
    |
 LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
-   |                -^ expected one of 12 possible tokens
+   |                -^ expected one of 13 possible tokens
    |                |
    |                help: missing `,`