Skip to content

Commit 57cb498

Browse files
committed
Generate the right MIR for by use closures
1 parent 81a926c commit 57cb498

File tree

10 files changed

+65
-47
lines changed

10 files changed

+65
-47
lines changed

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
10861086
);
10871087

10881088
match capture_info.capture_kind {
1089-
ty::UpvarCapture::ByValue => {
1089+
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
10901090
self.consume_or_copy(&place_with_id, place_with_id.hir_id);
10911091
}
10921092
ty::UpvarCapture::ByRef(upvar_borrow) => {

compiler/rustc_hir_typeck/src/upvar.rs

+29-9
Original file line numberDiff line numberDiff line change
@@ -670,9 +670,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
670670
origin = updated.1;
671671

672672
let (place, capture_kind) = match capture_clause {
673-
hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } => {
674-
adjust_for_move_closure(place, capture_kind)
675-
}
673+
hir::CaptureBy::Value { .. } => adjust_for_move_closure(place, capture_kind),
674+
hir::CaptureBy::Use { .. } => adjust_for_use_closure(place, capture_kind),
676675
hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
677676
};
678677

@@ -1307,7 +1306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13071306
for captured_place in root_var_min_capture_list.iter() {
13081307
match captured_place.info.capture_kind {
13091308
// Only care about captures that are moved into the closure
1310-
ty::UpvarCapture::ByValue => {
1309+
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
13111310
projections_list.push(captured_place.place.projections.as_slice());
13121311
diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise {
13131312
source_expr: captured_place.info.path_expr_id,
@@ -1931,7 +1930,7 @@ fn apply_capture_kind_on_capture_ty<'tcx>(
19311930
region: ty::Region<'tcx>,
19321931
) -> Ty<'tcx> {
19331932
match capture_kind {
1934-
ty::UpvarCapture::ByValue => ty,
1933+
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => ty,
19351934
ty::UpvarCapture::ByRef(kind) => Ty::new_ref(tcx, region, ty, kind.to_mutbl_lossy()),
19361935
}
19371936
}
@@ -2168,6 +2167,20 @@ fn adjust_for_move_closure(
21682167
(place, ty::UpvarCapture::ByValue)
21692168
}
21702169

2170+
/// Truncate deref of any reference.
2171+
fn adjust_for_use_closure(
2172+
mut place: Place<'_>,
2173+
mut kind: ty::UpvarCapture,
2174+
) -> (Place<'_>, ty::UpvarCapture) {
2175+
let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
2176+
2177+
if let Some(idx) = first_deref {
2178+
truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
2179+
}
2180+
2181+
(place, ty::UpvarCapture::ByUse)
2182+
}
2183+
21712184
/// Adjust closure capture just that if taking ownership of data, only move data
21722185
/// from enclosing stack frame.
21732186
fn adjust_for_non_move_closure(
@@ -2178,7 +2191,7 @@ fn adjust_for_non_move_closure(
21782191
place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
21792192

21802193
match kind {
2181-
ty::UpvarCapture::ByValue => {
2194+
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
21822195
if let Some(idx) = contains_deref {
21832196
truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
21842197
}
@@ -2223,6 +2236,7 @@ fn construct_capture_kind_reason_string<'tcx>(
22232236

22242237
let capture_kind_str = match capture_info.capture_kind {
22252238
ty::UpvarCapture::ByValue => "ByValue".into(),
2239+
ty::UpvarCapture::ByUse => "ByUse".into(),
22262240
ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"),
22272241
};
22282242

@@ -2244,6 +2258,7 @@ fn construct_capture_info_string<'tcx>(
22442258

22452259
let capture_kind_str = match capture_info.capture_kind {
22462260
ty::UpvarCapture::ByValue => "ByValue".into(),
2261+
ty::UpvarCapture::ByUse => "ByUse".into(),
22472262
ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"),
22482263
};
22492264
format!("{place_str} -> {capture_kind_str}")
@@ -2339,8 +2354,11 @@ fn determine_capture_info(
23392354
// expressions.
23402355
let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
23412356
(ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true,
2357+
(ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse) => true,
23422358
(ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b,
2343-
(ty::UpvarCapture::ByValue, _) | (ty::UpvarCapture::ByRef(_), _) => false,
2359+
(ty::UpvarCapture::ByValue, _)
2360+
| (ty::UpvarCapture::ByUse, _)
2361+
| (ty::UpvarCapture::ByRef(_), _) => false,
23442362
};
23452363

23462364
if eq_capture_kind {
@@ -2350,8 +2368,10 @@ fn determine_capture_info(
23502368
}
23512369
} else {
23522370
// We select the CaptureKind which ranks higher based the following priority order:
2353-
// ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow
2371+
// (ByUse | ByValue) > MutBorrow > UniqueImmBorrow > ImmBorrow
23542372
match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
2373+
(ty::UpvarCapture::ByUse, _) => capture_info_a,
2374+
(_, ty::UpvarCapture::ByUse) => capture_info_b,
23552375
(ty::UpvarCapture::ByValue, _) => capture_info_a,
23562376
(_, ty::UpvarCapture::ByValue) => capture_info_b,
23572377
(ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
@@ -2405,7 +2425,7 @@ fn truncate_place_to_len_and_update_capture_kind<'tcx>(
24052425
}
24062426

24072427
ty::UpvarCapture::ByRef(..) => {}
2408-
ty::UpvarCapture::ByValue => {}
2428+
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
24092429
}
24102430

24112431
place.projections.truncate(len);

compiler/rustc_middle/src/ty/closure.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ pub enum UpvarCapture {
5151
/// depending on inference.
5252
ByValue,
5353

54+
/// Upvar is captured by use. This is true when the closure is labeled `use`.
55+
ByUse,
56+
5457
/// Upvar is captured by reference.
5558
ByRef(BorrowKind),
5659
}
@@ -178,7 +181,7 @@ impl<'tcx> CapturedPlace<'tcx> {
178181

179182
pub fn is_by_ref(&self) -> bool {
180183
match self.info.capture_kind {
181-
ty::UpvarCapture::ByValue => false,
184+
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => false,
182185
ty::UpvarCapture::ByRef(..) => true,
183186
}
184187
}
@@ -214,7 +217,7 @@ impl<'tcx> TyCtxt<'tcx> {
214217
pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] {
215218
if !self.is_closure_like(def_id.to_def_id()) {
216219
return &[];
217-
};
220+
}
218221
self.closure_typeinfo(def_id).captures
219222
}
220223
}

compiler/rustc_mir_build/src/builder/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
3737
.map(|captured_place| {
3838
let name = captured_place.to_symbol();
3939
match captured_place.info.capture_kind {
40-
ty::UpvarCapture::ByValue => name,
40+
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => name,
4141
ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")),
4242
}
4343
})
@@ -871,7 +871,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
871871
let mut projs = closure_env_projs.clone();
872872
projs.push(ProjectionElem::Field(FieldIdx::new(i), ty));
873873
match capture {
874-
ty::UpvarCapture::ByValue => {}
874+
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
875875
ty::UpvarCapture::ByRef(..) => {
876876
projs.push(ProjectionElem::Deref);
877877
}

compiler/rustc_mir_build/src/thir/cx/expr.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
652652
}
653653
},
654654

655-
hir::ExprKind::Closure { .. } => {
655+
hir::ExprKind::Closure(hir::Closure { .. }) => {
656656
let closure_ty = self.typeck_results.expr_ty(expr);
657657
let (def_id, args, movability) = match *closure_ty.kind() {
658658
ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args), None),
@@ -1252,6 +1252,17 @@ impl<'tcx> ThirBuildCx<'tcx> {
12521252

12531253
match upvar_capture {
12541254
ty::UpvarCapture::ByValue => captured_place_expr,
1255+
ty::UpvarCapture::ByUse => {
1256+
let span = captured_place_expr.span;
1257+
let expr_id = self.thir.exprs.push(captured_place_expr);
1258+
1259+
Expr {
1260+
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
1261+
ty: upvar_ty,
1262+
span: closure_expr.span,
1263+
kind: ExprKind::ByUse { expr: expr_id, span },
1264+
}
1265+
}
12551266
ty::UpvarCapture::ByRef(upvar_borrow) => {
12561267
let borrow_kind = match upvar_borrow {
12571268
ty::BorrowKind::Immutable => BorrowKind::Shared,

compiler/rustc_mir_transform/src/coroutine/by_move_body.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
170170
// this when building the field projection in the MIR body later on.
171171
let mut parent_capture_ty = parent_capture.place.ty();
172172
parent_capture_ty = match parent_capture.info.capture_kind {
173-
ty::UpvarCapture::ByValue => parent_capture_ty,
173+
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => parent_capture_ty,
174174
ty::UpvarCapture::ByRef(kind) => Ty::new_ref(
175175
tcx,
176176
tcx.lifetimes.re_erased,

compiler/rustc_passes/src/liveness.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
706706
);
707707
self.acc(self.exit_ln, var, ACC_READ | ACC_USE);
708708
}
709-
ty::UpvarCapture::ByValue => {}
709+
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
710710
}
711711
}
712712
}
@@ -1500,7 +1500,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
15001500
for (&var_hir_id, min_capture_list) in closure_min_captures {
15011501
for captured_place in min_capture_list {
15021502
match captured_place.info.capture_kind {
1503-
ty::UpvarCapture::ByValue => {}
1503+
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
15041504
ty::UpvarCapture::ByRef(..) => continue,
15051505
};
15061506
let span = captured_place.get_capture_kind_span(self.ir.tcx);

tests/ui/ergonomic-clones/closure.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,27 @@
33

44
#![feature(ergonomic_clones)]
55

6-
fn ergonomic_clone_closure() -> i32 {
6+
fn ergonomic_clone_closure_no_captures() -> i32 {
77
let cl = use || {
88
1
99
};
1010
cl()
1111
}
1212

13+
fn ergonomic_clone_closure_with_captures() -> String {
14+
let s = String::from("hi");
15+
16+
let cl = use || {
17+
s
18+
};
19+
cl()
20+
}
21+
1322
fn ergonomic_clone_async_closures() -> String {
1423
let s = String::from("hi");
1524

1625
async use {
17-
22
26+
s
1827
};
1928

2029
s

tests/ui/feature-gates/feature-gate-ergonomic-clones.rs

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ fn ergonomic_closure_clone() {
1313

1414
let s3 = use || {
1515
//~^ ERROR `.use` calls are experimental [E0658]
16-
//~| ERROR use of moved value: `s1` [E0382]
1716
s1
1817
};
1918
}

tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr

+2-26
Original file line numberDiff line numberDiff line change
@@ -28,30 +28,6 @@ LL | let s3 = use || {
2828
= help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
2929
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
3030

31-
error[E0382]: use of moved value: `s1`
32-
--> $DIR/feature-gate-ergonomic-clones.rs:14:14
33-
|
34-
LL | let s1 = String::from("hi!");
35-
| -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
36-
LL |
37-
LL | let s2 = use || {
38-
| ------ value moved into closure here
39-
LL |
40-
LL | s1
41-
| -- variable moved due to use in closure
42-
...
43-
LL | let s3 = use || {
44-
| ^^^^^^ value used here after move
45-
...
46-
LL | s1
47-
| -- use occurs due to use in closure
48-
|
49-
help: consider cloning the value if the performance cost is acceptable
50-
|
51-
LL | s1.clone()
52-
| ++++++++
53-
54-
error: aborting due to 4 previous errors
31+
error: aborting due to 3 previous errors
5532

56-
Some errors have detailed explanations: E0382, E0658.
57-
For more information about an error, try `rustc --explain E0382`.
33+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)