about summary refs log tree commit diff
diff options
context:
space:
mode:
-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/messages.ftl2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs139
-rw-r--r--compiler/rustc_ast_passes/messages.ftl5
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs198
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs17
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs20
-rw-r--r--compiler/rustc_feature/src/unstable.rs4
-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/diagnostics.rs7
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs6
-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/mod.rs39
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs41
-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/librustdoc/clean/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs5
-rw-r--r--src/tools/rustfmt/src/spanned.rs1
-rw-r--r--src/tools/rustfmt/src/types.rs15
-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/call_method_ambiguous.next.stderr2
-rw-r--r--tests/ui/impl-trait/call_method_ambiguous.rs3
-rw-r--r--tests/ui/impl-trait/precise-capturing/apit.rs5
-rw-r--r--tests/ui/impl-trait/precise-capturing/apit.stderr19
-rw-r--r--tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs7
-rw-r--r--tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr39
-rw-r--r--tests/ui/impl-trait/precise-capturing/bad-params.rs9
-rw-r--r--tests/ui/impl-trait/precise-capturing/bad-params.stderr37
-rw-r--r--tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs9
-rw-r--r--tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr23
-rw-r--r--tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr8
-rw-r--r--tests/ui/impl-trait/precise-capturing/duplicated-use.rs10
-rw-r--r--tests/ui/impl-trait/precise-capturing/dyn-use.rs4
-rw-r--r--tests/ui/impl-trait/precise-capturing/dyn-use.stderr8
-rw-r--r--tests/ui/impl-trait/precise-capturing/elided.rs3
-rw-r--r--tests/ui/impl-trait/precise-capturing/elided.stderr11
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs3
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr17
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs5
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr27
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs5
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr23
-rw-r--r--tests/ui/impl-trait/precise-capturing/higher-ranked.rs3
-rw-r--r--tests/ui/impl-trait/precise-capturing/higher-ranked.stderr11
-rw-r--r--tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr57
-rw-r--r--tests/ui/impl-trait/precise-capturing/illegal-positions.rs27
-rw-r--r--tests/ui/impl-trait/precise-capturing/ordering.rs9
-rw-r--r--tests/ui/impl-trait/precise-capturing/ordering.stderr39
-rw-r--r--tests/ui/impl-trait/precise-capturing/outlives.rs3
-rw-r--r--tests/ui/impl-trait/precise-capturing/outlives.stderr11
-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.rs9
-rw-r--r--tests/ui/impl-trait/precise-capturing/redundant.stderr51
-rw-r--r--tests/ui/impl-trait/precise-capturing/self-capture.rs3
-rw-r--r--tests/ui/impl-trait/precise-capturing/self-capture.stderr11
-rw-r--r--tests/ui/impl-trait/precise-capturing/unexpected-token.rs3
-rw-r--r--tests/ui/impl-trait/precise-capturing/unexpected-token.stderr16
-rw-r--r--tests/ui/issues/issue-66706.rs4
-rw-r--r--tests/ui/issues/issue-66706.stderr8
-rw-r--r--tests/ui/parser/trait-object-delimiters.rs2
-rw-r--r--tests/ui/parser/trait-object-delimiters.stderr4
76 files changed, 628 insertions, 574 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/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 10efe6fba65..7d81e45d314 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -128,7 +128,7 @@ ast_lowering_never_pattern_with_guard =
     a guard on a never pattern will never be run
     .suggestion = remove this guard
 
-ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
+ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait`
 
 ast_lowering_previously_used_here = previously used here
 
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 88f6e6c3b78..f18ceb62e0b 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,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 }
                                 None
                             }
+                            // Ignore `use` syntax since that is not valid in objects.
+                            GenericBound::Use(_, span) => {
+                                this.dcx()
+                                    .span_delayed_bug(*span, "use<> not allowed in dyn types");
+                                None
+                            }
                         }));
                     let lifetime_bound =
                         lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
@@ -1391,7 +1397,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 +1407,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 +1526,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 +1534,64 @@ 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) =
+            // We only look for one `use<...>` syntax since we syntactially reject more than one.
+            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 +1601,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 +1613,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 +1699,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 +1745,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 origin,
                 lifetime_mapping,
                 in_trait,
-                precise_capturing_args,
             };
 
             // Generate an `type Foo = impl Trait;` declaration.
@@ -1955,7 +1955,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 +2037,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..2626631d800 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -215,6 +215,11 @@ ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer t
 ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations
     .label = pattern not allowed in foreign function
 
+ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing syntax
+    .label = second `use<...>` here
+
+ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}
+
 ast_passes_show_span = {$msg}
 
 ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 0fbb288cc96..93abe36a2db 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -193,8 +193,24 @@ impl<'a> AstValidator<'a> {
     // Mirrors `visit::walk_ty`, but tracks relevant state.
     fn walk_ty(&mut self, t: &'a Ty) {
         match &t.kind {
-            TyKind::ImplTrait(..) => {
-                self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
+            TyKind::ImplTrait(_, bounds) => {
+                self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t));
+
+                // FIXME(precise_capturing): If we were to allow `use` in other positions
+                // (e.g. GATs), then we must validate those as well. However, we don't have
+                // a good way of doing this with the current `Visitor` structure.
+                let mut use_bounds = bounds
+                    .iter()
+                    .filter_map(|bound| match bound {
+                        GenericBound::Use(_, span) => Some(span),
+                        _ => None,
+                    })
+                    .copied();
+                if let Some(bound1) = use_bounds.next()
+                    && let Some(bound2) = use_bounds.next()
+                {
+                    self.dcx().emit_err(errors::DuplicatePreciseCapturing { bound1, bound2 });
+                }
             }
             TyKind::TraitObject(..) => self
                 .with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| {
@@ -751,7 +767,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 +1320,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                                     }
                                 }
                                 GenericBound::Outlives(_) => {}
+                                GenericBound::Use(..) => {}
                             }
                         }
                     }
@@ -1322,95 +1339,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,
+            }
+            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,
                     });
                 }
-                None => {}
-            }
+            },
         }
 
         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..601910ded20 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -844,3 +844,20 @@ 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,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_precise_capturing_duplicated)]
+pub struct DuplicatePreciseCapturing {
+    #[primary_span]
+    pub bound1: Span,
+    #[label]
+    pub bound2: Span,
+}
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..066a5a8f046 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -567,8 +567,8 @@ 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.
-    (incomplete, precise_capturing, "1.79.0", Some(123432)),
+    /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.
+    (unstable, 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)),
     /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
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/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 2bb6fb53869..0c326c8eca2 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1,7 +1,6 @@
 use super::pat::Expected;
 use super::{
-    BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep,
-    TokenExpectType, TokenType,
+    BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType,
 };
 use crate::errors::{
     AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, BadTypePlus,
@@ -1045,9 +1044,7 @@ impl<'a> Parser<'a> {
     /// passes through any errors encountered. Used for error recovery.
     pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) {
         if let Err(err) =
-            self.parse_seq_to_before_tokens(kets, SeqSep::none(), TokenExpectType::Expect, |p| {
-                Ok(p.parse_token_tree())
-            })
+            self.parse_seq_to_before_tokens(kets, &[], SeqSep::none(), |p| Ok(p.parse_token_tree()))
         {
             err.cancel();
         }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index e15d6ab2123..8916c5de63d 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -4,7 +4,7 @@ use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{
     AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
-    SemiColonMode, SeqSep, TokenExpectType, TokenType, Trailing, TrailingToken,
+    SemiColonMode, SeqSep, TokenType, Trailing, TrailingToken,
 };
 
 use crate::errors;
@@ -2456,9 +2456,9 @@ impl<'a> Parser<'a> {
             self.expect(&token::BinOp(token::Or))?;
             let args = self
                 .parse_seq_to_before_tokens(
-                    &[&token::BinOp(token::Or), &token::OrOr],
+                    &[&token::BinOp(token::Or)],
+                    &[&token::OrOr],
                     SeqSep::trailing_allowed(token::Comma),
-                    TokenExpectType::NoExpect,
                     |p| p.parse_fn_block_param(),
                 )?
                 .0;
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/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index adf04fcf224..604959b1cda 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -335,18 +335,6 @@ impl TokenType {
     }
 }
 
-/// Used by [`Parser::expect_any_with_type`].
-#[derive(Copy, Clone, Debug)]
-enum TokenExpectType {
-    /// Unencountered tokens are inserted into [`Parser::expected_tokens`].
-    /// See [`Parser::check`].
-    Expect,
-
-    /// Unencountered tokens are not inserted into [`Parser::expected_tokens`].
-    /// See [`Parser::check_noexpect`].
-    NoExpect,
-}
-
 /// A sequence separator.
 #[derive(Debug)]
 struct SeqSep {
@@ -807,11 +795,13 @@ impl<'a> Parser<'a> {
     }
 
     /// Checks if the next token is contained within `kets`, and returns `true` if so.
-    fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool {
-        kets.iter().any(|k| match expect {
-            TokenExpectType::Expect => self.check(k),
-            TokenExpectType::NoExpect => self.check_noexpect(k),
-        })
+    fn expect_any_with_type(
+        &mut self,
+        kets_expected: &[&TokenKind],
+        kets_not_expected: &[&TokenKind],
+    ) -> bool {
+        kets_expected.iter().any(|k| self.check(k))
+            || kets_not_expected.iter().any(|k| self.check_noexpect(k))
     }
 
     /// Parses a sequence until the specified delimiters. The function
@@ -819,9 +809,9 @@ impl<'a> Parser<'a> {
     /// closing bracket.
     fn parse_seq_to_before_tokens<T>(
         &mut self,
-        kets: &[&TokenKind],
+        kets_expected: &[&TokenKind],
+        kets_not_expected: &[&TokenKind],
         sep: SeqSep,
-        expect: TokenExpectType,
         mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     ) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> {
         let mut first = true;
@@ -829,7 +819,7 @@ impl<'a> Parser<'a> {
         let mut trailing = Trailing::No;
         let mut v = ThinVec::new();
 
-        while !self.expect_any_with_type(kets, expect) {
+        while !self.expect_any_with_type(kets_expected, kets_not_expected) {
             if let token::CloseDelim(..) | token::Eof = self.token.kind {
                 break;
             }
@@ -927,7 +917,8 @@ impl<'a> Parser<'a> {
                                     if self.token == token::Colon {
                                         // we will try to recover in `maybe_recover_struct_lit_bad_delims`
                                         return Err(expect_err);
-                                    } else if let [token::CloseDelim(Delimiter::Parenthesis)] = kets
+                                    } else if let [token::CloseDelim(Delimiter::Parenthesis)] =
+                                        kets_expected
                                     {
                                         return Err(expect_err);
                                     } else {
@@ -940,7 +931,9 @@ impl<'a> Parser<'a> {
                     }
                 }
             }
-            if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) {
+            if sep.trailing_sep_allowed
+                && self.expect_any_with_type(kets_expected, kets_not_expected)
+            {
                 trailing = Trailing::Yes;
                 break;
             }
@@ -1020,7 +1013,7 @@ impl<'a> Parser<'a> {
         sep: SeqSep,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     ) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> {
-        self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
+        self.parse_seq_to_before_tokens(&[ket], &[], sep, f)
     }
 
     /// Parses a sequence, including only the closing delimiter. The function
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 5bed0317e5e..fcd623b477f 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -9,7 +9,7 @@ use crate::errors::{
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Token, TokenKind};
+use rustc_ast::token::{self, BinOpToken, Delimiter, Token, TokenKind};
 use rustc_ast::util::case::Case;
 use rustc_ast::{
     self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound,
@@ -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,33 +670,26 @@ 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(
         &mut self,
     ) -> PResult<'a, (ThinVec<PreciseCapturingArg>, Span)> {
         let lo = self.token.span;
-        let (args, _) = self.parse_unspanned_seq(
-            &TokenKind::Lt,
-            &TokenKind::Gt,
+        self.expect_lt()?;
+        let (args, _, _) = self.parse_seq_to_before_tokens(
+            &[&TokenKind::Gt],
+            &[
+                &TokenKind::Ge,
+                &TokenKind::BinOp(BinOpToken::Shr),
+                &TokenKind::BinOpEq(BinOpToken::Shr),
+            ],
             SeqSep::trailing_allowed(token::Comma),
             |self_| {
                 if self_.check_keyword(kw::SelfUpper) {
@@ -717,6 +710,7 @@ impl<'a> Parser<'a> {
                 }
             },
         )?;
+        self.expect_gt()?;
         Ok((args, lo.to(self.prev_token.span)))
     }
 
@@ -828,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:
@@ -844,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)?
         };
@@ -1003,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/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 2dcbbf0d150..da41f974068 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -228,6 +228,8 @@ fn clean_generic_bound<'tcx>(
 
             GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier)
         }
+        // FIXME(precise_capturing): Implement rustdoc support
+        hir::GenericBound::Use(..) => return None,
     })
 }
 
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/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index c70f5c2df84..fb43f7d80af 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -724,11 +724,8 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
         (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
         (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
         (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound),
-        (ImplTrait(_, lg, lc), ImplTrait(_, rg, rc)) => {
+        (ImplTrait(_, lg), ImplTrait(_, rg)) => {
             over(lg, rg, eq_generic_bound)
-                && both(lc, rc, |lc, rc| {
-                    over(lc.0.as_slice(), rc.0.as_slice(), eq_precise_capture)
-                })
         },
         (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs
index 4aaf7fdb27f..28911f8af1d 100644
--- a/src/tools/rustfmt/src/spanned.rs
+++ b/src/tools/rustfmt/src/spanned.rs
@@ -181,6 +181,7 @@ impl Spanned for ast::GenericBound {
         match *self {
             ast::GenericBound::Trait(ref ptr, _) => ptr.span,
             ast::GenericBound::Outlives(ref l) => l.ident.span,
+            ast::GenericBound::Use(_, span) => span,
         }
     }
 }
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 7d14d9e727a..c2c192738c9 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -563,6 +563,8 @@ impl Rewrite for ast::GenericBound {
                     .map(|s| if has_paren { format!("({})", s) } else { s })
             }
             ast::GenericBound::Outlives(ref lifetime) => lifetime.rewrite(context, shape),
+            // FIXME(precise_capturing): Should implement formatting before stabilization.
+            ast::GenericBound::Use(..) => None,
         }
     }
 }
@@ -843,11 +845,7 @@ impl Rewrite for ast::Ty {
                 rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
             }
             ast::TyKind::ImplicitSelf => Some(String::from("")),
-            ast::TyKind::ImplTrait(_, ref it, ref captures) => {
-                // FIXME(precise_capturing): Implement formatting.
-                if captures.is_some() {
-                    return None;
-                }
+            ast::TyKind::ImplTrait(_, ref it) => {
                 // Empty trait is not a parser error.
                 if it.is_empty() {
                     return Some("impl".to_owned());
@@ -932,6 +930,8 @@ fn is_generic_bounds_in_order(generic_bounds: &[ast::GenericBound]) -> bool {
     let is_trait = |b: &ast::GenericBound| match b {
         ast::GenericBound::Outlives(..) => false,
         ast::GenericBound::Trait(..) => true,
+        // FIXME(precise_capturing): This ordering fn should be reworked.
+        ast::GenericBound::Use(..) => false,
     };
     let is_lifetime = |b: &ast::GenericBound| !is_trait(b);
     let last_trait_index = generic_bounds.iter().rposition(is_trait);
@@ -966,6 +966,8 @@ fn join_bounds_inner(
     let is_bound_extendable = |s: &str, b: &ast::GenericBound| match b {
         ast::GenericBound::Outlives(..) => true,
         ast::GenericBound::Trait(..) => last_line_extendable(s),
+        // FIXME(precise_capturing): This ordering fn should be reworked.
+        ast::GenericBound::Use(..) => true,
     };
 
     // Whether a GenericBound item is a PathSegment segment that includes internal array
@@ -1110,8 +1112,7 @@ fn join_bounds_inner(
 
 pub(crate) fn opaque_ty(ty: &Option<ptr::P<ast::Ty>>) -> Option<&ast::GenericBounds> {
     ty.as_ref().and_then(|t| match &t.kind {
-        // FIXME(precise_capturing): Implement support here
-        ast::TyKind::ImplTrait(_, bounds, _) => Some(bounds),
+        ast::TyKind::ImplTrait(_, bounds) => Some(bounds),
         _ => None,
     })
 }
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/call_method_ambiguous.next.stderr b/tests/ui/impl-trait/call_method_ambiguous.next.stderr
index cd222aa7ae9..a1f9a8b40a8 100644
--- a/tests/ui/impl-trait/call_method_ambiguous.next.stderr
+++ b/tests/ui/impl-trait/call_method_ambiguous.next.stderr
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/call_method_ambiguous.rs:29:13
+  --> $DIR/call_method_ambiguous.rs:28:13
    |
 LL |         let mut iter = foo(n - 1, m);
    |             ^^^^^^^^
diff --git a/tests/ui/impl-trait/call_method_ambiguous.rs b/tests/ui/impl-trait/call_method_ambiguous.rs
index c26c01e002d..4dac605d6b8 100644
--- a/tests/ui/impl-trait/call_method_ambiguous.rs
+++ b/tests/ui/impl-trait/call_method_ambiguous.rs
@@ -3,7 +3,6 @@
 //@[current] run-pass
 
 #![feature(precise_capturing)]
-#![allow(incomplete_features)]
 
 trait Get {
     fn get(&mut self) -> u32;
@@ -24,7 +23,7 @@ where
     }
 }
 
-fn foo(n: usize, m: &mut ()) -> impl use<'_> Get {
+fn foo(n: usize, m: &mut ()) -> impl Get + use<'_> {
     if n > 0 {
         let mut iter = foo(n - 1, m);
         //[next]~^ type annotations needed
diff --git a/tests/ui/impl-trait/precise-capturing/apit.rs b/tests/ui/impl-trait/precise-capturing/apit.rs
index efcac9ebb0b..64c15d6df96 100644
--- a/tests/ui/impl-trait/precise-capturing/apit.rs
+++ b/tests/ui/impl-trait/precise-capturing/apit.rs
@@ -1,7 +1,6 @@
 #![feature(precise_capturing)]
-//~^ WARN the feature `precise_capturing` is incomplete
 
-fn hello(_: impl use<> Sized) {}
-//~^ ERROR `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
+fn hello(_: impl Sized + use<>) {}
+//~^ ERROR `use<...>` precise capturing syntax not allowed in 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..1d6225a1ff8 100644
--- a/tests/ui/impl-trait/precise-capturing/apit.stderr
+++ b/tests/ui/impl-trait/precise-capturing/apit.stderr
@@ -1,17 +1,8 @@
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/apit.rs:1:12
+error: `use<...>` precise capturing syntax not allowed in argument-position `impl Trait`
+  --> $DIR/apit.rs:3:26
    |
-LL | #![feature(precise_capturing)]
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error: `use<...>` precise capturing syntax not allowed on argument-position `impl Trait`
-  --> $DIR/apit.rs:4:18
-   |
-LL | fn hello(_: impl use<> Sized) {}
-   |                  ^^^^^
+LL | fn hello(_: impl Sized + use<>) {}
+   |                          ^^^^^
 
-error: aborting due to 1 previous error; 1 warning emitted
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs
index 623063a8f50..d2d4570c570 100644
--- a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs
+++ b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs
@@ -1,14 +1,13 @@
 #![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..550996ab5e5 100644
--- a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr
+++ b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr
@@ -1,45 +1,36 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/bad-lifetimes.rs:4:31
+  --> $DIR/bad-lifetimes.rs:3: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:10: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>`
 
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/bad-lifetimes.rs:1:12
-   |
-LL | #![feature(precise_capturing)]
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = 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:3: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:7: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
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0106, E0261.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.rs b/tests/ui/impl-trait/precise-capturing/bad-params.rs
index 7970d49bf7c..08eee67c0e5 100644
--- a/tests/ui/impl-trait/precise-capturing/bad-params.rs
+++ b/tests/ui/impl-trait/precise-capturing/bad-params.rs
@@ -1,19 +1,18 @@
 #![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..e104f115aa3 100644
--- a/tests/ui/impl-trait/precise-capturing/bad-params.stderr
+++ b/tests/ui/impl-trait/precise-capturing/bad-params.stderr
@@ -1,46 +1,37 @@
 error[E0412]: cannot find type `T` in this scope
-  --> $DIR/bad-params.rs:4:26
+  --> $DIR/bad-params.rs:3: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:6: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
 
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/bad-params.rs:1:12
-   |
-LL | #![feature(precise_capturing)]
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = 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:11: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:15: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
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0411, E0412.
 For more information about an error, try `rustc --explain E0411`.
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..82b953bfed4 100644
--- a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs
+++ b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs
@@ -1,5 +1,4 @@
 #![feature(precise_capturing)]
-//~^ WARN the feature `precise_capturing` is incomplete
 
 trait Tr {
     type Assoc;
@@ -13,25 +12,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..b521ee0a902 100644
--- a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr
+++ b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr
@@ -1,27 +1,18 @@
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/capture-parent-arg.rs:1:12
-   |
-LL | #![feature(precise_capturing)]
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = 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:27: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
+  --> $DIR/capture-parent-arg.rs:33: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
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr b/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr
new file mode 100644
index 00000000000..d8edd672b48
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr
@@ -0,0 +1,8 @@
+error: duplicate `use<...>` precise capturing syntax
+  --> $DIR/duplicated-use.rs:7:32
+   |
+LL | fn hello<'a>() -> impl Sized + use<'a> + use<'a> {}
+   |                                ^^^^^^^   ------- second `use<...>` here
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/impl-trait/precise-capturing/duplicated-use.rs b/tests/ui/impl-trait/precise-capturing/duplicated-use.rs
new file mode 100644
index 00000000000..bfbdcdbf311
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/duplicated-use.rs
@@ -0,0 +1,10 @@
+//@ revisions: real pre_expansion
+//@[pre_expansion] check-pass
+
+#![feature(precise_capturing)]
+
+#[cfg(real)]
+fn hello<'a>() -> impl Sized + use<'a> + use<'a> {}
+//[real]~^ ERROR duplicate `use<...>` precise capturing syntax
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/dyn-use.rs b/tests/ui/impl-trait/precise-capturing/dyn-use.rs
new file mode 100644
index 00000000000..ce7a0f3c7b2
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/dyn-use.rs
@@ -0,0 +1,4 @@
+#![feature(precise_capturing)]
+
+fn dyn() -> &'static dyn use<> { &() }
+//~^ ERROR expected one of `!`, `(`, `::`, `<`, `where`, or `{`, found keyword `use`
diff --git a/tests/ui/impl-trait/precise-capturing/dyn-use.stderr b/tests/ui/impl-trait/precise-capturing/dyn-use.stderr
new file mode 100644
index 00000000000..5519633de1f
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/dyn-use.stderr
@@ -0,0 +1,8 @@
+error: expected one of `!`, `(`, `::`, `<`, `where`, or `{`, found keyword `use`
+  --> $DIR/dyn-use.rs:3:26
+   |
+LL | fn dyn() -> &'static dyn use<> { &() }
+   |                          ^^^ expected one of `!`, `(`, `::`, `<`, `where`, or `{`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/impl-trait/precise-capturing/elided.rs b/tests/ui/impl-trait/precise-capturing/elided.rs
index de80e8a5d58..34d1ba620dc 100644
--- a/tests/ui/impl-trait/precise-capturing/elided.rs
+++ b/tests/ui/impl-trait/precise-capturing/elided.rs
@@ -1,8 +1,7 @@
 //@ check-pass
 
 #![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/elided.stderr b/tests/ui/impl-trait/precise-capturing/elided.stderr
deleted file mode 100644
index 38da0828de9..00000000000
--- a/tests/ui/impl-trait/precise-capturing/elided.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/elided.rs:3:12
-   |
-LL | #![feature(precise_capturing)]
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-warning: 1 warning emitted
-
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..26d29e456ea 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,6 @@
 #![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..989ed136d4c 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
@@ -1,21 +1,12 @@
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/forgot-to-capture-const.rs:1:12
-   |
-LL | #![feature(precise_capturing)]
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
 error: `impl Trait` must mention all const parameters in scope in `use<...>`
-  --> $DIR/forgot-to-capture-const.rs:4:34
+  --> $DIR/forgot-to-capture-const.rs:3: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`
    |
    = note: currently, all const parameters are required to be mentioned in the precise captures list
 
-error: aborting due to 1 previous error; 1 warning emitted
+error: aborting due to 1 previous error
 
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..f18dbca6c5e 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,9 @@
 #![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..6544837ba83 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
@@ -1,35 +1,26 @@
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/forgot-to-capture-lifetime.rs:1:12
-   |
-LL | #![feature(precise_capturing)]
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = 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:3: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:6: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
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0700`.
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..08014985783 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,10 @@
 #![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..93b44a0c18c 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
@@ -1,31 +1,22 @@
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/forgot-to-capture-type.rs:1:12
-   |
-LL | #![feature(precise_capturing)]
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
 error: `impl Trait` must mention all type parameters in scope in `use<...>`
-  --> $DIR/forgot-to-capture-type.rs:4:23
+  --> $DIR/forgot-to-capture-type.rs:3: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`
    |
    = note: currently, all type parameters are required to be mentioned in the precise captures list
 
 error: `impl Trait` must mention the `Self` type of the trait in `use<...>`
-  --> $DIR/forgot-to-capture-type.rs:8:17
+  --> $DIR/forgot-to-capture-type.rs:7:17
    |
 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
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/impl-trait/precise-capturing/higher-ranked.rs b/tests/ui/impl-trait/precise-capturing/higher-ranked.rs
index 28fb1fa4b9e..21ac19640bc 100644
--- a/tests/ui/impl-trait/precise-capturing/higher-ranked.rs
+++ b/tests/ui/impl-trait/precise-capturing/higher-ranked.rs
@@ -3,7 +3,6 @@
 // Show how precise captures allow us to skip capturing a higher-ranked lifetime
 
 #![feature(lifetime_capture_rules_2024, precise_capturing)]
-//~^ WARN the feature `precise_capturing` is incomplete
 
 trait Trait<'a> {
     type Item;
@@ -13,6 +12,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/higher-ranked.stderr b/tests/ui/impl-trait/precise-capturing/higher-ranked.stderr
deleted file mode 100644
index e48d6d42af0..00000000000
--- a/tests/ui/impl-trait/precise-capturing/higher-ranked.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/higher-ranked.rs:5:41
-   |
-LL | #![feature(lifetime_capture_rules_2024, precise_capturing)]
-   |                                         ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr b/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr
new file mode 100644
index 00000000000..2b234bcb6a5
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr
@@ -0,0 +1,57 @@
+error: `use<...>` precise capturing syntax not allowed in supertrait bounds
+  --> $DIR/illegal-positions.rs:8:12
+   |
+LL | trait Foo: use<> {
+   |            ^^^^^
+
+error: `use<...>` precise capturing syntax not allowed in bounds
+  --> $DIR/illegal-positions.rs:10:33
+   |
+LL |     type Assoc: use<> where (): use<>;
+   |                                 ^^^^^
+
+error: `use<...>` precise capturing syntax not allowed in bounds
+  --> $DIR/illegal-positions.rs:10:17
+   |
+LL |     type Assoc: use<> where (): use<>;
+   |                 ^^^^^
+
+error: `use<...>` precise capturing syntax not allowed in bounds
+  --> $DIR/illegal-positions.rs:16:11
+   |
+LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {}
+   |           ^^^^^
+
+error: `use<...>` precise capturing syntax not allowed in bounds
+  --> $DIR/illegal-positions.rs:16:43
+   |
+LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {}
+   |                                           ^^^^^
+
+error: at least one trait must be specified
+  --> $DIR/illegal-positions.rs:16:21
+   |
+LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {}
+   |                     ^^^^^^^^^^
+
+error: `use<...>` precise capturing syntax not allowed in `dyn` trait object bounds
+  --> $DIR/illegal-positions.rs:23:25
+   |
+LL | fn dynamic() -> Box<dyn use<>> {}
+   |                         ^^^^^
+
+error: `use<...>` precise capturing syntax not allowed in argument-position `impl Trait`
+  --> $DIR/illegal-positions.rs:16:26
+   |
+LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {}
+   |                          ^^^^^
+
+error[E0224]: at least one trait is required for an object type
+  --> $DIR/illegal-positions.rs:23:21
+   |
+LL | fn dynamic() -> Box<dyn use<>> {}
+   |                     ^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0224`.
diff --git a/tests/ui/impl-trait/precise-capturing/illegal-positions.rs b/tests/ui/impl-trait/precise-capturing/illegal-positions.rs
new file mode 100644
index 00000000000..681458e25f8
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/illegal-positions.rs
@@ -0,0 +1,27 @@
+//@ revisions: real pre_expansion
+//@[pre_expansion] check-pass
+//@ edition: 2021
+
+#![feature(precise_capturing)]
+
+#[cfg(real)]
+trait Foo: use<> {
+    //[real]~^ ERROR `use<...>` precise capturing syntax not allowed
+    type Assoc: use<> where (): use<>;
+    //[real]~^ ERROR `use<...>` precise capturing syntax not allowed
+    //[real]~| ERROR `use<...>` precise capturing syntax not allowed
+}
+
+#[cfg(real)]
+fn fun<T: use<>>(_: impl use<>) where (): use<> {}
+//[real]~^ ERROR `use<...>` precise capturing syntax not allowed
+//[real]~| ERROR `use<...>` precise capturing syntax not allowed
+//[real]~| ERROR `use<...>` precise capturing syntax not allowed
+//[real]~| ERROR at least one trait must be specified
+
+#[cfg(real)]
+fn dynamic() -> Box<dyn use<>> {}
+//[real]~^ ERROR `use<...>` precise capturing syntax not allowed in `dyn` trait object bounds
+//[real]~| ERROR at least one trait is required for an object type [E0224]
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/ordering.rs b/tests/ui/impl-trait/precise-capturing/ordering.rs
index 2bace798c57..eb570a120cc 100644
--- a/tests/ui/impl-trait/precise-capturing/ordering.rs
+++ b/tests/ui/impl-trait/precise-capturing/ordering.rs
@@ -1,16 +1,15 @@
 #![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..ecd47159059 100644
--- a/tests/ui/impl-trait/precise-capturing/ordering.stderr
+++ b/tests/ui/impl-trait/precise-capturing/ordering.stderr
@@ -1,37 +1,28 @@
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/ordering.rs:1:12
-   |
-LL | #![feature(precise_capturing)]
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
 error: cannot capture parameter `'a` twice
-  --> $DIR/ordering.rs:4:25
+  --> $DIR/ordering.rs:3: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:6: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:9: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:12: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
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/impl-trait/precise-capturing/outlives.rs b/tests/ui/impl-trait/precise-capturing/outlives.rs
index 71e6333934e..26ac922b5b9 100644
--- a/tests/ui/impl-trait/precise-capturing/outlives.rs
+++ b/tests/ui/impl-trait/precise-capturing/outlives.rs
@@ -3,9 +3,8 @@
 // Show that precise captures allow us to skip a lifetime param for outlives
 
 #![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/outlives.stderr b/tests/ui/impl-trait/precise-capturing/outlives.stderr
deleted file mode 100644
index 405c09cccd9..00000000000
--- a/tests/ui/impl-trait/precise-capturing/outlives.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/outlives.rs:5:41
-   |
-LL | #![feature(lifetime_capture_rules_2024, precise_capturing)]
-   |                                         ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-warning: 1 warning emitted
-
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..99c128fdc48 100644
--- a/tests/ui/impl-trait/precise-capturing/redundant.rs
+++ b/tests/ui/impl-trait/precise-capturing/redundant.rs
@@ -2,23 +2,22 @@
 //@ check-pass
 
 #![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..274d9d2375f 100644
--- a/tests/ui/impl-trait/precise-capturing/redundant.stderr
+++ b/tests/ui/impl-trait/precise-capturing/redundant.stderr
@@ -1,45 +1,36 @@
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/redundant.rs:4:12
-   |
-LL | #![feature(precise_capturing)]
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
 warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
-  --> $DIR/redundant.rs:7:19
+  --> $DIR/redundant.rs:6: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
+  --> $DIR/redundant.rs:11: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
+  --> $DIR/redundant.rs:16: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
+  --> $DIR/redundant.rs:20: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
+warning: 4 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..e0a4a8b658c 100644
--- a/tests/ui/impl-trait/precise-capturing/self-capture.rs
+++ b/tests/ui/impl-trait/precise-capturing/self-capture.rs
@@ -1,10 +1,9 @@
 //@ check-pass
 
 #![feature(precise_capturing)]
-//~^ 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/self-capture.stderr b/tests/ui/impl-trait/precise-capturing/self-capture.stderr
deleted file mode 100644
index 5a058c6826d..00000000000
--- a/tests/ui/impl-trait/precise-capturing/self-capture.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/self-capture.rs:3:12
-   |
-LL | #![feature(precise_capturing)]
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/impl-trait/precise-capturing/unexpected-token.rs b/tests/ui/impl-trait/precise-capturing/unexpected-token.rs
index 39c8c0def6b..a1089fd7bfc 100644
--- a/tests/ui/impl-trait/precise-capturing/unexpected-token.rs
+++ b/tests/ui/impl-trait/precise-capturing/unexpected-token.rs
@@ -2,8 +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 `{`
-//~| ERROR expected item, 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 989c479b248..51e4f0f6775 100644
--- a/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr
+++ b/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr
@@ -1,16 +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: expected item, found `>`
-  --> $DIR/unexpected-token.rs:5:29
-   |
-LL | fn hello() -> impl use<'a {}> Sized {}
-   |                             ^ expected item
-   |
-   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-66706.rs b/tests/ui/issues/issue-66706.rs
index 6d1d9f5e3a9..87dc3437a57 100644
--- a/tests/ui/issues/issue-66706.rs
+++ b/tests/ui/issues/issue-66706.rs
@@ -1,6 +1,6 @@
 fn a() {
     [0; [|_: _ &_| ()].len()]
-    //~^ ERROR expected `,`, found `&`
+    //~^ ERROR expected one of `,` or `|`, found `&`
     //~| ERROR type annotations needed
 }
 
@@ -11,7 +11,7 @@ fn b() {
 
 fn c() {
     [0; [|&_: _ &_| {}; 0 ].len()]
-    //~^ ERROR expected `,`, found `&`
+    //~^ ERROR expected one of `,` or `|`, found `&`
     //~| ERROR type annotations needed
 }
 
diff --git a/tests/ui/issues/issue-66706.stderr b/tests/ui/issues/issue-66706.stderr
index 0271db754bd..dd1e07589f5 100644
--- a/tests/ui/issues/issue-66706.stderr
+++ b/tests/ui/issues/issue-66706.stderr
@@ -1,8 +1,8 @@
-error: expected `,`, found `&`
+error: expected one of `,` or `|`, found `&`
   --> $DIR/issue-66706.rs:2:16
    |
 LL |     [0; [|_: _ &_| ()].len()]
-   |               -^ expected `,`
+   |               -^ expected one of `,` or `|`
    |               |
    |               help: missing `,`
 
@@ -12,11 +12,11 @@ error: expected identifier, found reserved identifier `_`
 LL |     [0; [|f @ &ref _| {} ; 0 ].len() ];
    |                    ^ expected identifier, found reserved identifier
 
-error: expected `,`, found `&`
+error: expected one of `,` or `|`, found `&`
   --> $DIR/issue-66706.rs:13:17
    |
 LL |     [0; [|&_: _ &_| {}; 0 ].len()]
-   |                -^ expected `,`
+   |                -^ expected one of `,` or `|`
    |                |
    |                help: missing `,`
 
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 `,`