From: Lishin <[email protected]>
Make unlabeled break return its translated tree, matching continue.
Emit tail-position break and continue expressions as statements so
they stay inside the TRY_FINALLY_EXPR body and run block cleanup.
gcc/rust/ChangeLog:
* backend/rust-compile-block.cc (is_control_flow_expr): New helper.
(CompileBlock::visit): Emit tail-position break and continue
expressions as statements.
* backend/rust-compile-expr.cc (CompileExpr::visit): Return the
translated expression for unlabeled break instead of emitting it
directly.
gcc/testsuite/ChangeLog:
* rust/execute/drop-unlabeled-break-continue.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/f3adcfed0203a2acf51e1e2a11dab0074cd9fbf3
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/4710
gcc/rust/backend/rust-compile-block.cc | 21 +-
gcc/rust/backend/rust-compile-expr.cc | 3 +-
.../execute/drop-unlabeled-break-continue.rs | 263 ++++++++++++++++++
3 files changed, 283 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/rust/execute/drop-unlabeled-break-continue.rs
diff --git a/gcc/rust/backend/rust-compile-block.cc
b/gcc/rust/backend/rust-compile-block.cc
index ca69315c3..6f61856c3 100644
--- a/gcc/rust/backend/rust-compile-block.cc
+++ b/gcc/rust/backend/rust-compile-block.cc
@@ -25,6 +25,15 @@
namespace Rust {
namespace Compile {
+static bool
+is_control_flow_expr (HIR::Expr &expr)
+{
+ HIR::Expr::ExprType expr_type = expr.get_expression_type ();
+
+ return expr_type == HIR::Expr::ExprType::Break
+ || expr_type == HIR::Expr::ExprType::Continue;
+}
+
CompileBlock::CompileBlock (Context *ctx, Bvariable *result)
: HIRCompileBase (ctx), translated (nullptr), result (result)
{}
@@ -62,10 +71,12 @@ CompileBlock::visit (HIR::BlockExpr &expr)
if (expr.has_expr ())
{
- tree compiled_expr = CompileExpr::Compile (expr.get_final_expr (), ctx);
+ HIR::Expr &final_expr = expr.get_final_expr ();
+ tree compiled_expr = CompileExpr::Compile (final_expr, ctx);
+
if (result != nullptr)
{
- location_t locus = expr.get_final_expr ().get_locus ();
+ location_t locus = final_expr.get_locus ();
tree result_reference = Backend::var_expression (result, locus);
tree assignment
@@ -73,6 +84,12 @@ CompileBlock::visit (HIR::BlockExpr &expr)
expr.get_locus ());
ctx->add_statement (assignment);
}
+ else if (compiled_expr != nullptr && is_control_flow_expr (final_expr)
+ && compiled_expr != error_mark_node)
+ {
+ tree stmt = convert_to_void (compiled_expr, ICV_STATEMENT);
+ ctx->add_statement (stmt);
+ }
}
else if (result != nullptr)
{
diff --git a/gcc/rust/backend/rust-compile-expr.cc
b/gcc/rust/backend/rust-compile-expr.cc
index 2c901187d..9eac66e8b 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -1132,10 +1132,9 @@ CompileExpr::visit (HIR::BreakExpr &expr)
}
else
{
- tree exit_expr
+ translated
= Backend::exit_expression (Backend::boolean_constant_expression (true),
expr.get_locus ());
- ctx->add_statement (exit_expr);
}
}
diff --git a/gcc/testsuite/rust/execute/drop-unlabeled-break-continue.rs
b/gcc/testsuite/rust/execute/drop-unlabeled-break-continue.rs
new file mode 100644
index 000000000..5bcae5592
--- /dev/null
+++ b/gcc/testsuite/rust/execute/drop-unlabeled-break-continue.rs
@@ -0,0 +1,263 @@
+// { dg-output "continue inner\r*\ncontinue outer\r*\ncontinue tail
inner\r*\ncontinue tail outer\r*\nbreak inner\r*\nbreak outer\r*\nbreak tail
inner\r*\nbreak tail outer\r*\nbreak value\r*\nvalue ok\r*\nwhile continue
inner\r*\nwhile continue outer\r*\nwhile break inner\r*\nwhile break
outer\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 ContinueOuter;
+struct ContinueInner;
+struct ContinueTailOuter;
+struct ContinueTailInner;
+struct BreakOuter;
+struct BreakInner;
+struct BreakTailOuter;
+struct BreakTailInner;
+struct BreakValue;
+struct WhileContinueOuter;
+struct WhileContinueInner;
+struct WhileBreakOuter;
+struct WhileBreakInner;
+
+impl Drop for ContinueOuter {
+ fn drop(&mut self) {
+ let msg = "continue outer\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for ContinueInner {
+ fn drop(&mut self) {
+ let msg = "continue inner\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for ContinueTailOuter {
+ fn drop(&mut self) {
+ let msg = "continue tail outer\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for ContinueTailInner {
+ fn drop(&mut self) {
+ let msg = "continue tail inner\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for BreakOuter {
+ fn drop(&mut self) {
+ let msg = "break outer\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for BreakInner {
+ fn drop(&mut self) {
+ let msg = "break inner\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for BreakTailOuter {
+ fn drop(&mut self) {
+ let msg = "break tail outer\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for BreakTailInner {
+ fn drop(&mut self) {
+ let msg = "break tail inner\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for BreakValue {
+ fn drop(&mut self) {
+ let msg = "break value\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for WhileContinueOuter {
+ fn drop(&mut self) {
+ let msg = "while continue outer\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for WhileContinueInner {
+ fn drop(&mut self) {
+ let msg = "while continue inner\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for WhileBreakOuter {
+ fn drop(&mut self) {
+ let msg = "while break outer\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for WhileBreakInner {
+ fn drop(&mut self) {
+ let msg = "while break inner\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+fn test_continue() {
+ let mut done = false;
+
+ loop {
+ if done {
+ break;
+ }
+
+ {
+ let _outer = ContinueOuter;
+
+ {
+ let _inner = ContinueInner;
+ done = true;
+ continue;
+ }
+ }
+ }
+}
+
+fn test_continue_tail_expr() {
+ let mut done = false;
+
+ loop {
+ if done {
+ break;
+ }
+
+ {
+ let _outer = ContinueTailOuter;
+
+ {
+ let _inner = ContinueTailInner;
+ done = true;
+ continue
+ }
+ }
+ }
+}
+
+fn test_break() {
+ loop {
+ let _outer = BreakOuter;
+
+ {
+ let _inner = BreakInner;
+ break;
+ }
+ }
+}
+
+fn test_break_tail_expr() {
+ loop {
+ let _outer = BreakTailOuter;
+
+ {
+ let _inner = BreakTailInner;
+ break
+ }
+ }
+}
+
+fn test_break_value() {
+ let x = loop {
+ let _value = BreakValue;
+ break 123;
+ };
+
+ if x == 123 {
+ let msg = "value ok\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+fn test_while_continue() {
+ let mut i = 0;
+
+ while i < 1 {
+ let _outer = WhileContinueOuter;
+
+ {
+ let _inner = WhileContinueInner;
+ i = i + 1;
+ continue;
+ }
+ }
+}
+
+fn test_while_break() {
+ let i = 0;
+
+ while i < 1 {
+ let _outer = WhileBreakOuter;
+
+ {
+ let _inner = WhileBreakInner;
+ break;
+ }
+ }
+}
+
+fn main() -> i32 {
+ test_continue();
+ test_continue_tail_expr();
+ test_break();
+ test_break_tail_expr();
+ test_break_value();
+ test_while_continue();
+ test_while_break();
+
+ 0
+}
base-commit: 78016dea955c55b476aef6a2d54786b060246c51
--
2.54.0