Skip to content

Commit 2db5b18

Browse files
committed
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-context.h: Insert/Lookup block temp variables. * 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 <islamimad404@gmail.com>
1 parent 3432069 commit 2db5b18

5 files changed

Lines changed: 145 additions & 8 deletions

File tree

gcc/rust/backend/rust-compile-context.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,21 @@ class Context
266266
return true;
267267
}
268268

269+
void insert_temp_var (HirId id, Bvariable *var)
270+
{
271+
compiled_temp_vars[id] = var;
272+
}
273+
274+
bool lookup_temp_var (HirId id, Bvariable **var)
275+
{
276+
auto it = compiled_temp_vars.find (id);
277+
if (it == compiled_temp_vars.end ())
278+
return false;
279+
280+
*var = it->second;
281+
return true;
282+
}
283+
269284
void insert_pattern_binding (HirId id, tree binding)
270285
{
271286
implicit_pattern_bindings[id] = binding;
@@ -417,6 +432,7 @@ class Context
417432
std::map<HirId, tree> compiled_fn_map;
418433
std::map<HirId, tree> compiled_consts;
419434
std::map<HirId, tree> compiled_labels;
435+
std::map<HirId, Bvariable *> compiled_temp_vars;
420436
std::vector<::std::vector<tree>> statements;
421437
std::vector<tree> scope_stack;
422438
std::vector<::Bvariable *> loop_value_stack;

gcc/rust/backend/rust-compile-expr.cc

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "rust-compile-expr.h"
2020
#include "rust-backend.h"
21+
#include "rust-compile-context.h"
2122
#include "rust-compile-type.h"
2223
#include "rust-compile-struct-field-expr.h"
2324
#include "rust-compile-pattern.h"
@@ -32,6 +33,7 @@
3233
#include "realmpfr.h"
3334
#include "convert.h"
3435
#include "print-tree.h"
36+
#include "rust-hir-bound.h"
3537
#include "rust-hir-expr.h"
3638
#include "rust-system.h"
3739
#include "rust-tree.h"
@@ -437,12 +439,6 @@ CompileExpr::visit (HIR::IfExprConseqElse &expr)
437439
void
438440
CompileExpr::visit (HIR::BlockExpr &expr)
439441
{
440-
if (expr.has_label ())
441-
{
442-
rust_error_at (expr.get_locus (), "labeled blocks are not supported");
443-
return;
444-
}
445-
446442
TyTy::BaseType *block_tyty = nullptr;
447443
if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
448444
&block_tyty))
@@ -455,18 +451,31 @@ CompileExpr::visit (HIR::BlockExpr &expr)
455451
fncontext fnctx = ctx->peek_fn ();
456452
tree enclosing_scope = ctx->peek_enclosing_scope ();
457453
tree block_type = TyTyResolveCompile::compile (ctx, block_tyty);
454+
tree block_label = NULL_TREE;
458455

459456
bool is_address_taken = false;
460457
tree ret_var_stmt = nullptr;
461458
tmp = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type,
462459
NULL, is_address_taken, expr.get_locus (),
463460
&ret_var_stmt);
461+
464462
ctx->add_statement (ret_var_stmt);
465463

464+
if (expr.has_label ())
465+
{
466+
ctx->insert_temp_var (
467+
expr.get_label ().get_lifetime ().get_mappings ().get_hirid (), tmp);
468+
block_label = construct_block_label (expr);
469+
}
470+
466471
auto block_stmt = CompileBlock::compile (expr, ctx, tmp);
467472
rust_assert (TREE_CODE (block_stmt) == BIND_EXPR);
468473
ctx->add_statement (block_stmt);
469474

475+
if (block_label != NULL_TREE)
476+
{
477+
ctx->add_statement (block_label);
478+
}
470479
translated = Backend::var_expression (tmp, expr.get_locus ());
471480
}
472481

@@ -854,11 +863,25 @@ CompileExpr::visit (HIR::WhileLoopExpr &expr)
854863
void
855864
CompileExpr::visit (HIR::BreakExpr &expr)
856865
{
866+
if (expr.has_break_expr () && expr.has_label ())
867+
{
868+
HIR::Lifetime label = expr.get_label ();
869+
auto tvar = lookup_temp_var (label.get_mappings ().get_nodeid ());
870+
tree value = CompileExpr::Compile (expr.get_expr (), ctx);
871+
tree assign
872+
= Backend::assignment_statement (tvar->get_tree (label.get_locus ()),
873+
value, label.get_locus ());
874+
tree block_label = lookup_label (label.get_mappings ().get_nodeid ());
875+
tree go_to = Backend::goto_statement (block_label, label.get_locus ());
876+
ctx->add_statement (assign);
877+
ctx->add_statement (go_to);
878+
return;
879+
}
857880
if (expr.has_break_expr ())
858881
{
859882
tree compiled_expr = CompileExpr::Compile (expr.get_expr (), ctx);
860-
861883
translated = error_mark_node;
884+
862885
if (!ctx->have_loop_context ())
863886
return;
864887

@@ -892,7 +915,6 @@ CompileExpr::visit (HIR::BreakExpr &expr)
892915
expr.get_label ().get_mappings ().as_string ().c_str ());
893916
return;
894917
}
895-
896918
tl::optional<HirId> hid
897919
= ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
898920
if (!hid.has_value ())
@@ -2759,5 +2781,58 @@ CompileExpr::generate_possible_fn_trait_call (HIR::CallExpr &expr,
27592781
return true;
27602782
}
27612783

2784+
tree
2785+
CompileExpr::construct_block_label (HIR::BlockExpr &expr)
2786+
{
2787+
if (expr.has_label ())
2788+
{
2789+
fncontext fnctx = ctx->peek_fn ();
2790+
HIR::LoopLabel label = expr.get_label ();
2791+
std::string label_name = label.get_lifetime ().get_name ();
2792+
HirId label_id = label.get_lifetime ().get_mappings ().get_hirid ();
2793+
tree label_decl
2794+
= Backend::label (fnctx.fndecl, label_name, label.get_locus ());
2795+
tree label_expr = Backend::label_definition_statement (label_decl);
2796+
ctx->insert_label_decl (label_id, label_decl);
2797+
return label_expr;
2798+
}
2799+
return NULL_TREE;
2800+
}
2801+
2802+
tree
2803+
CompileExpr::lookup_label (NodeId to_be_resolved)
2804+
{
2805+
HirId ref = resolve_NodeId (to_be_resolved);
2806+
tree label = NULL_TREE;
2807+
assert (ctx->lookup_label_decl (ref, &label) && "failed to lookup a label");
2808+
return label;
2809+
}
2810+
2811+
Bvariable *
2812+
CompileExpr::lookup_temp_var (NodeId to_be_resolved)
2813+
{
2814+
HirId ref = resolve_NodeId (to_be_resolved);
2815+
Bvariable *ltemp = nullptr;
2816+
if (!ctx->lookup_temp_var (ref, &ltemp))
2817+
{
2818+
assert (false && "hey we failed to lookup temp var here bro");
2819+
}
2820+
return ltemp;
2821+
}
2822+
2823+
HirId
2824+
CompileExpr::resolve_NodeId (NodeId to_be_resolved)
2825+
{
2826+
auto &nr_ctx
2827+
= Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
2828+
2829+
NodeId resolved_node_id;
2830+
resolved_node_id = nr_ctx.lookup (to_be_resolved).value ();
2831+
2832+
HirId ref
2833+
= ctx->get_mappings ().lookup_node_to_hir (resolved_node_id).value ();
2834+
return ref;
2835+
}
2836+
27622837
} // namespace Compile
27632838
} // namespace Rust

gcc/rust/backend/rust-compile-expr.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#define RUST_COMPILE_EXPR
2121

2222
#include "rust-compile-base.h"
23+
#include "rust-gcc.h"
24+
#include "rust-hir-expr.h"
2325
#include "rust-hir-visitor.h"
2426

2527
namespace Rust {
@@ -151,6 +153,11 @@ class CompileExpr : private HIRCompileBase, protected HIR::HIRExpressionVisitor
151153
bool generate_possible_fn_trait_call (HIR::CallExpr &expr, tree receiver,
152154
tree *result);
153155

156+
tree construct_block_label (HIR::BlockExpr &expr);
157+
tree lookup_label (NodeId to_be_resolved);
158+
Bvariable *lookup_temp_var (NodeId to_be_resolved);
159+
HirId resolve_NodeId (NodeId to_be_resolved);
160+
154161
private:
155162
CompileExpr (Context *ctx);
156163

gcc/rust/resolve/rust-late-name-resolver-2.0.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,9 @@ Late::visit (AST::BreakExpr &expr)
299299
void
300300
Late::visit (AST::LoopLabel &label)
301301
{
302+
auto resolved = ctx.lookup (label.get_lifetime ().get_node_id ());
303+
if (resolved.has_value ())
304+
return;
302305
auto &lifetime = label.get_lifetime ();
303306
ctx.labels.insert (Identifier (lifetime.as_string (), lifetime.get_locus ()),
304307
lifetime.get_node_id ());
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// { dg-output "222\r*\n333\r*\n" }
2+
#![feature(no_core)]
3+
#![no_core]
4+
extern "C" {
5+
fn printf(s: *const i8, ...);
6+
}
7+
fn dump_number(num: i32) {
8+
unsafe {
9+
let a = "%i\n\0";
10+
let c = a as *const str as *const i8;
11+
printf(c, num);
12+
}
13+
}
14+
15+
fn main() -> i32 {
16+
let a = 'block_a: {
17+
if false {
18+
break 'block_a 111;
19+
}
20+
222
21+
};
22+
dump_number(a);
23+
let b = 'block_b: {
24+
if true {
25+
break 'block_b 333;
26+
}
27+
444
28+
};
29+
dump_number(b);
30+
// ISSUE HERE :)
31+
// let c = 'block_c: {
32+
// break 'block_c 555;
33+
// };
34+
// dump_number(c);
35+
0
36+
}

0 commit comments

Comments
 (0)