[gcc r17-3089] gccrs: Evaluate non-unit tail expressions before drops

Arthur Cohen via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
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()
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.