From: Lishin <[email protected]>
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]>
---
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
diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc
index 1a6ce99f42f..e049e18a460 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 00000000000..71df1615cbe
--- /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()
+}
--
2.50.1
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.