summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs')
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs242
1 files changed, 0 insertions, 242 deletions
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
deleted file mode 100644
index 29413f080..000000000
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ /dev/null
@@ -1,242 +0,0 @@
-use super::TrackedValue;
-use crate::{
- expr_use_visitor::{self, ExprUseVisitor},
- FnCtxt,
-};
-use hir::{def_id::DefId, Body, HirId, HirIdMap};
-use rustc_data_structures::{fx::FxIndexSet, unord::UnordSet};
-use rustc_hir as hir;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
-use rustc_middle::{
- hir::place::{PlaceBase, Projection, ProjectionKind},
- ty::TypeVisitableExt,
-};
-
-pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
- fcx: &'a FnCtxt<'a, 'tcx>,
- def_id: DefId,
- body: &'tcx Body<'tcx>,
-) -> ConsumedAndBorrowedPlaces {
- let mut expr_use_visitor = ExprUseDelegate::new(fcx.tcx, fcx.param_env);
- expr_use_visitor.consume_body(fcx, def_id, body);
- expr_use_visitor.places
-}
-
-pub(super) struct ConsumedAndBorrowedPlaces {
- /// Records the variables/expressions that are dropped by a given expression.
- ///
- /// The key is the hir-id of the expression, and the value is a set or hir-ids for variables
- /// or values that are consumed by that expression.
- ///
- /// Note that this set excludes "partial drops" -- for example, a statement like `drop(x.y)` is
- /// not considered a drop of `x`, although it would be a drop of `x.y`.
- pub(super) consumed: HirIdMap<FxIndexSet<TrackedValue>>,
-
- /// A set of hir-ids of values or variables that are borrowed at some point within the body.
- pub(super) borrowed: UnordSet<TrackedValue>,
-
- /// A set of hir-ids of values or variables that are borrowed at some point within the body.
- pub(super) borrowed_temporaries: UnordSet<HirId>,
-}
-
-/// Works with ExprUseVisitor to find interesting values for the drop range analysis.
-///
-/// Interesting values are those that are either dropped or borrowed. For dropped values, we also
-/// record the parent expression, which is the point where the drop actually takes place.
-struct ExprUseDelegate<'tcx> {
- tcx: TyCtxt<'tcx>,
- param_env: ParamEnv<'tcx>,
- places: ConsumedAndBorrowedPlaces,
-}
-
-impl<'tcx> ExprUseDelegate<'tcx> {
- fn new(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
- Self {
- tcx,
- param_env,
- places: ConsumedAndBorrowedPlaces {
- consumed: <_>::default(),
- borrowed: <_>::default(),
- borrowed_temporaries: <_>::default(),
- },
- }
- }
-
- fn consume_body(&mut self, fcx: &'_ FnCtxt<'_, 'tcx>, def_id: DefId, body: &'tcx Body<'tcx>) {
- // Run ExprUseVisitor to find where values are consumed.
- ExprUseVisitor::new(
- self,
- &fcx.infcx,
- def_id.expect_local(),
- fcx.param_env,
- &fcx.typeck_results.borrow(),
- )
- .consume_body(body);
- }
-
- fn mark_consumed(&mut self, consumer: HirId, target: TrackedValue) {
- self.places.consumed.entry(consumer).or_insert_with(|| <_>::default());
-
- debug!(?consumer, ?target, "mark_consumed");
- self.places.consumed.get_mut(&consumer).map(|places| places.insert(target));
- }
-
- fn borrow_place(&mut self, place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>) {
- self.places
- .borrowed
- .insert(TrackedValue::from_place_with_projections_allowed(place_with_id));
-
- // Ordinarily a value is consumed by it's parent, but in the special case of a
- // borrowed RValue, we create a reference that lives as long as the temporary scope
- // for that expression (typically, the innermost statement, but sometimes the enclosing
- // block). We record this fact here so that later in generator_interior
- // we can use the correct scope.
- //
- // We special case borrows through a dereference (`&*x`, `&mut *x` where `x` is
- // some rvalue expression), since these are essentially a copy of a pointer.
- // In other words, this borrow does not refer to the
- // temporary (`*x`), but to the referent (whatever `x` is a borrow of).
- //
- // We were considering that we might encounter problems down the line if somehow,
- // some part of the compiler were to look at this result and try to use it to
- // drive a borrowck-like analysis (this does not currently happen, as of this writing).
- // But even this should be fine, because the lifetime of the dereferenced reference
- // found in the rvalue is only significant as an intermediate 'link' to the value we
- // are producing, and we separately track whether that value is live over a yield.
- // Example:
- //
- // ```notrust
- // fn identity<T>(x: &mut T) -> &mut T { x }
- // let a: A = ...;
- // let y: &'y mut A = &mut *identity(&'a mut a);
- // ^^^^^^^^^^^^^^^^^^^^^^^^^ the borrow we are talking about
- // ```
- //
- // The expression `*identity(...)` is a deref of an rvalue,
- // where the `identity(...)` (the rvalue) produces a return type
- // of `&'rv mut A`, where `'a: 'rv`. We then assign this result to
- // `'y`, resulting in (transitively) `'a: 'y` (i.e., while `y` is in use,
- // `a` will be considered borrowed). Other parts of the code will ensure
- // that if `y` is live over a yield, `&'y mut A` appears in the generator
- // state. If `'y` is live, then any sound region analysis must conclude
- // that `'a` is also live. So if this causes a bug, blame some other
- // part of the code!
- let is_deref = place_with_id
- .place
- .projections
- .iter()
- .any(|Projection { kind, .. }| *kind == ProjectionKind::Deref);
-
- if let (false, PlaceBase::Rvalue) = (is_deref, place_with_id.place.base) {
- self.places.borrowed_temporaries.insert(place_with_id.hir_id);
- }
- }
-}
-
-impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
- fn consume(
- &mut self,
- place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
- diag_expr_id: HirId,
- ) {
- let hir = self.tcx.hir();
- let parent = match hir.opt_parent_id(place_with_id.hir_id) {
- Some(parent) => parent,
- None => place_with_id.hir_id,
- };
- debug!(
- "consume {:?}; diag_expr_id={}, using parent {}",
- place_with_id,
- hir.node_to_string(diag_expr_id),
- hir.node_to_string(parent)
- );
-
- if let Ok(tracked_value) = place_with_id.try_into() {
- self.mark_consumed(parent, tracked_value)
- }
- }
-
- fn borrow(
- &mut self,
- place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
- diag_expr_id: HirId,
- bk: rustc_middle::ty::BorrowKind,
- ) {
- debug!(
- "borrow: place_with_id = {place_with_id:#?}, diag_expr_id={diag_expr_id:#?}, \
- borrow_kind={bk:#?}"
- );
-
- self.borrow_place(place_with_id);
- }
-
- fn copy(
- &mut self,
- place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
- _diag_expr_id: HirId,
- ) {
- debug!("copy: place_with_id = {place_with_id:?}");
-
- self.places
- .borrowed
- .insert(TrackedValue::from_place_with_projections_allowed(place_with_id));
-
- // For copied we treat this mostly like a borrow except that we don't add the place
- // to borrowed_temporaries because the copy is consumed.
- }
-
- fn mutate(
- &mut self,
- assignee_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
- diag_expr_id: HirId,
- ) {
- debug!("mutate {assignee_place:?}; diag_expr_id={diag_expr_id:?}");
-
- if assignee_place.place.base == PlaceBase::Rvalue
- && assignee_place.place.projections.is_empty()
- {
- // Assigning to an Rvalue is illegal unless done through a dereference. We would have
- // already gotten a type error, so we will just return here.
- return;
- }
-
- // If the type being assigned needs dropped, then the mutation counts as a borrow
- // since it is essentially doing `Drop::drop(&mut x); x = new_value;`.
- let ty = self.tcx.erase_regions(assignee_place.place.base_ty);
- if ty.has_infer() {
- self.tcx.sess.delay_span_bug(
- self.tcx.hir().span(assignee_place.hir_id),
- format!("inference variables in {ty}"),
- );
- } else if ty.needs_drop(self.tcx, self.param_env) {
- self.places
- .borrowed
- .insert(TrackedValue::from_place_with_projections_allowed(assignee_place));
- }
- }
-
- fn bind(
- &mut self,
- binding_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
- diag_expr_id: HirId,
- ) {
- debug!("bind {binding_place:?}; diag_expr_id={diag_expr_id:?}");
- }
-
- fn fake_read(
- &mut self,
- place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
- cause: rustc_middle::mir::FakeReadCause,
- diag_expr_id: HirId,
- ) {
- debug!(
- "fake_read place_with_id={place_with_id:?}; cause={cause:?}; diag_expr_id={diag_expr_id:?}"
- );
-
- // fake reads happen in places like the scrutinee of a match expression.
- // we treat those as a borrow, much like a copy: the idea is that we are
- // transiently creating a `&T` ref that we can read from to observe the current
- // value (this `&T` is immediately dropped afterwards).
- self.borrow_place(place_with_id);
- }
-}