Skip to content

Commit d37a07f

Browse files
committed
fixup! 2229: Capture box completely in move closures
fixup! 2229: Capture box completely in move closures
1 parent de2052a commit d37a07f

File tree

3 files changed

+36
-30
lines changed

3 files changed

+36
-30
lines changed

compiler/rustc_typeck/src/check/upvar.rs

+32-26
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
167167
);
168168
self.log_capture_analysis_first_pass(closure_def_id, &delegate.capture_information, span);
169169

170-
self.compute_min_captures(closure_def_id, delegate.capture_information);
170+
self.compute_min_captures(closure_def_id, capture_clause, delegate.capture_information);
171171

172172
let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
173173

@@ -200,7 +200,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
200200
}
201201

202202
// This will update the min captures based on this new fake information.
203-
self.compute_min_captures(closure_def_id, capture_information);
203+
self.compute_min_captures(closure_def_id, capture_clause, capture_information);
204204
}
205205

206206
if let Some(closure_substs) = infer_kind {
@@ -213,7 +213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
213213
// If we have an origin, store it.
214214
if let Some(origin) = delegate.current_origin.clone() {
215215
let origin = if enable_precise_capture(self.tcx, span) {
216-
(origin.0, restrict_capture_precision(origin.1))
216+
(origin.0, restrict_capture_precision(capture_clause, origin.1))
217217
} else {
218218
(origin.0, Place { projections: vec![], ..origin.1 })
219219
};
@@ -368,6 +368,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
368368
fn compute_min_captures(
369369
&self,
370370
closure_def_id: DefId,
371+
capture_clause: hir::CaptureBy,
371372
capture_information: InferredCaptureInformation<'tcx>,
372373
) {
373374
if capture_information.is_empty() {
@@ -385,7 +386,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
385386
base => bug!("Expected upvar, found={:?}", base),
386387
};
387388

388-
let place = restrict_capture_precision(place);
389+
let place = restrict_capture_precision(capture_clause, place);
389390

390391
let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
391392
None => {
@@ -1590,7 +1591,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
15901591
if let PlaceBase::Upvar(_) = place.base {
15911592
// We need to restrict Fake Read precision to avoid fake reading unsafe code,
15921593
// such as deref of a raw pointer.
1593-
let place = restrict_capture_precision(place);
1594+
let place = restrict_capture_precision(self.capture_clause, place);
15941595
let place =
15951596
restrict_repr_packed_field_ref_capture(self.fcx.tcx, self.fcx.param_env, &place);
15961597
self.fake_reads.push((place, cause, diag_expr_id));
@@ -1625,19 +1626,16 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
16251626
place_with_id, diag_expr_id, bk
16261627
);
16271628

1629+
// We only want repr packed restriction to be applied to reading references into a packed
1630+
// struct, and not when the data is being moved. There for we call this method here instead
1631+
// of in `restrict_capture_precision`.
16281632
let place = restrict_repr_packed_field_ref_capture(
16291633
self.fcx.tcx,
16301634
self.fcx.param_env,
16311635
&place_with_id.place,
16321636
);
16331637

1634-
let place = restrict_preicision_for_box(&place, self.capture_clause);
1635-
16361638
let place_with_id = PlaceWithHirId { place, ..*place_with_id };
1637-
debug!(
1638-
"borrow after restrictions:(place_with_id={:?}, diag_expr_id={:?}, bk={:?})",
1639-
place_with_id, diag_expr_id, bk
1640-
);
16411639

16421640
if !self.capture_information.contains_key(&place_with_id.place) {
16431641
self.init_capture_info_for_place(&place_with_id, diag_expr_id);
@@ -1661,39 +1659,46 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
16611659
}
16621660
}
16631661

1664-
// In case of move closures we don't want to capture derefs on a box.
1665-
// This is motivated by:
1666-
// 1. We only want to capture data that is on the stack
1667-
// 2. One motivatiton for the user to use a box might be to reduce the amount of data that gets
1668-
// moved (if size of pointer < size of data). We want to make sure that this optimization that
1669-
// the user made is respected.
1670-
fn restrict_preicision_for_box(place: &Place<'tcx>, capture_by: hir::CaptureBy) -> Place<'tcx> {
1671-
let mut rv = place.clone();
1672-
match capture_by {
1673-
hir::CaptureBy::Ref => rv,
1662+
/// Deref of a box isn't captured in move clousres. This is motivated by:
1663+
/// 1. We only want to capture data that is on the stack
1664+
/// 2. One motivation for the user to use a box might be to reduce the amount of data that gets
1665+
/// moved (if size of pointer < size of data). We want to make sure that this optimization that
1666+
/// the user made is respected.
1667+
fn restrict_precision_for_box<'tcx>(
1668+
capture_clause: hir::CaptureBy,
1669+
mut place: Place<'tcx>,
1670+
) -> Place<'tcx> {
1671+
match capture_clause {
1672+
hir::CaptureBy::Ref => {}
16741673
hir::CaptureBy::Value => {
16751674
if ty::TyS::is_box(place.base_ty) {
1676-
Place { projections: Vec::new(), ..rv }
1675+
place.projections.truncate(0);
16771676
} else {
16781677
// Either the box is the last access or there is a deref applied on the box
16791678
// In either case we want to stop at the box.
16801679
let pos = place.projections.iter().position(|proj| ty::TyS::is_box(proj.ty));
16811680
match pos {
1682-
None => rv,
1681+
None => {}
16831682
Some(idx) => {
1684-
Place { projections: rv.projections.drain(0..=idx).collect(), ..rv }
1683+
place.projections.truncate(idx + 1);
16851684
}
16861685
}
16871686
}
16881687
}
16891688
}
1689+
1690+
place
16901691
}
16911692

16921693
/// Truncate projections so that following rules are obeyed by the captured `place`:
16931694
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
16941695
/// them completely.
16951696
/// - No Index projections are captured, since arrays are captured completely.
1696-
fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
1697+
/// - Deref of a box isn't captured in move clousres.
1698+
fn restrict_capture_precision<'tcx>(
1699+
capture_clause: hir::CaptureBy,
1700+
mut place: Place<'tcx>,
1701+
) -> Place<'tcx> {
16971702
if place.projections.is_empty() {
16981703
// Nothing to do here
16991704
return place;
@@ -1728,7 +1733,8 @@ fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
17281733

17291734
place.projections.truncate(length);
17301735

1731-
place
1736+
// Dont't capture projections on top of a box in move closures.
1737+
restrict_precision_for_box(capture_clause, place)
17321738
}
17331739

17341740
/// Truncates a place so that the resultant capture doesn't move data out of a reference

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ fn truncate_box_derefs() {
141141
//~^ ERROR: First Pass analysis includes:
142142
//~| ERROR: Min Capture analysis includes:
143143
println!("{}", b.0);
144-
//~^ NOTE: Capturing b[] -> ByValue
144+
//~^ NOTE: Capturing b[Deref,(0, 0)] -> ByValue
145145
//~| NOTE: Min Capture b[] -> ByValue
146146
};
147147

@@ -158,7 +158,7 @@ fn truncate_box_derefs() {
158158
//~^ ERROR: First Pass analysis includes:
159159
//~| ERROR: Min Capture analysis includes:
160160
println!("{}", t.1.0);
161-
//~^ NOTE: Capturing t[(1, 0)] -> ByValue
161+
//~^ NOTE: Capturing t[(1, 0),Deref,(0, 0)] -> ByValue
162162
//~| NOTE: Min Capture t[(1, 0)] -> ByValue
163163
};
164164
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ LL | |
317317
LL | | };
318318
| |_____^
319319
|
320-
note: Capturing b[] -> ByValue
320+
note: Capturing b[Deref,(0, 0)] -> ByValue
321321
--> $DIR/move_closure.rs:143:24
322322
|
323323
LL | println!("{}", b.0);
@@ -353,7 +353,7 @@ LL | |
353353
LL | | };
354354
| |_____^
355355
|
356-
note: Capturing t[(1, 0)] -> ByValue
356+
note: Capturing t[(1, 0),Deref,(0, 0)] -> ByValue
357357
--> $DIR/move_closure.rs:160:24
358358
|
359359
LL | println!("{}", t.1.0);

0 commit comments

Comments
 (0)