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]>
---
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 e0947a787ca..fb01fc3db1a 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 36e3cdc1e35..ca6601705ed 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 f270356e1ee..52342146346 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 c0d4ab0a04b..b76f1bcc2ac 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 00000000000..c138823f9ab
--- /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
--
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.