Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce drop range tracking to generator interior analysis #91032

Merged
merged 35 commits into from
Jan 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4be32f8
Add test case for #57478
eholk Oct 8, 2021
f712df8
Track drop points in generator_interior
eholk Oct 20, 2021
c4dee40
Track drops across multiple yields
eholk Oct 22, 2021
f664cfc
Make generator and async-await tests pass
eholk Oct 22, 2021
f246c0b
Attribute drop to parent expression of the consume point
eholk Oct 26, 2021
aa029d4
Support conditional drops
eholk Oct 28, 2021
9611770
Support reinitialization of variables
eholk Nov 3, 2021
298ca2f
Basic loop support
eholk Nov 4, 2021
4574152
Handle more cases with conditionally initialized/dropped values
eholk Nov 4, 2021
ba7d127
More tracing and tests
eholk Nov 5, 2021
ff0e8f4
Revamped DropRange data structure
eholk Nov 11, 2021
c7afaa1
Handle break and continue. Change fixpoint computation to handle unre…
eholk Nov 17, 2021
b39fb9b
Fix control flow handling in generator_interior
eholk Nov 18, 2021
904c270
More comments and small cleanups
eholk Nov 19, 2021
5feb4d0
Refactor code to keep most drop range analysis in drop_ranges.rs
eholk Nov 19, 2021
46760b4
Update async-fn-nonsend.stderr
eholk Nov 22, 2021
006f547
Add more comments
eholk Dec 6, 2021
30e1b1e
Address code review comments
eholk Dec 13, 2021
f5f98d7
Refactor drop_ranges
eholk Dec 13, 2021
9347bf4
Additional cleanup
eholk Dec 13, 2021
6a28afb
Fixing formatting
eholk Dec 14, 2021
7d82e4f
Update stderr files
eholk Dec 15, 2021
2af02cf
More comments and refactoring
eholk Dec 16, 2021
4a70de7
Handle reinits in match guards
eholk Dec 16, 2021
6e281a7
Explicitly list all ExprKinds in cfg_build
eholk Dec 16, 2021
a7df4e8
Handle empty loops better
eholk Dec 16, 2021
7d11b33
Remove clones and most allocations from propagate_to_fixpoint
eholk Dec 16, 2021
f730bd0
Track changed bitsets in CFG propagation
eholk Dec 17, 2021
787f4cb
Handle uninhabited return types
eholk Dec 17, 2021
887e843
Update async-fn-nonsend.rs
eholk Dec 17, 2021
78c5644
drop_ranges: Add TrackedValue enum
eholk Dec 20, 2021
32930d9
Safely handle partial drops
eholk Jan 5, 2022
e0a5370
Respond to code review comments
eholk Jan 15, 2022
d840d0c
Use .. patterns in cfg_build.rs
eholk Jan 18, 2022
76f6b57
Fix build after rebase
eholk Jan 18, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4388,13 +4388,15 @@ dependencies = [
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
"rustc_graphviz",
"rustc_hir",
"rustc_hir_pretty",
"rustc_index",
"rustc_infer",
"rustc_lint",
"rustc_macros",
"rustc_middle",
"rustc_serialize",
"rustc_session",
"rustc_span",
"rustc_target",
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/middle/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ pub struct ScopeTree {
/// The reason is that semantically, until the `box` expression returns,
/// the values are still owned by their containing expressions. So
/// we'll see that `&x`.
pub yield_in_scope: FxHashMap<Scope, YieldData>,
pub yield_in_scope: FxHashMap<Scope, Vec<YieldData>>,

/// The number of visit_expr and visit_pat calls done in the body.
/// Used to sanity check visit_expr/visit_pat call count when
Expand Down Expand Up @@ -423,8 +423,8 @@ impl ScopeTree {

/// Checks whether the given scope contains a `yield`. If so,
/// returns `Some(YieldData)`. If not, returns `None`.
pub fn yield_in_scope(&self, scope: Scope) -> Option<YieldData> {
self.yield_in_scope.get(&scope).cloned()
pub fn yield_in_scope(&self, scope: Scope) -> Option<&Vec<YieldData>> {
self.yield_in_scope.get(&scope)
}

/// Gives the number of expressions visited in a body.
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_passes/src/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
let target_scopes = visitor.fixup_scopes.drain(start_point..);

for scope in target_scopes {
let mut yield_data = visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap();
let mut yield_data =
visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap().last_mut().unwrap();
let count = yield_data.expr_and_pat_count;
let span = yield_data.span;

Expand Down Expand Up @@ -429,7 +430,13 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
};
let data =
YieldData { span, expr_and_pat_count: visitor.expr_and_pat_count, source: *source };
visitor.scope_tree.yield_in_scope.insert(scope, data);
match visitor.scope_tree.yield_in_scope.get_mut(&scope) {
Some(yields) => yields.push(data),
None => {
visitor.scope_tree.yield_in_scope.insert(scope, vec![data]);
}
}

if visitor.pessimistic_yield {
debug!("resolve_expr in pessimistic_yield - marking scope {:?} for fixup", scope);
visitor.fixup_scopes.push(scope);
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_typeck/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ rustc_middle = { path = "../rustc_middle" }
rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_graphviz = { path = "../rustc_graphviz" }
rustc_hir = { path = "../rustc_hir" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_target = { path = "../rustc_target" }
Expand All @@ -27,3 +28,4 @@ rustc_infer = { path = "../rustc_infer" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
rustc_lint = { path = "../rustc_lint" }
rustc_serialize = { path = "../rustc_serialize" }
48 changes: 30 additions & 18 deletions compiler/rustc_typeck/src/check/generator_interior.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! is calculated in `rustc_const_eval::transform::generator` and may be a subset of the
//! types computed here.

use self::drop_ranges::DropRanges;
use super::FnCtxt;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::pluralize;
Expand All @@ -19,6 +20,8 @@ use rustc_span::Span;
use smallvec::SmallVec;
use tracing::debug;

mod drop_ranges;

struct InteriorVisitor<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
Expand All @@ -34,6 +37,7 @@ struct InteriorVisitor<'a, 'tcx> {
guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>,
guard_bindings_set: HirIdSet,
linted_values: HirIdSet,
drop_ranges: DropRanges,
}

impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
Expand All @@ -48,9 +52,11 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
) {
use rustc_span::DUMMY_SP;

let ty = self.fcx.resolve_vars_if_possible(ty);

debug!(
"generator_interior: attempting to record type {:?} {:?} {:?} {:?}",
ty, scope, expr, source_span
"attempting to record type ty={:?}; hir_id={:?}; scope={:?}; expr={:?}; source_span={:?}; expr_count={:?}",
ty, hir_id, scope, expr, source_span, self.expr_count,
);

let live_across_yield = scope
Expand All @@ -63,29 +69,34 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
//
// See the mega-comment at `yield_in_scope` for a proof.

debug!(
"comparing counts yield: {} self: {}, source_span = {:?}",
yield_data.expr_and_pat_count, self.expr_count, source_span
);
yield_data
.iter()
.find(|yield_data| {
debug!(
"comparing counts yield: {} self: {}, source_span = {:?}",
yield_data.expr_and_pat_count, self.expr_count, source_span
);

if self.drop_ranges.is_dropped_at(hir_id, yield_data.expr_and_pat_count)
{
debug!("value is dropped at yield point; not recording");
return false;
}

// If it is a borrowing happening in the guard,
// it needs to be recorded regardless because they
// do live across this yield point.
if guard_borrowing_from_pattern
|| yield_data.expr_and_pat_count >= self.expr_count
{
Some(yield_data)
} else {
None
}
// If it is a borrowing happening in the guard,
// it needs to be recorded regardless because they
// do live across this yield point.
guard_borrowing_from_pattern
|| yield_data.expr_and_pat_count >= self.expr_count
})
.cloned()
})
})
.unwrap_or_else(|| {
Some(YieldData { span: DUMMY_SP, expr_and_pat_count: 0, source: self.kind.into() })
});

if let Some(yield_data) = live_across_yield {
let ty = self.fcx.resolve_vars_if_possible(ty);
debug!(
"type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
expr, scope, ty, self.expr_count, yield_data.span
Expand Down Expand Up @@ -154,7 +165,6 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
self.expr_count,
expr.map(|e| e.span)
);
let ty = self.fcx.resolve_vars_if_possible(ty);
if let Some((unresolved_type, unresolved_type_span)) =
self.fcx.unresolved_type_vars(&ty)
{
Expand Down Expand Up @@ -186,6 +196,7 @@ pub fn resolve_interior<'a, 'tcx>(
guard_bindings: <_>::default(),
guard_bindings_set: <_>::default(),
linted_values: <_>::default(),
drop_ranges: drop_ranges::compute_drop_ranges(fcx, def_id, body),
};
intravisit::walk_body(&mut visitor, body);

Expand Down Expand Up @@ -313,6 +324,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {

fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
let mut guard_borrowing_from_pattern = false;

match &expr.kind {
ExprKind::Call(callee, args) => match &callee.kind {
ExprKind::Path(qpath) => {
Expand Down
Loading