try to fix issue 57017, but not quite there yet
Co-authored-by: Eric Holk <eric@theincredibleholk.org>
This commit is contained in:
parent
d137c3a7bd
commit
60f5cad6eb
5 changed files with 70 additions and 9 deletions
|
@ -13,7 +13,7 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::hir_id::HirIdSet;
|
use rustc_hir::hir_id::HirIdSet;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
|
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_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -369,7 +369,17 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
self.expr_count += 1;
|
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 --
|
// If there are adjustments, then record the final type --
|
||||||
// this is the actual value that is being produced.
|
// this is the actual value that is being produced.
|
||||||
|
|
|
@ -18,6 +18,7 @@ use crate::check::FnCtxt;
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use hir::{Body, HirId, HirIdMap, Node};
|
use hir::{Body, HirId, HirIdMap, Node};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_data_structures::stable_set::FxHashSet;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_index::bit_set::BitSet;
|
use rustc_index::bit_set::BitSet;
|
||||||
use rustc_index::vec::IndexVec;
|
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 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 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.hir(),
|
||||||
fcx.tcx,
|
fcx.tcx,
|
||||||
&fcx.typeck_results.borrow(),
|
&fcx.typeck_results.borrow(),
|
||||||
|
@ -52,11 +53,20 @@ pub fn compute_drop_ranges<'a, 'tcx>(
|
||||||
|
|
||||||
drop_ranges.propagate_to_fixpoint();
|
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 {
|
} else {
|
||||||
// If drop range tracking is not enabled, skip all the analysis and produce an
|
// If drop range tracking is not enabled, skip all the analysis and produce an
|
||||||
// empty set of DropRanges.
|
// 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 {
|
pub struct DropRanges {
|
||||||
tracked_value_map: FxHashMap<TrackedValue, TrackedValueIndex>,
|
tracked_value_map: FxHashMap<TrackedValue, TrackedValueIndex>,
|
||||||
nodes: IndexVec<PostOrderId, NodeInfo>,
|
nodes: IndexVec<PostOrderId, NodeInfo>,
|
||||||
|
borrowed_temporaries: Option<FxHashSet<HirId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DropRanges {
|
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
|
/// Returns a reference to the NodeInfo for a node, panicking if it does not exist
|
||||||
fn expect_node(&self, id: PostOrderId) -> &NodeInfo {
|
fn expect_node(&self, id: PostOrderId) -> &NodeInfo {
|
||||||
&self.nodes[id]
|
&self.nodes[id]
|
||||||
|
|
|
@ -6,7 +6,7 @@ use hir::{
|
||||||
intravisit::{self, Visitor},
|
intravisit::{self, Visitor},
|
||||||
Body, Expr, ExprKind, Guard, HirId, LoopIdError,
|
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_hir as hir;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_middle::{
|
use rustc_middle::{
|
||||||
|
@ -27,14 +27,14 @@ pub(super) fn build_control_flow_graph<'tcx>(
|
||||||
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
|
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
|
||||||
body: &'tcx Body<'tcx>,
|
body: &'tcx Body<'tcx>,
|
||||||
num_exprs: usize,
|
num_exprs: usize,
|
||||||
) -> DropRangesBuilder {
|
) -> (DropRangesBuilder, FxHashSet<HirId>) {
|
||||||
let mut drop_range_visitor =
|
let mut drop_range_visitor =
|
||||||
DropRangeVisitor::new(hir, tcx, typeck_results, consumed_borrowed_places, num_exprs);
|
DropRangeVisitor::new(hir, tcx, typeck_results, consumed_borrowed_places, num_exprs);
|
||||||
intravisit::walk_body(&mut drop_range_visitor, body);
|
intravisit::walk_body(&mut drop_range_visitor, body);
|
||||||
|
|
||||||
drop_range_visitor.drop_ranges.process_deferred_edges();
|
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
|
/// This struct is used to gather the information for `DropRanges` to determine the regions of the
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
use hir::{def_id::DefId, Body, HirId, HirIdMap};
|
use hir::{def_id::DefId, Body, HirId, HirIdMap};
|
||||||
use rustc_data_structures::stable_set::FxHashSet;
|
use rustc_data_structures::stable_set::FxHashSet;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_middle::hir::place::PlaceBase;
|
||||||
use rustc_middle::ty::{ParamEnv, TyCtxt};
|
use rustc_middle::ty::{ParamEnv, TyCtxt};
|
||||||
|
|
||||||
pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
|
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
|
/// 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`.
|
/// not considered a drop of `x`, although it would be a drop of `x.y`.
|
||||||
pub(super) consumed: HirIdMap<FxHashSet<TrackedValue>>,
|
pub(super) consumed: HirIdMap<FxHashSet<TrackedValue>>,
|
||||||
|
|
||||||
/// A set of hir-ids of values or variables that are borrowed at some point within the body.
|
/// A set of hir-ids of values or variables that are borrowed at some point within the body.
|
||||||
pub(super) borrowed: FxHashSet<TrackedValue>,
|
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.
|
/// Works with ExprUseVisitor to find interesting values for the drop range analysis.
|
||||||
|
@ -49,6 +54,7 @@ impl<'tcx> ExprUseDelegate<'tcx> {
|
||||||
places: ConsumedAndBorrowedPlaces {
|
places: ConsumedAndBorrowedPlaces {
|
||||||
consumed: <_>::default(),
|
consumed: <_>::default(),
|
||||||
borrowed: <_>::default(),
|
borrowed: <_>::default(),
|
||||||
|
borrowed_temporaries: <_>::default(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,10 +104,19 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
|
||||||
diag_expr_id: HirId,
|
diag_expr_id: HirId,
|
||||||
_bk: rustc_middle::ty::BorrowKind,
|
_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
|
self.places
|
||||||
.borrowed
|
.borrowed
|
||||||
.insert(TrackedValue::from_place_with_projections_allowed(place_with_id));
|
.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(
|
fn mutate(
|
||||||
|
|
21
foo.rs
Normal file
21
foo.rs
Normal 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);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue