Skip to content

Commit f5a2a7f

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 f5a2a7f

5 files changed

Lines changed: 150 additions & 5 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: 88 additions & 5 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,11 +33,14 @@
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"
3840
#include "rust-tyty.h"
3941
#include "tree-core.h"
42+
#include "tree.h"
43+
#include <cassert>
4044

4145
namespace Rust {
4246
namespace Compile {
@@ -437,10 +441,13 @@ CompileExpr::visit (HIR::IfExprConseqElse &expr)
437441
void
438442
CompileExpr::visit (HIR::BlockExpr &expr)
439443
{
444+
tree block_label = NULL_TREE;
440445
if (expr.has_label ())
441446
{
442-
rust_error_at (expr.get_locus (), "labeled blocks are not supported");
443-
return;
447+
// rust_error_at (expr.get_locus (), "labeled blocks are not supported");
448+
// return;
449+
block_label = construct_block_label (expr);
450+
// construct_temp_var (expr);
444451
}
445452

446453
TyTy::BaseType *block_tyty = nullptr;
@@ -461,12 +468,22 @@ CompileExpr::visit (HIR::BlockExpr &expr)
461468
tmp = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type,
462469
NULL, is_address_taken, expr.get_locus (),
463470
&ret_var_stmt);
471+
472+
if (expr.has_label ())
473+
{
474+
ctx->insert_temp_var (
475+
expr.get_label ().get_lifetime ().get_mappings ().get_hirid (), tmp);
476+
}
477+
464478
ctx->add_statement (ret_var_stmt);
465479

466480
auto block_stmt = CompileBlock::compile (expr, ctx, tmp);
467481
rust_assert (TREE_CODE (block_stmt) == BIND_EXPR);
468482
ctx->add_statement (block_stmt);
469-
483+
if (block_label)
484+
{
485+
ctx->add_statement (block_label);
486+
}
470487
translated = Backend::var_expression (tmp, expr.get_locus ());
471488
}
472489

@@ -854,11 +871,25 @@ CompileExpr::visit (HIR::WhileLoopExpr &expr)
854871
void
855872
CompileExpr::visit (HIR::BreakExpr &expr)
856873
{
874+
if (expr.has_break_expr () && expr.has_label ())
875+
{
876+
HIR::Lifetime label = expr.get_label ();
877+
auto tvar = lookup_temp_var (label.get_mappings ().get_nodeid ());
878+
tree value = CompileExpr::Compile (expr.get_expr (), ctx);
879+
tree assign
880+
= Backend::assignment_statement (tvar->get_tree (label.get_locus ()),
881+
value, label.get_locus ());
882+
tree block_label = lookup_label (label.get_mappings ().get_nodeid ());
883+
tree go_to = Backend::goto_statement (block_label, label.get_locus ());
884+
ctx->add_statement (assign);
885+
ctx->add_statement (go_to);
886+
return;
887+
}
857888
if (expr.has_break_expr ())
858889
{
859890
tree compiled_expr = CompileExpr::Compile (expr.get_expr (), ctx);
860-
861891
translated = error_mark_node;
892+
862893
if (!ctx->have_loop_context ())
863894
return;
864895

@@ -892,7 +923,6 @@ CompileExpr::visit (HIR::BreakExpr &expr)
892923
expr.get_label ().get_mappings ().as_string ().c_str ());
893924
return;
894925
}
895-
896926
tl::optional<HirId> hid
897927
= ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
898928
if (!hid.has_value ())
@@ -2759,5 +2789,58 @@ CompileExpr::generate_possible_fn_trait_call (HIR::CallExpr &expr,
27592789
return true;
27602790
}
27612791

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