[gccrs,COMMIT] gccrs: Evaluate non-unit tail expressions before drops

Message ID 20260708100250.3079-1-gerris.rs@gmail.com
State New
Headers
Series [gccrs,COMMIT] gccrs: Evaluate non-unit tail expressions before drops |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-arm-bootstrap fail Patch failed to apply
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed

Commit Message

gerris.rs@gmail.com July 8, 2026, 10:02 a.m. UTC
  From: Lishin <lishin1008@gmail.com>

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 <lishin1008@gmail.com>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: https://github.com/Rust-GCC/gccrs/commit/99edb212c204385d994c72b85e8098be6f464226

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4602

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


base-commit: 25ab7ba2877cec8bb831ddfeea9ecb72ef23c9d5
  

Patch

diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc
index 1a6ce99f4..e049e18a4 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 000000000..71df1615c
--- /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()
+}