diff options
| author | bors <bors@rust-lang.org> | 2025-08-11 09:03:18 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-08-11 09:03:18 +0000 |
| commit | 577166503aee7290e09374da21f4045c455acfd5 (patch) | |
| tree | d59f60d60e5a9e39f62f2f6d2ff8eac97d9d996d /compiler | |
| parent | a6620a45bd29575cce67b6a0ab2956aef105e324 (diff) | |
| parent | 3ce0ee2555bb34c9dc51f0b4afc6a9dba61b26df (diff) | |
| download | rust-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.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/handle_placeholders.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/region_infer/mod.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/renumber.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/type_check/relate_tys.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/mod.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs | 74 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/select/mod.rs | 17 |
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(), |
