From: Lishin <[email protected]>

Add the missing drop emission before returning from explicit return expressions.

Explicit returns can leave more than the current block scope, so emit drops for
all active block scopes before the return statement.

When the explicit return has a value, save it before running drops. When a
unit return has an explicit expression, emit that expression before running
drops and returning unit.

The new test covers `return;`, `return make_unit();`, `return make_value();`,
and nested explicit returns.

gcc/rust/ChangeLog:

        * backend/rust-compile-drop-builder.cc
        (DropBuilder::get_block_drop_candidate_stack): New function returning 
all
        active block drop candidate scopes.
        * backend/rust-compile-drop-builder.h
        (DropBuilder::get_block_drop_candidate_stack): Declare.
        * backend/rust-compile-drop.h:
        (CompileDrop::emit_drop_candidate_calls): Declare.
        * backend/rust-compile-expr.cc (CompileExpr::visit): Save return values 
and
        emit drops before explicit return statements.

gcc/testsuite/ChangeLog:

        * rust/execute/drop-explicit-return.rs: New test.

Signed-off-by: Lishin <[email protected]>
---
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/4b316571b59a9956c614e5f706e48ed5cbb0fbd4

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/4621

 gcc/rust/backend/rust-compile-drop-builder.cc |   7 ++
 gcc/rust/backend/rust-compile-drop-builder.h  |   2 +
 gcc/rust/backend/rust-compile-drop.h          |   3 +
 gcc/rust/backend/rust-compile-expr.cc         |  24 ++++
 .../rust/execute/drop-explicit-return.rs      | 105 ++++++++++++++++++
 5 files changed, 141 insertions(+)
 create mode 100644 gcc/testsuite/rust/execute/drop-explicit-return.rs

diff --git a/gcc/rust/backend/rust-compile-drop-builder.cc 
b/gcc/rust/backend/rust-compile-drop-builder.cc
index e0947a787..fb01fc3db 100644
--- a/gcc/rust/backend/rust-compile-drop-builder.cc
+++ b/gcc/rust/backend/rust-compile-drop-builder.cc
@@ -38,5 +38,12 @@ DropBuilder::peek_block_drop_candidates ()
   return ctx.block_drop_candidates.back ();
 }
 
+const std::vector<std::vector<DropCandidate>> &
+DropBuilder::get_block_drop_candidate_stack () const
+{
+  rust_assert (!ctx.block_drop_candidates.empty ());
+  return ctx.block_drop_candidates;
+}
+
 } // namespace Compile
 } // namespace Rust
\ No newline at end of file
diff --git a/gcc/rust/backend/rust-compile-drop-builder.h 
b/gcc/rust/backend/rust-compile-drop-builder.h
index 36e3cdc1e..ca6601705 100644
--- a/gcc/rust/backend/rust-compile-drop-builder.h
+++ b/gcc/rust/backend/rust-compile-drop-builder.h
@@ -33,6 +33,8 @@ public:
 
   void note_simple_drop_candidate (HirId hirid, location_t locus);
   std::vector<DropCandidate> &peek_block_drop_candidates ();
+  const std::vector<std::vector<DropCandidate>> &
+  get_block_drop_candidate_stack () const;
 
 private:
   Context &ctx;
diff --git a/gcc/rust/backend/rust-compile-drop.h 
b/gcc/rust/backend/rust-compile-drop.h
index f270356e1..523421463 100644
--- a/gcc/rust/backend/rust-compile-drop.h
+++ b/gcc/rust/backend/rust-compile-drop.h
@@ -36,6 +36,9 @@ public:
 private:
   tree compile_drop_call (Bvariable *var, TyTy::BaseType *ty, location_t 
locus);
 
+  void
+  emit_drop_candidate_calls (const std::vector<DropCandidate> 
&drop_candidates);
+
   Context *ctx;
 };
 
diff --git a/gcc/rust/backend/rust-compile-expr.cc 
b/gcc/rust/backend/rust-compile-expr.cc
index c0d4ab0a0..b76f1bcc2 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -272,6 +272,30 @@ CompileExpr::visit (HIR::ReturnExpr &expr)
                                    lvalue_locus, rvalue_locus);
     }
 
+  if (fncontext.retty->is_unit ())
+    {
+      if (expr.has_return_expr ())
+       {
+         ctx->add_statement (return_value);
+         return_value = unit_expression (expr.get_locus ());
+       }
+    }
+  else if (expr.has_return_expr ())
+    {
+      tree result_reference
+       = Backend::var_expression (fncontext.ret_addr, expr.get_locus ());
+
+      tree assignment
+       = Backend::assignment_statement (result_reference, return_value,
+                                        expr.get_locus ());
+
+      ctx->add_statement (assignment);
+      return_value
+       = Backend::var_expression (fncontext.ret_addr, expr.get_locus ());
+    }
+
+  CompileDrop (ctx).emit_return_scope_drop_calls ();
+
   tree return_stmt = Backend::return_statement (fncontext.fndecl, return_value,
                                                expr.get_locus ());
   ctx->add_statement (return_stmt);
diff --git a/gcc/testsuite/rust/execute/drop-explicit-return.rs 
b/gcc/testsuite/rust/execute/drop-explicit-return.rs
new file mode 100644
index 000000000..c138823f9
--- /dev/null
+++ b/gcc/testsuite/rust/execute/drop-explicit-return.rs
@@ -0,0 +1,105 @@
+// { dg-output 
"unit\r*\nmake_unit\r*\nunit_expr\r*\nmake_value\r*\nnonunit\r*\ninner\r*\nouter\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 UnitDroppable;
+struct UnitExprDroppable;
+struct NonUnitDroppable;
+struct OuterDroppable;
+struct InnerDroppable;
+
+impl Drop for UnitDroppable {
+    fn drop(&mut self) {
+        let msg = "unit\n\0" as *const str as *const i8;
+        unsafe { printf(msg); }
+    }
+}
+impl Drop for UnitExprDroppable {
+    fn drop(&mut self) {
+        let msg = "unit_expr\n\0" as *const str as *const i8;
+        unsafe { printf(msg); }
+    }
+}
+
+impl Drop for NonUnitDroppable {
+    fn drop(&mut self) {
+        let msg = "nonunit\n\0" as *const str as *const i8;
+        unsafe { printf(msg); }
+    }
+}
+
+impl Drop for OuterDroppable {
+    fn drop(&mut self) {
+        let msg = "outer\n\0" as *const str as *const i8;
+        unsafe { printf(msg); }
+    }
+}
+
+impl Drop for InnerDroppable {
+    fn drop(&mut self) {
+        let msg = "inner\n\0" as *const str as *const i8;
+        unsafe { printf(msg); }
+    }
+}
+
+fn make_unit () {
+    let msg = "make_unit\n\0" as *const str as *const i8;
+    unsafe { printf(msg); }
+}
+
+fn make_value () -> i32 {
+    let msg = "make_value\n\0" as *const str as *const i8;
+    unsafe { printf(msg); }
+    42
+}
+
+fn unit_return () {
+    let _x = UnitDroppable;
+    return;
+}
+
+fn unit_return_expr () {
+    let _x = UnitExprDroppable;
+    return make_unit();
+}
+
+fn non_unit_return () -> i32 {
+    let _x = NonUnitDroppable;
+    return make_value();
+}
+
+fn nested_return() {
+    let _outer = OuterDroppable;
+    {
+        let _inner = InnerDroppable;
+        return;
+    }
+}
+
+fn main() -> i32 {
+    unit_return ();
+    unit_return_expr ();
+
+    let value = non_unit_return ();
+    if value != 42 {
+        return 1;
+    }
+
+    nested_return();
+
+    0
+}
\ No newline at end of file

base-commit: 0fcbc90bccd36ba142e3e978e0c29c5b5711a323
-- 
2.54.0

Reply via email to