Skip to content

Commit ce700c4

Browse files
committed
Add support for enums on the match expression
Add initial support for MatchExpr there is an issue once LTO is enabled where it hits and ICE: /home/../rust/execute/torture/match1.rs:48:1: internal compiler error: in find_taken_edge_switch_expr, at tree-cfg.c:2481 0x121bc38 find_taken_edge_switch_expr(gswitch const*, tree_node*) ../../gccrs/gcc/tree-cfg.c:2481 0x121b925 find_taken_edge(basic_block_def*, tree_node*) ../../gccrs/gcc/tree-cfg.c:2377 0x147e7bb process_bb ../../gccrs/gcc/tree-ssa-sccvn.c:7300 0x14809a6 do_rpo_vn ../../gccrs/gcc/tree-ssa-sccvn.c:7777 0x1481a7c execute ../../gccrs/gcc/tree-ssa-sccvn.c:8045 I believe this might be due to the qualifier type used within the enum type creating an enumeral type with all variants of it might fix this and or moving to the qual_union_type instead of a big union. Fixes #190
1 parent a8a3456 commit ce700c4

File tree

8 files changed

+593
-0
lines changed

8 files changed

+593
-0
lines changed

gcc/rust/Make-lang.in

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ GRS_OBJS = \
9494
rust/rust-lint-marklive.o \
9595
rust/rust-hir-type-check-path.o \
9696
rust/rust-compile-intrinsic.o \
97+
rust/rust-compile-pattern.o \
9798
rust/rust-base62.o \
9899
rust/rust-compile-expr.o \
99100
rust/rust-compile-type.o \

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

+16
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,21 @@ class Context
233233
return true;
234234
}
235235

236+
void insert_pattern_binding (HirId id, tree binding)
237+
{
238+
implicit_pattern_bindings[id] = binding;
239+
}
240+
241+
bool lookup_pattern_binding (HirId id, tree *binding)
242+
{
243+
auto it = implicit_pattern_bindings.find (id);
244+
if (it == implicit_pattern_bindings.end ())
245+
return false;
246+
247+
*binding = it->second;
248+
return true;
249+
}
250+
236251
void push_fn (tree fn, ::Bvariable *ret_addr)
237252
{
238253
fn_stack.push_back (fncontext{fn, ret_addr});
@@ -326,6 +341,7 @@ class Context
326341
std::map<const TyTy::BaseType *, std::pair<HirId, tree>> mono;
327342
std::map<DefId, std::vector<std::pair<const TyTy::BaseType *, tree>>>
328343
mono_fns;
344+
std::map<HirId, tree> implicit_pattern_bindings;
329345

330346
// To GCC middle-end
331347
std::vector<tree> type_decls;

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

+172
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
#include "rust-hir-path-probe.h"
2525
#include "rust-hir-type-bounds.h"
2626
#include "rust-hir-dot-operator.h"
27+
#include "rust-compile-pattern.h"
28+
29+
#include "fold-const.h"
2730

2831
namespace Rust {
2932
namespace Compile {
@@ -154,6 +157,175 @@ CompileExpr::visit (HIR::DereferenceExpr &expr)
154157
known_valid, expr.get_locus ());
155158
}
156159

160+
void
161+
CompileExpr::visit (HIR::MatchExpr &expr)
162+
{
163+
// https://gcc.gnu.org/onlinedocs/gccint/Basic-Statements.html#Basic-Statements
164+
// TODO
165+
// SWITCH_ALL_CASES_P is true if the switch includes a default label or the
166+
// case label ranges cover all possible values of the condition expression
167+
168+
/* Switch expression.
169+
170+
TREE_TYPE is the original type of the condition, before any
171+
language required type conversions. It may be NULL, in which case
172+
the original type and final types are assumed to be the same.
173+
174+
Operand 0 is the expression used to perform the branch,
175+
Operand 1 is the body of the switch, which probably contains
176+
CASE_LABEL_EXPRs. It may also be NULL, in which case operand 2
177+
must not be NULL. */
178+
// DEFTREECODE (SWITCH_EXPR, "switch_expr", tcc_statement, 2)
179+
180+
/* Used to represent a case label.
181+
182+
Operand 0 is CASE_LOW. It may be NULL_TREE, in which case the label
183+
is a 'default' label.
184+
Operand 1 is CASE_HIGH. If it is NULL_TREE, the label is a simple
185+
(one-value) case label. If it is non-NULL_TREE, the case is a range.
186+
Operand 2 is CASE_LABEL, which has the corresponding LABEL_DECL.
187+
Operand 3 is CASE_CHAIN. This operand is only used in tree-cfg.c to
188+
speed up the lookup of case labels which use a particular edge in
189+
the control flow graph. */
190+
// DEFTREECODE (CASE_LABEL_EXPR, "case_label_expr", tcc_statement, 4)
191+
192+
TyTy::BaseType *scrutinee_expr_tyty = nullptr;
193+
if (!ctx->get_tyctx ()->lookup_type (
194+
expr.get_scrutinee_expr ()->get_mappings ().get_hirid (),
195+
&scrutinee_expr_tyty))
196+
{
197+
translated = ctx->get_backend ()->error_expression ();
198+
return;
199+
}
200+
201+
rust_assert (scrutinee_expr_tyty->get_kind () == TyTy::TypeKind::ADT);
202+
203+
// this will need to change but for now the first pass implementation, lets
204+
// assert this is the case
205+
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (scrutinee_expr_tyty);
206+
rust_assert (adt->is_enum ());
207+
rust_assert (adt->number_of_variants () > 0);
208+
209+
TyTy::BaseType *expr_tyty = nullptr;
210+
if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
211+
&expr_tyty))
212+
{
213+
translated = ctx->get_backend ()->error_expression ();
214+
return;
215+
}
216+
217+
fncontext fnctx = ctx->peek_fn ();
218+
Bvariable *tmp = NULL;
219+
bool needs_temp = !expr_tyty->is_unit ();
220+
if (needs_temp)
221+
{
222+
tree enclosing_scope = ctx->peek_enclosing_scope ();
223+
tree block_type = TyTyResolveCompile::compile (ctx, expr_tyty);
224+
225+
bool is_address_taken = false;
226+
tree ret_var_stmt = nullptr;
227+
tmp = ctx->get_backend ()->temporary_variable (
228+
fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken,
229+
expr.get_locus (), &ret_var_stmt);
230+
ctx->add_statement (ret_var_stmt);
231+
}
232+
233+
// lets compile the scrutinee expression
234+
tree match_scrutinee_expr
235+
= CompileExpr::Compile (expr.get_scrutinee_expr ().get (), ctx);
236+
237+
// need to access the qualifier field, if we use QUAL_UNION_TYPE this would be
238+
// DECL_QUALIFIER i think. For now this will just access the first record
239+
// field and its respective qualifier because it will always be set because
240+
// this is all a big special union
241+
tree scrutinee_first_record_expr
242+
= ctx->get_backend ()->struct_field_expression (
243+
match_scrutinee_expr, 0, expr.get_scrutinee_expr ()->get_locus ());
244+
tree match_scrutinee_expr_qualifier_expr
245+
= ctx->get_backend ()->struct_field_expression (
246+
scrutinee_first_record_expr, 0, expr.get_scrutinee_expr ()->get_locus ());
247+
248+
// setup the end label so the cases can exit properly
249+
tree fndecl = fnctx.fndecl;
250+
Location end_label_locus = expr.get_locus (); // FIXME
251+
tree end_label
252+
= ctx->get_backend ()->label (fndecl,
253+
"" /* empty creates an artificial label */,
254+
end_label_locus);
255+
tree end_label_decl_statement
256+
= ctx->get_backend ()->label_definition_statement (end_label);
257+
258+
// setup the switch-body-block
259+
Location start_location; // FIXME
260+
Location end_location; // FIXME
261+
tree enclosing_scope = ctx->peek_enclosing_scope ();
262+
tree switch_body_block
263+
= ctx->get_backend ()->block (fndecl, enclosing_scope, {}, start_location,
264+
end_location);
265+
ctx->push_block (switch_body_block);
266+
267+
for (auto &kase : expr.get_match_cases ())
268+
{
269+
// for now lets just get single pattern's working
270+
HIR::MatchArm &kase_arm = kase.get_arm ();
271+
rust_assert (kase_arm.get_patterns ().size () > 0);
272+
273+
// generate implicit label
274+
Location arm_locus = kase_arm.get_patterns ().at (0)->get_locus ();
275+
tree case_label = ctx->get_backend ()->label (
276+
fndecl, "" /* empty creates an artificial label */, arm_locus);
277+
278+
// not sure if we need to add this to the block or if the CASE_LABEL_EXPR
279+
// does this implicitly
280+
//
281+
// tree case_label_decl_statement
282+
// = ctx->get_backend ()->label_definition_statement (case_label);
283+
284+
// setup the bindings for the block
285+
for (auto &kase_pattern : kase_arm.get_patterns ())
286+
{
287+
tree switch_kase_expr
288+
= CompilePatternCaseLabelExpr::Compile (kase_pattern.get (),
289+
case_label, ctx);
290+
// ctx->add_statement (case_label_decl_statement);
291+
ctx->add_statement (switch_kase_expr);
292+
293+
CompilePatternBindings::Compile (kase_pattern.get (),
294+
match_scrutinee_expr, ctx);
295+
}
296+
297+
// compile the expr and setup the assignment if required when tmp != NULL
298+
tree kase_expr_tree = CompileExpr::Compile (kase.get_expr ().get (), ctx);
299+
if (tmp != NULL)
300+
{
301+
tree result_reference
302+
= ctx->get_backend ()->var_expression (tmp, arm_locus);
303+
tree assignment = ctx->get_backend ()->assignment_statement (
304+
fnctx.fndecl, result_reference, kase_expr_tree, arm_locus);
305+
ctx->add_statement (assignment);
306+
}
307+
308+
// go to end label
309+
tree goto_end_label = build1_loc (arm_locus.gcc_location (), GOTO_EXPR,
310+
void_type_node, end_label);
311+
ctx->add_statement (goto_end_label);
312+
}
313+
314+
// setup the switch expression
315+
tree match_body = ctx->pop_block ();
316+
tree match_expr_stmt
317+
= build2_loc (expr.get_locus ().gcc_location (), SWITCH_EXPR,
318+
TREE_TYPE (match_scrutinee_expr_qualifier_expr),
319+
match_scrutinee_expr_qualifier_expr, match_body);
320+
ctx->add_statement (match_expr_stmt);
321+
ctx->add_statement (end_label_decl_statement);
322+
323+
if (tmp != NULL)
324+
{
325+
translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ());
326+
}
327+
}
328+
157329
void
158330
CompileExpr::visit (HIR::CallExpr &expr)
159331
{

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

+6
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ class CompileExpr : public HIRCompileBase
221221
translated
222222
= ctx->get_backend ()->var_expression (var, expr.get_locus ());
223223
}
224+
else if (ctx->lookup_pattern_binding (ref, &translated))
225+
{
226+
return;
227+
}
224228
else
225229
{
226230
rust_fatal_error (expr.get_locus (),
@@ -1043,6 +1047,8 @@ class CompileExpr : public HIRCompileBase
10431047

10441048
void visit (HIR::DereferenceExpr &expr) override;
10451049

1050+
void visit (HIR::MatchExpr &expr) override;
1051+
10461052
protected:
10471053
tree compile_dyn_dispatch_call (const TyTy::DynamicObjectType *dyn,
10481054
TyTy::BaseType *receiver,

0 commit comments

Comments
 (0)