Skip to content

Commit 1b86ad8

Browse files
committed
Treat read of COpy types via refs as not move in move-closure
1 parent e39c3c0 commit 1b86ad8

File tree

3 files changed

+256
-35
lines changed

3 files changed

+256
-35
lines changed

compiler/rustc_typeck/src/check/upvar.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1116,14 +1116,21 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
11161116
place_with_id, diag_expr_id, mode
11171117
);
11181118

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

1123+
// We want to capture Copy types that read through a ref via a reborrow
1124+
(hir::CaptureBy::Value, euv::Copy)
1125+
if place_with_id.place.deref_tys().any(ty::TyS::is_ref) =>
1126+
{
1127+
return;
1128+
}
1129+
11241130
(hir::CaptureBy::Ref, euv::Move) | (hir::CaptureBy::Value, euv::Move | euv::Copy) => {}
11251131
};
11261132

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

11291136
if !self.capture_information.contains_key(&place) {

src/test/ui/closures/2229_closure_analysis/move_closure.rs

+81-12
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,25 @@
66
//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
77
#![feature(rustc_attrs)]
88

9-
// Test we truncate derefs properly
9+
fn simple_move_closure() {
10+
struct S(String);
11+
struct T(S);
12+
13+
let t = T(S("s".into()));
14+
let mut c = #[rustc_capture_analysis]
15+
//~^ ERROR: attributes on expressions are experimental
16+
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
17+
move || {
18+
//~^ ERROR: First Pass analysis includes:
19+
//~| ERROR: Min Capture analysis includes:
20+
t.0.0 = "new S".into();
21+
//~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue
22+
//~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue
23+
};
24+
c();
25+
}
26+
27+
// Test move closure use reborrows when using references
1028
fn simple_ref() {
1129
let mut s = 10;
1230
let ref_s = &mut s;
@@ -24,8 +42,8 @@ fn simple_ref() {
2442
c();
2543
}
2644

27-
// Test we truncate derefs properly
28-
fn struct_contains_ref_to_another_struct() {
45+
// Test move closure use reborrows when using references
46+
fn struct_contains_ref_to_another_struct_1() {
2947
struct S(String);
3048
struct T<'a>(&'a mut S);
3149

@@ -46,27 +64,78 @@ fn struct_contains_ref_to_another_struct() {
4664
c();
4765
}
4866

49-
// Test that we don't reduce precision when there is nothing deref.
50-
fn no_ref() {
67+
// Test that we can use reborrows to read data of Copy types
68+
// i.e. without truncating derefs
69+
fn struct_contains_ref_to_another_struct_2() {
70+
struct S(i32);
71+
struct T<'a>(&'a S);
72+
73+
let s = S(0);
74+
let t = T(&s);
75+
76+
let mut c = #[rustc_capture_analysis]
77+
//~^ ERROR: attributes on expressions are experimental
78+
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
79+
move || {
80+
//~^ ERROR: First Pass analysis includes:
81+
//~| ERROR: Min Capture analysis includes:
82+
let _t = t.0.0;
83+
//~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
84+
//~| NOTE: Min Capture t[(0, 0),Deref,(0, 0)] -> ImmBorrow
85+
};
86+
87+
c();
88+
}
89+
90+
// Test that we can use truncate to move out of !Copy types
91+
fn struct_contains_ref_to_another_struct_3() {
5192
struct S(String);
52-
struct T(S);
93+
struct T<'a>(&'a S);
94+
95+
let s = S("s".into());
96+
let t = T(&s);
5397

54-
let t = T(S("s".into()));
5598
let mut c = #[rustc_capture_analysis]
5699
//~^ ERROR: attributes on expressions are experimental
57100
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
58101
move || {
59102
//~^ ERROR: First Pass analysis includes:
60103
//~| ERROR: Min Capture analysis includes:
61-
t.0.0 = "new S".into();
62-
//~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue
63-
//~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue
104+
let _t = t.0.0;
105+
//~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow
106+
//~| NOTE: Capturing t[(0, 0)] -> ByValue
107+
//~| NOTE: Min Capture t[(0, 0)] -> ByValue
108+
};
109+
110+
c();
111+
}
112+
113+
// Test that derefs of box are truncated in move closures
114+
fn truncate_box_derefs() {
115+
struct S(i32);
116+
117+
let b = Box::new(S(10));
118+
119+
let c = #[rustc_capture_analysis]
120+
//~^ ERROR: attributes on expressions are experimental
121+
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
122+
move || {
123+
//~^ ERROR: First Pass analysis includes:
124+
//~| ERROR: Min Capture analysis includes:
125+
let _t = b.0;
126+
//~^ NOTE: Capturing b[Deref,(0, 0)] -> ByValue
127+
//~| NOTE: Capturing b[] -> ByValue
128+
//~| NOTE: Min Capture b[] -> ByValue
64129
};
130+
65131
c();
66132
}
67133

68134
fn main() {
135+
simple_move_closure();
69136
simple_ref();
70-
struct_contains_ref_to_another_struct();
71-
no_ref();
137+
struct_contains_ref_to_another_struct_1();
138+
struct_contains_ref_to_another_struct_2();
139+
struct_contains_ref_to_another_struct_3();
140+
truncate_box_derefs();
72141
}

0 commit comments

Comments
 (0)