about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs42
-rw-r--r--src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr32
-rw-r--r--src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout2
3 files changed, 58 insertions, 18 deletions
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 53b99a14f37..036e1037383 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -602,7 +602,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
-        debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list);
+        debug!(
+            "For closure={:?}, min_captures before sorting={:?}",
+            closure_def_id, root_var_min_capture_list
+        );
+
+        // Now that we have the minimized list of captures, sort the captures by field id.
+        // This causes the closure to capture the upvars in the same order as the fields are
+        // declared which is also the drop order. Thus, in situations where we capture all the
+        // fields of some type, the obserable drop order will remain the same as it previously
+        // was even though we're dropping each capture individually.
+        // See https://github.com/rust-lang/project-rfc-2229/issues/42 and
+        // `src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs`.
+        for (_, captures) in &mut root_var_min_capture_list {
+            captures.sort_by(|capture1, capture2| {
+                for (p1, p2) in capture1.place.projections.iter().zip(&capture2.place.projections) {
+                    match (p1.kind, p2.kind) {
+                        // Paths are the same, continue to next loop.
+                        (ProjectionKind::Deref, ProjectionKind::Deref) => {}
+                        (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _))
+                            if i1 == i2 => {}
+
+                        // Fields are different, compare them.
+                        (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) => {
+                            return i1.cmp(&i2);
+                        }
+
+                        (l, r) => bug!("ProjectionKinds were different: ({:?}, {:?})", l, r),
+                    }
+                }
+
+                unreachable!(
+                    "we captured two identical projections: capture1 = {:?}, capture2 = {:?}",
+                    capture1, capture2
+                );
+            });
+        }
+
+        debug!(
+            "For closure={:?}, min_captures after sorting={:#?}",
+            closure_def_id, root_var_min_capture_list
+        );
         typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list);
     }
 
diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr
index 7fdeab6a74d..559580ec059 100644
--- a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr
@@ -136,26 +136,26 @@ LL | |
 LL | |     };
    | |_____^
    |
-note: Min Capture a[(1, 0)] -> ImmBorrow
-  --> $DIR/preserve_field_drop_order.rs:52:26
-   |
-LL |         println!("{:?}", a.1);
-   |                          ^^^
 note: Min Capture a[(0, 0)] -> ImmBorrow
   --> $DIR/preserve_field_drop_order.rs:55:26
    |
 LL |         println!("{:?}", a.0);
    |                          ^^^
-note: Min Capture b[(1, 0)] -> ImmBorrow
-  --> $DIR/preserve_field_drop_order.rs:59:26
+note: Min Capture a[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:52:26
    |
-LL |         println!("{:?}", b.1);
+LL |         println!("{:?}", a.1);
    |                          ^^^
 note: Min Capture b[(0, 0)] -> ImmBorrow
   --> $DIR/preserve_field_drop_order.rs:62:26
    |
 LL |         println!("{:?}", b.0);
    |                          ^^^
+note: Min Capture b[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:59:26
+   |
+LL |         println!("{:?}", b.1);
+   |                          ^^^
 
 error: First Pass analysis includes:
   --> $DIR/preserve_field_drop_order.rs:75:5
@@ -202,26 +202,26 @@ LL | |
 LL | |     };
    | |_____^
    |
-note: Min Capture b[(1, 0)] -> ImmBorrow
-  --> $DIR/preserve_field_drop_order.rs:78:26
-   |
-LL |         println!("{:?}", b.1);
-   |                          ^^^
 note: Min Capture b[(0, 0)] -> ImmBorrow
   --> $DIR/preserve_field_drop_order.rs:88:26
    |
 LL |         println!("{:?}", b.0);
    |                          ^^^
-note: Min Capture a[(1, 0)] -> ImmBorrow
-  --> $DIR/preserve_field_drop_order.rs:81:26
+note: Min Capture b[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:78:26
    |
-LL |         println!("{:?}", a.1);
+LL |         println!("{:?}", b.1);
    |                          ^^^
 note: Min Capture a[(0, 0)] -> ImmBorrow
   --> $DIR/preserve_field_drop_order.rs:84:26
    |
 LL |         println!("{:?}", a.0);
    |                          ^^^
+note: Min Capture a[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:81:26
+   |
+LL |         println!("{:?}", a.1);
+   |                          ^^^
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout
index 90b1200fd08..e3931696518 100644
--- a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout
+++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout
@@ -1,3 +1,3 @@
 Dropable("y") Dropable("x")
-Dropping y
 Dropping x
+Dropping y