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::move_paths::MoveData;
9use rustc_mir_dataflow::points::DenseLocationMap;
10use tracing::debug;
11
12use super::TypeChecker;
13use crate::constraints::OutlivesConstraintSet;
14use crate::polonius::PoloniusLivenessContext;
15use crate::region_infer::values::LivenessValues;
16use crate::universal_regions::UniversalRegions;
17
18mod local_use_map;
19mod trace;
20
21pub(super) fn generate<'tcx>(
30 typeck: &mut TypeChecker<'_, 'tcx>,
31 location_map: &DenseLocationMap,
32 move_data: &MoveData<'tcx>,
33) {
34 debug!("liveness::generate");
35
36 let mut free_regions = regions_that_outlive_free_regions(
37 typeck.infcx.num_region_vars(),
38 &typeck.universal_regions,
39 &typeck.constraints.outlives_constraints,
40 );
41
42 if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
49 let (_, boring_locals) =
50 compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body);
51 typeck.polonius_liveness.as_mut().unwrap().boring_nll_locals =
52 boring_locals.into_iter().collect();
53 free_regions = typeck.universal_regions.universal_regions_iter().collect();
54 }
55 let (relevant_live_locals, boring_locals) =
56 compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body);
57
58 trace::trace(typeck, location_map, move_data, relevant_live_locals, boring_locals);
59
60 record_regular_live_regions(
63 typeck.tcx(),
64 &mut typeck.constraints.liveness_constraints,
65 &typeck.universal_regions,
66 &mut typeck.polonius_liveness,
67 typeck.body,
68 );
69}
70
71fn compute_relevant_live_locals<'tcx>(
77 tcx: TyCtxt<'tcx>,
78 free_regions: &FxHashSet<RegionVid>,
79 body: &Body<'tcx>,
80) -> (Vec<Local>, Vec<Local>) {
81 let (boring_locals, relevant_live_locals): (Vec<_>, Vec<_>) =
82 body.local_decls.iter_enumerated().partition_map(|(local, local_decl)| {
83 if tcx.all_free_regions_meet(&local_decl.ty, |r| free_regions.contains(&r.as_var())) {
84 Either::Left(local)
85 } else {
86 Either::Right(local)
87 }
88 });
89
90 debug!("{} total variables", body.local_decls.len());
91 debug!("{} variables need liveness", relevant_live_locals.len());
92 debug!("{} regions outlive free regions", free_regions.len());
93
94 (relevant_live_locals, boring_locals)
95}
96
97fn regions_that_outlive_free_regions<'tcx>(
102 num_region_vars: usize,
103 universal_regions: &UniversalRegions<'tcx>,
104 constraint_set: &OutlivesConstraintSet<'tcx>,
105) -> FxHashSet<RegionVid> {
106 let rev_constraint_graph = constraint_set.reverse_graph(num_region_vars);
112 let fr_static = universal_regions.fr_static;
113 let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static);
114
115 let mut stack: Vec<_> = universal_regions.universal_regions_iter().collect();
117
118 let mut outlives_free_region: FxHashSet<_> = stack.iter().cloned().collect();
121
122 while let Some(sub_region) = stack.pop() {
126 stack.extend(
127 rev_region_graph
128 .outgoing_regions(sub_region)
129 .filter(|&r| outlives_free_region.insert(r)),
130 );
131 }
132
133 outlives_free_region
135}
136
137fn record_regular_live_regions<'tcx>(
140 tcx: TyCtxt<'tcx>,
141 liveness_constraints: &mut LivenessValues,
142 universal_regions: &UniversalRegions<'tcx>,
143 polonius_liveness: &mut Option<PoloniusLivenessContext>,
144 body: &Body<'tcx>,
145) {
146 let mut visitor =
147 LiveVariablesVisitor { tcx, liveness_constraints, universal_regions, polonius_liveness };
148 for (bb, data) in body.basic_blocks.iter_enumerated() {
149 visitor.visit_basic_block_data(bb, data);
150 }
151}
152
153struct LiveVariablesVisitor<'a, 'tcx> {
155 tcx: TyCtxt<'tcx>,
156 liveness_constraints: &'a mut LivenessValues,
157 universal_regions: &'a UniversalRegions<'tcx>,
158 polonius_liveness: &'a mut Option<PoloniusLivenessContext>,
159}
160
161impl<'a, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'a, 'tcx> {
162 fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) {
165 self.record_regions_live_at(*args, location);
166 self.super_args(args);
167 }
168
169 fn visit_region(&mut self, region: Region<'tcx>, location: Location) {
172 self.record_regions_live_at(region, location);
173 self.super_region(region);
174 }
175
176 fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) {
179 match ty_context {
180 TyContext::ReturnTy(SourceInfo { span, .. })
181 | TyContext::YieldTy(SourceInfo { span, .. })
182 | TyContext::ResumeTy(SourceInfo { span, .. })
183 | TyContext::UserTy(span)
184 | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => {
185 span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context);
186 }
187 TyContext::Location(location) => {
188 self.record_regions_live_at(ty, location);
189 }
190 }
191
192 self.super_ty(ty);
193 }
194}
195
196impl<'a, 'tcx> LiveVariablesVisitor<'a, 'tcx> {
197 fn record_regions_live_at<T>(&mut self, value: T, location: Location)
200 where
201 T: TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
202 {
203 debug!("record_regions_live_at(value={:?}, location={:?})", value, location);
204 self.tcx.for_each_free_region(&value, |live_region| {
205 let live_region_vid = live_region.as_var();
206 self.liveness_constraints.add_location(live_region_vid, location);
207 });
208
209 if let Some(polonius_liveness) = self.polonius_liveness {
211 polonius_liveness.record_live_region_variance(self.tcx, self.universal_regions, value);
212 }
213 }
214}