1use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
2use rustc_index::bit_set::DenseBitSet;
3use rustc_index::interval::IntervalSet;
4use rustc_infer::infer::canonical::QueryRegionConstraints;
5use rustc_infer::infer::outlives::for_liveness;
6use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Local, Location};
7use rustc_middle::traits::query::DropckOutlivesResult;
8use rustc_middle::ty::relate::Relate;
9use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
10use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
11use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
12use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
13use rustc_mir_dataflow::{Analysis, ResultsCursor};
14use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
15use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
16use rustc_trait_selection::traits::ObligationCtxt;
17use rustc_trait_selection::traits::query::dropck_outlives;
18use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOp, TypeOpOutput};
19use tracing::debug;
2021use crate::polonius;
22use crate::region_infer::values;
23use crate::type_check::liveness::local_use_map::LocalUseMap;
24use crate::type_check::{NormalizeLocation, TypeChecker};
2526/// This is the heart of the liveness computation. For each variable X
27/// that requires a liveness computation, it walks over all the uses
28/// of X and does a reverse depth-first search ("trace") through the
29/// MIR. This search stops when we find a definition of that variable.
30/// The points visited in this search is the USE-LIVE set for the variable;
31/// of those points is added to all the regions that appear in the variable's
32/// type.
33///
34/// We then also walks through each *drop* of those variables and does
35/// another search, stopping when we reach a use or definition. This
36/// is the DROP-LIVE set of points. Each of the points in the
37/// DROP-LIVE set are to the liveness sets for regions found in the
38/// `dropck_outlives` result of the variable's type (in particular,
39/// this respects `#[may_dangle]` annotations).
40pub(super) fn trace<'tcx>(
41 typeck: &mut TypeChecker<'_, 'tcx>,
42 location_map: &DenseLocationMap,
43 move_data: &MoveData<'tcx>,
44 relevant_live_locals: Vec<Local>,
45 boring_locals: Vec<Local>,
46) {
47let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, typeck.body);
48let cx = LivenessContext {
49typeck,
50 flow_inits: None,
51location_map,
52local_use_map,
53move_data,
54 drop_data: FxIndexMap::default(),
55 };
5657let mut results = LivenessResults::new(cx);
5859results.add_extra_drop_facts(&relevant_live_locals);
6061results.compute_for_all_locals(relevant_live_locals);
6263results.dropck_boring_locals(boring_locals);
64}
6566/// Contextual state for the type-liveness coroutine.
67struct LivenessContext<'a, 'typeck, 'tcx> {
68/// Current type-checker, giving us our inference context etc.
69 ///
70 /// This also stores the body we're currently analyzing.
71typeck: &'a mut TypeChecker<'typeck, 'tcx>,
7273/// Defines the `PointIndex` mapping
74location_map: &'a DenseLocationMap,
7576/// Mapping to/from the various indices used for initialization tracking.
77move_data: &'a MoveData<'tcx>,
7879/// Cache for the results of `dropck_outlives` query.
80drop_data: FxIndexMap<Ty<'tcx>, DropData<'tcx>>,
8182/// Results of dataflow tracking which variables (and paths) have been
83 /// initialized. Computed lazily when needed by drop-liveness.
84flow_inits: Option<ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>>,
8586/// Index indicating where each variable is assigned, used, or
87 /// dropped.
88local_use_map: &'a LocalUseMap,
89}
9091struct DropData<'tcx> {
92 dropck_result: DropckOutlivesResult<'tcx>,
93 region_constraint_data: Option<&'tcx QueryRegionConstraints<'tcx>>,
94}
9596struct LivenessResults<'a, 'typeck, 'tcx> {
97 cx: LivenessContext<'a, 'typeck, 'tcx>,
9899/// Set of points that define the current local.
100defs: DenseBitSet<PointIndex>,
101102/// Points where the current variable is "use live" -- meaning
103 /// that there is a future "full use" that may use its value.
104use_live_at: IntervalSet<PointIndex>,
105106/// Points where the current variable is "drop live" -- meaning
107 /// that there is no future "full use" that may use its value, but
108 /// there is a future drop.
109drop_live_at: IntervalSet<PointIndex>,
110111/// Locations where drops may occur.
112drop_locations: Vec<Location>,
113114/// Stack used when doing (reverse) DFS.
115stack: Vec<PointIndex>,
116}
117118impl<'a, 'typeck, 'tcx> LivenessResults<'a, 'typeck, 'tcx> {
119fn new(cx: LivenessContext<'a, 'typeck, 'tcx>) -> Self {
120let num_points = cx.location_map.num_points();
121LivenessResults {
122cx,
123 defs: DenseBitSet::new_empty(num_points),
124 use_live_at: IntervalSet::new(num_points),
125 drop_live_at: IntervalSet::new(num_points),
126 drop_locations: ::alloc::vec::Vec::new()vec![],
127 stack: ::alloc::vec::Vec::new()vec![],
128 }
129 }
130131fn compute_for_all_locals(&mut self, relevant_live_locals: Vec<Local>) {
132for local in relevant_live_locals {
133self.reset_local_state();
134self.add_defs_for(local);
135self.compute_use_live_points_for(local);
136self.compute_drop_live_points_for(local);
137138let local_ty = self.cx.body().local_decls[local].ty;
139140if !self.use_live_at.is_empty() {
141self.cx.add_use_live_facts_for(local_ty, &self.use_live_at);
142 }
143144if !self.drop_live_at.is_empty() {
145self.cx.add_drop_live_facts_for(
146 local,
147 local_ty,
148&self.drop_locations,
149&self.drop_live_at,
150 );
151 }
152 }
153 }
154155/// Runs dropck for locals whose liveness isn't relevant. This is
156 /// necessary to eagerly detect unbound recursion during drop glue computation.
157 ///
158 /// These are all the locals which do not potentially reference a region local
159 /// to this body. Locals which only reference free regions are always drop-live
160 /// and can therefore safely be dropped.
161fn dropck_boring_locals(&mut self, boring_locals: Vec<Local>) {
162for local in boring_locals {
163let local_ty = self.cx.body().local_decls[local].ty;
164let local_span = self.cx.body().local_decls[local].source_info.span;
165let drop_data = self.cx.drop_data.entry(local_ty).or_insert_with({
166let typeck = &self.cx.typeck;
167move || LivenessContext::compute_drop_data(typeck, local_ty, local_span)
168 });
169170 drop_data.dropck_result.report_overflows(
171self.cx.typeck.infcx.tcx,
172self.cx.typeck.body.local_decls[local].source_info.span,
173 local_ty,
174 );
175 }
176 }
177178/// Add extra drop facts needed for Polonius.
179 ///
180 /// Add facts for all locals with free regions, since regions may outlive
181 /// the function body only at certain nodes in the CFG.
182fn add_extra_drop_facts(&mut self, relevant_live_locals: &[Local]) {
183// This collect is more necessary than immediately apparent
184 // because these facts go into `add_drop_live_facts_for()`,
185 // which also writes to `polonius_facts`, and so this is genuinely
186 // a simultaneous overlapping mutable borrow.
187 // FIXME for future hackers: investigate whether this is
188 // actually necessary; these facts come from Polonius
189 // and probably maybe plausibly does not need to go back in.
190 // It may be necessary to just pick out the parts of
191 // `add_drop_live_facts_for()` that make sense.
192let Some(facts) = self.cx.typeck.polonius_facts.as_ref() else { return };
193let facts_to_add: Vec<_> = {
194let relevant_live_locals: FxIndexSet<_> =
195relevant_live_locals.iter().copied().collect();
196197facts198 .var_dropped_at
199 .iter()
200 .filter_map(|&(local, location_index)| {
201let local_ty = self.cx.body().local_decls[local].ty;
202if relevant_live_locals.contains(&local) || !local_ty.has_free_regions() {
203return None;
204 }
205206let location = self.cx.typeck.location_table.to_location(location_index);
207Some((local, local_ty, location))
208 })
209 .collect()
210 };
211212let live_at = IntervalSet::new(self.cx.location_map.num_points());
213for (local, local_ty, location) in facts_to_add {
214self.cx.add_drop_live_facts_for(local, local_ty, &[location], &live_at);
215 }
216 }
217218/// Clear the value of fields that are "per local variable".
219fn reset_local_state(&mut self) {
220self.defs.clear();
221self.use_live_at.clear();
222self.drop_live_at.clear();
223self.drop_locations.clear();
224if !self.stack.is_empty() {
::core::panicking::panic("assertion failed: self.stack.is_empty()")
};assert!(self.stack.is_empty());
225 }
226227/// Adds the definitions of `local` into `self.defs`.
228fn add_defs_for(&mut self, local: Local) {
229for def in self.cx.local_use_map.defs(local) {
230{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:230",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(230u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("- defined at {0:?}",
def) as &dyn Value))])
});
} else { ; }
};debug!("- defined at {:?}", def);
231self.defs.insert(def);
232 }
233 }
234235/// Computes all points where local is "use live" -- meaning its
236 /// current value may be used later (except by a drop). This is
237 /// done by walking backwards from each use of `local` until we
238 /// find a `def` of local.
239 ///
240 /// Requires `add_defs_for(local)` to have been executed.
241fn compute_use_live_points_for(&mut self, local: Local) {
242{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:242",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(242u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_use_live_points_for(local={0:?})",
local) as &dyn Value))])
});
} else { ; }
};debug!("compute_use_live_points_for(local={:?})", local);
243244self.stack.extend(self.cx.local_use_map.uses(local));
245while let Some(p) = self.stack.pop() {
246// We are live in this block from the closest to us of:
247 //
248 // * Inclusively, the block start
249 // * Exclusively, the previous definition (if it's in this block)
250 // * Exclusively, the previous live_at setting (an optimization)
251let block_start = self.cx.location_map.to_block_start(p);
252let previous_defs = self.defs.last_set_in(block_start..=p);
253let previous_live_at = self.use_live_at.last_set_in(block_start..=p);
254255let exclusive_start = match (previous_defs, previous_live_at) {
256 (Some(a), Some(b)) => Some(std::cmp::max(a, b)),
257 (Some(a), None) | (None, Some(a)) => Some(a),
258 (None, None) => None,
259 };
260261if let Some(exclusive) = exclusive_start {
262self.use_live_at.insert_range(exclusive + 1..=p);
263264// If we have a bound after the start of the block, we should
265 // not add the predecessors for this block.
266continue;
267 } else {
268// Add all the elements of this block.
269self.use_live_at.insert_range(block_start..=p);
270271// Then add the predecessors for this block, which are the
272 // terminators of predecessor basic blocks. Push those onto the
273 // stack so that the next iteration(s) will process them.
274275let block = self.cx.location_map.to_location(block_start).block;
276self.stack.extend(
277self.cx.body().basic_blocks.predecessors()[block]
278 .iter()
279 .map(|&pred_bb| self.cx.body().terminator_loc(pred_bb))
280 .map(|pred_loc| self.cx.location_map.point_from_location(pred_loc)),
281 );
282 }
283 }
284 }
285286/// Computes all points where local is "drop live" -- meaning its
287 /// current value may be dropped later (but not used). This is
288 /// done by iterating over the drops of `local` where `local` (or
289 /// some subpart of `local`) is initialized. For each such drop,
290 /// we walk backwards until we find a point where `local` is
291 /// either defined or use-live.
292 ///
293 /// Requires `compute_use_live_points_for` and `add_defs_for` to
294 /// have been executed.
295fn compute_drop_live_points_for(&mut self, local: Local) {
296{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:296",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(296u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for(local={0:?})",
local) as &dyn Value))])
});
} else { ; }
};debug!("compute_drop_live_points_for(local={:?})", local);
297298let Some(mpi) = self.cx.move_data.rev_lookup.find_local(local) else { return };
299{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:299",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(299u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for: mpi = {0:?}",
mpi) as &dyn Value))])
});
} else { ; }
};debug!("compute_drop_live_points_for: mpi = {:?}", mpi);
300301// Find the drops where `local` is initialized.
302for drop_point in self.cx.local_use_map.drops(local) {
303let location = self.cx.location_map.to_location(drop_point);
304if true {
match (&self.cx.body().terminator_loc(location.block), &location) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(self.cx.body().terminator_loc(location.block), location,);
305306if self.cx.initialized_at_terminator(location.block, mpi)
307 && self.drop_live_at.insert(drop_point)
308 {
309self.drop_locations.push(location);
310self.stack.push(drop_point);
311 }
312 }
313314{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:314",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(314u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for: drop_locations={0:?}",
self.drop_locations) as &dyn Value))])
});
} else { ; }
};debug!("compute_drop_live_points_for: drop_locations={:?}", self.drop_locations);
315316// Reverse DFS. But for drops, we do it a bit differently.
317 // The stack only ever stores *terminators of blocks*. Within
318 // a block, we walk back the statements in an inner loop.
319while let Some(term_point) = self.stack.pop() {
320self.compute_drop_live_points_for_block(mpi, term_point);
321 }
322 }
323324/// Executes one iteration of the drop-live analysis loop.
325 ///
326 /// The parameter `mpi` is the `MovePathIndex` of the local variable
327 /// we are currently analyzing.
328 ///
329 /// The point `term_point` represents some terminator in the MIR,
330 /// where the local `mpi` is drop-live on entry to that terminator.
331 ///
332 /// This method adds all drop-live points within the block and --
333 /// where applicable -- pushes the terminators of preceding blocks
334 /// onto `self.stack`.
335fn compute_drop_live_points_for_block(&mut self, mpi: MovePathIndex, term_point: PointIndex) {
336{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:336",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(336u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for_block(mpi={0:?}, term_point={1:?})",
self.cx.move_data.move_paths[mpi].place,
self.cx.location_map.to_location(term_point)) as
&dyn Value))])
});
} else { ; }
};debug!(
337"compute_drop_live_points_for_block(mpi={:?}, term_point={:?})",
338self.cx.move_data.move_paths[mpi].place,
339self.cx.location_map.to_location(term_point),
340 );
341342// We are only invoked with terminators where `mpi` is
343 // drop-live on entry.
344if true {
if !self.drop_live_at.contains(term_point) {
::core::panicking::panic("assertion failed: self.drop_live_at.contains(term_point)")
};
};debug_assert!(self.drop_live_at.contains(term_point));
345346// Otherwise, scan backwards through the statements in the
347 // block. One of them may be either a definition or use
348 // live point.
349let term_location = self.cx.location_map.to_location(term_point);
350if true {
match (&self.cx.body().terminator_loc(term_location.block),
&term_location) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(self.cx.body().terminator_loc(term_location.block), term_location,);
351let block = term_location.block;
352let entry_point = self.cx.location_map.entry_point(term_location.block);
353for p in (entry_point..term_point).rev() {
354{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:354",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(354u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for_block: p = {0:?}",
self.cx.location_map.to_location(p)) as &dyn Value))])
});
} else { ; }
};debug!(
355"compute_drop_live_points_for_block: p = {:?}",
356self.cx.location_map.to_location(p)
357 );
358359if self.defs.contains(p) {
360{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:360",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(360u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for_block: def site")
as &dyn Value))])
});
} else { ; }
};debug!("compute_drop_live_points_for_block: def site");
361return;
362 }
363364if self.use_live_at.contains(p) {
365{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:365",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(365u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for_block: use-live at {0:?}",
p) as &dyn Value))])
});
} else { ; }
};debug!("compute_drop_live_points_for_block: use-live at {:?}", p);
366return;
367 }
368369if !self.drop_live_at.insert(p) {
370{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:370",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(370u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for_block: already drop-live")
as &dyn Value))])
});
} else { ; }
};debug!("compute_drop_live_points_for_block: already drop-live");
371return;
372 }
373 }
374375let body = self.cx.typeck.body;
376for &pred_block in body.basic_blocks.predecessors()[block].iter() {
377{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:377",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(377u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for_block: pred_block = {0:?}",
pred_block) as &dyn Value))])
});
} else { ; }
};debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,);
378379// Check whether the variable is (at least partially)
380 // initialized at the exit of this predecessor. If so, we
381 // want to enqueue it on our list. If not, go check the
382 // next block.
383 //
384 // Note that we only need to check whether `live_local`
385 // became de-initialized at basic block boundaries. If it
386 // were to become de-initialized within the block, that
387 // would have been a "use-live" transition in the earlier
388 // loop, and we'd have returned already.
389 //
390 // NB. It's possible that the pred-block ends in a call
391 // which stores to the variable; in that case, the
392 // variable may be uninitialized "at exit" because this
393 // call only considers the *unconditional effects* of the
394 // terminator. *But*, in that case, the terminator is also
395 // a *definition* of the variable, in which case we want
396 // to stop the search anyhow. (But see Note 1 below.)
397if !self.cx.initialized_at_exit(pred_block, mpi) {
398{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:398",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(398u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for_block: not initialized")
as &dyn Value))])
});
} else { ; }
};debug!("compute_drop_live_points_for_block: not initialized");
399continue;
400 }
401402let pred_term_loc = self.cx.body().terminator_loc(pred_block);
403let pred_term_point = self.cx.location_map.point_from_location(pred_term_loc);
404405// If the terminator of this predecessor either *assigns*
406 // our value or is a "normal use", then stop.
407if self.defs.contains(pred_term_point) {
408{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:408",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(408u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for_block: defined at {0:?}",
pred_term_loc) as &dyn Value))])
});
} else { ; }
};debug!("compute_drop_live_points_for_block: defined at {:?}", pred_term_loc);
409continue;
410 }
411412if self.use_live_at.contains(pred_term_point) {
413{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:413",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(413u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for_block: use-live at {0:?}",
pred_term_loc) as &dyn Value))])
});
} else { ; }
};debug!("compute_drop_live_points_for_block: use-live at {:?}", pred_term_loc);
414continue;
415 }
416417// Otherwise, we are drop-live on entry to the terminator,
418 // so walk it.
419if self.drop_live_at.insert(pred_term_point) {
420{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:420",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(420u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_live_points_for_block: pushed to stack")
as &dyn Value))])
});
} else { ; }
};debug!("compute_drop_live_points_for_block: pushed to stack");
421self.stack.push(pred_term_point);
422 }
423 }
424425// Note 1. There is a weird scenario that you might imagine
426 // being problematic here, but which actually cannot happen.
427 // The problem would be if we had a variable that *is* initialized
428 // (but dead) on entry to the terminator, and where the current value
429 // will be dropped in the case of unwind. In that case, we ought to
430 // consider `X` to be drop-live in between the last use and call.
431 // Here is the example:
432 //
433 // ```
434 // BB0 {
435 // X = ...
436 // use(X); // last use
437 // ... // <-- X ought to be drop-live here
438 // X = call() goto BB1 unwind BB2
439 // }
440 //
441 // BB1 {
442 // DROP(X)
443 // }
444 //
445 // BB2 {
446 // DROP(X)
447 // }
448 // ```
449 //
450 // However, the current code would, when walking back from BB2,
451 // simply stop and never explore BB0. This seems bad! But it turns
452 // out this code is flawed anyway -- note that the existing value of
453 // `X` would leak in the case where unwinding did *not* occur.
454 //
455 // What we *actually* generate is a store to a temporary
456 // for the call (`TMP = call()...`) and then a
457 // `Drop(X)` followed by `X = TMP` to swap that with `X`.
458}
459}
460461impl<'a, 'typeck, 'tcx> LivenessContext<'a, 'typeck, 'tcx> {
462/// Computes the `MaybeInitializedPlaces` dataflow analysis if it hasn't been done already.
463 ///
464 /// In practice, the results of this dataflow analysis are rarely needed but can be expensive to
465 /// compute on big functions, so we compute them lazily as a fast path when:
466 /// - there are relevant live locals
467 /// - there are drop points for these relevant live locals.
468 ///
469 /// This happens as part of the drop-liveness computation: it's the only place checking for
470 /// maybe-initializedness of `MovePathIndex`es.
471fn flow_inits(&mut self) -> &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>> {
472self.flow_inits.get_or_insert_with(|| {
473let tcx = self.typeck.tcx();
474let body = self.typeck.body;
475// FIXME: reduce the `MaybeInitializedPlaces` domain to the useful `MovePath`s.
476 //
477 // This dataflow analysis computes maybe-initializedness of all move paths, which
478 // explains why it can be expensive on big functions. But this data is only used in
479 // drop-liveness. Therefore, most of the move paths computed here are ultimately unused,
480 // even if the results are computed lazily and "no relevant live locals with drop
481 // points" is the common case.
482 //
483 // So we only need the ones for 1) relevant live locals 2) that have drop points. That's
484 // a much, much smaller domain: in our benchmarks, when it's not zero (the most likely
485 // case), there are a few dozens compared to e.g. thousands or tens of thousands of
486 // locals and move paths.
487let flow_inits = MaybeInitializedPlaces::new(tcx, body, self.move_data)
488 .iterate_to_fixpoint(tcx, body, Some("borrowck"))
489 .into_results_cursor(body);
490flow_inits491 })
492 }
493}
494495impl<'tcx> LivenessContext<'_, '_, 'tcx> {
496fn body(&self) -> &Body<'tcx> {
497self.typeck.body
498 }
499500/// Returns `true` if the local variable (or some part of it) is initialized at the current
501 /// cursor position. Callers should call one of the `seek` methods immediately before to point
502 /// the cursor to the desired location.
503fn initialized_at_curr_loc(&mut self, mpi: MovePathIndex) -> bool {
504let flow_inits = self.flow_inits();
505let state = flow_inits.get();
506if state.contains(mpi) {
507return true;
508 }
509510let move_paths = &flow_inits.analysis().move_data().move_paths;
511move_paths[mpi].find_descendant(move_paths, |mpi| state.contains(mpi)).is_some()
512 }
513514/// Returns `true` if the local variable (or some part of it) is initialized in
515 /// the terminator of `block`. We need to check this to determine if a
516 /// DROP of some local variable will have an effect -- note that
517 /// drops, as they may unwind, are always terminators.
518fn initialized_at_terminator(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool {
519let terminator_location = self.body().terminator_loc(block);
520self.flow_inits().seek_before_primary_effect(terminator_location);
521self.initialized_at_curr_loc(mpi)
522 }
523524/// Returns `true` if the path `mpi` (or some part of it) is initialized at
525 /// the exit of `block`.
526 ///
527 /// **Warning:** Does not account for the result of `Call`
528 /// instructions.
529fn initialized_at_exit(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool {
530let terminator_location = self.body().terminator_loc(block);
531self.flow_inits().seek_after_primary_effect(terminator_location);
532self.initialized_at_curr_loc(mpi)
533 }
534535/// Stores the result that all regions in `value` are live for the
536 /// points `live_at`.
537fn add_use_live_facts_for(&mut self, value: Ty<'tcx>, live_at: &IntervalSet<PointIndex>) {
538{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:538",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(538u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("add_use_live_facts_for(value={0:?})",
value) as &dyn Value))])
});
} else { ; }
};debug!("add_use_live_facts_for(value={:?})", value);
539Self::make_all_regions_live(self.location_map, self.typeck, value, live_at);
540 }
541542/// Some variable with type `live_ty` is "drop live" at `location`
543 /// -- i.e., it may be dropped later. This means that *some* of
544 /// the regions in its type must be live at `location`. The
545 /// precise set will depend on the dropck constraints, and in
546 /// particular this takes `#[may_dangle]` into account.
547fn add_drop_live_facts_for(
548&mut self,
549 dropped_local: Local,
550 dropped_ty: Ty<'tcx>,
551 drop_locations: &[Location],
552 live_at: &IntervalSet<PointIndex>,
553 ) {
554{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:554",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(554u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("add_drop_live_constraint(dropped_local={0:?}, dropped_ty={1:?}, drop_locations={2:?}, live_at={3:?})",
dropped_local, dropped_ty, drop_locations,
values::pretty_print_points(self.location_map,
live_at.iter())) as &dyn Value))])
});
} else { ; }
};debug!(
555"add_drop_live_constraint(\
556 dropped_local={:?}, \
557 dropped_ty={:?}, \
558 drop_locations={:?}, \
559 live_at={:?})",
560 dropped_local,
561 dropped_ty,
562 drop_locations,
563 values::pretty_print_points(self.location_map, live_at.iter()),
564 );
565566let local_span = self.body().local_decls()[dropped_local].source_info.span;
567let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
568let typeck = &self.typeck;
569move || Self::compute_drop_data(typeck, dropped_ty, local_span)
570 });
571572if let Some(data) = &drop_data.region_constraint_data {
573for &drop_location in drop_locations {
574self.typeck.push_region_constraints(
575 drop_location.to_locations(),
576 ConstraintCategory::Boring,
577 data,
578 );
579 }
580 }
581582drop_data.dropck_result.report_overflows(
583self.typeck.infcx.tcx,
584self.typeck.body.source_info(*drop_locations.first().unwrap()).span,
585dropped_ty,
586 );
587588// All things in the `outlives` array may be touched by
589 // the destructor and must be live at this point.
590for &kind in &drop_data.dropck_result.kinds {
591Self::make_all_regions_live(self.location_map, self.typeck, kind, live_at);
592 polonius::legacy::emit_drop_facts(
593self.typeck.tcx(),
594 dropped_local,
595&kind,
596self.typeck.universal_regions,
597self.typeck.polonius_facts,
598 );
599 }
600 }
601602fn make_all_regions_live(
603 location_map: &DenseLocationMap,
604 typeck: &mut TypeChecker<'_, 'tcx>,
605 value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
606 live_at: &IntervalSet<PointIndex>,
607 ) {
608{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:608",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(608u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("make_all_regions_live(value={0:?})",
value) as &dyn Value))])
});
} else { ; }
};debug!("make_all_regions_live(value={:?})", value);
609{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:609",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(609u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("make_all_regions_live: live_at={0}",
values::pretty_print_points(location_map, live_at.iter()))
as &dyn Value))])
});
} else { ; }
};debug!(
610"make_all_regions_live: live_at={}",
611 values::pretty_print_points(location_map, live_at.iter()),
612 );
613614value.visit_with(&mut for_liveness::FreeRegionsVisitor {
615 tcx: typeck.tcx(),
616 param_env: typeck.infcx.param_env,
617 op: |r| {
618let live_region_vid = typeck.universal_regions.to_region_vid(r);
619620typeck.constraints.liveness_constraints.add_points(live_region_vid, live_at);
621 },
622 });
623624// When using `-Zpolonius=next`, we record the variance of each live region.
625if let Some(polonius_liveness) = typeck.polonius_liveness.as_mut() {
626polonius_liveness.record_live_region_variance(
627typeck.infcx.tcx,
628typeck.universal_regions,
629value,
630 );
631 }
632 }
633634fn compute_drop_data(
635 typeck: &TypeChecker<'_, 'tcx>,
636 dropped_ty: Ty<'tcx>,
637 span: Span,
638 ) -> DropData<'tcx> {
639{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/type_check/liveness/trace.rs:639",
"rustc_borrowck::type_check::liveness::trace",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/type_check/liveness/trace.rs"),
::tracing_core::__macro_support::Option::Some(639u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::type_check::liveness::trace"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("compute_drop_data(dropped_ty={0:?})",
dropped_ty) as &dyn Value))])
});
} else { ; }
};debug!("compute_drop_data(dropped_ty={:?})", dropped_ty);
640641let op = typeck.infcx.param_env.and(DropckOutlives { dropped_ty });
642643match op.fully_perform(typeck.infcx, typeck.root_cx.root_def_id(), DUMMY_SP) {
644Ok(TypeOpOutput { output, constraints, .. }) => {
645DropData { dropck_result: output, region_constraint_data: constraints }
646 }
647Err(ErrorGuaranteed { .. }) => {
648// We don't run dropck on HIR, and dropck looks inside fields of
649 // types, so there's no guarantee that it succeeds. We also
650 // can't rely on the `ErrorGuaranteed` from `fully_perform` here
651 // because it comes from delay_span_bug.
652 //
653 // Do this inside of a probe because we don't particularly care (or want)
654 // any region side-effects of this operation in our infcx.
655typeck.infcx.probe(|_| {
656let ocx = ObligationCtxt::new_with_diagnostics(&typeck.infcx);
657let errors = match dropck_outlives::compute_dropck_outlives_with_errors(
658&ocx, op, span,
659 ) {
660Ok(_) => ocx.evaluate_obligations_error_on_ambiguity(),
661Err(e) => e,
662 };
663664// Could have no errors if a type lowering error, say, caused the query
665 // to fail.
666if !errors.is_empty() {
667typeck.infcx.err_ctxt().report_fulfillment_errors(errors);
668 }
669 });
670DropData { dropck_result: Default::default(), region_constraint_data: None }
671 }
672 }
673 }
674}