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

Reply via email to