https://gcc.gnu.org/g:93442d52b78f281a1a9764e86c387662de04c4d8

commit r17-3089-g93442d52b78f281a1a9764e86c387662de04c4d8
Author: Lishin <[email protected]>
Date:   Wed Jun 24 13:02:20 2026 +0000

    gccrs: Evaluate non-unit tail expressions before drops
    
    A non-unit tail call could run after local drops. Store the tail expression
    result before emitting drops, then return the stored value.
    
    gcc/rust/ChangeLog:
    
            * backend/rust-compile-base.cc
            (HIRCompileBase::compile_function_body): Store non-unit tail 
expression
            results before emitting current scope drops.
    
    gcc/testsuite/ChangeLog:
    
            * rust/execute/drop-function-scope-non-unit-tail.rs: New test.
    
    Signed-off-by: Lishin <[email protected]>

Diff:
---
 gcc/rust/backend/rust-compile-base.cc              | 22 ++++++++++-
 .../execute/drop-function-scope-non-unit-tail.rs   | 46 ++++++++++++++++++++++
 2 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/gcc/rust/backend/rust-compile-base.cc 
b/gcc/rust/backend/rust-compile-base.cc
index 1a6ce99f42f2..e049e18a4604 100644
--- a/gcc/rust/backend/rust-compile-base.cc
+++ b/gcc/rust/backend/rust-compile-base.cc
@@ -708,10 +708,30 @@ HIRCompileBase::compile_function_body (tree fndecl,
          return_value = coercion_site (id, return_value, actual, expected,
                                        lvalue_locus, rvalue_locus);
 
+         /* Save the non-unit tail expression result before emitting scope
+           drops, so a tail call like foo() is evaluated before locals are
+           dropped.  Conceptually, this changes lowering from:
+
+             drop (_x);
+             return foo ();
+
+           to:
+
+             ret_slot = foo ();
+             drop (_x);
+             return ret_slot; */
+         fncontext fnctx = ctx->peek_fn ();
+         tree result_reference
+           = Backend::var_expression (fnctx.ret_addr, lvalue_locus);
+         tree assignment = Backend::assignment_statement (result_reference,
+                                                          return_value, locus);
+         ctx->add_statement (assignment);
+
          CompileDrop (ctx).emit_current_scope_drop_calls ();
 
+         result_reference = Backend::var_expression (fnctx.ret_addr, locus);
          tree return_stmt
-           = Backend::return_statement (fndecl, return_value, locus);
+           = Backend::return_statement (fndecl, result_reference, locus);
          ctx->add_statement (return_stmt);
        }
       else
diff --git a/gcc/testsuite/rust/execute/drop-function-scope-non-unit-tail.rs 
b/gcc/testsuite/rust/execute/drop-function-scope-non-unit-tail.rs
new file mode 100644
index 000000000000..71df1615cbed
--- /dev/null
+++ b/gcc/testsuite/rust/execute/drop-function-scope-non-unit-tail.rs
@@ -0,0 +1,46 @@
+// { dg-output "f\r*\nd\r*\n" }
+// { dg-additional-options "-w" }
+#![feature(no_core)]
+#![feature(lang_items)]
+#![no_core]
+
+extern "C" {
+    fn printf(s: *const i8, ...);
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "drop"]
+pub trait Drop {
+    fn drop(&mut self);
+}
+
+struct Droppable;
+
+impl Drop for Droppable {
+    fn drop(&mut self) {
+        let msg = "d\n\0" as *const str as *const i8;
+        unsafe {
+            printf(msg);
+        }
+    }
+}
+
+fn foo() -> i32 {
+    let msg = "f\n\0" as *const str as *const i8;
+    unsafe {
+        printf(msg);
+    }
+
+    0
+}
+
+fn f() -> i32 {
+    let _x = Droppable;
+    foo()
+}
+
+fn main() -> i32 {
+    f()
+}

Reply via email to