rustc_borrowck/type_check/liveness/
mod.rs1use itertools::{Either, Itertools};
2use rustc_data_structures::fx::FxHashSet;
3use rustc_middle::mir::visit::{TyContext, Visitor};
4use rustc_middle::mir::{Body, Local, Location, SourceInfo};
5use rustc_middle::span_bug;
6use rustc_middle::ty::relate::Relate;
7use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt, TypeVisitable};
8use rustc_mir_dataflow::ResultsCursor;
9use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
10use rustc_mir_dataflow::move_paths::MoveData;
11use rustc_mir_dataflow::points::DenseLocationMap;
12use tracing::debug;
13
14use super::TypeChecker;
15use crate::constraints::OutlivesConstraintSet;
16use crate::polonius::PoloniusLivenessContext;
17use crate::region_infer::values::LivenessValues;
18use crate::universal_regions::UniversalRegions;
19
20mod local_use_map;
21mod trace;
22
23pub(super) fn generate<'a, 'tcx>(
32 typeck: &mut TypeChecker<'_, 'tcx>,
33 location_map: &DenseLocationMap,
34 flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
35 move_data: &MoveData<'tcx>,
36) {
37 debug!("liveness::generate");
38
39 let mut free_regions = regions_that_outlive_free_regions(
40 typeck.infcx.num_region_vars(),
41 &typeck.universal_regions,
42 &typeck.constraints.outlives_constraints,
43 );
44
45 if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
52 let (_, boring_locals) =
53 compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body);
54 typeck.polonius_liveness.as_mut().unwrap().boring_nll_locals =
55 boring_locals.into_iter().collect();
56 free_regions = typeck.universal_regions.universal_regions_iter().collect();
57 }
58 let (relevant_live_locals, boring_locals) =
59 compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body);
60
61 trace::trace(typeck, location_map, flow_inits, move_data, relevant_live_locals, boring_locals);
62
63 record_regular_live_regions(
66 typeck.tcx(),
67 &mut typeck.constraints.liveness_constraints,
68 &typeck.universal_regions,
69 &mut typeck.polonius_liveness,
70 typeck.body,
71 );
72}
73
74fn compute_relevant_live_locals<'tcx>(
80 tcx: TyCtxt<'tcx>,
81 free_regions: &FxHashSet<RegionVid>,
82 body: &Body<'tcx>,
83) -> (Vec<Local>, Vec<Local>) {
84 let (boring_locals, relevant_live_locals): (Vec<_>, Vec<_>) =
85 body.local_decls.iter_enumerated().partition_map(|(local, local_decl)| {
86 if tcx.all_free_regions_meet(&local_decl.ty, |r| free_regions.contains(&r.as_var())) {
87 Either::Left(local)
88 } else {
89 Either::Right(local)
90 }
91 });
92
93 debug!("{} total variables", body.local_decls.len());
94 debug!("{} variables need liveness", relevant_live_locals.len());
95 debug!("{} regions outlive free regions", free_regions.len());
96
97 (relevant_live_locals, boring_locals)
98}
99
100fn regions_that_outlive_free_regions<'tcx>(
105 num_region_vars: usize,
106 universal_regions: &UniversalRegions<'tcx>,
107 constraint_set: &OutlivesConstraintSet<'tcx>,
108) -> FxHashSet<RegionVid> {
109 let rev_constraint_graph = constraint_set.reverse_graph(num_region_vars);
115 let fr_static = universal_regions.fr_static;
116 let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static);
117
118 let mut stack: Vec<_> = universal_regions.universal_regions_iter().collect();
120
121 let mut outlives_free_region: FxHashSet<_> = stack.iter().cloned().collect();
124
125 while let Some(sub_region) = stack.pop() {
129 stack.extend(
130 rev_region_graph
131 .outgoing_regions(sub_region)
132 .filter(|&r| outlives_free_region.insert(r)),
133 );
134 }
135
136 outlives_free_region
138}
139
140fn record_regular_live_regions<'tcx>(
143 tcx: TyCtxt<'tcx>,
144 liveness_constraints: &mut LivenessValues,
145 universal_regions: &UniversalRegions<'tcx>,
146 polonius_liveness: &mut Option<PoloniusLivenessContext>,
147 body: &Body<'tcx>,
148) {
149 let mut visitor =
150 LiveVariablesVisitor { tcx, liveness_constraints, universal_regions, polonius_liveness };
151 for (bb, data) in body.basic_blocks.iter_enumerated() {
152 visitor.visit_basic_block_data(bb, data);
153 }
154}
155
156struct LiveVariablesVisitor<'a, 'tcx> {
158 tcx: TyCtxt<'tcx>,
159 liveness_constraints: &'a mut LivenessValues,
160 universal_regions: &'a UniversalRegions<'tcx>,
161 polonius_liveness: &'a mut Option<PoloniusLivenessContext>,
162}
163
164impl<'a, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'a, 'tcx> {
165 fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) {
168 self.record_regions_live_at(*args, location);
169 self.super_args(args);
170 }
171
172 fn visit_region(&mut self, region: Region<'tcx>, location: Location) {
175 self.record_regions_live_at(region, location);
176 self.super_region(region);
177 }
178
179 fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) {
182 match ty_context {
183 TyContext::ReturnTy(SourceInfo { span, .. })
184 | TyContext::YieldTy(SourceInfo { span, .. })
185 | TyContext::ResumeTy(SourceInfo { span, .. })
186 | TyContext::UserTy(span)
187 | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => {
188 span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context);
189 }
190 TyContext::Location(location) => {
191 self.record_regions_live_at(ty, location);
192 }
193 }
194
195 self.super_ty(ty);
196 }
197}
198
199impl<'a, 'tcx> LiveVariablesVisitor<'a, 'tcx> {
200 fn record_regions_live_at<T>(&mut self, value: T, location: Location)
203 where
204 T: TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
205 {
206 debug!("record_regions_live_at(value={:?}, location={:?})", value, location);
207 self.tcx.for_each_free_region(&value, |live_region| {
208 let live_region_vid = live_region.as_var();
209 self.liveness_constraints.add_location(live_region_vid, location);
210 });
211
212 if let Some(polonius_liveness) = self.polonius_liveness {
214 polonius_liveness.record_live_region_variance(self.tcx, self.universal_regions, value);
215 }
216 }
217}