summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-12-20 17:47:53 +0000
committerJosh Stone <jistone@redhat.com>2025-01-02 14:28:32 -0800
commit730b84074daddf85905b70f6df9ce438b02cdedc (patch)
treeee07ee380f85a4f6f839d236112415075e2ccbaa
parentf757f962962ce4ce2a004a6b32c7ec33996b5121 (diff)
downloadrust-730b84074daddf85905b70f6df9ce438b02cdedc.tar.gz
rust-730b84074daddf85905b70f6df9ce438b02cdedc.zip
Handle DropKind::ForLint in coroutines correctly
(cherry picked from commit 42d1a4c48bd2c914f30fc6e97f9a1beda0c97729)
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs20
-rw-r--r--tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.rs29
-rw-r--r--tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr52
3 files changed, 91 insertions, 10 deletions
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index e352db2585f..c2af064925c 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -1484,14 +1484,6 @@ fn build_scope_drops<'tcx>(
                 block = next;
             }
             DropKind::ForLint => {
-                // If the operand has been moved, and we are not on an unwind
-                // path, then don't generate the drop. (We only take this into
-                // account for non-unwind paths so as not to disturb the
-                // caching mechanism.)
-                if scope.moved_locals.iter().any(|&o| o == local) {
-                    continue;
-                }
-
                 // As in the `DropKind::Storage` case below:
                 // normally lint-related drops are not emitted for unwind,
                 // so we can just leave `unwind_to` unmodified, but in some
@@ -1503,6 +1495,14 @@ fn build_scope_drops<'tcx>(
                     unwind_to = unwind_drops.drops[unwind_to].next;
                 }
 
+                // If the operand has been moved, and we are not on an unwind
+                // path, then don't generate the drop. (We only take this into
+                // account for non-unwind paths so as not to disturb the
+                // caching mechanism.)
+                if scope.moved_locals.iter().any(|&o| o == local) {
+                    continue;
+                }
+
                 cfg.push(block, Statement {
                     source_info,
                     kind: StatementKind::BackwardIncompatibleDropHint {
@@ -1555,7 +1555,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
             let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1);
             for (drop_idx, drop_node) in drops.drops.iter_enumerated().skip(1) {
                 match drop_node.data.kind {
-                    DropKind::Storage => {
+                    DropKind::Storage | DropKind::ForLint => {
                         if is_coroutine {
                             let unwind_drop = self
                                 .scopes
@@ -1566,7 +1566,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
                             unwind_indices.push(unwind_indices[drop_node.next]);
                         }
                     }
-                    DropKind::Value | DropKind::ForLint => {
+                    DropKind::Value => {
                         let unwind_drop = self
                             .scopes
                             .unwind_drops
diff --git a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.rs b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.rs
new file mode 100644
index 00000000000..8d85cee19fd
--- /dev/null
+++ b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.rs
@@ -0,0 +1,29 @@
+//@ edition: 2021
+//@ build-fail
+
+// Make sure we don't ICE when emitting the "lint" drop statement
+// used for tail_expr_drop_order.
+
+#![deny(tail_expr_drop_order)]
+
+struct Drop;
+impl std::ops::Drop for Drop {
+    fn drop(&mut self) {}
+}
+
+async fn func() -> Result<(), Drop> {
+    todo!()
+}
+
+async fn retry_db() -> Result<(), Drop> {
+    loop {
+        match func().await {
+            //~^ ERROR relative drop order changing in Rust 2024
+            //~| WARNING this changes meaning in Rust 2024
+            Ok(()) => return Ok(()),
+            Err(e) => {}
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr
new file mode 100644
index 00000000000..37220c40b8b
--- /dev/null
+++ b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr
@@ -0,0 +1,52 @@
+error: relative drop order changing in Rust 2024
+  --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:20:15
+   |
+LL |         match func().await {
+   |               ^^^^^^^-----
+   |               |      |
+   |               |      this value will be stored in a temporary; let us call it `#1`
+   |               |      `#1` will be dropped later as of Edition 2024
+   |               this value will be stored in a temporary; let us call it `#2`
+   |               up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024
+...
+LL |             Err(e) => {}
+   |                 -
+   |                 |
+   |                 `e` calls a custom destructor
+   |                 `e` will be dropped later as of Edition 2024
+LL |         }
+LL |     }
+   |     - now the temporary value is dropped here, before the local variables in the block or statement
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#2` invokes this custom destructor
+  --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:10:1
+   |
+LL | / impl std::ops::Drop for Drop {
+LL | |     fn drop(&mut self) {}
+LL | | }
+   | |_^
+note: `#1` invokes this custom destructor
+  --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:10:1
+   |
+LL | / impl std::ops::Drop for Drop {
+LL | |     fn drop(&mut self) {}
+LL | | }
+   | |_^
+note: `e` invokes this custom destructor
+  --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:10:1
+   |
+LL | / impl std::ops::Drop for Drop {
+LL | |     fn drop(&mut self) {}
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+note: the lint level is defined here
+  --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:7:9
+   |
+LL | #![deny(tail_expr_drop_order)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+