summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck/src/type_check/liveness/mod.rs')
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs88
1 files changed, 83 insertions, 5 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index f1ad0ca55..dc4695fd2 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -1,7 +1,9 @@
use itertools::{Either, Itertools};
use rustc_data_structures::fx::FxHashSet;
-use rustc_middle::mir::{Body, Local};
-use rustc_middle::ty::{RegionVid, TyCtxt};
+use rustc_middle::mir::visit::{TyContext, Visitor};
+use rustc_middle::mir::{Body, Local, Location, SourceInfo};
+use rustc_middle::ty::visit::TypeVisitable;
+use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt};
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::ResultsCursor;
@@ -11,7 +13,7 @@ use crate::{
constraints::OutlivesConstraintSet,
facts::{AllFacts, AllFactsExt},
location::LocationTable,
- region_infer::values::RegionValueElements,
+ region_infer::values::{LivenessValues, RegionValueElements},
universal_regions::UniversalRegions,
};
@@ -42,11 +44,11 @@ pub(super) fn generate<'mir, 'tcx>(
let free_regions = regions_that_outlive_free_regions(
typeck.infcx.num_region_vars(),
- &typeck.borrowck_context.universal_regions,
+ typeck.borrowck_context.universal_regions,
&typeck.borrowck_context.constraints.outlives_constraints,
);
let (relevant_live_locals, boring_locals) =
- compute_relevant_live_locals(typeck.tcx(), &free_regions, &body);
+ compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
let facts_enabled = use_polonius || AllFacts::enabled(typeck.tcx());
let polonius_drop_used = facts_enabled.then(|| {
@@ -65,6 +67,14 @@ pub(super) fn generate<'mir, 'tcx>(
boring_locals,
polonius_drop_used,
);
+
+ // Mark regions that should be live where they appear within rvalues or within a call: like
+ // args, regions, and types.
+ record_regular_live_regions(
+ typeck.tcx(),
+ &mut typeck.borrowck_context.constraints.liveness_constraints,
+ body,
+ );
}
// The purpose of `compute_relevant_live_locals` is to define the subset of `Local`
@@ -132,3 +142,71 @@ fn regions_that_outlive_free_regions<'tcx>(
// Return the final set of things we visited.
outlives_free_region
}
+
+/// Some variables are "regular live" at `location` -- i.e., they may be used later. This means that
+/// all regions appearing in their type must be live at `location`.
+fn record_regular_live_regions<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ liveness_constraints: &mut LivenessValues,
+ body: &Body<'tcx>,
+) {
+ let mut visitor = LiveVariablesVisitor { tcx, liveness_constraints };
+ for (bb, data) in body.basic_blocks.iter_enumerated() {
+ visitor.visit_basic_block_data(bb, data);
+ }
+}
+
+/// Visitor looking for regions that should be live within rvalues or calls.
+struct LiveVariablesVisitor<'cx, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ liveness_constraints: &'cx mut LivenessValues,
+}
+
+impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> {
+ /// We sometimes have `args` within an rvalue, or within a
+ /// call. Make them live at the location where they appear.
+ fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) {
+ self.record_regions_live_at(*args, location);
+ self.super_args(args);
+ }
+
+ /// We sometimes have `region`s within an rvalue, or within a
+ /// call. Make them live at the location where they appear.
+ fn visit_region(&mut self, region: Region<'tcx>, location: Location) {
+ self.record_regions_live_at(region, location);
+ self.super_region(region);
+ }
+
+ /// We sometimes have `ty`s within an rvalue, or within a
+ /// call. Make them live at the location where they appear.
+ fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) {
+ match ty_context {
+ TyContext::ReturnTy(SourceInfo { span, .. })
+ | TyContext::YieldTy(SourceInfo { span, .. })
+ | TyContext::UserTy(span)
+ | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => {
+ span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context);
+ }
+ TyContext::Location(location) => {
+ self.record_regions_live_at(ty, location);
+ }
+ }
+
+ self.super_ty(ty);
+ }
+}
+
+impl<'cx, 'tcx> LiveVariablesVisitor<'cx, 'tcx> {
+ /// Some variable is "regular live" at `location` -- i.e., it may be used later. This means that
+ /// all regions appearing in the type of `value` must be live at `location`.
+ fn record_regions_live_at<T>(&mut self, value: T, location: Location)
+ where
+ T: TypeVisitable<TyCtxt<'tcx>>,
+ {
+ debug!("record_regions_live_at(value={:?}, location={:?})", value, location);
+ self.tcx.for_each_free_region(&value, |live_region| {
+ let live_region_vid = live_region.as_var();
+ self.liveness_constraints.add_location(live_region_vid, location);
+ });
+ }
+}