try to fix issue 57017, but not quite there yet

Co-authored-by: Eric Holk <eric@theincredibleholk.org>
This commit is contained in:
Niko Matsakis 2022-02-18 17:06:48 -05:00 committed by Eric Holk
parent d137c3a7bd
commit 60f5cad6eb
5 changed files with 70 additions and 9 deletions

View File

@ -13,7 +13,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
use rustc_middle::middle::region::{self, YieldData};
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::symbol::sym;
use rustc_span::Span;
@ -369,7 +369,17 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
self.expr_count += 1;
let scope = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
debug!("is_borrowed_temporary: {:?}", self.drop_ranges.is_borrowed_temporary(expr));
let scope = if self.drop_ranges.is_borrowed_temporary(expr) {
self.region_scope_tree.temporary_scope(expr.hir_id.local_id)
} else {
debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id));
match self.fcx.tcx.hir().find_parent_node(expr.hir_id) {
Some(parent) => Some(Scope { id: parent.local_id, data: ScopeData::Node }),
None => self.region_scope_tree.temporary_scope(expr.hir_id.local_id),
}
};
// If there are adjustments, then record the final type --
// this is the actual value that is being produced.

View File

@ -18,6 +18,7 @@ use crate::check::FnCtxt;
use hir::def_id::DefId;
use hir::{Body, HirId, HirIdMap, Node};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_set::FxHashSet;
use rustc_hir as hir;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
@ -41,7 +42,7 @@ pub fn compute_drop_ranges<'a, 'tcx>(
let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body);
let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
let mut drop_ranges = build_control_flow_graph(
let (mut drop_ranges, borrowed_temporaries) = build_control_flow_graph(
fcx.tcx.hir(),
fcx.tcx,
&fcx.typeck_results.borrow(),
@ -52,11 +53,20 @@ pub fn compute_drop_ranges<'a, 'tcx>(
drop_ranges.propagate_to_fixpoint();
DropRanges { tracked_value_map: drop_ranges.tracked_value_map, nodes: drop_ranges.nodes }
debug!("borrowed_temporaries = {borrowed_temporaries:?}");
DropRanges {
tracked_value_map: drop_ranges.tracked_value_map,
nodes: drop_ranges.nodes,
borrowed_temporaries: Some(borrowed_temporaries),
}
} else {
// If drop range tracking is not enabled, skip all the analysis and produce an
// empty set of DropRanges.
DropRanges { tracked_value_map: FxHashMap::default(), nodes: IndexVec::new() }
DropRanges {
tracked_value_map: FxHashMap::default(),
nodes: IndexVec::new(),
borrowed_temporaries: None,
}
}
}
@ -161,6 +171,7 @@ impl TryFrom<&PlaceWithHirId<'_>> for TrackedValue {
pub struct DropRanges {
tracked_value_map: FxHashMap<TrackedValue, TrackedValueIndex>,
nodes: IndexVec<PostOrderId, NodeInfo>,
borrowed_temporaries: Option<FxHashSet<HirId>>,
}
impl DropRanges {
@ -174,6 +185,10 @@ impl DropRanges {
})
}
pub fn is_borrowed_temporary(&self, expr: &hir::Expr<'_>) -> bool {
if let Some(b) = &self.borrowed_temporaries { b.contains(&expr.hir_id) } else { true }
}
/// Returns a reference to the NodeInfo for a node, panicking if it does not exist
fn expect_node(&self, id: PostOrderId) -> &NodeInfo {
&self.nodes[id]

View File

@ -6,7 +6,7 @@ use hir::{
intravisit::{self, Visitor},
Body, Expr, ExprKind, Guard, HirId, LoopIdError,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet};
use rustc_hir as hir;
use rustc_index::vec::IndexVec;
use rustc_middle::{
@ -27,14 +27,14 @@ pub(super) fn build_control_flow_graph<'tcx>(
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
body: &'tcx Body<'tcx>,
num_exprs: usize,
) -> DropRangesBuilder {
) -> (DropRangesBuilder, FxHashSet<HirId>) {
let mut drop_range_visitor =
DropRangeVisitor::new(hir, tcx, typeck_results, consumed_borrowed_places, num_exprs);
intravisit::walk_body(&mut drop_range_visitor, body);
drop_range_visitor.drop_ranges.process_deferred_edges();
drop_range_visitor.drop_ranges
(drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
}
/// This struct is used to gather the information for `DropRanges` to determine the regions of the

View File

@ -6,6 +6,7 @@ use crate::{
use hir::{def_id::DefId, Body, HirId, HirIdMap};
use rustc_data_structures::stable_set::FxHashSet;
use rustc_hir as hir;
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::ty::{ParamEnv, TyCtxt};
pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
@ -27,8 +28,12 @@ pub(super) struct ConsumedAndBorrowedPlaces {
/// 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<FxHashSet<TrackedValue>>,
/// A set of hir-ids of values or variables that are borrowed at some point within the body.
pub(super) borrowed: FxHashSet<TrackedValue>,
/// A set of hir-ids of values or variables that are borrowed at some point within the body.
pub(super) borrowed_temporaries: FxHashSet<HirId>,
}
/// Works with ExprUseVisitor to find interesting values for the drop range analysis.
@ -49,6 +54,7 @@ impl<'tcx> ExprUseDelegate<'tcx> {
places: ConsumedAndBorrowedPlaces {
consumed: <_>::default(),
borrowed: <_>::default(),
borrowed_temporaries: <_>::default(),
},
}
}
@ -98,10 +104,19 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
diag_expr_id: HirId,
_bk: rustc_middle::ty::BorrowKind,
) {
debug!("borrow {:?}; diag_expr_id={:?}", place_with_id, diag_expr_id);
debug!("borrow: place_with_id = {place_with_id:?}, diag_expr_id={diag_expr_id:?}");
self.places
.borrowed
.insert(TrackedValue::from_place_with_projections_allowed(place_with_id));
// XXX -- we need to distinguish "consuming a copy" from other borrows
//
// XXX -- we need to distinguish `&*E` where `E: &T` which is not creating a temporary
// even though the place-base E is an rvalue
if let PlaceBase::Rvalue = place_with_id.place.base {
self.places.borrowed_temporaries.insert(place_with_id.hir_id);
}
}
fn mutate(

21
foo.rs Normal file
View File

@ -0,0 +1,21 @@
// check-pass
#![feature(generators, negative_impls)]
struct Client;
impl !Sync for Client {}
fn status(_client_status: &Client) -> i16 {
200
}
fn assert_send<T: Send>(_thing: T) {}
// This is the same bug as issue 57017, but using yield instead of await
fn main() {
let client = Client;
let g = move || match status(&client) {
_status => yield,
};
assert_send(g);
}