Skip to content

Commit 8e819ff

Browse files
committed
Auto merge of #156027 - jackh726:opaque-liveness, r=<try>
Consider captured regions for opaque type region liveness.
2 parents 53509ca + ca97579 commit 8e819ff

20 files changed

Lines changed: 448 additions & 197 deletions

File tree

compiler/rustc_borrowck/src/type_check/liveness/trace.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
22
use rustc_index::bit_set::DenseBitSet;
33
use rustc_index::interval::IntervalSet;
44
use rustc_infer::infer::canonical::QueryRegionConstraints;
5-
use rustc_infer::infer::outlives::for_liveness;
65
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Local, Location};
76
use rustc_middle::traits::query::DropckOutlivesResult;
87
use rustc_middle::ty::relate::Relate;
@@ -14,6 +13,7 @@ use rustc_mir_dataflow::{Analysis, ResultsCursor};
1413
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
1514
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
1615
use rustc_trait_selection::traits::ObligationCtxt;
16+
use rustc_trait_selection::traits::outlives_for_liveness::FreeRegionsVisitor;
1717
use rustc_trait_selection::traits::query::dropck_outlives;
1818
use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOp, TypeOpOutput};
1919
use tracing::debug;
@@ -611,7 +611,7 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
611611
values::pretty_print_points(location_map, live_at.iter()),
612612
);
613613

614-
value.visit_with(&mut for_liveness::FreeRegionsVisitor {
614+
value.visit_with(&mut FreeRegionsVisitor {
615615
tcx: typeck.tcx(),
616616
param_env: typeck.infcx.param_env,
617617
op: |r| {

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 4 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use rustc_hir::def::{DefKind, Res};
1313
use rustc_hir::def_id::{DefId, LocalDefId};
1414
use rustc_hir::lang_items::LangItem;
1515
use rustc_hir::{AmbigArg, ItemKind, find_attr};
16+
use rustc_infer::infer::TyCtxtInferExt;
1617
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
17-
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin, TyCtxtInferExt};
1818
use rustc_infer::traits::PredicateObligations;
1919
use rustc_lint_defs::builtin::SHADOWING_SUPERTRAIT_ITEMS;
2020
use rustc_macros::Diagnostic;
@@ -30,7 +30,9 @@ use rustc_middle::{bug, span_bug};
3030
use rustc_session::errors::feature_err;
3131
use rustc_span::{DUMMY_SP, Span, sym};
3232
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
33-
use rustc_trait_selection::regions::{InferCtxtRegionExt, OutlivesEnvironmentBuildExt};
33+
use rustc_trait_selection::regions::{
34+
InferCtxtRegionExt, OutlivesEnvironmentBuildExt, region_known_to_outlive, ty_known_to_outlive,
35+
};
3436
use rustc_trait_selection::traits::misc::{
3537
ConstParamTyImplementationError, type_allowed_to_implement_const_param_ty,
3638
};
@@ -695,70 +697,6 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
695697
Some(bounds)
696698
}
697699

698-
/// Given a known `param_env` and a set of well formed types, can we prove that
699-
/// `ty` outlives `region`.
700-
fn ty_known_to_outlive<'tcx>(
701-
tcx: TyCtxt<'tcx>,
702-
id: LocalDefId,
703-
param_env: ty::ParamEnv<'tcx>,
704-
wf_tys: &FxIndexSet<Ty<'tcx>>,
705-
ty: Ty<'tcx>,
706-
region: ty::Region<'tcx>,
707-
) -> bool {
708-
test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
709-
infcx.register_type_outlives_constraint_inner(infer::TypeOutlivesConstraint {
710-
sub_region: region,
711-
sup_type: ty,
712-
origin: SubregionOrigin::RelateParamBound(DUMMY_SP, ty, None),
713-
});
714-
})
715-
}
716-
717-
/// Given a known `param_env` and a set of well formed types, can we prove that
718-
/// `region_a` outlives `region_b`
719-
fn region_known_to_outlive<'tcx>(
720-
tcx: TyCtxt<'tcx>,
721-
id: LocalDefId,
722-
param_env: ty::ParamEnv<'tcx>,
723-
wf_tys: &FxIndexSet<Ty<'tcx>>,
724-
region_a: ty::Region<'tcx>,
725-
region_b: ty::Region<'tcx>,
726-
) -> bool {
727-
test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
728-
infcx.sub_regions(
729-
SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None),
730-
region_b,
731-
region_a,
732-
ty::VisibleForLeakCheck::Unreachable,
733-
);
734-
})
735-
}
736-
737-
/// Given a known `param_env` and a set of well formed types, set up an
738-
/// `InferCtxt`, call the passed function (to e.g. set up region constraints
739-
/// to be tested), then resolve region and return errors
740-
fn test_region_obligations<'tcx>(
741-
tcx: TyCtxt<'tcx>,
742-
id: LocalDefId,
743-
param_env: ty::ParamEnv<'tcx>,
744-
wf_tys: &FxIndexSet<Ty<'tcx>>,
745-
add_constraints: impl FnOnce(&InferCtxt<'tcx>),
746-
) -> bool {
747-
// Unfortunately, we have to use a new `InferCtxt` each call, because
748-
// region constraints get added and solved there and we need to test each
749-
// call individually.
750-
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
751-
752-
add_constraints(&infcx);
753-
754-
let errors = infcx.resolve_regions(id, param_env, wf_tys.iter().copied());
755-
debug!(?errors, "errors");
756-
757-
// If we were able to prove that the type outlives the region without
758-
// an error, it must be because of the implied or explicit bounds...
759-
errors.is_empty()
760-
}
761-
762700
/// TypeVisitor that looks for uses of GATs like
763701
/// `<P0 as Trait<P1..Pn>>::GAT<Pn..Pm>` and adds the arguments `P0..Pm` into
764702
/// the two vectors, `regions` and `types` (depending on their kind). For each

compiler/rustc_infer/src/infer/outlives/for_liveness.rs

Lines changed: 0 additions & 111 deletions
This file was deleted.

compiler/rustc_infer/src/infer/outlives/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use crate::infer::lexical_region_resolve;
1616
use crate::infer::region_constraints::ConstraintKind;
1717

1818
pub mod env;
19-
pub mod for_liveness;
2019
pub mod obligations;
2120
pub mod test_type_match;
2221
pub(crate) mod verify;

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ provide! { tcx, def_id, other, cdata,
416416
}
417417
anon_const_kind => { table }
418418
const_of_item => { table }
419+
live_regions_for_opaque_from_outlives_bounds => { table }
419420
}
420421

421422
pub(in crate::rmeta) fn provide(providers: &mut Providers) {

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,6 +1620,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
16201620
record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
16211621
<- tcx.explicit_implied_const_bounds(def_id).skip_binder());
16221622
}
1623+
record!(self.tables.live_regions_for_opaque_from_outlives_bounds[def_id] <- tcx.live_regions_for_opaque_from_outlives_bounds(def_id));
16231624
}
16241625
if let DefKind::AnonConst = def_kind {
16251626
record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id));

compiler/rustc_metadata/src/rmeta/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ define_tables! {
473473
anon_const_kind: Table<DefIndex, LazyValue<ty::AnonConstKind>>,
474474
const_of_item: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::Const<'static>>>>,
475475
associated_types_for_impl_traits_in_trait_or_impl: Table<DefIndex, LazyValue<DefIdMap<Vec<DefId>>>>,
476+
live_regions_for_opaque_from_outlives_bounds: Table<DefIndex, LazyValue<Option<ty::EarlyBinder<'static, Vec<ty::Region<'static>>>>>>,
476477
}
477478

478479
#[derive(TyEncodable, TyDecodable)]

compiler/rustc_metadata/src/rmeta/parameterized.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::hash::Hash;
33
use rustc_data_structures::unord::UnordMap;
44
use rustc_hir::def_id::DefIndex;
55
use rustc_index::{Idx, IndexVec};
6-
use rustc_middle::ty::{Binder, EarlyBinder};
6+
use rustc_middle::ty::{Binder, EarlyBinder, Region};
77
use rustc_span::Symbol;
88

99
use crate::rmeta::{LazyArray, LazyValue};
@@ -48,6 +48,10 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> {
4848
type Value<'tcx> = LazyArray<T::Value<'tcx>>;
4949
}
5050

51+
impl ParameterizedOverTcx for Region<'static> {
52+
type Value<'tcx> = Region<'tcx>;
53+
}
54+
5155
macro_rules! trivially_parameterized_over_tcx {
5256
($($ty:ty),+ $(,)?) => {
5357
$(

compiler/rustc_middle/src/queries.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2118,6 +2118,24 @@ rustc_queries! {
21182118
desc { "listing captured lifetimes for opaque `{}`", tcx.def_path_str(def_id) }
21192119
}
21202120

2121+
/// For an opaque type, return the list of potentially live args from the set of outlives bounds on that opaque.
2122+
/// ```ignore (illustrative)
2123+
/// // Edition 2024: all args are captured
2124+
/// fn foo<'a, 'b, T: 'static>(&'a &'b T) -> impl Sized + 'a {}
2125+
/// fn bar<'a, 'b, T: 'static>(&'a &'b T) -> impl Sized + 'static {}
2126+
/// fn baz<'a, 'b, T: 'static>(&'a &'b T) -> impl Sized {}
2127+
/// ```
2128+
///
2129+
/// In the above:
2130+
/// - `foo` outlives `'a`, but we know that `'b: 'a` holds, so `'b` is *also* potentially live
2131+
/// - `bar` outlives `'static`, so we know that all lifetimes are potentially live and we can return an empty set
2132+
/// - `baz` has not outlives bound, so return `None` and let the caller decide what to do
2133+
query live_regions_for_opaque_from_outlives_bounds(def_id: DefId) -> &'tcx Option<ty::EarlyBinder<'tcx, Vec<ty::Region<'tcx>>>> {
2134+
arena_cache
2135+
desc { "identifying live args for opaque `{}`", tcx.def_path_str(def_id) }
2136+
separate_provide_extern
2137+
}
2138+
21212139
/// Computes the visibility of the provided `def_id`.
21222140
///
21232141
/// If the item from the `def_id` doesn't have a visibility, it will panic. For example

compiler/rustc_trait_selection/src/regions.rs

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
use rustc_data_structures::fx::FxIndexSet;
12
use rustc_hir::def_id::LocalDefId;
23
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
3-
use rustc_infer::infer::{InferCtxt, RegionResolutionError};
4+
use rustc_infer::infer::{
5+
InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt, TypeOutlivesConstraint,
6+
};
47
use rustc_macros::extension;
58
use rustc_middle::traits::ObligationCause;
69
use rustc_middle::traits::query::NoSolution;
7-
use rustc_middle::ty::{self, Ty, Unnormalized, elaborate};
8-
use rustc_span::Span;
10+
use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode, Unnormalized, elaborate};
11+
use rustc_span::{DUMMY_SP, Span};
912

1013
use crate::traits::ScrubbedTraitError;
1114
use crate::traits::outlives_bounds::InferCtxtExt;
@@ -120,3 +123,67 @@ impl<'tcx> InferCtxt<'tcx> {
120123
)
121124
}
122125
}
126+
127+
/// Given a known `param_env` and a set of well formed types, can we prove that
128+
/// `ty` outlives `region`.
129+
pub fn ty_known_to_outlive<'tcx>(
130+
tcx: TyCtxt<'tcx>,
131+
id: LocalDefId,
132+
param_env: ty::ParamEnv<'tcx>,
133+
wf_tys: &FxIndexSet<Ty<'tcx>>,
134+
ty: Ty<'tcx>,
135+
region: ty::Region<'tcx>,
136+
) -> bool {
137+
test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
138+
infcx.register_type_outlives_constraint_inner(TypeOutlivesConstraint {
139+
sub_region: region,
140+
sup_type: ty,
141+
origin: SubregionOrigin::RelateParamBound(DUMMY_SP, ty, None),
142+
});
143+
})
144+
}
145+
146+
/// Given a known `param_env` and a set of well formed types, can we prove that
147+
/// `region_a` outlives `region_b`
148+
pub fn region_known_to_outlive<'tcx>(
149+
tcx: TyCtxt<'tcx>,
150+
id: LocalDefId,
151+
param_env: ty::ParamEnv<'tcx>,
152+
wf_tys: &FxIndexSet<Ty<'tcx>>,
153+
region_a: ty::Region<'tcx>,
154+
region_b: ty::Region<'tcx>,
155+
) -> bool {
156+
test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
157+
infcx.sub_regions(
158+
SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None),
159+
region_b,
160+
region_a,
161+
ty::VisibleForLeakCheck::Unreachable,
162+
);
163+
})
164+
}
165+
166+
/// Given a known `param_env` and a set of well formed types, set up an
167+
/// `InferCtxt`, call the passed function (to e.g. set up region constraints
168+
/// to be tested), then resolve region and return errors
169+
pub fn test_region_obligations<'tcx>(
170+
tcx: TyCtxt<'tcx>,
171+
id: LocalDefId,
172+
param_env: ty::ParamEnv<'tcx>,
173+
wf_tys: &FxIndexSet<Ty<'tcx>>,
174+
add_constraints: impl FnOnce(&InferCtxt<'tcx>),
175+
) -> bool {
176+
// Unfortunately, we have to use a new `InferCtxt` each call, because
177+
// region constraints get added and solved there and we need to test each
178+
// call individually.
179+
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
180+
181+
add_constraints(&infcx);
182+
183+
let errors = infcx.resolve_regions(id, param_env, wf_tys.iter().copied());
184+
tracing::debug!(?errors, "errors");
185+
186+
// If we were able to prove that the type outlives the region without
187+
// an error, it must be because of the implied or explicit bounds...
188+
errors.is_empty()
189+
}

0 commit comments

Comments
 (0)