mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-26 06:35:27 +00:00
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
@ -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.
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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
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…
Reference in New Issue
Block a user