From 7a3e450df45d2e40cff0ab6a4928084d6f61e993 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 23 Sep 2021 15:15:51 -0400 Subject: [PATCH 1/3] Add tests to verify the drop order of fields in fully captured upvars --- .../preserve_field_drop_order.rs | 98 ++++++++ .../preserve_field_drop_order.stderr | 228 ++++++++++++++++++ .../preserve_field_drop_order2.rs | 28 +++ ...eld_drop_order2.twenty_eighteen.run.stdout | 3 + ...ld_drop_order2.twenty_twentyone.run.stdout | 3 + 5 files changed, 360 insertions(+) create mode 100644 src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout create mode 100644 src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs new file mode 100644 index 0000000000000..ecc265208c56e --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs @@ -0,0 +1,98 @@ +// edition:2021 + +// Tests that in cases where we individually capture all the fields of a type, +// we still drop them in the order they would have been dropped in the 2018 edition. + +#![feature(rustc_attrs)] + +#[derive(Debug)] +struct HasDrop; +impl Drop for HasDrop { + fn drop(&mut self) { + println!("dropped"); + } +} + +fn test_one() { + let a = (HasDrop, HasDrop); + let b = (HasDrop, HasDrop); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + println!("{:?}", a.0); + //~^ NOTE: Capturing a[(0, 0)] -> ImmBorrow + //~| NOTE: Min Capture a[(0, 0)] -> ImmBorrow + println!("{:?}", a.1); + //~^ NOTE: Capturing a[(1, 0)] -> ImmBorrow + //~| NOTE: Min Capture a[(1, 0)] -> ImmBorrow + + println!("{:?}", b.0); + //~^ NOTE: Capturing b[(0, 0)] -> ImmBorrow + //~| NOTE: Min Capture b[(0, 0)] -> ImmBorrow + println!("{:?}", b.1); + //~^ NOTE: Capturing b[(1, 0)] -> ImmBorrow + //~| NOTE: Min Capture b[(1, 0)] -> ImmBorrow + }; +} + +fn test_two() { + let a = (HasDrop, HasDrop); + let b = (HasDrop, HasDrop); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + println!("{:?}", a.1); + //~^ NOTE: Capturing a[(1, 0)] -> ImmBorrow + //~| NOTE: Min Capture a[(1, 0)] -> ImmBorrow + println!("{:?}", a.0); + //~^ NOTE: Capturing a[(0, 0)] -> ImmBorrow + //~| NOTE: Min Capture a[(0, 0)] -> ImmBorrow + + println!("{:?}", b.1); + //~^ NOTE: Capturing b[(1, 0)] -> ImmBorrow + //~| NOTE: Min Capture b[(1, 0)] -> ImmBorrow + println!("{:?}", b.0); + //~^ NOTE: Capturing b[(0, 0)] -> ImmBorrow + //~| NOTE: Min Capture b[(0, 0)] -> ImmBorrow + }; +} + +fn test_three() { + let a = (HasDrop, HasDrop); + let b = (HasDrop, HasDrop); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + println!("{:?}", b.1); + //~^ NOTE: Capturing b[(1, 0)] -> ImmBorrow + //~| NOTE: Min Capture b[(1, 0)] -> ImmBorrow + println!("{:?}", a.1); + //~^ NOTE: Capturing a[(1, 0)] -> ImmBorrow + //~| NOTE: Min Capture a[(1, 0)] -> ImmBorrow + println!("{:?}", a.0); + //~^ NOTE: Capturing a[(0, 0)] -> ImmBorrow + //~| NOTE: Min Capture a[(0, 0)] -> ImmBorrow + + println!("{:?}", b.0); + //~^ NOTE: Capturing b[(0, 0)] -> ImmBorrow + //~| NOTE: Min Capture b[(0, 0)] -> ImmBorrow + }; +} + +fn main() { + test_one(); + test_two(); + test_three(); +} 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 new file mode 100644 index 0000000000000..7fdeab6a74d71 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr @@ -0,0 +1,228 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/preserve_field_drop_order.rs:20:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/preserve_field_drop_order.rs:46:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/preserve_field_drop_order.rs:72:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error: First Pass analysis includes: + --> $DIR/preserve_field_drop_order.rs:23:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", a.0); +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:26:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Capturing a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:29:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Capturing b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:33:26 + | +LL | println!("{:?}", b.0); + | ^^^ +note: Capturing b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:36:26 + | +LL | println!("{:?}", b.1); + | ^^^ + +error: Min Capture analysis includes: + --> $DIR/preserve_field_drop_order.rs:23:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", a.0); +... | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:26:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Min Capture a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:29:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Min Capture b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:33:26 + | +LL | println!("{:?}", b.0); + | ^^^ +note: Min Capture b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:36:26 + | +LL | println!("{:?}", b.1); + | ^^^ + +error: First Pass analysis includes: + --> $DIR/preserve_field_drop_order.rs:49:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", a.1); +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:52:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Capturing a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:55:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Capturing b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:59:26 + | +LL | println!("{:?}", b.1); + | ^^^ +note: Capturing b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:62:26 + | +LL | println!("{:?}", b.0); + | ^^^ + +error: Min Capture analysis includes: + --> $DIR/preserve_field_drop_order.rs:49:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", a.1); +... | +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 + | +LL | println!("{:?}", b.1); + | ^^^ +note: Min Capture b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:62:26 + | +LL | println!("{:?}", b.0); + | ^^^ + +error: First Pass analysis includes: + --> $DIR/preserve_field_drop_order.rs:75:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", b.1); +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:78:26 + | +LL | println!("{:?}", b.1); + | ^^^ +note: Capturing a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:81:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Capturing a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:84:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Capturing b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:88:26 + | +LL | println!("{:?}", b.0); + | ^^^ + +error: Min Capture analysis includes: + --> $DIR/preserve_field_drop_order.rs:75:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", b.1); +... | +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 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Min Capture a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:84:26 + | +LL | println!("{:?}", a.0); + | ^^^ + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs new file mode 100644 index 0000000000000..bc5c92122c6c8 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs @@ -0,0 +1,28 @@ +// run-pass +// check-run-results +// revisions: twenty_eighteen twenty_twentyone +// [twenty_eighteen]compile-flags: --edition 2018 +// [twenty_twentyone]compile-flags: --edition 2021 + +#[derive(Debug)] +struct Dropable(String); + +impl Drop for Dropable { + fn drop(&mut self) { + println!("Dropping {}", self.0) + } +} + +#[derive(Debug)] +struct A { + x: Dropable, + y: Dropable, +} + +fn main() { + let a = A { x: Dropable(format!("x")), y: Dropable(format!("y")) }; + + let c = move || println!("{:?} {:?}", a.y, a.x); + + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout new file mode 100644 index 0000000000000..e393169651817 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout @@ -0,0 +1,3 @@ +Dropable("y") Dropable("x") +Dropping x +Dropping y 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 new file mode 100644 index 0000000000000..90b1200fd08d1 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout @@ -0,0 +1,3 @@ +Dropable("y") Dropable("x") +Dropping y +Dropping x From ab8aef40b1e3a7151daebe7acea2c8b0117a8c9f Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 23 Sep 2021 16:36:49 -0400 Subject: [PATCH 2/3] 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 https://github.com/rust-lang/project-rfc-2229/issues/42 --- compiler/rustc_typeck/src/check/upvar.rs | 42 ++++++++++++++++++- .../preserve_field_drop_order.stderr | 32 +++++++------- ...ld_drop_order2.twenty_twentyone.run.stdout | 2 +- 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 53b99a14f379d..036e103738364 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 7fdeab6a74d71..559580ec05995 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 90b1200fd08d1..e393169651817 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 From 389365631d3e6d2f533f896635e7768f26359575 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 23 Sep 2021 22:15:12 -0400 Subject: [PATCH 3/3] Fix tidy and respond to some feedback --- compiler/rustc_typeck/src/check/upvar.rs | 33 ++++++++++++++++++- .../preserve_field_drop_order.rs | 2 +- .../preserve_field_drop_order2.rs | 2 +- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 036e103738364..917bf4ecd8c4a 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -617,6 +617,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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) { + // We do not need to look at the `Projection.ty` fields here because at each + // step of the iteration, the projections will either be the same and therefore + // the types must be as well or the current projection will be different and + // we will return the result of comparing the field indexes. match (p1.kind, p2.kind) { // Paths are the same, continue to next loop. (ProjectionKind::Deref, ProjectionKind::Deref) => {} @@ -628,7 +632,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return i1.cmp(&i2); } - (l, r) => bug!("ProjectionKinds were different: ({:?}, {:?})", l, r), + // We should have either a pair of `Deref`s or a pair of `Field`s. + // Anything else is a bug. + ( + l @ (ProjectionKind::Deref | ProjectionKind::Field(..)), + r @ (ProjectionKind::Deref | ProjectionKind::Field(..)), + ) => bug!( + "ProjectionKinds Deref and Field were mismatched: ({:?}, {:?})", + l, + r + ), + ( + l + @ + (ProjectionKind::Index + | ProjectionKind::Subslice + | ProjectionKind::Deref + | ProjectionKind::Field(..)), + r + @ + (ProjectionKind::Index + | ProjectionKind::Subslice + | ProjectionKind::Deref + | ProjectionKind::Field(..)), + ) => bug!( + "ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})", + l, + r + ), } } diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs index ecc265208c56e..ca3bfff2cf30a 100644 --- a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs @@ -94,5 +94,5 @@ fn test_three() { fn main() { test_one(); test_two(); - test_three(); + test_three(); } diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs index bc5c92122c6c8..3d39cb7ed481b 100644 --- a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs @@ -23,6 +23,6 @@ fn main() { let a = A { x: Dropable(format!("x")), y: Dropable(format!("y")) }; let c = move || println!("{:?} {:?}", a.y, a.x); - + c(); }