https://gcc.gnu.org/g:3de372beefccbba9e0b4e15b0f2098cc62d3f2a3
commit r17-1087-g3de372beefccbba9e0b4e15b0f2098cc62d3f2a3 Author: Islam-Imad <[email protected]> Date: Tue Apr 21 15:18:40 2026 +0200 gccrs: Support labeled block value breaks in HIR lowering This change implements backend lowering support for Rust labeled blocks. Previously, labeled blocks were rejected in "CompileExpr::visit(BlockExpr)" as unsupported. With this patch, labeled blocks are lowered by introducing the following :- 1. A backend "LABEL_DECL" used as the jump target for "break 'label". 2. A temporary "Bvariable" used to hold the block’s resulting value. gcc/rust/ChangeLog: * backend/rust-compile-expr.cc (CompileExpr::visit): Lower labeled block. (CompileExpr::construct_block_label): Utility function to construct block label. (CompileExpr::lookup_label): Utility function to lookup label. (CompileExpr::lookup_temp_var): Utility function to lookup block temp variables. (CompileExpr::resolve_util): Utility to resolve NodeId to HirId. * backend/rust-compile-expr.h: Header functions. * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Fix label resolution. gcc/testsuite/ChangeLog: * rust/execute/cf-labeled-block.rs: New test. Signed-off-by: Islam-Imad <[email protected]> Diff: --- gcc/rust/backend/rust-compile-expr.cc | 90 ++++++++++++++++++++++--- gcc/rust/backend/rust-compile-expr.h | 7 ++ gcc/rust/resolve/rust-late-name-resolver-2.0.cc | 3 + gcc/testsuite/rust/execute/cf-labeled-block.rs | 36 ++++++++++ 4 files changed, 128 insertions(+), 8 deletions(-) diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index 6b21a7745771..1c69d511e52f 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -18,6 +18,7 @@ #include "rust-compile-expr.h" #include "rust-backend.h" +#include "rust-compile-context.h" #include "rust-compile-type.h" #include "rust-compile-struct-field-expr.h" #include "rust-compile-pattern.h" @@ -32,6 +33,7 @@ #include "realmpfr.h" #include "convert.h" #include "print-tree.h" +#include "rust-hir-bound.h" #include "rust-hir-expr.h" #include "rust-system.h" #include "rust-tree.h" @@ -436,12 +438,6 @@ CompileExpr::visit (HIR::IfExprConseqElse &expr) void CompileExpr::visit (HIR::BlockExpr &expr) { - if (expr.has_label ()) - { - rust_error_at (expr.get_locus (), "labeled blocks are not supported"); - return; - } - TyTy::BaseType *block_tyty = nullptr; if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &block_tyty)) @@ -454,18 +450,31 @@ CompileExpr::visit (HIR::BlockExpr &expr) fncontext fnctx = ctx->peek_fn (); tree enclosing_scope = ctx->peek_enclosing_scope (); tree block_type = TyTyResolveCompile::compile (ctx, block_tyty); + tree block_label = NULL_TREE; bool is_address_taken = false; tree ret_var_stmt = nullptr; tmp = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken, expr.get_locus (), &ret_var_stmt); + ctx->add_statement (ret_var_stmt); + if (expr.has_label ()) + { + ctx->insert_var_decl ( + expr.get_label ().get_lifetime ().get_mappings ().get_hirid (), tmp); + block_label = construct_block_label (expr); + } + auto block_stmt = CompileBlock::compile (expr, ctx, tmp); rust_assert (TREE_CODE (block_stmt) == BIND_EXPR); ctx->add_statement (block_stmt); + if (block_label != NULL_TREE) + { + ctx->add_statement (block_label); + } translated = Backend::var_expression (tmp, expr.get_locus ()); } @@ -853,11 +862,25 @@ CompileExpr::visit (HIR::WhileLoopExpr &expr) void CompileExpr::visit (HIR::BreakExpr &expr) { + if (expr.has_break_expr () && expr.has_label ()) + { + HIR::Lifetime &label = expr.get_label (); + auto tvar = lookup_temp_var (label.get_mappings ().get_nodeid ()); + tree value = CompileExpr::Compile (expr.get_expr (), ctx); + tree assign + = Backend::assignment_statement (tvar->get_tree (label.get_locus ()), + value, label.get_locus ()); + tree block_label = lookup_label (label.get_mappings ().get_nodeid ()); + tree go_to = Backend::goto_statement (block_label, label.get_locus ()); + ctx->add_statement (assign); + ctx->add_statement (go_to); + return; + } if (expr.has_break_expr ()) { tree compiled_expr = CompileExpr::Compile (expr.get_expr (), ctx); - translated = error_mark_node; + if (!ctx->have_loop_context ()) return; @@ -891,7 +914,6 @@ CompileExpr::visit (HIR::BreakExpr &expr) expr.get_label ().get_mappings ().as_string ().c_str ()); return; } - tl::optional<HirId> hid = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id); if (!hid.has_value ()) @@ -2758,5 +2780,57 @@ CompileExpr::generate_possible_fn_trait_call (HIR::CallExpr &expr, return true; } +tree +CompileExpr::construct_block_label (HIR::BlockExpr &expr) +{ + if (expr.has_label ()) + { + fncontext fnctx = ctx->peek_fn (); + HIR::LoopLabel &label = expr.get_label (); + std::string label_name = label.get_lifetime ().get_name (); + HirId label_id = label.get_lifetime ().get_mappings ().get_hirid (); + tree label_decl + = Backend::label (fnctx.fndecl, label_name, label.get_locus ()); + tree label_expr = Backend::label_definition_statement (label_decl); + ctx->insert_label_decl (label_id, label_decl); + return label_expr; + } + return NULL_TREE; +} + +tree +CompileExpr::lookup_label (NodeId to_be_resolved) +{ + HirId ref = resolve_NodeId (to_be_resolved); + tree label = NULL_TREE; + rust_assert (ctx->lookup_label_decl (ref, &label) + && "failed to lookup a label"); + return label; +} + +Bvariable * +CompileExpr::lookup_temp_var (NodeId to_be_resolved) +{ + HirId ref = resolve_NodeId (to_be_resolved); + Bvariable *ltemp = nullptr; + rust_assert (ctx->lookup_var_decl (ref, <emp) + && "failed to lookup a temp var"); + return ltemp; +} + +HirId +CompileExpr::resolve_NodeId (NodeId to_be_resolved) +{ + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + NodeId resolved_node_id; + resolved_node_id = nr_ctx.lookup (to_be_resolved).value (); + + HirId ref + = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id).value (); + return ref; +} + } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index 11c99ed024a3..7764448d8633 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -20,6 +20,8 @@ #define RUST_COMPILE_EXPR #include "rust-compile-base.h" +#include "rust-gcc.h" +#include "rust-hir-expr.h" #include "rust-hir-visitor.h" namespace Rust { @@ -151,6 +153,11 @@ protected: bool generate_possible_fn_trait_call (HIR::CallExpr &expr, tree receiver, tree *result); + tree construct_block_label (HIR::BlockExpr &expr); + tree lookup_label (NodeId to_be_resolved); + Bvariable *lookup_temp_var (NodeId to_be_resolved); + HirId resolve_NodeId (NodeId to_be_resolved); + private: CompileExpr (Context *ctx); diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index 05b2b56b0df6..f0db8277598d 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -299,6 +299,9 @@ Late::visit (AST::BreakExpr &expr) void Late::visit (AST::LoopLabel &label) { + auto resolved = ctx.lookup (label.get_lifetime ().get_node_id ()); + if (resolved.has_value ()) + return; auto &lifetime = label.get_lifetime (); ctx.labels.insert (Identifier (lifetime.as_string (), lifetime.get_locus ()), lifetime.get_node_id ()); diff --git a/gcc/testsuite/rust/execute/cf-labeled-block.rs b/gcc/testsuite/rust/execute/cf-labeled-block.rs new file mode 100644 index 000000000000..edfc4833008e --- /dev/null +++ b/gcc/testsuite/rust/execute/cf-labeled-block.rs @@ -0,0 +1,36 @@ +// { dg-output "222\r*\n333\r*\n" } +#![feature(no_core)] +#![no_core] +extern "C" { + fn printf(s: *const i8, ...); +} +fn dump_number(num: i32) { + unsafe { + let a = "%i\n\0"; + let c = a as *const str as *const i8; + printf(c, num); + } +} + +fn main() -> i32 { + let a = 'block_a: { + if false { + break 'block_a 111; + } + 222 + }; + dump_number(a); + let b = 'block_b: { + if true { + break 'block_b 333; + } + 444 + }; + dump_number(b); + // ISSUE : Rust-GCC/gccrs#4538 + // let c = 'block_c: { + // break 'block_c 555; + // }; + // dump_number(c); + 0 +}
