Skip to content

Commit ab8aef4

Browse files
committed
Drop fully captured upvars in the same order as the regular drop code
Currently, with the new 2021 edition, if a closure captures all of the fields of an upvar, we'll drop those fields in the order they are used within the closure instead of the normal drop order (the definition order of the fields in the type). This changes that so we sort the captured fields by the definition order which causes them to drop in that same order as well. Fixes rust-lang/project-rfc-2229#42
1 parent 7a3e450 commit ab8aef4

File tree

3 files changed

+58
-18
lines changed

3 files changed

+58
-18
lines changed

compiler/rustc_typeck/src/check/upvar.rs

+41-1
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
602602
}
603603
}
604604

605-
debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list);
605+
debug!(
606+
"For closure={:?}, min_captures before sorting={:?}",
607+
closure_def_id, root_var_min_capture_list
608+
);
609+
610+
// Now that we have the minimized list of captures, sort the captures by field id.
611+
// This causes the closure to capture the upvars in the same order as the fields are
612+
// declared which is also the drop order. Thus, in situations where we capture all the
613+
// fields of some type, the obserable drop order will remain the same as it previously
614+
// was even though we're dropping each capture individually.
615+
// See https://github.com/rust-lang/project-rfc-2229/issues/42 and
616+
// `src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs`.
617+
for (_, captures) in &mut root_var_min_capture_list {
618+
captures.sort_by(|capture1, capture2| {
619+
for (p1, p2) in capture1.place.projections.iter().zip(&capture2.place.projections) {
620+
match (p1.kind, p2.kind) {
621+
// Paths are the same, continue to next loop.
622+
(ProjectionKind::Deref, ProjectionKind::Deref) => {}
623+
(ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _))
624+
if i1 == i2 => {}
625+
626+
// Fields are different, compare them.
627+
(ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) => {
628+
return i1.cmp(&i2);
629+
}
630+
631+
(l, r) => bug!("ProjectionKinds were different: ({:?}, {:?})", l, r),
632+
}
633+
}
634+
635+
unreachable!(
636+
"we captured two identical projections: capture1 = {:?}, capture2 = {:?}",
637+
capture1, capture2
638+
);
639+
});
640+
}
641+
642+
debug!(
643+
"For closure={:?}, min_captures after sorting={:#?}",
644+
closure_def_id, root_var_min_capture_list
645+
);
606646
typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list);
607647
}
608648

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

+16-16
Original file line numberDiff line numberDiff line change
@@ -136,26 +136,26 @@ LL | |
136136
LL | | };
137137
| |_____^
138138
|
139-
note: Min Capture a[(1, 0)] -> ImmBorrow
140-
--> $DIR/preserve_field_drop_order.rs:52:26
141-
|
142-
LL | println!("{:?}", a.1);
143-
| ^^^
144139
note: Min Capture a[(0, 0)] -> ImmBorrow
145140
--> $DIR/preserve_field_drop_order.rs:55:26
146141
|
147142
LL | println!("{:?}", a.0);
148143
| ^^^
149-
note: Min Capture b[(1, 0)] -> ImmBorrow
150-
--> $DIR/preserve_field_drop_order.rs:59:26
144+
note: Min Capture a[(1, 0)] -> ImmBorrow
145+
--> $DIR/preserve_field_drop_order.rs:52:26
151146
|
152-
LL | println!("{:?}", b.1);
147+
LL | println!("{:?}", a.1);
153148
| ^^^
154149
note: Min Capture b[(0, 0)] -> ImmBorrow
155150
--> $DIR/preserve_field_drop_order.rs:62:26
156151
|
157152
LL | println!("{:?}", b.0);
158153
| ^^^
154+
note: Min Capture b[(1, 0)] -> ImmBorrow
155+
--> $DIR/preserve_field_drop_order.rs:59:26
156+
|
157+
LL | println!("{:?}", b.1);
158+
| ^^^
159159

160160
error: First Pass analysis includes:
161161
--> $DIR/preserve_field_drop_order.rs:75:5
@@ -202,26 +202,26 @@ LL | |
202202
LL | | };
203203
| |_____^
204204
|
205-
note: Min Capture b[(1, 0)] -> ImmBorrow
206-
--> $DIR/preserve_field_drop_order.rs:78:26
207-
|
208-
LL | println!("{:?}", b.1);
209-
| ^^^
210205
note: Min Capture b[(0, 0)] -> ImmBorrow
211206
--> $DIR/preserve_field_drop_order.rs:88:26
212207
|
213208
LL | println!("{:?}", b.0);
214209
| ^^^
215-
note: Min Capture a[(1, 0)] -> ImmBorrow
216-
--> $DIR/preserve_field_drop_order.rs:81:26
210+
note: Min Capture b[(1, 0)] -> ImmBorrow
211+
--> $DIR/preserve_field_drop_order.rs:78:26
217212
|
218-
LL | println!("{:?}", a.1);
213+
LL | println!("{:?}", b.1);
219214
| ^^^
220215
note: Min Capture a[(0, 0)] -> ImmBorrow
221216
--> $DIR/preserve_field_drop_order.rs:84:26
222217
|
223218
LL | println!("{:?}", a.0);
224219
| ^^^
220+
note: Min Capture a[(1, 0)] -> ImmBorrow
221+
--> $DIR/preserve_field_drop_order.rs:81:26
222+
|
223+
LL | println!("{:?}", a.1);
224+
| ^^^
225225

226226
error: aborting due to 9 previous errors
227227

Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Dropable("y") Dropable("x")
2-
Dropping y
32
Dropping x
3+
Dropping y

0 commit comments

Comments
 (0)