--- /dev/null
+#![deny(disjoint_capture_drop_reorder)]
+//~^ NOTE: the lint level is defined here
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+struct ConstainsDropField(Foo, Foo);
+
+#[derive(Debug)]
+struct ContainsAndImplsDrop(Foo);
+impl Drop for ContainsAndImplsDrop {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+// Test that even if all paths starting at root variable that implement Drop are captured,
+// the lint is triggered if the root variable implements drop and isn't captured.
+fn test_precise_analysis_parent_root_impl_drop_not_captured() {
+ let t = ContainsAndImplsDrop(Foo(10));
+
+ let c = || {
+ //~^ERROR: drop order affected for closure because of `capture_disjoint_fields`
+ //~| NOTE: drop(&(t));
+ let _t = t.0;
+ };
+
+ c();
+}
+
+// Test that lint is triggered if a path that implements Drop is not captured by move
+fn test_precise_analysis_drop_paths_not_captured_by_move() {
+ let t = ConstainsDropField(Foo(10), Foo(20));
+
+ let c = || {
+ //~^ERROR: drop order affected for closure because of `capture_disjoint_fields`
+ //~| NOTE: drop(&(t));
+ let _t = t.0;
+ let _t = &t.1;
+ };
+
+ c();
+}
+
+struct S;
+impl Drop for S {
+ fn drop(&mut self) {
+ }
+}
+
+struct T(S, S);
+struct U(T, T);
+
+// Test precise analysis for the lint works with paths longer than one.
+fn test_precise_analysis_long_path_missing() {
+ let u = U(T(S, S), T(S, S));
+
+ let c = || {
+ //~^ERROR: drop order affected for closure because of `capture_disjoint_fields`
+ //~| NOTE: drop(&(u));
+ let _x = u.0.0;
+ let _x = u.0.1;
+ let _x = u.1.0;
+ };
+
+ c();
+}
+
+fn main() {
+ test_precise_analysis_parent_root_impl_drop_not_captured();
+ test_precise_analysis_drop_paths_not_captured_by_move();
+ test_precise_analysis_long_path_missing();
+}
--- /dev/null
+error: drop order affected for closure because of `capture_disjoint_fields`
+ --> $DIR/precise.rs:27:13
+ |
+LL | let c = || {
+ | _____________^
+LL | |
+LL | |
+LL | | let _t = t.0;
+LL | | };
+ | |_____^
+ |
+note: the lint level is defined here
+ --> $DIR/precise.rs:1:9
+ |
+LL | #![deny(disjoint_capture_drop_reorder)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: drop(&(t));
+
+error: drop order affected for closure because of `capture_disjoint_fields`
+ --> $DIR/precise.rs:40:13
+ |
+LL | let c = || {
+ | _____________^
+LL | |
+LL | |
+LL | | let _t = t.0;
+LL | | let _t = &t.1;
+LL | | };
+ | |_____^
+ |
+ = note: drop(&(t));
+
+error: drop order affected for closure because of `capture_disjoint_fields`
+ --> $DIR/precise.rs:63:13
+ |
+LL | let c = || {
+ | _____________^
+LL | |
+LL | |
+LL | | let _x = u.0.0;
+LL | | let _x = u.0.1;
+LL | | let _x = u.1.0;
+LL | | };
+ | |_____^
+ |
+ = note: drop(&(u));
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// run-pass
+
+#![deny(disjoint_capture_drop_reorder)]
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+struct ConstainsDropField(Foo, Foo);
+
+// Test that if all paths starting at root variable that implement Drop are captured
+// then it doesn't trigger the lint.
+fn test_precise_analysis_simple_1() {
+ let t = (Foo(10), Foo(20), Foo(30));
+
+ let c = || {
+ let _t = t.0;
+ let _t = t.1;
+ let _t = t.2;
+ };
+
+ c();
+}
+
+// Test that if all paths starting at root variable that implement Drop are captured
+// then it doesn't trigger the lint.
+fn test_precise_analysis_simple_2() {
+ let t = ConstainsDropField(Foo(10), Foo(20));
+
+ let c = || {
+ let _t = t.0;
+ let _t = t.1;
+ };
+
+ c();
+}
+
+#[derive(Debug)]
+struct ContainsAndImplsDrop(Foo);
+impl Drop for ContainsAndImplsDrop {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+// If a path isn't directly captured but requires Drop, then this tests that migrations aren't
+// needed if the a parent to that path is captured.
+fn test_precise_analysis_parent_captured_1() {
+ let t = ConstainsDropField(Foo(10), Foo(20));
+
+ let c = || {
+ let _t = t;
+ };
+
+ c();
+}
+
+// If a path isn't directly captured but requires Drop, then this tests that migrations aren't
+// needed if the a parent to that path is captured.
+fn test_precise_analysis_parent_captured_2() {
+ let t = ContainsAndImplsDrop(Foo(10));
+
+ let c = || {
+ let _t = t;
+ };
+
+ c();
+}
+
+struct S;
+impl Drop for S {
+ fn drop(&mut self) {
+ }
+}
+
+struct T(S, S);
+struct U(T, T);
+
+// Test that if the path is longer than just one element, precise analysis works correctly.
+fn test_precise_analysis_long_path() {
+ let u = U(T(S, S), T(S, S));
+
+ let c = || {
+ let _x = u.0.0;
+ let _x = u.0.1;
+ let _x = u.1.0;
+ let _x = u.1.1;
+ };
+
+ c();
+}
+
+fn main() {
+ test_precise_analysis_simple_1();
+ test_precise_analysis_simple_2();
+
+ test_precise_analysis_parent_captured_1();
+ test_precise_analysis_parent_captured_2();
+
+ test_precise_analysis_long_path();
+}