Skip to content

Commit

Permalink
Auto merge of #89648 - nbdd0121:issue-89606, r=nikomatsakis
Browse files Browse the repository at this point in the history
Ignore type of projections for upvar capturing

Fix #89606

Ignore type of projections for upvar capturing. Originally HashMap is used, and the hash/eq implementation of Place takes the type of projections into account. These types may differ by lifetime which causes #89606 to ICE.

I originally considered erasing regions but `place.ty()` is used when creating upvar tuple type, more than just serving as a key type, so I switched to a linear comparison with custom eq (`compare_place_ignore_ty`) instead.

r? `@wesleywiser`

`@rustbot` label +T-compiler
  • Loading branch information
bors committed Oct 11, 2021
2 parents 5b21064 + 7275cfa commit 7cc8c44
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 6 deletions.
15 changes: 9 additions & 6 deletions compiler/rustc_typeck/src/check/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ use std::iter;
enum PlaceAncestryRelation {
Ancestor,
Descendant,
SamePlace,
Divergent,
}

Expand Down Expand Up @@ -564,7 +565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for possible_ancestor in min_cap_list.iter_mut() {
match determine_place_ancestry_relation(&place, &possible_ancestor.place) {
// current place is descendant of possible_ancestor
PlaceAncestryRelation::Descendant => {
PlaceAncestryRelation::Descendant | PlaceAncestryRelation::SamePlace => {
ancestor_found = true;
let backup_path_expr_id = possible_ancestor.info.path_expr_id;

Expand Down Expand Up @@ -2278,15 +2279,17 @@ fn determine_place_ancestry_relation(
let projections_b = &place_b.projections;

let same_initial_projections =
iter::zip(projections_a, projections_b).all(|(proj_a, proj_b)| proj_a == proj_b);
iter::zip(projections_a, projections_b).all(|(proj_a, proj_b)| proj_a.kind == proj_b.kind);

if same_initial_projections {
use std::cmp::Ordering;

// First min(n, m) projections are the same
// Select Ancestor/Descendant
if projections_b.len() >= projections_a.len() {
PlaceAncestryRelation::Ancestor
} else {
PlaceAncestryRelation::Descendant
match projections_b.len().cmp(&projections_a.len()) {
Ordering::Greater => PlaceAncestryRelation::Ancestor,
Ordering::Equal => PlaceAncestryRelation::SamePlace,
Ordering::Less => PlaceAncestryRelation::Descendant,
}
} else {
PlaceAncestryRelation::Divergent
Expand Down
40 changes: 40 additions & 0 deletions src/test/ui/closures/2229_closure_analysis/issue-89606.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Regression test for #89606. Used to ICE.
//
// check-pass
// revisions: twenty_eighteen twenty_twentyone
// [twenty_eighteen]compile-flags: --edition 2018
// [twenty_twentyone]compile-flags: --edition 2021

struct S<'a>(Option<&'a mut i32>);

fn by_ref(s: &mut S<'_>) {
(|| {
let S(_o) = s;
s.0 = None;
})();
}

fn by_value(s: S<'_>) {
(|| {
let S(ref _o) = s;
let _g = s.0;
})();
}

struct V<'a>((Option<&'a mut i32>,));

fn nested(v: &mut V<'_>) {
(|| {
let V((_o,)) = v;
v.0 = (None, );
})();
}

fn main() {
let mut s = S(None);
by_ref(&mut s);
by_value(s);

let mut v = V((None, ));
nested(&mut v);
}

0 comments on commit 7cc8c44

Please sign in to comment.