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
