https://gcc.gnu.org/g:a99c41f91ddedd84f8c3309a907a3d2a7f571ed9

commit r17-3117-ga99c41f91ddedd84f8c3309a907a3d2a7f571ed9
Author: Lishin <[email protected]>
Date:   Wed Jun 24 18:46:19 2026 +0000

    gccrs: Emit drops before explicit returns
    
    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]>

Diff:
---
 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 +++++
 gcc/testsuite/rust/execute/drop-explicit-return.rs | 105 +++++++++++++++++++++
 5 files changed, 141 insertions(+)

diff --git a/gcc/rust/backend/rust-compile-drop-builder.cc 
b/gcc/rust/backend/rust-compile-drop-builder.cc
index e0947a787ca4..fb01fc3db1ab 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 36e3cdc1e356..ca6601705ed7 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 f270356e1ee9..52342146346b 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 c0d4ab0a04b9..b76f1bcc2ac3 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 000000000000..c138823f9abc
--- /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

Reply via email to