about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-08-11 09:03:18 +0000
committerbors <bors@rust-lang.org>2025-08-11 09:03:18 +0000
commit577166503aee7290e09374da21f4045c455acfd5 (patch)
treed59f60d60e5a9e39f62f2f6d2ff8eac97d9d996d /compiler
parenta6620a45bd29575cce67b6a0ab2956aef105e324 (diff)
parent3ce0ee2555bb34c9dc51f0b4afc6a9dba61b26df (diff)
downloadrust-577166503aee7290e09374da21f4045c455acfd5.tar.gz
rust-577166503aee7290e09374da21f4045c455acfd5.zip
Auto merge of #145240 - Zalathar:rollup-7r97lia, r=Zalathar
Rollup of 5 pull requests

Successful merges:

 - rust-lang/rust#135331 (Reject relaxed bounds inside associated type bounds (ATB))
 - rust-lang/rust#144156 (Check coroutine upvars in dtorck constraint)
 - rust-lang/rust#145091 (`NllRegionVariableOrigin` remove `from_forall`)
 - rust-lang/rust#145194 (Ignore coroutine witness type region args in auto trait confirmation)
 - rust-lang/rust#145225 (Fix macro infinite recursion test to not trigger warning about semicolon in expr)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs12
-rw-r--r--compiler/rustc_borrowck/src/handle_placeholders.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs13
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs8
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs74
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs17
9 files changed, 91 insertions, 64 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 64c1b53f633..465d9dc82bc 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -296,6 +296,7 @@ enum RelaxedBoundPolicy<'a> {
 enum RelaxedBoundForbiddenReason {
     TraitObjectTy,
     SuperTrait,
+    AssocTyBounds,
     LateBoundVarsInScope,
 }
 
@@ -1109,9 +1110,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         &*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar)));
                     hir::AssocItemConstraintKind::Equality { term: err_ty.into() }
                 } else {
-                    // FIXME(#135229): These should be forbidden!
-                    let bounds =
-                        self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx);
+                    let bounds = self.lower_param_bounds(
+                        bounds,
+                        RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::AssocTyBounds),
+                        itctx,
+                    );
                     hir::AssocItemConstraintKind::Bound { bounds }
                 }
             }
@@ -2124,7 +2127,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         diag.emit();
                         return;
                     }
-                    RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
+                    RelaxedBoundForbiddenReason::AssocTyBounds
+                    | RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
                 };
             }
         }
diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs
index e168b819a8d..34599ac55b8 100644
--- a/compiler/rustc_borrowck/src/handle_placeholders.rs
+++ b/compiler/rustc_borrowck/src/handle_placeholders.rs
@@ -157,7 +157,7 @@ fn region_definitions<'tcx>(
     for info in var_infos.iter() {
         let origin = match info.origin {
             RegionVariableOrigin::Nll(origin) => origin,
-            _ => NllRegionVariableOrigin::Existential { from_forall: false, name: None },
+            _ => NllRegionVariableOrigin::Existential { name: None },
         };
 
         let definition = RegionDefinition { origin, universe: info.universe, external_name: None };
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index dbd245214a2..b0c31ac9601 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -1939,10 +1939,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         //
         // and here we prefer to blame the source (the y = x statement).
         let blame_source = match from_region_origin {
-            NllRegionVariableOrigin::FreeRegion
-            | NllRegionVariableOrigin::Existential { from_forall: false, name: _ } => true,
-            NllRegionVariableOrigin::Placeholder(_)
-            | NllRegionVariableOrigin::Existential { from_forall: true, name: _ } => false,
+            NllRegionVariableOrigin::FreeRegion => true,
+            NllRegionVariableOrigin::Placeholder(_) => false,
+            // `'existential: 'whatever` never results in a region error by itself.
+            // We may always infer it to `'static` afterall. This means while an error
+            // path may go through an existential, these existentials are never the
+            // `from_region`.
+            NllRegionVariableOrigin::Existential { name: _ } => {
+                unreachable!("existentials can outlive everything")
+            }
         };
 
         // To pick a constraint to blame, we organize constraints by how interesting we expect them
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 100d30704b9..fa3064afee8 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -66,7 +66,7 @@ impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> {
         T: TypeFoldable<TyCtxt<'tcx>>,
         F: Fn() -> RegionCtxt,
     {
-        let origin = NllRegionVariableOrigin::Existential { from_forall: false, name: None };
+        let origin = NllRegionVariableOrigin::Existential { name: None };
         fold_regions(self.infcx.tcx, value, |_region, _depth| {
             self.infcx.next_nll_region_var(origin, || region_ctxt_fn())
         })
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 393adafea0b..84ca9bad2c1 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -216,7 +216,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
                     *ex_reg_var
                 } else {
                     let ex_reg_var =
-                        self.next_existential_region_var(true, br.kind.get_name(infcx.infcx.tcx));
+                        self.next_existential_region_var(br.kind.get_name(infcx.infcx.tcx));
                     debug!(?ex_reg_var);
                     reg_map.insert(br, ex_reg_var);
 
@@ -244,17 +244,9 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    fn next_existential_region_var(
-        &mut self,
-        from_forall: bool,
-        name: Option<Symbol>,
-    ) -> ty::Region<'tcx> {
-        let origin = NllRegionVariableOrigin::Existential { name, from_forall };
-
-        let reg_var =
-            self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name));
-
-        reg_var
+    fn next_existential_region_var(&mut self, name: Option<Symbol>) -> ty::Region<'tcx> {
+        let origin = NllRegionVariableOrigin::Existential { name };
+        self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name))
     }
 
     #[instrument(skip(self), level = "debug")]
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 386e1091ac4..d14aef8ace4 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -199,12 +199,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             //        However, this can easily get out of sync! Ideally, we would perform this step
             //        where we are guaranteed to catch *all* bounds like in
             //        `Self::lower_poly_trait_ref`. List of concrete issues:
-            //        FIXME(more_maybe_bounds): We don't call this for e.g., trait object tys or
-            //                                  supertrait bounds!
+            //        FIXME(more_maybe_bounds): We don't call this for trait object tys, supertrait
+            //                                  bounds or associated type bounds (ATB)!
             //        FIXME(trait_alias, #143122): We don't call it for the RHS. Arguably however,
-            //                                       AST lowering should reject them outright.
-            //        FIXME(associated_type_bounds): We don't call this for them. However, AST
-            //                                       lowering should reject them outright (#135229).
+            //                                     AST lowering should reject them outright.
             let bounds = collect_relaxed_bounds(hir_bounds, self_ty_where_predicates);
             self.check_and_report_invalid_relaxed_bounds(bounds);
         }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index a2afdc45fa8..82d4856df39 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -485,17 +485,6 @@ pub enum NllRegionVariableOrigin {
 
     Existential {
         name: Option<Symbol>,
-        /// If this is true, then this variable was created to represent a lifetime
-        /// bound in a `for` binder. For example, it might have been created to
-        /// represent the lifetime `'a` in a type like `for<'a> fn(&'a u32)`.
-        /// Such variables are created when we are trying to figure out if there
-        /// is any valid instantiation of `'a` that could fit into some scenario.
-        ///
-        /// This is used to inform error reporting: in the case that we are trying to
-        /// determine whether there is any valid instantiation of a `'a` variable that meets
-        /// some constraint C, we want to blame the "source" of that `for` type,
-        /// rather than blaming the source of the constraint C.
-        from_forall: bool,
     },
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index b1b331d1b61..de404532899 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -319,39 +319,65 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
         }
 
         ty::Coroutine(def_id, args) => {
-            // rust-lang/rust#49918: types can be constructed, stored
-            // in the interior, and sit idle when coroutine yields
-            // (and is subsequently dropped).
+            // rust-lang/rust#49918: Locals can be stored across await points in the coroutine,
+            // called interior/witness types. Since we do not compute these witnesses until after
+            // building MIR, we consider all coroutines to unconditionally require a drop during
+            // MIR building. However, considering the coroutine to unconditionally require a drop
+            // here may unnecessarily require its upvars' regions to be live when they don't need
+            // to be, leading to borrowck errors: <https://github.com/rust-lang/rust/issues/116242>.
             //
-            // It would be nice to descend into interior of a
-            // coroutine to determine what effects dropping it might
-            // have (by looking at any drop effects associated with
-            // its interior).
+            // Here, we implement a more precise approximation for the coroutine's dtorck constraint
+            // by considering whether any of the interior types needs drop. Note that this is still
+            // an approximation because the coroutine interior has its regions erased, so we must add
+            // *all* of the upvars to live types set if we find that *any* interior type needs drop.
+            // This is because any of the regions captured in the upvars may be stored in the interior,
+            // which then has its regions replaced by a binder (conceptually erasing the regions),
+            // so there's no way to enforce that the precise region in the interior type is live
+            // since we've lost that information by this point.
             //
-            // However, the interior's representation uses things like
-            // CoroutineWitness that explicitly assume they are not
-            // traversed in such a manner. So instead, we will
-            // simplify things for now by treating all coroutines as
-            // if they were like trait objects, where its upvars must
-            // all be alive for the coroutine's (potential)
-            // destructor.
+            // Note also that this check requires that the coroutine's upvars are use-live, since
+            // a region from a type that does not have a destructor that was captured in an upvar
+            // may flow into an interior type with a destructor. This is stronger than requiring
+            // the upvars are drop-live.
             //
-            // In particular, skipping over `_interior` is safe
-            // because any side-effects from dropping `_interior` can
-            // only take place through references with lifetimes
-            // derived from lifetimes attached to the upvars and resume
-            // argument, and we *do* incorporate those here.
+            // For example, if we capture two upvar references `&'1 (), &'2 ()` and have some type
+            // in the interior, `for<'r> { NeedsDrop<'r> }`, we have no way to tell whether the
+            // region `'r` came from the `'1` or `'2` region, so we require both are live. This
+            // could even be unnecessary if `'r` was actually a `'static` region or some region
+            // local to the coroutine! That's why it's an approximation.
             let args = args.as_coroutine();
 
-            // While we conservatively assume that all coroutines require drop
-            // to avoid query cycles during MIR building, we can check the actual
-            // witness during borrowck to avoid unnecessary liveness constraints.
+            // Note that we don't care about whether the resume type has any drops since this is
+            // redundant; there is no storage for the resume type, so if it is actually stored
+            // in the interior, we'll already detect the need for a drop by checking the interior.
             let typing_env = tcx.erase_regions(typing_env);
-            if tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| {
+            let needs_drop = tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| {
                 witness.field_tys.iter().any(|field| field.ty.needs_drop(tcx, typing_env))
-            }) {
+            });
+            if needs_drop {
+                // Pushing types directly to `constraints.outlives` is equivalent
+                // to requiring them to be use-live, since if we were instead to
+                // recurse on them like we do below, we only end up collecting the
+                // types that are relevant for drop-liveness.
                 constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from));
                 constraints.outlives.push(args.resume_ty().into());
+            } else {
+                // Even if a witness type doesn't need a drop, we still require that
+                // the upvars are drop-live. This is only needed if we aren't already
+                // counting *all* of the upvars as use-live above, since use-liveness
+                // is a *stronger requirement* than drop-liveness. Recursing here
+                // unconditionally would just be collecting duplicated types for no
+                // reason.
+                for ty in args.upvar_tys() {
+                    dtorck_constraint_for_ty_inner(
+                        tcx,
+                        typing_env,
+                        span,
+                        depth + 1,
+                        ty,
+                        constraints,
+                    );
+                }
             }
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 7ea1548f8f2..468c42abf48 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2333,10 +2333,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
 
             ty::Coroutine(def_id, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
+                let tcx = self.tcx();
                 let witness = Ty::new_coroutine_witness(
-                    self.tcx(),
+                    tcx,
                     def_id,
-                    self.tcx().mk_args(args.as_coroutine().parent_args()),
+                    ty::GenericArgs::for_item(tcx, def_id, |def, _| match def.kind {
+                        // HACK: Coroutine witnesse types are lifetime erased, so they
+                        // never reference any lifetime args from the coroutine. We erase
+                        // the regions here since we may get into situations where a
+                        // coroutine is recursively contained within itself, leading to
+                        // witness types that differ by region args. This means that
+                        // cycle detection in fulfillment will not kick in, which leads
+                        // to unnecessary overflows in async code. See the issue:
+                        // <https://github.com/rust-lang/rust/issues/145151>.
+                        ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+                        ty::GenericParamDefKind::Type { .. }
+                        | ty::GenericParamDefKind::Const { .. } => args[def.index as usize],
+                    }),
                 );
                 ty::Binder::dummy(AutoImplConstituents {
                     types: [ty].into_iter().chain(iter::once(witness)).collect(),