Skip to content

Commit

Permalink
Treat read of COpy types via refs as not move in move-closure
Browse files Browse the repository at this point in the history
  • Loading branch information
arora-aman committed Feb 16, 2021
1 parent e39c3c0 commit 1b86ad8
Show file tree
Hide file tree
Showing 3 changed files with 256 additions and 35 deletions.
9 changes: 8 additions & 1 deletion compiler/rustc_typeck/src/check/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1116,14 +1116,21 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
place_with_id, diag_expr_id, mode
);

let place = truncate_capture_for_move(place_with_id.place.clone());
match (self.capture_clause, mode) {
// In non-move closures, we only care about moves
(hir::CaptureBy::Ref, euv::Copy) => return,

// We want to capture Copy types that read through a ref via a reborrow
(hir::CaptureBy::Value, euv::Copy)
if place_with_id.place.deref_tys().any(ty::TyS::is_ref) =>
{
return;
}

(hir::CaptureBy::Ref, euv::Move) | (hir::CaptureBy::Value, euv::Move | euv::Copy) => {}
};

let place = truncate_capture_for_move(place_with_id.place.clone());
let place_with_id = PlaceWithHirId { place: place.clone(), hir_id: place_with_id.hir_id };

if !self.capture_information.contains_key(&place) {
Expand Down
93 changes: 81 additions & 12 deletions src/test/ui/closures/2229_closure_analysis/move_closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,25 @@
//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
#![feature(rustc_attrs)]

// Test we truncate derefs properly
fn simple_move_closure() {
struct S(String);
struct T(S);

let t = T(S("s".into()));
let mut c = #[rustc_capture_analysis]
//~^ ERROR: attributes on expressions are experimental
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
move || {
//~^ ERROR: First Pass analysis includes:
//~| ERROR: Min Capture analysis includes:
t.0.0 = "new S".into();
//~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue
//~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue
};
c();
}

// Test move closure use reborrows when using references
fn simple_ref() {
let mut s = 10;
let ref_s = &mut s;
Expand All @@ -24,8 +42,8 @@ fn simple_ref() {
c();
}

// Test we truncate derefs properly
fn struct_contains_ref_to_another_struct() {
// Test move closure use reborrows when using references
fn struct_contains_ref_to_another_struct_1() {
struct S(String);
struct T<'a>(&'a mut S);

Expand All @@ -46,27 +64,78 @@ fn struct_contains_ref_to_another_struct() {
c();
}

// Test that we don't reduce precision when there is nothing deref.
fn no_ref() {
// Test that we can use reborrows to read data of Copy types
// i.e. without truncating derefs
fn struct_contains_ref_to_another_struct_2() {
struct S(i32);
struct T<'a>(&'a S);

let s = S(0);
let t = T(&s);

let mut c = #[rustc_capture_analysis]
//~^ ERROR: attributes on expressions are experimental
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
move || {
//~^ ERROR: First Pass analysis includes:
//~| ERROR: Min Capture analysis includes:
let _t = t.0.0;
//~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
//~| NOTE: Min Capture t[(0, 0),Deref,(0, 0)] -> ImmBorrow
};

c();
}

// Test that we can use truncate to move out of !Copy types
fn struct_contains_ref_to_another_struct_3() {
struct S(String);
struct T(S);
struct T<'a>(&'a S);

let s = S("s".into());
let t = T(&s);

let t = T(S("s".into()));
let mut c = #[rustc_capture_analysis]
//~^ ERROR: attributes on expressions are experimental
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
move || {
//~^ ERROR: First Pass analysis includes:
//~| ERROR: Min Capture analysis includes:
t.0.0 = "new S".into();
//~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue
//~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue
let _t = t.0.0;
//~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
//~| NOTE: Capturing t[(0, 0)] -> ByValue
//~| NOTE: Min Capture t[(0, 0)] -> ByValue
};

c();
}

// Test that derefs of box are truncated in move closures
fn truncate_box_derefs() {
struct S(i32);

let b = Box::new(S(10));

let c = #[rustc_capture_analysis]
//~^ ERROR: attributes on expressions are experimental
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
move || {
//~^ ERROR: First Pass analysis includes:
//~| ERROR: Min Capture analysis includes:
let _t = b.0;
//~^ NOTE: Capturing b[Deref,(0, 0)] -> ByValue
//~| NOTE: Capturing b[] -> ByValue
//~| NOTE: Min Capture b[] -> ByValue
};

c();
}

fn main() {
simple_move_closure();
simple_ref();
struct_contains_ref_to_another_struct();
no_ref();
struct_contains_ref_to_another_struct_1();
struct_contains_ref_to_another_struct_2();
struct_contains_ref_to_another_struct_3();
truncate_box_derefs();
}
Loading

0 comments on commit 1b86ad8

Please sign in to comment.