]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/rust/backend/rust-compile-expr.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / rust / backend / rust-compile-expr.cc
CommitLineData
a945c346 1// Copyright (C) 2020-2024 Free Software Foundation, Inc.
019b2f15
PH
2
3// This file is part of GCC.
4
5// GCC is free software; you can redistribute it and/or modify it under
6// the terms of the GNU General Public License as published by the Free
7// Software Foundation; either version 3, or (at your option) any later
8// version.
9
10// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11// WARRANTY; without even the implied warranty of MERCHANTABILITY or
12// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13// for more details.
14
15// You should have received a copy of the GNU General Public License
16// along with GCC; see the file COPYING3. If not see
17// <http://www.gnu.org/licenses/>.
18
19#include "rust-compile-expr.h"
20#include "rust-compile-struct-field-expr.h"
21#include "rust-hir-trait-resolve.h"
22#include "rust-hir-path-probe.h"
23#include "rust-hir-type-bounds.h"
24#include "rust-compile-pattern.h"
25#include "rust-compile-resolve-path.h"
26#include "rust-compile-block.h"
27#include "rust-compile-implitem.h"
28#include "rust-constexpr.h"
68d671ac 29#include "rust-unify.h"
9c87dc0a 30#include "rust-gcc.h"
019b2f15
PH
31
32#include "fold-const.h"
33#include "realmpfr.h"
34#include "convert.h"
35#include "print-tree.h"
36
37namespace Rust {
38namespace Compile {
39
40CompileExpr::CompileExpr (Context *ctx)
41 : HIRCompileBase (ctx), translated (error_mark_node)
42{}
43
44tree
45CompileExpr::Compile (HIR::Expr *expr, Context *ctx)
46{
47 CompileExpr compiler (ctx);
48 expr->accept_vis (compiler);
49 return compiler.translated;
50}
51
52void
53CompileExpr::visit (HIR::TupleIndexExpr &expr)
54{
55 HIR::Expr *tuple_expr = expr.get_tuple_expr ().get ();
56 TupleIndex index = expr.get_tuple_index ();
57
58 tree receiver_ref = CompileExpr::Compile (tuple_expr, ctx);
59
60 TyTy::BaseType *tuple_expr_ty = nullptr;
61 bool ok
62 = ctx->get_tyctx ()->lookup_type (tuple_expr->get_mappings ().get_hirid (),
63 &tuple_expr_ty);
64 rust_assert (ok);
65
66 // do we need to add an indirect reference
67 if (tuple_expr_ty->get_kind () == TyTy::TypeKind::REF)
68 {
69 tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
70 receiver_ref = indirect;
71 }
72
73 translated
74 = ctx->get_backend ()->struct_field_expression (receiver_ref, index,
75 expr.get_locus ());
76}
77
78void
79CompileExpr::visit (HIR::TupleExpr &expr)
80{
81 if (expr.is_unit ())
82 {
83 translated = ctx->get_backend ()->unit_expression ();
84 return;
85 }
86
87 TyTy::BaseType *tyty = nullptr;
88 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
89 &tyty))
90 {
91 rust_fatal_error (expr.get_locus (),
92 "did not resolve type for this TupleExpr");
93 return;
94 }
95
96 tree tuple_type = TyTyResolveCompile::compile (ctx, tyty);
97 rust_assert (tuple_type != nullptr);
98
99 // this assumes all fields are in order from type resolution
100 std::vector<tree> vals;
101 for (auto &elem : expr.get_tuple_elems ())
102 {
103 auto e = CompileExpr::Compile (elem.get (), ctx);
104 vals.push_back (e);
105 }
106
107 translated
108 = ctx->get_backend ()->constructor_expression (tuple_type, false, vals, -1,
109 expr.get_locus ());
110}
111
112void
113CompileExpr::visit (HIR::ReturnExpr &expr)
114{
115 auto fncontext = ctx->peek_fn ();
116
117 std::vector<tree> retstmts;
118 if (expr.has_return_expr ())
119 {
120 tree compiled_expr = CompileExpr::Compile (expr.return_expr.get (), ctx);
121 rust_assert (compiled_expr != nullptr);
122
123 retstmts.push_back (compiled_expr);
124 }
125
126 auto s = ctx->get_backend ()->return_statement (fncontext.fndecl, retstmts,
127 expr.get_locus ());
128 ctx->add_statement (s);
129}
130
131void
132CompileExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
133{
134 auto op = expr.get_expr_type ();
135 auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
136 auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
137
138 // this might be an operator overload situation lets check
139 TyTy::FnType *fntype;
140 bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
141 expr.get_mappings ().get_hirid (), &fntype);
142 if (is_op_overload)
143 {
144 auto lang_item_type
145 = Analysis::RustLangItem::OperatorToLangItem (expr.get_expr_type ());
146 translated = resolve_operator_overload (lang_item_type, expr, lhs, rhs,
147 expr.get_lhs (), expr.get_rhs ());
148 return;
149 }
150
9c87dc0a
AC
151 if (ctx->in_fn () && !ctx->const_context_p ())
152 {
153 auto receiver_tmp = NULL_TREE;
154 auto receiver
155 = ctx->get_backend ()->temporary_variable (ctx->peek_fn ().fndecl,
156 NULL_TREE, TREE_TYPE (lhs),
157 lhs, true, expr.get_locus (),
158 &receiver_tmp);
159 auto check
160 = ctx->get_backend ()->arithmetic_or_logical_expression_checked (
161 op, lhs, rhs, expr.get_locus (), receiver);
162
163 ctx->add_statement (check);
164 translated = receiver->get_tree (expr.get_locus ());
165 }
166 else
167 {
168 translated = ctx->get_backend ()->arithmetic_or_logical_expression (
169 op, lhs, rhs, expr.get_locus ());
170 }
019b2f15
PH
171}
172
173void
174CompileExpr::visit (HIR::CompoundAssignmentExpr &expr)
175{
176 auto op = expr.get_expr_type ();
177 auto lhs = CompileExpr::Compile (expr.get_left_expr ().get (), ctx);
178 auto rhs = CompileExpr::Compile (expr.get_right_expr ().get (), ctx);
179
180 // this might be an operator overload situation lets check
181 TyTy::FnType *fntype;
182 bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
183 expr.get_mappings ().get_hirid (), &fntype);
184 if (is_op_overload)
185 {
186 auto lang_item_type
187 = Analysis::RustLangItem::CompoundAssignmentOperatorToLangItem (
188 expr.get_expr_type ());
189 auto compound_assignment
190 = resolve_operator_overload (lang_item_type, expr, lhs, rhs,
191 expr.get_left_expr ().get (),
192 expr.get_right_expr ().get ());
193 ctx->add_statement (compound_assignment);
194
195 return;
196 }
197
9c87dc0a
AC
198 if (ctx->in_fn () && !ctx->const_context_p ())
199 {
200 auto tmp = NULL_TREE;
201 auto receiver
202 = ctx->get_backend ()->temporary_variable (ctx->peek_fn ().fndecl,
203 NULL_TREE, TREE_TYPE (lhs),
204 lhs, true, expr.get_locus (),
205 &tmp);
206 auto check
207 = ctx->get_backend ()->arithmetic_or_logical_expression_checked (
208 op, lhs, rhs, expr.get_locus (), receiver);
209 ctx->add_statement (check);
210
211 translated = ctx->get_backend ()->assignment_statement (
212 lhs, receiver->get_tree (expr.get_locus ()), expr.get_locus ());
213 }
214 else
215 {
216 translated = ctx->get_backend ()->arithmetic_or_logical_expression (
217 op, lhs, rhs, expr.get_locus ());
218 }
019b2f15
PH
219}
220
221void
222CompileExpr::visit (HIR::NegationExpr &expr)
223{
224 auto op = expr.get_expr_type ();
225 auto negated_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx);
226 auto location = expr.get_locus ();
227
228 // this might be an operator overload situation lets check
229 TyTy::FnType *fntype;
230 bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
231 expr.get_mappings ().get_hirid (), &fntype);
232 if (is_op_overload)
233 {
234 auto lang_item_type
235 = Analysis::RustLangItem::NegationOperatorToLangItem (op);
236 translated
237 = resolve_operator_overload (lang_item_type, expr, negated_expr,
238 nullptr, expr.get_expr ().get (), nullptr);
239 return;
240 }
241
242 translated
243 = ctx->get_backend ()->negation_expression (op, negated_expr, location);
244}
245
246void
247CompileExpr::visit (HIR::ComparisonExpr &expr)
248{
249 auto op = expr.get_expr_type ();
250 auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
251 auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
252 auto location = expr.get_locus ();
253
254 translated
255 = ctx->get_backend ()->comparison_expression (op, lhs, rhs, location);
256}
257
258void
259CompileExpr::visit (HIR::LazyBooleanExpr &expr)
260{
261 auto op = expr.get_expr_type ();
262 auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx);
263 auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
264 auto location = expr.get_locus ();
265
266 translated
267 = ctx->get_backend ()->lazy_boolean_expression (op, lhs, rhs, location);
268}
269
270void
271CompileExpr::visit (HIR::TypeCastExpr &expr)
272{
273 TyTy::BaseType *type_to_cast_to_ty = nullptr;
274 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
275 &type_to_cast_to_ty))
276 {
277 translated = error_mark_node;
278 return;
279 }
280
281 TyTy::BaseType *casted_tyty = nullptr;
282 if (!ctx->get_tyctx ()->lookup_type (
283 expr.get_casted_expr ()->get_mappings ().get_hirid (), &casted_tyty))
284 {
285 translated = error_mark_node;
286 return;
287 }
288
289 auto type_to_cast_to = TyTyResolveCompile::compile (ctx, type_to_cast_to_ty);
290 auto casted_expr = CompileExpr::Compile (expr.get_casted_expr ().get (), ctx);
291
292 std::vector<Resolver::Adjustment> *adjustments = nullptr;
293 bool ok = ctx->get_tyctx ()->lookup_cast_autoderef_mappings (
294 expr.get_mappings ().get_hirid (), &adjustments);
295 if (ok)
296 {
297 casted_expr
298 = resolve_adjustements (*adjustments, casted_expr, expr.get_locus ());
299 }
300
301 translated
302 = type_cast_expression (type_to_cast_to, casted_expr, expr.get_locus ());
303}
304
305void
306CompileExpr::visit (HIR::IfExpr &expr)
307{
308 auto stmt = CompileConditionalBlocks::compile (&expr, ctx, nullptr);
309 ctx->add_statement (stmt);
310}
311
312void
313CompileExpr::visit (HIR::IfExprConseqElse &expr)
314{
315 TyTy::BaseType *if_type = nullptr;
316 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
317 &if_type))
318 {
319 rust_error_at (expr.get_locus (),
320 "failed to lookup type of IfExprConseqElse");
321 return;
322 }
323
324 Bvariable *tmp = NULL;
325 bool needs_temp = !if_type->is_unit ();
326 if (needs_temp)
327 {
328 fncontext fnctx = ctx->peek_fn ();
329 tree enclosing_scope = ctx->peek_enclosing_scope ();
330 tree block_type = TyTyResolveCompile::compile (ctx, if_type);
331
332 bool is_address_taken = false;
333 tree ret_var_stmt = nullptr;
334 tmp = ctx->get_backend ()->temporary_variable (
335 fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken,
336 expr.get_locus (), &ret_var_stmt);
337 ctx->add_statement (ret_var_stmt);
338 }
339
340 auto stmt = CompileConditionalBlocks::compile (&expr, ctx, tmp);
341 ctx->add_statement (stmt);
342
343 if (tmp != NULL)
344 {
345 translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ());
346 }
347}
348
349void
350CompileExpr::visit (HIR::IfExprConseqIf &expr)
351{
352 TyTy::BaseType *if_type = nullptr;
353 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
354 &if_type))
355 {
356 rust_error_at (expr.get_locus (),
357 "failed to lookup type of IfExprConseqElse");
358 return;
359 }
360
361 Bvariable *tmp = NULL;
362 bool needs_temp = !if_type->is_unit ();
363 if (needs_temp)
364 {
365 fncontext fnctx = ctx->peek_fn ();
366 tree enclosing_scope = ctx->peek_enclosing_scope ();
367 tree block_type = TyTyResolveCompile::compile (ctx, if_type);
368
369 bool is_address_taken = false;
370 tree ret_var_stmt = nullptr;
371 tmp = ctx->get_backend ()->temporary_variable (
372 fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken,
373 expr.get_locus (), &ret_var_stmt);
374 ctx->add_statement (ret_var_stmt);
375 }
376
377 auto stmt = CompileConditionalBlocks::compile (&expr, ctx, tmp);
378 ctx->add_statement (stmt);
379
380 if (tmp != NULL)
381 {
382 translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ());
383 }
384}
385
386void
387CompileExpr::visit (HIR::BlockExpr &expr)
388{
389 TyTy::BaseType *block_tyty = nullptr;
390 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
391 &block_tyty))
392 {
393 rust_error_at (expr.get_locus (), "failed to lookup type of BlockExpr");
394 return;
395 }
396
397 Bvariable *tmp = NULL;
398 bool needs_temp = !block_tyty->is_unit ();
399 if (needs_temp)
400 {
401 fncontext fnctx = ctx->peek_fn ();
402 tree enclosing_scope = ctx->peek_enclosing_scope ();
403 tree block_type = TyTyResolveCompile::compile (ctx, block_tyty);
404
405 bool is_address_taken = false;
406 tree ret_var_stmt = nullptr;
407 tmp = ctx->get_backend ()->temporary_variable (
408 fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken,
409 expr.get_locus (), &ret_var_stmt);
410 ctx->add_statement (ret_var_stmt);
411 }
412
413 auto block_stmt = CompileBlock::compile (&expr, ctx, tmp);
414 rust_assert (TREE_CODE (block_stmt) == BIND_EXPR);
415 ctx->add_statement (block_stmt);
416
417 if (tmp != NULL)
418 {
419 translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ());
420 }
421}
422
423void
424CompileExpr::visit (HIR::UnsafeBlockExpr &expr)
425{
426 expr.get_block_expr ()->accept_vis (*this);
427}
428
429void
430CompileExpr::visit (HIR::StructExprStruct &struct_expr)
431{
432 TyTy::BaseType *tyty = nullptr;
433 if (!ctx->get_tyctx ()->lookup_type (struct_expr.get_mappings ().get_hirid (),
434 &tyty))
435 {
436 rust_error_at (struct_expr.get_locus (), "unknown type");
437 return;
438 }
439
440 rust_assert (tyty->is_unit ());
441 translated = ctx->get_backend ()->unit_expression ();
442}
443
444void
445CompileExpr::visit (HIR::StructExprStructFields &struct_expr)
446{
447 TyTy::BaseType *tyty = nullptr;
448 if (!ctx->get_tyctx ()->lookup_type (struct_expr.get_mappings ().get_hirid (),
449 &tyty))
450 {
451 rust_error_at (struct_expr.get_locus (), "unknown type");
452 return;
453 }
454
455 // it must be an ADT
456 rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT);
457 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
458
459 // what variant is it?
460 int union_disriminator = struct_expr.union_index;
461 TyTy::VariantDef *variant = nullptr;
462 if (!adt->is_enum ())
463 {
464 rust_assert (adt->number_of_variants () == 1);
465 variant = adt->get_variants ().at (0);
466 }
467 else
468 {
469 HirId variant_id;
470 bool ok = ctx->get_tyctx ()->lookup_variant_definition (
471 struct_expr.get_struct_name ().get_mappings ().get_hirid (),
472 &variant_id);
473 rust_assert (ok);
474
475 ok
476 = adt->lookup_variant_by_id (variant_id, &variant, &union_disriminator);
477 rust_assert (ok);
478 }
479
480 // compile it
481 tree compiled_adt_type = TyTyResolveCompile::compile (ctx, tyty);
482
483 std::vector<tree> arguments;
484 if (adt->is_union ())
485 {
486 rust_assert (struct_expr.get_fields ().size () == 1);
487
488 // assignments are coercion sites so lets convert the rvalue if
489 // necessary
490 auto respective_field = variant->get_field_at_index (union_disriminator);
491 auto expected = respective_field->get_field_type ();
492
493 // process arguments
494 auto &argument = struct_expr.get_fields ().at (0);
495 auto lvalue_locus
496 = ctx->get_mappings ()->lookup_location (expected->get_ty_ref ());
497 auto rvalue_locus = argument->get_locus ();
498 auto rvalue = CompileStructExprField::Compile (argument.get (), ctx);
499
500 TyTy::BaseType *actual = nullptr;
501 bool ok = ctx->get_tyctx ()->lookup_type (
502 argument->get_mappings ().get_hirid (), &actual);
503
504 if (ok)
505 {
506 rvalue
507 = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
508 actual, expected, lvalue_locus, rvalue_locus);
509 }
510
511 // add it to the list
512 arguments.push_back (rvalue);
513 }
514 else
515 {
516 // this assumes all fields are in order from type resolution and if a
517 // base struct was specified those fields are filed via accesors
518 for (size_t i = 0; i < struct_expr.get_fields ().size (); i++)
519 {
520 // assignments are coercion sites so lets convert the rvalue if
521 // necessary
522 auto respective_field = variant->get_field_at_index (i);
523 auto expected = respective_field->get_field_type ();
524
525 // process arguments
526 auto &argument = struct_expr.get_fields ().at (i);
527 auto lvalue_locus
528 = ctx->get_mappings ()->lookup_location (expected->get_ty_ref ());
529 auto rvalue_locus = argument->get_locus ();
530 auto rvalue = CompileStructExprField::Compile (argument.get (), ctx);
531
532 TyTy::BaseType *actual = nullptr;
533 bool ok = ctx->get_tyctx ()->lookup_type (
534 argument->get_mappings ().get_hirid (), &actual);
535
536 // coerce it if required/possible see
537 // compile/torture/struct_base_init_1.rs
538 if (ok)
539 {
540 rvalue
541 = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
542 actual, expected, lvalue_locus, rvalue_locus);
543 }
544
545 // add it to the list
546 arguments.push_back (rvalue);
547 }
548 }
549
550 // the constructor depends on whether this is actually an enum or not if
551 // its an enum we need to setup the discriminator
552 std::vector<tree> ctor_arguments;
553 if (adt->is_enum ())
554 {
555 HIR::Expr *discrim_expr = variant->get_discriminant ();
556 tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
557 tree folded_discrim_expr = fold_expr (discrim_expr_node);
558 tree qualifier = folded_discrim_expr;
559
560 ctor_arguments.push_back (qualifier);
561 }
562 for (auto &arg : arguments)
563 ctor_arguments.push_back (arg);
564
565 translated = ctx->get_backend ()->constructor_expression (
566 compiled_adt_type, adt->is_enum (), ctor_arguments, union_disriminator,
567 struct_expr.get_locus ());
568}
569
570void
571CompileExpr::visit (HIR::GroupedExpr &expr)
572{
573 translated = CompileExpr::Compile (expr.get_expr_in_parens ().get (), ctx);
574}
575
576void
577CompileExpr::visit (HIR::FieldAccessExpr &expr)
578{
579 HIR::Expr *receiver_expr = expr.get_receiver_expr ().get ();
580 tree receiver_ref = CompileExpr::Compile (receiver_expr, ctx);
581
582 // resolve the receiver back to ADT type
583 TyTy::BaseType *receiver = nullptr;
584 if (!ctx->get_tyctx ()->lookup_type (
585 expr.get_receiver_expr ()->get_mappings ().get_hirid (), &receiver))
586 {
587 rust_error_at (expr.get_receiver_expr ()->get_locus (),
588 "unresolved type for receiver");
589 return;
590 }
591
592 size_t field_index = 0;
593 if (receiver->get_kind () == TyTy::TypeKind::ADT)
594 {
595 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver);
596 rust_assert (!adt->is_enum ());
597 rust_assert (adt->number_of_variants () == 1);
598
599 TyTy::VariantDef *variant = adt->get_variants ().at (0);
600 bool ok
601 = variant->lookup_field (expr.get_field_name (), nullptr, &field_index);
602 rust_assert (ok);
603 }
604 else if (receiver->get_kind () == TyTy::TypeKind::REF)
605 {
606 TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (receiver);
607 TyTy::BaseType *b = r->get_base ();
608 rust_assert (b->get_kind () == TyTy::TypeKind::ADT);
609
610 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (b);
611 rust_assert (!adt->is_enum ());
612 rust_assert (adt->number_of_variants () == 1);
613
614 TyTy::VariantDef *variant = adt->get_variants ().at (0);
615 bool ok
616 = variant->lookup_field (expr.get_field_name (), nullptr, &field_index);
617 rust_assert (ok);
618
619 tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
620 receiver_ref = indirect;
621 }
622
623 translated
624 = ctx->get_backend ()->struct_field_expression (receiver_ref, field_index,
625 expr.get_locus ());
626}
627
628void
629CompileExpr::visit (HIR::QualifiedPathInExpression &expr)
630{
631 translated = ResolvePathRef::Compile (expr, ctx);
632}
633
634void
635CompileExpr::visit (HIR::PathInExpression &expr)
636{
637 translated = ResolvePathRef::Compile (expr, ctx);
638}
639
640void
641CompileExpr::visit (HIR::LoopExpr &expr)
642{
643 TyTy::BaseType *block_tyty = nullptr;
644 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
645 &block_tyty))
646 {
647 rust_error_at (expr.get_locus (), "failed to lookup type of BlockExpr");
648 return;
649 }
650
651 fncontext fnctx = ctx->peek_fn ();
652 tree enclosing_scope = ctx->peek_enclosing_scope ();
653 tree block_type = TyTyResolveCompile::compile (ctx, block_tyty);
654
655 bool is_address_taken = false;
656 tree ret_var_stmt = NULL_TREE;
657 Bvariable *tmp = ctx->get_backend ()->temporary_variable (
658 fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken,
659 expr.get_locus (), &ret_var_stmt);
660 ctx->add_statement (ret_var_stmt);
661 ctx->push_loop_context (tmp);
662
663 if (expr.has_loop_label ())
664 {
665 HIR::LoopLabel &loop_label = expr.get_loop_label ();
666 tree label
667 = ctx->get_backend ()->label (fnctx.fndecl,
668 loop_label.get_lifetime ().get_name (),
669 loop_label.get_locus ());
670 tree label_decl = ctx->get_backend ()->label_definition_statement (label);
671 ctx->add_statement (label_decl);
672 ctx->insert_label_decl (
673 loop_label.get_lifetime ().get_mappings ().get_hirid (), label);
674 }
675
676 tree loop_begin_label
677 = ctx->get_backend ()->label (fnctx.fndecl, "", expr.get_locus ());
678 tree loop_begin_label_decl
679 = ctx->get_backend ()->label_definition_statement (loop_begin_label);
680 ctx->add_statement (loop_begin_label_decl);
681 ctx->push_loop_begin_label (loop_begin_label);
682
683 tree code_block
684 = CompileBlock::compile (expr.get_loop_block ().get (), ctx, nullptr);
685 tree loop_expr
686 = ctx->get_backend ()->loop_expression (code_block, expr.get_locus ());
687 ctx->add_statement (loop_expr);
688
689 ctx->pop_loop_context ();
690 translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ());
691
692 ctx->pop_loop_begin_label ();
693}
694
695void
696CompileExpr::visit (HIR::WhileLoopExpr &expr)
697{
698 fncontext fnctx = ctx->peek_fn ();
699 if (expr.has_loop_label ())
700 {
701 HIR::LoopLabel &loop_label = expr.get_loop_label ();
702 tree label
703 = ctx->get_backend ()->label (fnctx.fndecl,
704 loop_label.get_lifetime ().get_name (),
705 loop_label.get_locus ());
706 tree label_decl = ctx->get_backend ()->label_definition_statement (label);
707 ctx->add_statement (label_decl);
708 ctx->insert_label_decl (
709 loop_label.get_lifetime ().get_mappings ().get_hirid (), label);
710 }
711
712 std::vector<Bvariable *> locals;
713 Location start_location = expr.get_loop_block ()->get_locus ();
714 Location end_location = expr.get_loop_block ()->get_locus (); // FIXME
715
716 tree enclosing_scope = ctx->peek_enclosing_scope ();
717 tree loop_block
718 = ctx->get_backend ()->block (fnctx.fndecl, enclosing_scope, locals,
719 start_location, end_location);
720 ctx->push_block (loop_block);
721
722 tree loop_begin_label
723 = ctx->get_backend ()->label (fnctx.fndecl, "", expr.get_locus ());
724 tree loop_begin_label_decl
725 = ctx->get_backend ()->label_definition_statement (loop_begin_label);
726 ctx->add_statement (loop_begin_label_decl);
727 ctx->push_loop_begin_label (loop_begin_label);
728
729 tree condition
730 = CompileExpr::Compile (expr.get_predicate_expr ().get (), ctx);
e6a3886a 731 tree exit_condition
732 = fold_build1_loc (expr.get_locus ().gcc_location (), TRUTH_NOT_EXPR,
733 boolean_type_node, condition);
019b2f15 734 tree exit_expr
e6a3886a 735 = ctx->get_backend ()->exit_expression (exit_condition, expr.get_locus ());
019b2f15
PH
736 ctx->add_statement (exit_expr);
737
738 tree code_block_stmt
739 = CompileBlock::compile (expr.get_loop_block ().get (), ctx, nullptr);
740 rust_assert (TREE_CODE (code_block_stmt) == BIND_EXPR);
741 ctx->add_statement (code_block_stmt);
742
743 ctx->pop_loop_begin_label ();
744 ctx->pop_block ();
745
746 tree loop_expr
747 = ctx->get_backend ()->loop_expression (loop_block, expr.get_locus ());
748 ctx->add_statement (loop_expr);
749}
750
751void
752CompileExpr::visit (HIR::BreakExpr &expr)
753{
754 if (expr.has_break_expr ())
755 {
756 tree compiled_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx);
757
758 Bvariable *loop_result_holder = ctx->peek_loop_context ();
759 tree result_reference
760 = ctx->get_backend ()->var_expression (loop_result_holder,
761 expr.get_expr ()->get_locus ());
762
763 tree assignment
764 = ctx->get_backend ()->assignment_statement (result_reference,
765 compiled_expr,
766 expr.get_locus ());
767 ctx->add_statement (assignment);
768 }
769
770 if (expr.has_label ())
771 {
772 NodeId resolved_node_id = UNKNOWN_NODEID;
773 if (!ctx->get_resolver ()->lookup_resolved_label (
774 expr.get_label ().get_mappings ().get_nodeid (), &resolved_node_id))
775 {
776 rust_error_at (
777 expr.get_label ().get_locus (),
778 "failed to resolve compiled label for label %s",
779 expr.get_label ().get_mappings ().as_string ().c_str ());
780 return;
781 }
782
783 HirId ref = UNKNOWN_HIRID;
784 if (!ctx->get_mappings ()->lookup_node_to_hir (resolved_node_id, &ref))
785 {
786 rust_fatal_error (expr.get_locus (), "reverse lookup label failure");
787 return;
788 }
789
790 tree label = NULL_TREE;
791 if (!ctx->lookup_label_decl (ref, &label))
792 {
793 rust_error_at (expr.get_label ().get_locus (),
794 "failed to lookup compiled label");
795 return;
796 }
797
798 tree goto_label
799 = ctx->get_backend ()->goto_statement (label, expr.get_locus ());
800 ctx->add_statement (goto_label);
801 }
802 else
803 {
804 tree exit_expr = ctx->get_backend ()->exit_expression (
805 ctx->get_backend ()->boolean_constant_expression (true),
806 expr.get_locus ());
807 ctx->add_statement (exit_expr);
808 }
809}
810
811void
812CompileExpr::visit (HIR::ContinueExpr &expr)
813{
814 tree label = ctx->peek_loop_begin_label ();
815 if (expr.has_label ())
816 {
817 NodeId resolved_node_id = UNKNOWN_NODEID;
818 if (!ctx->get_resolver ()->lookup_resolved_label (
819 expr.get_label ().get_mappings ().get_nodeid (), &resolved_node_id))
820 {
821 rust_error_at (
822 expr.get_label ().get_locus (),
823 "failed to resolve compiled label for label %s",
824 expr.get_label ().get_mappings ().as_string ().c_str ());
825 return;
826 }
827
828 HirId ref = UNKNOWN_HIRID;
829 if (!ctx->get_mappings ()->lookup_node_to_hir (resolved_node_id, &ref))
830 {
831 rust_fatal_error (expr.get_locus (), "reverse lookup label failure");
832 return;
833 }
834
835 if (!ctx->lookup_label_decl (ref, &label))
836 {
837 rust_error_at (expr.get_label ().get_locus (),
838 "failed to lookup compiled label");
839 return;
840 }
841 }
842
843 translated = ctx->get_backend ()->goto_statement (label, expr.get_locus ());
844}
845
846void
847CompileExpr::visit (HIR::BorrowExpr &expr)
848{
849 tree main_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx);
850 if (SLICE_TYPE_P (TREE_TYPE (main_expr)))
851 {
852 translated = main_expr;
853 return;
854 }
855
856 TyTy::BaseType *tyty = nullptr;
857 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
858 &tyty))
859 return;
860
861 translated = address_expression (main_expr, expr.get_locus ());
862}
863
864void
865CompileExpr::visit (HIR::DereferenceExpr &expr)
866{
867 TyTy::BaseType *tyty = nullptr;
868 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
869 &tyty))
870 {
871 rust_fatal_error (expr.get_locus (),
872 "did not resolve type for this TupleExpr");
873 return;
874 }
875
876 tree main_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx);
877
878 // this might be an operator overload situation lets check
879 TyTy::FnType *fntype;
880 bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
881 expr.get_mappings ().get_hirid (), &fntype);
882 if (is_op_overload)
883 {
884 auto lang_item_type = Analysis::RustLangItem::ItemType::DEREF;
885 tree operator_overload_call
886 = resolve_operator_overload (lang_item_type, expr, main_expr, nullptr,
887 expr.get_expr ().get (), nullptr);
888
889 // rust deref always returns a reference from this overload then we can
890 // actually do the indirection
891 main_expr = operator_overload_call;
892 }
893
894 tree expected_type = TyTyResolveCompile::compile (ctx, tyty);
895 if (SLICE_TYPE_P (TREE_TYPE (main_expr)) && SLICE_TYPE_P (expected_type))
896 {
897 translated = main_expr;
898 return;
899 }
900
901 translated = indirect_expression (main_expr, expr.get_locus ());
902}
903
904void
905CompileExpr::visit (HIR::LiteralExpr &expr)
906{
907 TyTy::BaseType *tyty = nullptr;
908 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
909 &tyty))
910 return;
911
912 switch (expr.get_lit_type ())
913 {
914 case HIR::Literal::BOOL:
915 translated = compile_bool_literal (expr, tyty);
916 return;
917
918 case HIR::Literal::INT:
919 translated = compile_integer_literal (expr, tyty);
920 return;
921
922 case HIR::Literal::FLOAT:
923 translated = compile_float_literal (expr, tyty);
924 return;
925
926 case HIR::Literal::CHAR:
927 translated = compile_char_literal (expr, tyty);
928 return;
929
930 case HIR::Literal::BYTE:
931 translated = compile_byte_literal (expr, tyty);
932 return;
933
934 case HIR::Literal::STRING:
935 translated = compile_string_literal (expr, tyty);
936 return;
937
938 case HIR::Literal::BYTE_STRING:
939 translated = compile_byte_string_literal (expr, tyty);
940 return;
941 }
942}
943
944void
945CompileExpr::visit (HIR::AssignmentExpr &expr)
946{
947 auto lvalue = CompileExpr::Compile (expr.get_lhs (), ctx);
948 auto rvalue = CompileExpr::Compile (expr.get_rhs (), ctx);
949
950 // assignments are coercion sites so lets convert the rvalue if necessary
951 TyTy::BaseType *expected = nullptr;
952 TyTy::BaseType *actual = nullptr;
953
954 bool ok;
955 ok = ctx->get_tyctx ()->lookup_type (
956 expr.get_lhs ()->get_mappings ().get_hirid (), &expected);
957 rust_assert (ok);
958
959 ok = ctx->get_tyctx ()->lookup_type (
960 expr.get_rhs ()->get_mappings ().get_hirid (), &actual);
961 rust_assert (ok);
962
963 rvalue = coercion_site (expr.get_mappings ().get_hirid (), rvalue, actual,
964 expected, expr.get_lhs ()->get_locus (),
965 expr.get_rhs ()->get_locus ());
966
967 tree assignment
968 = ctx->get_backend ()->assignment_statement (lvalue, rvalue,
969 expr.get_locus ());
970
971 ctx->add_statement (assignment);
972}
973
974// Helper for sort_tuple_patterns.
975// Determine whether Patterns a and b are really the same pattern.
976// FIXME: This is a nasty hack to avoid properly implementing a comparison
977// for Patterns, which we really probably do want at some point.
978static bool
979patterns_mergeable (HIR::Pattern *a, HIR::Pattern *b)
980{
981 if (!a || !b)
982 return false;
983
984 HIR::Pattern::PatternType pat_type = a->get_pattern_type ();
985 if (b->get_pattern_type () != pat_type)
986 return false;
987
988 switch (pat_type)
989 {
990 case HIR::Pattern::PatternType::PATH: {
991 // FIXME: this is far too naive
992 HIR::PathPattern &aref = *static_cast<HIR::PathPattern *> (a);
993 HIR::PathPattern &bref = *static_cast<HIR::PathPattern *> (b);
994 if (aref.get_num_segments () != bref.get_num_segments ())
995 return false;
996
997 const auto &asegs = aref.get_segments ();
998 const auto &bsegs = bref.get_segments ();
999 for (size_t i = 0; i < asegs.size (); i++)
1000 {
1001 if (asegs[i].as_string () != bsegs[i].as_string ())
1002 return false;
1003 }
1004 return true;
1005 }
1006 break;
1007 case HIR::Pattern::PatternType::LITERAL: {
1008 HIR::LiteralPattern &aref = *static_cast<HIR::LiteralPattern *> (a);
1009 HIR::LiteralPattern &bref = *static_cast<HIR::LiteralPattern *> (b);
1010 return aref.get_literal ().is_equal (bref.get_literal ());
1011 }
1012 break;
1013 case HIR::Pattern::PatternType::IDENTIFIER: {
1014 // TODO
1015 }
1016 break;
1017 case HIR::Pattern::PatternType::WILDCARD:
1018 return true;
1019 break;
1020
1021 // TODO
1022
1023 default:;
1024 }
1025 return false;
1026}
1027
1028// A little container for rearranging the patterns and cases in a match
1029// expression while simplifying.
1030struct PatternMerge
1031{
1032 std::unique_ptr<HIR::MatchCase> wildcard;
1033 std::vector<std::unique_ptr<HIR::Pattern>> heads;
1034 std::vector<std::vector<HIR::MatchCase>> cases;
1035};
1036
1037// Helper for simplify_tuple_match.
1038// For each tuple pattern in a given match, pull out the first elt of the
1039// tuple and construct a new MatchCase with the remaining tuple elts as the
1040// pattern. Return a mapping from each _unique_ first tuple element to a
1041// vec of cases for a new match.
1042//
1043// FIXME: This used to be a std::map<Pattern, Vec<MatchCase>>, but it doesn't
1044// actually work like we want - the Pattern includes an HIR ID, which is unique
1045// per Pattern object. This means we don't have a good means for comparing
1046// Patterns. It would probably be best to actually implement a means of
1047// properly comparing patterns, and then use an actual map.
1048//
1049static struct PatternMerge
1050sort_tuple_patterns (HIR::MatchExpr &expr)
1051{
1052 rust_assert (expr.get_scrutinee_expr ()->get_expression_type ()
1053 == HIR::Expr::ExprType::Tuple);
1054
1055 struct PatternMerge result;
1056 result.wildcard = nullptr;
1057 result.heads = std::vector<std::unique_ptr<HIR::Pattern>> ();
1058 result.cases = std::vector<std::vector<HIR::MatchCase>> ();
1059
1060 for (auto &match_case : expr.get_match_cases ())
1061 {
1062 HIR::MatchArm &case_arm = match_case.get_arm ();
1063
1064 // FIXME: Note we are only dealing with the first pattern in the arm.
1065 // The patterns vector in the arm might hold many patterns, which are the
1066 // patterns separated by the '|' token. Rustc abstracts these as "Or"
1067 // patterns, and part of its simplification process is to get rid of them.
1068 // We should get rid of the ORs too, maybe here or earlier than here?
1069 auto pat = case_arm.get_patterns ()[0]->clone_pattern ();
1070
1071 // Record wildcards so we can add them in inner matches.
1072 if (pat->get_pattern_type () == HIR::Pattern::PatternType::WILDCARD)
1073 {
1074 // The *whole* pattern is a wild card (_).
1075 result.wildcard
1076 = std::unique_ptr<HIR::MatchCase> (new HIR::MatchCase (match_case));
1077 continue;
1078 }
1079
1080 rust_assert (pat->get_pattern_type ()
1081 == HIR::Pattern::PatternType::TUPLE);
1082
1083 auto ref = *static_cast<HIR::TuplePattern *> (pat.get ());
1084
1085 rust_assert (ref.has_tuple_pattern_items ());
1086
1087 auto items
1088 = HIR::TuplePattern (ref).get_items ()->clone_tuple_pattern_items ();
1089 if (items->get_pattern_type ()
1090 == HIR::TuplePatternItems::TuplePatternItemType::MULTIPLE)
1091 {
1092 auto items_ref
1093 = *static_cast<HIR::TuplePatternItemsMultiple *> (items.get ());
1094
1095 // Pop the first pattern out
1096 auto patterns = std::vector<std::unique_ptr<HIR::Pattern>> ();
1097 auto first = items_ref.get_patterns ()[0]->clone_pattern ();
1098 for (auto p = items_ref.get_patterns ().begin () + 1;
1099 p != items_ref.get_patterns ().end (); p++)
1100 {
1101 patterns.push_back ((*p)->clone_pattern ());
1102 }
1103
1104 // if there is only one pattern left, don't make a tuple out of it
1105 std::unique_ptr<HIR::Pattern> result_pattern;
1106 if (patterns.size () == 1)
1107 {
1108 result_pattern = std::move (patterns[0]);
1109 }
1110 else
1111 {
1112 auto new_items = std::unique_ptr<HIR::TuplePatternItems> (
1113 new HIR::TuplePatternItemsMultiple (std::move (patterns)));
1114
1115 // Construct a TuplePattern from the rest of the patterns
1116 result_pattern = std::unique_ptr<HIR::Pattern> (
1117 new HIR::TuplePattern (ref.get_pattern_mappings (),
1118 std::move (new_items),
1119 ref.get_locus ()));
1120 }
1121
1122 // I don't know why we need to make foo separately here but
1123 // using the { new_tuple } syntax in new_arm constructor does not
1124 // compile.
1125 auto foo = std::vector<std::unique_ptr<HIR::Pattern>> ();
1126 foo.emplace_back (std::move (result_pattern));
1127 HIR::MatchArm new_arm (std::move (foo), Location (), nullptr,
1128 AST::AttrVec ());
1129
1130 HIR::MatchCase new_case (match_case.get_mappings (), new_arm,
1131 match_case.get_expr ()->clone_expr ());
1132
1133 bool pushed = false;
1134 for (size_t i = 0; i < result.heads.size (); i++)
1135 {
1136 if (patterns_mergeable (result.heads[i].get (), first.get ()))
1137 {
1138 result.cases[i].push_back (new_case);
1139 pushed = true;
1140 }
1141 }
1142
1143 if (!pushed)
1144 {
1145 result.heads.push_back (std::move (first));
1146 result.cases.push_back ({new_case});
1147 }
1148 }
1149 else /* TuplePatternItemType::RANGED */
1150 {
1151 // FIXME
1152 gcc_unreachable ();
1153 }
1154 }
1155
1156 return result;
1157}
1158
1159// Helper for CompileExpr::visit (HIR::MatchExpr).
1160// Given a MatchExpr where the scrutinee is some kind of tuple, build an
1161// equivalent match where only one element of the tuple is examined at a time.
1162// This resulting match can then be lowered to a SWITCH_EXPR tree directly.
1163//
1164// The approach is as follows:
1165// 1. Split the scrutinee and each pattern into the first (head) and the
1166// rest (tail).
1167// 2. Build a mapping of unique pattern heads to the cases (tail and expr)
1168// that shared that pattern head in the original match.
1169// (This is the job of sort_tuple_patterns ()).
1170// 3. For each unique pattern head, build a new MatchCase where the pattern
1171// is the unique head, and the expression is a new match where:
1172// - The scrutinee is the tail of the original scrutinee
1173// - The cases are are those built by the mapping in step 2, i.e. the
1174// tails of the patterns and the corresponing expressions from the
1175// original match expression.
1176// 4. Do this recursively for each inner match, until there is nothing more
1177// to simplify.
1178// 5. Build the resulting match which scrutinizes the head of the original
1179// scrutinee, using the cases built in step 3.
1180static HIR::MatchExpr
1181simplify_tuple_match (HIR::MatchExpr &expr)
1182{
1183 if (expr.get_scrutinee_expr ()->get_expression_type ()
1184 != HIR::Expr::ExprType::Tuple)
1185 return expr;
1186
1187 auto ref = *static_cast<HIR::TupleExpr *> (expr.get_scrutinee_expr ().get ());
1188
1189 auto &tail = ref.get_tuple_elems ();
1190 rust_assert (tail.size () > 1);
1191
1192 auto head = std::move (tail[0]);
1193 tail.erase (tail.begin (), tail.begin () + 1);
1194
1195 // e.g.
1196 // match (tupA, tupB, tupC) {
1197 // (a1, b1, c1) => { blk1 },
1198 // (a2, b2, c2) => { blk2 },
1199 // (a1, b3, c3) => { blk3 },
1200 // }
1201 // tail = (tupB, tupC)
1202 // head = tupA
1203
1204 // Make sure the tail is only a tuple if it consists of at least 2 elements.
1205 std::unique_ptr<HIR::Expr> remaining;
1206 if (tail.size () == 1)
1207 remaining = std::move (tail[0]);
1208 else
1209 remaining = std::unique_ptr<HIR::Expr> (
1210 new HIR::TupleExpr (ref.get_mappings (), std::move (tail),
1211 AST::AttrVec (), ref.get_outer_attrs (),
1212 ref.get_locus ()));
1213
1214 // e.g.
1215 // a1 -> [(b1, c1) => { blk1 },
1216 // (b3, c3) => { blk3 }]
1217 // a2 -> [(b2, c2) => { blk2 }]
1218 struct PatternMerge map = sort_tuple_patterns (expr);
1219
1220 std::vector<HIR::MatchCase> cases;
1221 // Construct the inner match for each unique first elt of the tuple
1222 // patterns
1223 for (size_t i = 0; i < map.heads.size (); i++)
1224 {
1225 auto inner_match_cases = map.cases[i];
1226
1227 // If there is a wildcard at the outer match level, then need to
1228 // propegate the wildcard case into *every* inner match.
1229 // FIXME: It is probably not correct to add this unconditionally, what if
1230 // we have a pattern like (a, _, c)? Then there is already a wildcard in
1231 // the inner matches, and having two will cause two 'default:' blocks
1232 // which is an error.
1233 if (map.wildcard != nullptr)
1234 {
1235 inner_match_cases.push_back (*(map.wildcard.get ()));
1236 }
1237
1238 // match (tupB, tupC) {
1239 // (b1, c1) => { blk1 },
1240 // (b3, c3) => { blk3 }
1241 // }
1242 HIR::MatchExpr inner_match (expr.get_mappings (),
1243 remaining->clone_expr (), inner_match_cases,
1244 AST::AttrVec (), expr.get_outer_attrs (),
1245 expr.get_locus ());
1246
1247 inner_match = simplify_tuple_match (inner_match);
1248
1249 auto outer_arm_pat = std::vector<std::unique_ptr<HIR::Pattern>> ();
1250 outer_arm_pat.emplace_back (map.heads[i]->clone_pattern ());
1251
1252 HIR::MatchArm outer_arm (std::move (outer_arm_pat), expr.get_locus ());
1253
1254 // Need to move the inner match to the heap and put it in a unique_ptr to
1255 // build the actual match case of the outer expression
1256 // auto inner_expr = std::unique_ptr<HIR::Expr> (new HIR::MatchExpr
1257 // (inner_match));
1258 auto inner_expr = inner_match.clone_expr ();
1259
1260 // a1 => match (tupB, tupC) { ... }
1261 HIR::MatchCase outer_case (expr.get_mappings (), outer_arm,
1262 std::move (inner_expr));
1263
1264 cases.push_back (outer_case);
1265 }
1266
1267 // If there was a wildcard, make sure to include it at the outer match level
1268 // too.
1269 if (map.wildcard != nullptr)
1270 {
1271 cases.push_back (*(map.wildcard.get ()));
1272 }
1273
1274 // match tupA {
1275 // a1 => match (tupB, tupC) {
1276 // (b1, c1) => { blk1 },
1277 // (b3, c3) => { blk3 }
1278 // }
1279 // a2 => match (tupB, tupC) {
1280 // (b2, c2) => { blk2 }
1281 // }
1282 // }
1283 HIR::MatchExpr outer_match (expr.get_mappings (), std::move (head), cases,
1284 AST::AttrVec (), expr.get_outer_attrs (),
1285 expr.get_locus ());
1286
1287 return outer_match;
1288}
1289
1290// Helper for CompileExpr::visit (HIR::MatchExpr).
1291// Check that the scrutinee of EXPR is a valid kind of expression to match on.
1292// Return the TypeKind of the scrutinee if it is valid, or TyTy::TypeKind::ERROR
1293// if not.
1294static TyTy::TypeKind
1295check_match_scrutinee (HIR::MatchExpr &expr, Context *ctx)
1296{
1297 TyTy::BaseType *scrutinee_expr_tyty = nullptr;
1298 if (!ctx->get_tyctx ()->lookup_type (
1299 expr.get_scrutinee_expr ()->get_mappings ().get_hirid (),
1300 &scrutinee_expr_tyty))
1301 {
1302 return TyTy::TypeKind::ERROR;
1303 }
1304
1305 TyTy::TypeKind scrutinee_kind = scrutinee_expr_tyty->get_kind ();
1306 rust_assert ((TyTy::is_primitive_type_kind (scrutinee_kind)
1307 && scrutinee_kind != TyTy::TypeKind::NEVER)
1308 || scrutinee_kind == TyTy::TypeKind::ADT
1309 || scrutinee_kind == TyTy::TypeKind::TUPLE);
1310
1311 if (scrutinee_kind == TyTy::TypeKind::ADT)
1312 {
1313 // this will need to change but for now the first pass implementation,
1314 // lets assert this is the case
1315 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (scrutinee_expr_tyty);
1316 rust_assert (adt->is_enum ());
1317 rust_assert (adt->number_of_variants () > 0);
1318 }
1319 else if (scrutinee_kind == TyTy::TypeKind::FLOAT)
1320 {
1321 // FIXME: CASE_LABEL_EXPR does not support floating point types.
1322 // Find another way to compile these.
1323 rust_sorry_at (expr.get_locus (),
1324 "match on floating-point types is not yet supported");
1325 }
1326
1327 TyTy::BaseType *expr_tyty = nullptr;
1328 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
1329 &expr_tyty))
1330 {
1331 return TyTy::TypeKind::ERROR;
1332 }
1333
1334 return scrutinee_kind;
1335}
1336
1337void
1338CompileExpr::visit (HIR::MatchExpr &expr)
1339{
1340 // https://gcc.gnu.org/onlinedocs/gccint/Basic-Statements.html#Basic-Statements
1341 // TODO
1342 // SWITCH_ALL_CASES_P is true if the switch includes a default label or the
1343 // case label ranges cover all possible values of the condition expression
1344
019b2f15
PH
1345 TyTy::TypeKind scrutinee_kind = check_match_scrutinee (expr, ctx);
1346 if (scrutinee_kind == TyTy::TypeKind::ERROR)
1347 {
1348 translated = error_mark_node;
1349 return;
1350 }
1351
1352 TyTy::BaseType *expr_tyty = nullptr;
1353 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
1354 &expr_tyty))
1355 {
1356 translated = error_mark_node;
1357 return;
1358 }
1359
1360 fncontext fnctx = ctx->peek_fn ();
1361 Bvariable *tmp = NULL;
1362 bool needs_temp = !expr_tyty->is_unit ();
1363 if (needs_temp)
1364 {
1365 tree enclosing_scope = ctx->peek_enclosing_scope ();
1366 tree block_type = TyTyResolveCompile::compile (ctx, expr_tyty);
1367
1368 bool is_address_taken = false;
1369 tree ret_var_stmt = nullptr;
1370 tmp = ctx->get_backend ()->temporary_variable (
1371 fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken,
1372 expr.get_locus (), &ret_var_stmt);
1373 ctx->add_statement (ret_var_stmt);
1374 }
1375
1376 // lets compile the scrutinee expression
1377 tree match_scrutinee_expr
1378 = CompileExpr::Compile (expr.get_scrutinee_expr ().get (), ctx);
1379
1380 tree match_scrutinee_expr_qualifier_expr;
1381 if (TyTy::is_primitive_type_kind (scrutinee_kind))
1382 {
1383 match_scrutinee_expr_qualifier_expr = match_scrutinee_expr;
1384 }
1385 else if (scrutinee_kind == TyTy::TypeKind::ADT)
1386 {
1387 // need to access qualifier the field, if we use QUAL_UNION_TYPE this
1388 // would be DECL_QUALIFIER i think. For now this will just access the
1389 // first record field and its respective qualifier because it will always
1390 // be set because this is all a big special union
1391 tree scrutinee_first_record_expr
1392 = ctx->get_backend ()->struct_field_expression (
1393 match_scrutinee_expr, 0, expr.get_scrutinee_expr ()->get_locus ());
1394 match_scrutinee_expr_qualifier_expr
1395 = ctx->get_backend ()->struct_field_expression (
1396 scrutinee_first_record_expr, 0,
1397 expr.get_scrutinee_expr ()->get_locus ());
1398 }
1399 else if (scrutinee_kind == TyTy::TypeKind::TUPLE)
1400 {
1401 // match on tuple becomes a series of nested switches, with one level
1402 // for each element of the tuple from left to right.
1403 auto exprtype = expr.get_scrutinee_expr ()->get_expression_type ();
1404 switch (exprtype)
1405 {
1406 case HIR::Expr::ExprType::Tuple: {
1407 // Build an equivalent expression which is nicer to lower.
1408 HIR::MatchExpr outer_match = simplify_tuple_match (expr);
1409
1410 // We've rearranged the match into something that lowers better
1411 // to GENERIC trees.
1412 // For actually doing the lowering we need to compile the match
1413 // we've just made. But we're half-way through compiling the
1414 // original one.
1415 // ...
1416 // For now, let's just replace the original with the rearranged one
1417 // we just made, and compile that instead. What could go wrong? :)
1418 //
1419 // FIXME: What about when we decide a temporary is needed above?
1420 // We might have already pushed a statement for it that
1421 // we no longer need. Probably need to rearrange the order
1422 // of these steps.
1423 expr = outer_match;
1424
1425 scrutinee_kind = check_match_scrutinee (expr, ctx);
1426 if (scrutinee_kind == TyTy::TypeKind::ERROR)
1427 {
1428 translated = error_mark_node;
1429 return;
1430 }
1431
1432 // Now compile the scrutinee of the simplified match.
1433 // FIXME: this part is duplicated from above.
1434 match_scrutinee_expr
1435 = CompileExpr::Compile (expr.get_scrutinee_expr ().get (), ctx);
1436
1437 if (TyTy::is_primitive_type_kind (scrutinee_kind))
1438 {
1439 match_scrutinee_expr_qualifier_expr = match_scrutinee_expr;
1440 }
1441 else if (scrutinee_kind == TyTy::TypeKind::ADT)
1442 {
1443 // need to access qualifier the field, if we use QUAL_UNION_TYPE
1444 // this would be DECL_QUALIFIER i think. For now this will just
1445 // access the first record field and its respective qualifier
1446 // because it will always be set because this is all a big
1447 // special union
1448 tree scrutinee_first_record_expr
1449 = ctx->get_backend ()->struct_field_expression (
1450 match_scrutinee_expr, 0,
1451 expr.get_scrutinee_expr ()->get_locus ());
1452 match_scrutinee_expr_qualifier_expr
1453 = ctx->get_backend ()->struct_field_expression (
1454 scrutinee_first_record_expr, 0,
1455 expr.get_scrutinee_expr ()->get_locus ());
1456 }
1457 else
1458 {
1459 // FIXME: There are other cases, but it better not be a Tuple
1460 gcc_unreachable ();
1461 }
1462 }
1463 break;
1464
1465 case HIR::Expr::ExprType::Path: {
1466 // FIXME
1467 gcc_unreachable ();
1468 }
1469 break;
1470
1471 default:
1472 gcc_unreachable ();
1473 }
1474 }
1475 else
1476 {
1477 // FIXME: match on other types of expressions not yet implemented.
1478 gcc_unreachable ();
1479 }
1480
1481 // setup the end label so the cases can exit properly
1482 tree fndecl = fnctx.fndecl;
1483 Location end_label_locus = expr.get_locus (); // FIXME
1484 tree end_label
1485 = ctx->get_backend ()->label (fndecl,
1486 "" /* empty creates an artificial label */,
1487 end_label_locus);
1488 tree end_label_decl_statement
1489 = ctx->get_backend ()->label_definition_statement (end_label);
1490
1491 // setup the switch-body-block
1492 Location start_location; // FIXME
1493 Location end_location; // FIXME
1494 tree enclosing_scope = ctx->peek_enclosing_scope ();
1495 tree switch_body_block
1496 = ctx->get_backend ()->block (fndecl, enclosing_scope, {}, start_location,
1497 end_location);
1498 ctx->push_block (switch_body_block);
1499
1500 for (auto &kase : expr.get_match_cases ())
1501 {
1502 // for now lets just get single pattern's working
1503 HIR::MatchArm &kase_arm = kase.get_arm ();
1504 rust_assert (kase_arm.get_patterns ().size () > 0);
1505
1506 // generate implicit label
1507 Location arm_locus = kase_arm.get_locus ();
1508 tree case_label = ctx->get_backend ()->label (
1509 fndecl, "" /* empty creates an artificial label */, arm_locus);
1510
1511 // setup the bindings for the block
1512 for (auto &kase_pattern : kase_arm.get_patterns ())
1513 {
1514 tree switch_kase_expr
1515 = CompilePatternCaseLabelExpr::Compile (kase_pattern.get (),
1516 case_label, ctx);
1517 ctx->add_statement (switch_kase_expr);
1518
1519 CompilePatternBindings::Compile (kase_pattern.get (),
1520 match_scrutinee_expr, ctx);
1521 }
1522
1523 // compile the expr and setup the assignment if required when tmp != NULL
1524 tree kase_expr_tree = CompileExpr::Compile (kase.get_expr ().get (), ctx);
1525 if (tmp != NULL)
1526 {
1527 tree result_reference
1528 = ctx->get_backend ()->var_expression (tmp, arm_locus);
1529 tree assignment
1530 = ctx->get_backend ()->assignment_statement (result_reference,
1531 kase_expr_tree,
1532 arm_locus);
1533 ctx->add_statement (assignment);
1534 }
1535
1536 // go to end label
1537 tree goto_end_label = build1_loc (arm_locus.gcc_location (), GOTO_EXPR,
1538 void_type_node, end_label);
1539 ctx->add_statement (goto_end_label);
1540 }
1541
1542 // setup the switch expression
1543 tree match_body = ctx->pop_block ();
1544 tree match_expr_stmt
1545 = build2_loc (expr.get_locus ().gcc_location (), SWITCH_EXPR,
1546 TREE_TYPE (match_scrutinee_expr_qualifier_expr),
1547 match_scrutinee_expr_qualifier_expr, match_body);
1548 ctx->add_statement (match_expr_stmt);
1549 ctx->add_statement (end_label_decl_statement);
1550
1551 if (tmp != NULL)
1552 {
1553 translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ());
1554 }
1555}
1556
1557void
1558CompileExpr::visit (HIR::CallExpr &expr)
1559{
1560 TyTy::BaseType *tyty = nullptr;
1561 if (!ctx->get_tyctx ()->lookup_type (
1562 expr.get_fnexpr ()->get_mappings ().get_hirid (), &tyty))
1563 {
1564 rust_error_at (expr.get_locus (), "unknown type");
1565 return;
1566 }
1567
1568 // must be a tuple constructor
699e7e86 1569 bool is_adt_ctor = tyty->get_kind () == TyTy::TypeKind::ADT;
019b2f15
PH
1570 if (is_adt_ctor)
1571 {
1572 rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT);
1573 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
1574 tree compiled_adt_type = TyTyResolveCompile::compile (ctx, tyty);
1575
1576 // what variant is it?
1577 int union_disriminator = -1;
1578 TyTy::VariantDef *variant = nullptr;
1579 if (!adt->is_enum ())
1580 {
1581 rust_assert (adt->number_of_variants () == 1);
1582 variant = adt->get_variants ().at (0);
1583 }
1584 else
1585 {
1586 HirId variant_id;
1587 bool ok = ctx->get_tyctx ()->lookup_variant_definition (
1588 expr.get_fnexpr ()->get_mappings ().get_hirid (), &variant_id);
1589 rust_assert (ok);
1590
1591 ok = adt->lookup_variant_by_id (variant_id, &variant,
1592 &union_disriminator);
1593 rust_assert (ok);
1594 }
1595
1596 // this assumes all fields are in order from type resolution and if a
1597 // base struct was specified those fields are filed via accesors
1598 std::vector<tree> arguments;
1599 for (size_t i = 0; i < expr.get_arguments ().size (); i++)
1600 {
1601 auto &argument = expr.get_arguments ().at (i);
1602 auto rvalue = CompileExpr::Compile (argument.get (), ctx);
1603
1604 // assignments are coercion sites so lets convert the rvalue if
1605 // necessary
1606 auto respective_field = variant->get_field_at_index (i);
1607 auto expected = respective_field->get_field_type ();
1608
1609 TyTy::BaseType *actual = nullptr;
1610 bool ok = ctx->get_tyctx ()->lookup_type (
1611 argument->get_mappings ().get_hirid (), &actual);
1612 rust_assert (ok);
1613
1614 // coerce it if required
1615 Location lvalue_locus
1616 = ctx->get_mappings ()->lookup_location (expected->get_ty_ref ());
1617 Location rvalue_locus = argument->get_locus ();
1618 rvalue
1619 = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
1620 actual, expected, lvalue_locus, rvalue_locus);
1621
1622 // add it to the list
1623 arguments.push_back (rvalue);
1624 }
1625
1626 // the constructor depends on whether this is actually an enum or not if
1627 // its an enum we need to setup the discriminator
1628 std::vector<tree> ctor_arguments;
1629 if (adt->is_enum ())
1630 {
1631 HIR::Expr *discrim_expr = variant->get_discriminant ();
1632 tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
1633 tree folded_discrim_expr = fold_expr (discrim_expr_node);
1634 tree qualifier = folded_discrim_expr;
1635
1636 ctor_arguments.push_back (qualifier);
1637 }
1638 for (auto &arg : arguments)
1639 ctor_arguments.push_back (arg);
1640
1641 translated = ctx->get_backend ()->constructor_expression (
1642 compiled_adt_type, adt->is_enum (), ctor_arguments, union_disriminator,
1643 expr.get_locus ());
1644
1645 return;
1646 }
1647
1648 auto get_parameter_tyty_at_index
1649 = [] (const TyTy::BaseType *base, size_t index,
1650 TyTy::BaseType **result) -> bool {
1651 bool is_fn = base->get_kind () == TyTy::TypeKind::FNDEF
1652 || base->get_kind () == TyTy::TypeKind::FNPTR;
1653 rust_assert (is_fn);
1654
1655 if (base->get_kind () == TyTy::TypeKind::FNPTR)
1656 {
1657 const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (base);
1658 *result = fn->param_at (index);
1659
1660 return true;
1661 }
1662
1663 const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (base);
1664 auto param = fn->param_at (index);
1665 *result = param.second;
1666
1667 return true;
1668 };
1669
699e7e86
PH
1670 auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx);
1671
1672 // is this a closure call?
21d19d2c
PH
1673 bool possible_trait_call
1674 = generate_possible_fn_trait_call (expr, fn_address, &translated);
1675 if (possible_trait_call)
1676 return;
699e7e86 1677
019b2f15
PH
1678 bool is_varadic = false;
1679 if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
1680 {
1681 const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (tyty);
1682 is_varadic = fn->is_varadic ();
1683 }
1684
699e7e86 1685 size_t required_num_args = expr.get_arguments ().size ();
019b2f15
PH
1686 if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
1687 {
1688 const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (tyty);
1689 required_num_args = fn->num_params ();
1690 }
699e7e86 1691 else if (tyty->get_kind () == TyTy::TypeKind::FNPTR)
019b2f15
PH
1692 {
1693 const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (tyty);
1694 required_num_args = fn->num_params ();
1695 }
1696
1697 std::vector<tree> args;
1698 for (size_t i = 0; i < expr.get_arguments ().size (); i++)
1699 {
1700 auto &argument = expr.get_arguments ().at (i);
1701 auto rvalue = CompileExpr::Compile (argument.get (), ctx);
1702
1703 if (is_varadic && i >= required_num_args)
1704 {
1705 args.push_back (rvalue);
1706 continue;
1707 }
1708
1709 // assignments are coercion sites so lets convert the rvalue if
1710 // necessary
1711 bool ok;
1712 TyTy::BaseType *expected = nullptr;
1713 ok = get_parameter_tyty_at_index (tyty, i, &expected);
1714 rust_assert (ok);
1715
1716 TyTy::BaseType *actual = nullptr;
1717 ok = ctx->get_tyctx ()->lookup_type (
1718 argument->get_mappings ().get_hirid (), &actual);
1719 rust_assert (ok);
1720
1721 // coerce it if required
1722 Location lvalue_locus
1723 = ctx->get_mappings ()->lookup_location (expected->get_ty_ref ());
1724 Location rvalue_locus = argument->get_locus ();
1725 rvalue = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
1726 actual, expected, lvalue_locus, rvalue_locus);
1727
1728 // add it to the list
1729 args.push_back (rvalue);
1730 }
1731
699e7e86 1732 // must be a regular call to a function
019b2f15
PH
1733 translated = ctx->get_backend ()->call_expression (fn_address, args, nullptr,
1734 expr.get_locus ());
1735}
1736
1737void
1738CompileExpr::visit (HIR::MethodCallExpr &expr)
1739{
1740 // method receiver
1741 tree self = CompileExpr::Compile (expr.get_receiver ().get (), ctx);
1742
1743 // lookup the resolved name
1744 NodeId resolved_node_id = UNKNOWN_NODEID;
1745 if (!ctx->get_resolver ()->lookup_resolved_name (
1746 expr.get_mappings ().get_nodeid (), &resolved_node_id))
1747 {
1748 rust_error_at (expr.get_locus (), "failed to lookup resolved MethodCall");
1749 return;
1750 }
1751
1752 // reverse lookup
1753 HirId ref;
1754 if (!ctx->get_mappings ()->lookup_node_to_hir (resolved_node_id, &ref))
1755 {
1756 rust_fatal_error (expr.get_locus (), "reverse lookup failure");
1757 return;
1758 }
1759
1760 // lookup the expected function type
1761 TyTy::BaseType *lookup_fntype = nullptr;
1762 bool ok = ctx->get_tyctx ()->lookup_type (
1763 expr.get_method_name ().get_mappings ().get_hirid (), &lookup_fntype);
1764 rust_assert (ok);
1765 rust_assert (lookup_fntype->get_kind () == TyTy::TypeKind::FNDEF);
1766 TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup_fntype);
1767
1768 TyTy::BaseType *receiver = nullptr;
1769 ok = ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hirid (),
1770 &receiver);
1771 rust_assert (ok);
1772
1773 bool is_dyn_dispatch
1774 = receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC;
1775 bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
1776 if (is_generic_receiver)
1777 {
1778 TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
1779 receiver = p->resolve ();
1780 }
1781
1782 tree fn_expr = error_mark_node;
1783 if (is_dyn_dispatch)
1784 {
1785 const TyTy::DynamicObjectType *dyn
1786 = static_cast<const TyTy::DynamicObjectType *> (receiver->get_root ());
1787
1788 std::vector<HIR::Expr *> arguments;
1789 for (auto &arg : expr.get_arguments ())
1790 arguments.push_back (arg.get ());
1791
1792 fn_expr
1793 = get_fn_addr_from_dyn (dyn, receiver, fntype, self, expr.get_locus ());
1794 self = get_receiver_from_dyn (dyn, receiver, fntype, self,
1795 expr.get_locus ());
1796 }
1797 else
1798 {
1799 // lookup compiled functions since it may have already been compiled
1800 HIR::PathExprSegment method_name = expr.get_method_name ();
1801 HIR::PathIdentSegment segment_name = method_name.get_segment ();
1802 fn_expr
1803 = resolve_method_address (fntype, ref, receiver, segment_name,
1804 expr.get_mappings (), expr.get_locus ());
1805 }
1806
1807 // lookup the autoderef mappings
1808 HirId autoderef_mappings_id
1809 = expr.get_receiver ()->get_mappings ().get_hirid ();
1810 std::vector<Resolver::Adjustment> *adjustments = nullptr;
1811 ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id,
1812 &adjustments);
1813 rust_assert (ok);
1814
1815 // apply adjustments for the fn call
1816 self = resolve_adjustements (*adjustments, self,
1817 expr.get_receiver ()->get_locus ());
1818
1819 std::vector<tree> args;
1820 args.push_back (self); // adjusted self
1821
1822 // normal args
1823 for (size_t i = 0; i < expr.get_arguments ().size (); i++)
1824 {
1825 auto &argument = expr.get_arguments ().at (i);
1826 auto rvalue = CompileExpr::Compile (argument.get (), ctx);
1827
1828 // assignments are coercion sites so lets convert the rvalue if
1829 // necessary, offset from the already adjusted implicit self
1830 bool ok;
1831 TyTy::BaseType *expected = fntype->param_at (i + 1).second;
1832
1833 TyTy::BaseType *actual = nullptr;
1834 ok = ctx->get_tyctx ()->lookup_type (
1835 argument->get_mappings ().get_hirid (), &actual);
1836 rust_assert (ok);
1837
1838 // coerce it if required
1839 Location lvalue_locus
1840 = ctx->get_mappings ()->lookup_location (expected->get_ty_ref ());
1841 Location rvalue_locus = argument->get_locus ();
1842 rvalue = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
1843 actual, expected, lvalue_locus, rvalue_locus);
1844
1845 // add it to the list
1846 args.push_back (rvalue);
1847 }
1848
1849 translated = ctx->get_backend ()->call_expression (fn_expr, args, nullptr,
1850 expr.get_locus ());
1851}
1852
1853tree
1854CompileExpr::get_fn_addr_from_dyn (const TyTy::DynamicObjectType *dyn,
1855 TyTy::BaseType *receiver,
1856 TyTy::FnType *fntype, tree receiver_ref,
1857 Location expr_locus)
1858{
1859 size_t offs = 0;
1860 const Resolver::TraitItemReference *ref = nullptr;
1861 for (auto &bound : dyn->get_object_items ())
1862 {
1863 const Resolver::TraitItemReference *item = bound.first;
1864 auto t = item->get_tyty ();
1865 rust_assert (t->get_kind () == TyTy::TypeKind::FNDEF);
1866 auto ft = static_cast<TyTy::FnType *> (t);
1867
1868 if (ft->get_id () == fntype->get_id ())
1869 {
1870 ref = item;
1871 break;
1872 }
1873 offs++;
1874 }
1875
1876 if (ref == nullptr)
1877 return error_mark_node;
1878
1879 // get any indirection sorted out
1880 if (receiver->get_kind () == TyTy::TypeKind::REF)
1881 {
1882 tree indirect = indirect_expression (receiver_ref, expr_locus);
1883 receiver_ref = indirect;
1884 }
1885
1886 // cast it to the correct fntype
1887 tree expected_fntype = TyTyResolveCompile::compile (ctx, fntype, true);
1888 tree idx = build_int_cst (size_type_node, offs);
1889
1890 tree vtable_ptr
1891 = ctx->get_backend ()->struct_field_expression (receiver_ref, 1,
1892 expr_locus);
1893 tree vtable_array_access = build4_loc (expr_locus.gcc_location (), ARRAY_REF,
1894 TREE_TYPE (TREE_TYPE (vtable_ptr)),
1895 vtable_ptr, idx, NULL_TREE, NULL_TREE);
1896
1897 tree vcall
1898 = build3_loc (expr_locus.gcc_location (), OBJ_TYPE_REF, expected_fntype,
1899 vtable_array_access, receiver_ref, idx);
1900
1901 return vcall;
1902}
1903
1904tree
1905CompileExpr::get_receiver_from_dyn (const TyTy::DynamicObjectType *dyn,
1906 TyTy::BaseType *receiver,
1907 TyTy::FnType *fntype, tree receiver_ref,
1908 Location expr_locus)
1909{
1910 // get any indirection sorted out
1911 if (receiver->get_kind () == TyTy::TypeKind::REF)
1912 {
1913 tree indirect = indirect_expression (receiver_ref, expr_locus);
1914 receiver_ref = indirect;
1915 }
1916
1917 // access the offs + 1 for the fnptr and offs=0 for the reciever obj
1918 return ctx->get_backend ()->struct_field_expression (receiver_ref, 0,
1919 expr_locus);
1920}
1921
1922tree
1923CompileExpr::resolve_method_address (TyTy::FnType *fntype, HirId ref,
1924 TyTy::BaseType *receiver,
1925 HIR::PathIdentSegment &segment,
1926 Analysis::NodeMapping expr_mappings,
1927 Location expr_locus)
1928{
1929 // lookup compiled functions since it may have already been compiled
1930 tree fn = NULL_TREE;
1931 if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
1932 {
1933 return address_expression (fn, expr_locus);
1934 }
1935
1936 // Now we can try and resolve the address since this might be a forward
1937 // declared function, generic function which has not be compiled yet or
1938 // its an not yet trait bound function
1939 HIR::ImplItem *resolved_item
1940 = ctx->get_mappings ()->lookup_hir_implitem (ref, nullptr);
1941 if (resolved_item != nullptr)
1942 {
1943 if (!fntype->has_subsititions_defined ())
1944 return CompileInherentImplItem::Compile (resolved_item, ctx);
1945
1946 return CompileInherentImplItem::Compile (resolved_item, ctx, fntype);
1947 }
1948
1949 // it might be resolved to a trait item
1950 HIR::TraitItem *trait_item
1951 = ctx->get_mappings ()->lookup_hir_trait_item (ref);
1952 HIR::Trait *trait = ctx->get_mappings ()->lookup_trait_item_mapping (
1953 trait_item->get_mappings ().get_hirid ());
1954
1955 Resolver::TraitReference *trait_ref
1956 = &Resolver::TraitReference::error_node ();
1957 bool ok = ctx->get_tyctx ()->lookup_trait_reference (
1958 trait->get_mappings ().get_defid (), &trait_ref);
1959 rust_assert (ok);
1960
1961 // the type resolver can only resolve type bounds to their trait
1962 // item so its up to us to figure out if this path should resolve
1963 // to an trait-impl-block-item or if it can be defaulted to the
1964 // trait-impl-item's definition
1965
1966 auto root = receiver->get_root ();
31b77593 1967 auto candidates
019b2f15
PH
1968 = Resolver::PathProbeType::Probe (root, segment, true /* probe_impls */,
1969 false /* probe_bounds */,
1970 true /* ignore_mandatory_trait_items */);
1971 if (candidates.size () == 0)
1972 {
1973 // this means we are defaulting back to the trait_item if
1974 // possible
1975 Resolver::TraitItemReference *trait_item_ref = nullptr;
1976 bool ok = trait_ref->lookup_hir_trait_item (*trait_item, &trait_item_ref);
1977 rust_assert (ok); // found
1978 rust_assert (trait_item_ref->is_optional ()); // has definition
1979
1980 // FIXME Optional means it has a definition and an associated
1981 // block which can be a default implementation, if it does not
1982 // contain an implementation we should actually return
1983 // error_mark_node
1984
1985 return CompileTraitItem::Compile (trait_item_ref->get_hir_trait_item (),
1986 ctx, fntype, true, expr_locus);
1987 }
1988 else
1989 {
1990 // FIXME this will be a case to return error_mark_node, there is
1991 // an error scenario where a Trait Foo has a method Bar, but this
1992 // receiver does not implement this trait or has an incompatible
1993 // implementation and we should just return error_mark_node
1994
1995 rust_assert (candidates.size () == 1);
31b77593 1996 auto &candidate = *candidates.begin ();
019b2f15
PH
1997 rust_assert (candidate.is_impl_candidate ());
1998 rust_assert (candidate.ty->get_kind () == TyTy::TypeKind::FNDEF);
1999 TyTy::FnType *candidate_call = static_cast<TyTy::FnType *> (candidate.ty);
2000
2001 HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
2002 if (!candidate_call->has_subsititions_defined ())
2003 return CompileInherentImplItem::Compile (impl_item, ctx);
2004
2005 TyTy::BaseType *monomorphized = candidate_call;
2006 if (candidate_call->needs_generic_substitutions ())
2007 {
2008 TyTy::BaseType *infer_impl_call
2009 = candidate_call->infer_substitions (expr_locus);
68d671ac
PH
2010 monomorphized = Resolver::UnifyRules::Resolve (
2011 TyTy::TyWithLocation (infer_impl_call),
2012 TyTy::TyWithLocation (fntype), expr_locus, true /* commit */,
2013 true /* emit_errors */);
019b2f15
PH
2014 }
2015
2016 return CompileInherentImplItem::Compile (impl_item, ctx, monomorphized);
2017 }
2018}
2019
2020tree
2021CompileExpr::resolve_operator_overload (
2022 Analysis::RustLangItem::ItemType lang_item_type, HIR::OperatorExprMeta expr,
2023 tree lhs, tree rhs, HIR::Expr *lhs_expr, HIR::Expr *rhs_expr)
2024{
2025 TyTy::FnType *fntype;
2026 bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
2027 expr.get_mappings ().get_hirid (), &fntype);
2028 rust_assert (is_op_overload);
2029
2030 // lookup the resolved name
2031 NodeId resolved_node_id = UNKNOWN_NODEID;
2032 bool ok = ctx->get_resolver ()->lookup_resolved_name (
2033 expr.get_mappings ().get_nodeid (), &resolved_node_id);
2034 rust_assert (ok);
2035
2036 // reverse lookup
2037 HirId ref;
2038 ok = ctx->get_mappings ()->lookup_node_to_hir (resolved_node_id, &ref);
2039 rust_assert (ok);
2040
2041 TyTy::BaseType *receiver = nullptr;
2042 ok = ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hirid (),
2043 &receiver);
2044 rust_assert (ok);
2045
2046 bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
2047 if (is_generic_receiver)
2048 {
2049 TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
2050 receiver = p->resolve ();
2051 }
2052
2053 // lookup compiled functions since it may have already been compiled
2054 HIR::PathIdentSegment segment_name (
2055 Analysis::RustLangItem::ToString (lang_item_type));
2056 tree fn_expr
2057 = resolve_method_address (fntype, ref, receiver, segment_name,
2058 expr.get_mappings (), expr.get_locus ());
2059
2060 // lookup the autoderef mappings
2061 std::vector<Resolver::Adjustment> *adjustments = nullptr;
2062 ok = ctx->get_tyctx ()->lookup_autoderef_mappings (
2063 expr.get_lvalue_mappings ().get_hirid (), &adjustments);
2064 rust_assert (ok);
2065
2066 // apply adjustments for the fn call
2067 tree self = resolve_adjustements (*adjustments, lhs, lhs_expr->get_locus ());
2068
2069 std::vector<tree> args;
2070 args.push_back (self); // adjusted self
2071 if (rhs != nullptr) // can be null for negation_expr (unary ones)
2072 args.push_back (rhs);
2073
2074 return ctx->get_backend ()->call_expression (fn_expr, args, nullptr,
2075 expr.get_locus ());
2076}
2077
2078tree
2079CompileExpr::compile_bool_literal (const HIR::LiteralExpr &expr,
2080 const TyTy::BaseType *tyty)
2081{
2082 rust_assert (expr.get_lit_type () == HIR::Literal::BOOL);
2083
2084 const auto literal_value = expr.get_literal ();
2085 bool bval = literal_value.as_string ().compare ("true") == 0;
2086 return ctx->get_backend ()->boolean_constant_expression (bval);
2087}
2088
2089tree
2090CompileExpr::compile_integer_literal (const HIR::LiteralExpr &expr,
2091 const TyTy::BaseType *tyty)
2092{
2093 rust_assert (expr.get_lit_type () == HIR::Literal::INT);
2094 const auto literal_value = expr.get_literal ();
2095
2096 tree type = TyTyResolveCompile::compile (ctx, tyty);
2097
2098 mpz_t ival;
2099 if (mpz_init_set_str (ival, literal_value.as_string ().c_str (), 10) != 0)
2100 {
2101 rust_error_at (expr.get_locus (), "bad number in literal");
2102 return error_mark_node;
2103 }
2104
2105 mpz_t type_min;
2106 mpz_t type_max;
2107 mpz_init (type_min);
2108 mpz_init (type_max);
2109 get_type_static_bounds (type, type_min, type_max);
2110
2111 if (mpz_cmp (ival, type_min) < 0 || mpz_cmp (ival, type_max) > 0)
2112 {
2113 rust_error_at (expr.get_locus (),
2114 "integer overflows the respective type %<%s%>",
2115 tyty->get_name ().c_str ());
2116 return error_mark_node;
2117 }
2118
2119 tree result = wide_int_to_tree (type, wi::from_mpz (type, ival, true));
2120
2121 mpz_clear (type_min);
2122 mpz_clear (type_max);
2123 mpz_clear (ival);
2124
2125 return result;
2126}
2127
2128tree
2129CompileExpr::compile_float_literal (const HIR::LiteralExpr &expr,
2130 const TyTy::BaseType *tyty)
2131{
2132 rust_assert (expr.get_lit_type () == HIR::Literal::FLOAT);
2133 const auto literal_value = expr.get_literal ();
2134
2135 mpfr_t fval;
2136 if (mpfr_init_set_str (fval, literal_value.as_string ().c_str (), 10,
2137 MPFR_RNDN)
2138 != 0)
2139 {
2140 rust_error_at (expr.get_locus (), "bad number in literal");
2141 return error_mark_node;
2142 }
2143
2144 tree type = TyTyResolveCompile::compile (ctx, tyty);
2145
2146 // taken from:
2147 // see go/gofrontend/expressions.cc:check_float_type
2148 mpfr_exp_t exp = mpfr_get_exp (fval);
2149 bool real_value_overflow = exp > TYPE_PRECISION (type);
2150
2151 REAL_VALUE_TYPE r1;
2152 real_from_mpfr (&r1, fval, type, GMP_RNDN);
2153 REAL_VALUE_TYPE r2;
2154 real_convert (&r2, TYPE_MODE (type), &r1);
2155
2156 tree real_value = build_real (type, r2);
2157 if (TREE_OVERFLOW (real_value) || real_value_overflow)
2158 {
2159 rust_error_at (expr.get_locus (),
2160 "decimal overflows the respective type %<%s%>",
2161 tyty->get_name ().c_str ());
2162 return error_mark_node;
2163 }
2164
2165 return real_value;
2166}
2167
2168tree
2169CompileExpr::compile_char_literal (const HIR::LiteralExpr &expr,
2170 const TyTy::BaseType *tyty)
2171{
2172 rust_assert (expr.get_lit_type () == HIR::Literal::CHAR);
2173 const auto literal_value = expr.get_literal ();
2174
2175 // FIXME needs wchar_t
2176 char c = literal_value.as_string ().c_str ()[0];
2177 return ctx->get_backend ()->wchar_constant_expression (c);
2178}
2179
2180tree
2181CompileExpr::compile_byte_literal (const HIR::LiteralExpr &expr,
2182 const TyTy::BaseType *tyty)
2183{
2184 rust_assert (expr.get_lit_type () == HIR::Literal::BYTE);
2185 const auto literal_value = expr.get_literal ();
2186
2187 tree type = TyTyResolveCompile::compile (ctx, tyty);
2188 char c = literal_value.as_string ().c_str ()[0];
2189 return build_int_cst (type, c);
2190}
2191
2192tree
2193CompileExpr::compile_string_literal (const HIR::LiteralExpr &expr,
2194 const TyTy::BaseType *tyty)
2195{
2196 tree fat_pointer = TyTyResolveCompile::compile (ctx, tyty);
2197
2198 rust_assert (expr.get_lit_type () == HIR::Literal::STRING);
2199 const auto literal_value = expr.get_literal ();
2200
2201 auto base = ctx->get_backend ()->string_constant_expression (
2202 literal_value.as_string ());
2203 tree data = address_expression (base, expr.get_locus ());
2204
2205 TyTy::BaseType *usize = nullptr;
2206 bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
2207 rust_assert (ok);
2208 tree type = TyTyResolveCompile::compile (ctx, usize);
2209
2210 tree size = build_int_cstu (type, literal_value.as_string ().size ());
2211
2212 return ctx->get_backend ()->constructor_expression (fat_pointer, false,
2213 {data, size}, -1,
2214 expr.get_locus ());
2215}
2216
2217tree
2218CompileExpr::compile_byte_string_literal (const HIR::LiteralExpr &expr,
2219 const TyTy::BaseType *tyty)
2220{
2221 rust_assert (expr.get_lit_type () == HIR::Literal::BYTE_STRING);
2222
2223 // the type here is &[ty; capacity]
2224 rust_assert (tyty->get_kind () == TyTy::TypeKind::REF);
2225 const auto ref_tyty = static_cast<const TyTy::ReferenceType *> (tyty);
2226 auto base_tyty = ref_tyty->get_base ();
2227 rust_assert (base_tyty->get_kind () == TyTy::TypeKind::ARRAY);
2228 auto array_tyty = static_cast<TyTy::ArrayType *> (base_tyty);
2229
2230 std::string value_str = expr.get_literal ().as_string ();
2231 std::vector<tree> vals;
2232 std::vector<unsigned long> indexes;
2233 for (size_t i = 0; i < value_str.size (); i++)
2234 {
2235 char b = value_str.at (i);
2236 tree bb = ctx->get_backend ()->char_constant_expression (b);
2237 vals.push_back (bb);
2238 indexes.push_back (i);
2239 }
2240
2241 tree array_type = TyTyResolveCompile::compile (ctx, array_tyty);
2242 tree constructed
2243 = ctx->get_backend ()->array_constructor_expression (array_type, indexes,
2244 vals,
2245 expr.get_locus ());
2246
2247 return address_expression (constructed, expr.get_locus ());
2248}
2249
2250tree
2251CompileExpr::type_cast_expression (tree type_to_cast_to, tree expr_tree,
2252 Location location)
2253{
2254 if (type_to_cast_to == error_mark_node || expr_tree == error_mark_node
2255 || TREE_TYPE (expr_tree) == error_mark_node)
2256 return error_mark_node;
2257
2258 if (ctx->get_backend ()->type_size (type_to_cast_to) == 0
2259 || TREE_TYPE (expr_tree) == void_type_node)
2260 {
2261 // Do not convert zero-sized types.
2262 return expr_tree;
2263 }
2264 else if (TREE_CODE (type_to_cast_to) == INTEGER_TYPE)
2265 {
2266 tree cast = convert_to_integer (type_to_cast_to, expr_tree);
2267 // FIXME check for TREE_OVERFLOW?
2268 return cast;
2269 }
2270 else if (TREE_CODE (type_to_cast_to) == REAL_TYPE)
2271 {
2272 tree cast = convert_to_real (type_to_cast_to, expr_tree);
2273 // FIXME
2274 // We might need to check that the tree is MAX val and thusly saturate it
2275 // to inf. we can get the bounds and check the value if its >= or <= to
2276 // the min and max bounds
2277 //
2278 // https://github.com/Rust-GCC/gccrs/issues/635
2279 return cast;
2280 }
2281 else if (TREE_CODE (type_to_cast_to) == COMPLEX_TYPE)
2282 {
2283 return convert_to_complex (type_to_cast_to, expr_tree);
2284 }
2285 else if (TREE_CODE (type_to_cast_to) == POINTER_TYPE
2286 && TREE_CODE (TREE_TYPE (expr_tree)) == INTEGER_TYPE)
2287 {
2288 return convert_to_pointer (type_to_cast_to, expr_tree);
2289 }
2290 else if (TREE_CODE (type_to_cast_to) == RECORD_TYPE
2291 || TREE_CODE (type_to_cast_to) == ARRAY_TYPE)
2292 {
2293 return fold_build1_loc (location.gcc_location (), VIEW_CONVERT_EXPR,
2294 type_to_cast_to, expr_tree);
2295 }
2296 else if (TREE_CODE (type_to_cast_to) == POINTER_TYPE
2297 && SLICE_TYPE_P (TREE_TYPE (expr_tree)))
2298 {
2299 // returning a raw cast using NOP_EXPR seems to resut in an ICE:
2300 //
2301 // Analyzing compilation unit
2302 // Performing interprocedural optimizations
2303 // <*free_lang_data> {heap 2644k} <visibility> {heap 2644k}
2304 // <build_ssa_passes> {heap 2644k} <opt_local_passes> {heap 2644k}during
2305 // GIMPLE pass: cddce
2306 // In function ‘*T::as_ptr<i32>’:
2307 // rust1: internal compiler error: in propagate_necessity, at
2308 // tree-ssa-dce.cc:984 0x1d5b43e propagate_necessity
2309 // ../../gccrs/gcc/tree-ssa-dce.cc:984
2310 // 0x1d5e180 perform_tree_ssa_dce
2311 // ../../gccrs/gcc/tree-ssa-dce.cc:1876
2312 // 0x1d5e2c8 tree_ssa_cd_dce
2313 // ../../gccrs/gcc/tree-ssa-dce.cc:1920
2314 // 0x1d5e49a execute
2315 // ../../gccrs/gcc/tree-ssa-dce.cc:1992
2316
2317 // this is returning the direct raw pointer of the slice an assumes a very
2318 // specific layout
2319 return ctx->get_backend ()->struct_field_expression (expr_tree, 0,
2320 location);
2321 }
2322
2323 return fold_convert_loc (location.gcc_location (), type_to_cast_to,
2324 expr_tree);
2325}
2326
2327void
2328CompileExpr::visit (HIR::ArrayExpr &expr)
2329{
2330 TyTy::BaseType *tyty = nullptr;
2331 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
2332 &tyty))
2333 {
2334 rust_fatal_error (expr.get_locus (),
2335 "did not resolve type for this array expr");
2336 return;
2337 }
2338
2339 tree array_type = TyTyResolveCompile::compile (ctx, tyty);
2340 if (TREE_CODE (array_type) != ARRAY_TYPE)
2341 {
2342 translated = error_mark_node;
2343 return;
2344 }
2345
2346 rust_assert (tyty->get_kind () == TyTy::TypeKind::ARRAY);
2347 const TyTy::ArrayType &array_tyty
2348 = static_cast<const TyTy::ArrayType &> (*tyty);
2349
2350 HIR::ArrayElems &elements = *expr.get_internal_elements ();
2351 switch (elements.get_array_expr_type ())
2352 {
2353 case HIR::ArrayElems::ArrayExprType::VALUES: {
2354 HIR::ArrayElemsValues &elems
2355 = static_cast<HIR::ArrayElemsValues &> (elements);
2356 translated
2357 = array_value_expr (expr.get_locus (), array_tyty, array_type, elems);
2358 }
2359 return;
2360
2361 case HIR::ArrayElems::ArrayExprType::COPIED:
2362 HIR::ArrayElemsCopied &elems
2363 = static_cast<HIR::ArrayElemsCopied &> (elements);
2364 translated
2365 = array_copied_expr (expr.get_locus (), array_tyty, array_type, elems);
2366 }
2367}
2368
2369tree
2370CompileExpr::array_value_expr (Location expr_locus,
2371 const TyTy::ArrayType &array_tyty,
2372 tree array_type, HIR::ArrayElemsValues &elems)
2373{
2374 std::vector<unsigned long> indexes;
2375 std::vector<tree> constructor;
2376 size_t i = 0;
2377 for (auto &elem : elems.get_values ())
2378 {
2379 tree translated_expr = CompileExpr::Compile (elem.get (), ctx);
2380 constructor.push_back (translated_expr);
2381 indexes.push_back (i++);
2382 }
2383
2384 return ctx->get_backend ()->array_constructor_expression (array_type, indexes,
2385 constructor,
2386 expr_locus);
2387}
2388
2389tree
2390CompileExpr::array_copied_expr (Location expr_locus,
2391 const TyTy::ArrayType &array_tyty,
2392 tree array_type, HIR::ArrayElemsCopied &elems)
2393{
2394 // see gcc/cp/typeck2.cc:1369-1401
2395 gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
2396 tree domain = TYPE_DOMAIN (array_type);
2397 if (!domain)
2398 return error_mark_node;
2399
2400 if (!TREE_CONSTANT (TYPE_MAX_VALUE (domain)))
2401 {
2402 rust_error_at (expr_locus, "non const capacity domain %qT", array_type);
2403 return error_mark_node;
2404 }
2405
9c87dc0a 2406 ctx->push_const_context ();
019b2f15 2407 tree capacity_expr = CompileExpr::Compile (elems.get_num_copies_expr (), ctx);
9c87dc0a
AC
2408 ctx->pop_const_context ();
2409
019b2f15
PH
2410 if (!TREE_CONSTANT (capacity_expr))
2411 {
2412 rust_error_at (expr_locus, "non const num copies %qT", array_type);
2413 return error_mark_node;
2414 }
2415
2416 // get the compiled value
2417 tree translated_expr = CompileExpr::Compile (elems.get_elem_to_copy (), ctx);
2418
2419 tree max_domain = TYPE_MAX_VALUE (domain);
2420 tree min_domain = TYPE_MIN_VALUE (domain);
2421
2422 auto max = wi::to_offset (max_domain);
2423 auto min = wi::to_offset (min_domain);
2424 auto precision = TYPE_PRECISION (TREE_TYPE (domain));
2425 auto sign = TYPE_SIGN (TREE_TYPE (domain));
2426 unsigned HOST_WIDE_INT len
2427 = wi::ext (max - min + 1, precision, sign).to_uhwi ();
2428
2429 // In a const context we must initialize the entire array, which entails
2430 // allocating for each element. If the user wants a huge array, we will OOM
2431 // and die horribly.
2432 if (ctx->const_context_p ())
2433 {
2434 size_t idx = 0;
2435 std::vector<unsigned long> indexes;
2436 std::vector<tree> constructor;
2437 for (unsigned HOST_WIDE_INT i = 0; i < len; i++)
2438 {
2439 constructor.push_back (translated_expr);
2440 indexes.push_back (idx++);
2441 }
2442
2443 return ctx->get_backend ()->array_constructor_expression (array_type,
2444 indexes,
2445 constructor,
2446 expr_locus);
2447 }
2448
2449 else
2450 {
2451 // Create a new block scope in which to initialize the array
2452 tree fndecl = NULL_TREE;
2453 if (ctx->in_fn ())
2454 fndecl = ctx->peek_fn ().fndecl;
2455
2456 std::vector<Bvariable *> locals;
2457 tree enclosing_scope = ctx->peek_enclosing_scope ();
2458 tree init_block
2459 = ctx->get_backend ()->block (fndecl, enclosing_scope, locals,
2460 expr_locus, expr_locus);
2461 ctx->push_block (init_block);
2462
2463 tree tmp;
2464 tree stmts
2465 = ctx->get_backend ()->array_initializer (fndecl, init_block,
2466 array_type, capacity_expr,
2467 translated_expr, &tmp,
2468 expr_locus);
2469 ctx->add_statement (stmts);
2470
2471 tree block = ctx->pop_block ();
2472
2473 // The result is a compound expression which creates a temporary array,
2474 // initializes all the elements in a loop, and then yeilds the array.
2475 return ctx->get_backend ()->compound_expression (block, tmp, expr_locus);
2476 }
2477}
2478
2479tree
2480HIRCompileBase::resolve_adjustements (
2481 std::vector<Resolver::Adjustment> &adjustments, tree expression,
2482 Location locus)
2483{
2484 tree e = expression;
2485 for (auto &adjustment : adjustments)
2486 {
2487 switch (adjustment.get_type ())
2488 {
2489 case Resolver::Adjustment::AdjustmentType::ERROR:
2490 return error_mark_node;
2491
2492 case Resolver::Adjustment::AdjustmentType::IMM_REF:
2493 case Resolver::Adjustment::AdjustmentType::MUT_REF: {
2494 if (!SLICE_TYPE_P (TREE_TYPE (e)))
2495 {
2496 e = address_expression (e, locus);
2497 }
2498 }
2499 break;
2500
2501 case Resolver::Adjustment::AdjustmentType::DEREF:
2502 case Resolver::Adjustment::AdjustmentType::DEREF_MUT:
2503 e = resolve_deref_adjustment (adjustment, e, locus);
2504 break;
2505
2506 case Resolver::Adjustment::AdjustmentType::INDIRECTION:
2507 e = resolve_indirection_adjustment (adjustment, e, locus);
2508 break;
2509
2510 case Resolver::Adjustment::AdjustmentType::UNSIZE:
2511 e = resolve_unsized_adjustment (adjustment, e, locus);
2512 break;
2513 }
2514 }
2515
2516 return e;
2517}
2518
2519tree
2520HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustment,
2521 tree expression, Location locus)
2522{
2523 rust_assert (adjustment.is_deref_adjustment ()
2524 || adjustment.is_deref_mut_adjustment ());
2525 rust_assert (adjustment.has_operator_overload ());
2526
2527 TyTy::FnType *lookup = adjustment.get_deref_operator_fn ();
2528 HIR::ImplItem *resolved_item = adjustment.get_deref_hir_item ();
2529
2530 tree fn_address = error_mark_node;
2531 if (!lookup->has_subsititions_defined ())
2532 fn_address = CompileInherentImplItem::Compile (resolved_item, ctx, nullptr,
2533 true, locus);
2534 else
2535 fn_address = CompileInherentImplItem::Compile (resolved_item, ctx, lookup,
2536 true, locus);
2537
2538 // does it need a reference to call
2539 tree adjusted_argument = expression;
2540 bool needs_borrow = adjustment.get_deref_adjustment_type ()
2541 != Resolver::Adjustment::AdjustmentType::ERROR;
2542 if (needs_borrow)
2543 {
2544 adjusted_argument = address_expression (expression, locus);
2545 }
2546
2547 // make the call
2548 return ctx->get_backend ()->call_expression (fn_address, {adjusted_argument},
2549 nullptr, locus);
2550}
2551
2552tree
2553HIRCompileBase::resolve_indirection_adjustment (
2554 Resolver::Adjustment &adjustment, tree expression, Location locus)
2555{
2556 return indirect_expression (expression, locus);
2557}
2558
2559tree
2560HIRCompileBase::resolve_unsized_adjustment (Resolver::Adjustment &adjustment,
2561 tree expression, Location locus)
2562{
2563 bool expect_slice
2564 = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::SLICE;
2565 bool expect_dyn
2566 = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::DYNAMIC;
2567
2568 // assumes this is an array
2569 tree expr_type = TREE_TYPE (expression);
2570 if (expect_slice)
2571 {
2572 rust_assert (TREE_CODE (expr_type) == ARRAY_TYPE);
2573 return resolve_unsized_slice_adjustment (adjustment, expression, locus);
2574 }
2575
2576 rust_assert (expect_dyn);
2577 return resolve_unsized_dyn_adjustment (adjustment, expression, locus);
2578}
2579
2580tree
2581HIRCompileBase::resolve_unsized_slice_adjustment (
2582 Resolver::Adjustment &adjustment, tree expression, Location locus)
2583{
2584 // assumes this is an array
2585 tree expr_type = TREE_TYPE (expression);
2586 rust_assert (TREE_CODE (expr_type) == ARRAY_TYPE);
2587
2588 // takes an array and returns a fat-pointer so this becomes a constructor
2589 // expression
2590 rust_assert (adjustment.get_expected ()->get_kind ()
2591 == TyTy::TypeKind::SLICE);
2592 tree fat_pointer
2593 = TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
2594
2595 // make a constructor for this
2596 tree data = address_expression (expression, locus);
2597
2598 // fetch the size from the domain
2599 tree domain = TYPE_DOMAIN (expr_type);
2600 unsigned HOST_WIDE_INT array_size
2601 = wi::ext (wi::to_offset (TYPE_MAX_VALUE (domain))
2602 - wi::to_offset (TYPE_MIN_VALUE (domain)) + 1,
2603 TYPE_PRECISION (TREE_TYPE (domain)),
2604 TYPE_SIGN (TREE_TYPE (domain)))
2605 .to_uhwi ();
2606 tree size = build_int_cstu (size_type_node, array_size);
2607
2608 return ctx->get_backend ()->constructor_expression (fat_pointer, false,
2609 {data, size}, -1, locus);
2610}
2611
2612tree
2613HIRCompileBase::resolve_unsized_dyn_adjustment (
2614 Resolver::Adjustment &adjustment, tree expression, Location locus)
2615{
2616 tree rvalue = expression;
2617 Location rvalue_locus = locus;
2618
2619 const TyTy::BaseType *actual = adjustment.get_actual ();
2620 const TyTy::BaseType *expected = adjustment.get_expected ();
2621
2622 const TyTy::DynamicObjectType *dyn
2623 = static_cast<const TyTy::DynamicObjectType *> (expected);
2624
2625 rust_debug ("resolve_unsized_dyn_adjustment actual={%s} dyn={%s}",
2626 actual->debug_str ().c_str (), dyn->debug_str ().c_str ());
2627
2628 return coerce_to_dyn_object (rvalue, actual, dyn, rvalue_locus);
2629}
2630
2631void
2632CompileExpr::visit (HIR::RangeFromToExpr &expr)
2633{
2634 tree from = CompileExpr::Compile (expr.get_from_expr ().get (), ctx);
2635 tree to = CompileExpr::Compile (expr.get_to_expr ().get (), ctx);
2636 if (from == error_mark_node || to == error_mark_node)
2637 {
2638 translated = error_mark_node;
2639 return;
2640 }
2641
2642 TyTy::BaseType *tyty = nullptr;
2643 bool ok
2644 = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
2645 rust_assert (ok);
2646
2647 tree adt = TyTyResolveCompile::compile (ctx, tyty);
2648
2649 // make the constructor
2650 translated
2651 = ctx->get_backend ()->constructor_expression (adt, false, {from, to}, -1,
2652 expr.get_locus ());
2653}
2654
2655void
2656CompileExpr::visit (HIR::RangeFromExpr &expr)
2657{
2658 tree from = CompileExpr::Compile (expr.get_from_expr ().get (), ctx);
2659 if (from == error_mark_node)
2660 {
2661 translated = error_mark_node;
2662 return;
2663 }
2664
2665 TyTy::BaseType *tyty = nullptr;
2666 bool ok
2667 = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
2668 rust_assert (ok);
2669
2670 tree adt = TyTyResolveCompile::compile (ctx, tyty);
2671
2672 // make the constructor
2673 translated
2674 = ctx->get_backend ()->constructor_expression (adt, false, {from}, -1,
2675 expr.get_locus ());
2676}
2677
2678void
2679CompileExpr::visit (HIR::RangeToExpr &expr)
2680{
2681 tree to = CompileExpr::Compile (expr.get_to_expr ().get (), ctx);
2682 if (to == error_mark_node)
2683 {
2684 translated = error_mark_node;
2685 return;
2686 }
2687
2688 TyTy::BaseType *tyty = nullptr;
2689 bool ok
2690 = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
2691 rust_assert (ok);
2692
2693 tree adt = TyTyResolveCompile::compile (ctx, tyty);
2694
2695 // make the constructor
2696 translated
2697 = ctx->get_backend ()->constructor_expression (adt, false, {to}, -1,
2698 expr.get_locus ());
2699}
2700
2701void
2702CompileExpr::visit (HIR::RangeFullExpr &expr)
2703{
2704 TyTy::BaseType *tyty = nullptr;
2705 bool ok
2706 = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
2707 rust_assert (ok);
2708
2709 tree adt = TyTyResolveCompile::compile (ctx, tyty);
2710 translated = ctx->get_backend ()->constructor_expression (adt, false, {}, -1,
2711 expr.get_locus ());
2712}
2713
2714void
2715CompileExpr::visit (HIR::RangeFromToInclExpr &expr)
2716{
2717 tree from = CompileExpr::Compile (expr.get_from_expr ().get (), ctx);
2718 tree to = CompileExpr::Compile (expr.get_to_expr ().get (), ctx);
2719 if (from == error_mark_node || to == error_mark_node)
2720 {
2721 translated = error_mark_node;
2722 return;
2723 }
2724
2725 TyTy::BaseType *tyty = nullptr;
2726 bool ok
2727 = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty);
2728 rust_assert (ok);
2729
2730 tree adt = TyTyResolveCompile::compile (ctx, tyty);
2731
2732 // make the constructor
2733 translated
2734 = ctx->get_backend ()->constructor_expression (adt, false, {from, to}, -1,
2735 expr.get_locus ());
2736}
2737
2738void
2739CompileExpr::visit (HIR::ArrayIndexExpr &expr)
2740{
2741 tree array_reference = CompileExpr::Compile (expr.get_array_expr (), ctx);
2742 tree index = CompileExpr::Compile (expr.get_index_expr (), ctx);
2743
2744 // this might be an core::ops::index lang item situation
2745 TyTy::FnType *fntype;
2746 bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
2747 expr.get_mappings ().get_hirid (), &fntype);
2748 if (is_op_overload)
2749 {
2750 auto lang_item_type = Analysis::RustLangItem::ItemType::INDEX;
2751 tree operator_overload_call
2752 = resolve_operator_overload (lang_item_type, expr, array_reference,
2753 index, expr.get_array_expr (),
2754 expr.get_index_expr ());
2755
2756 tree actual_type = TREE_TYPE (operator_overload_call);
2757 bool can_indirect = TYPE_PTR_P (actual_type) || TYPE_REF_P (actual_type);
2758 if (!can_indirect)
2759 {
2760 // nothing to do
2761 translated = operator_overload_call;
2762 return;
2763 }
2764
2765 // rust deref always returns a reference from this overload then we can
2766 // actually do the indirection
2767 translated
2768 = indirect_expression (operator_overload_call, expr.get_locus ());
2769 return;
2770 }
2771
2772 // lets check if the array is a reference type then we can add an
2773 // indirection if required
2774 TyTy::BaseType *array_expr_ty = nullptr;
2775 bool ok = ctx->get_tyctx ()->lookup_type (
2776 expr.get_array_expr ()->get_mappings ().get_hirid (), &array_expr_ty);
2777 rust_assert (ok);
2778
2779 // do we need to add an indirect reference
2780 if (array_expr_ty->get_kind () == TyTy::TypeKind::REF)
2781 {
2782 array_reference
2783 = indirect_expression (array_reference, expr.get_locus ());
2784 }
2785
2786 translated
2787 = ctx->get_backend ()->array_index_expression (array_reference, index,
2788 expr.get_locus ());
2789}
2790
870dd9d5
PH
2791void
2792CompileExpr::visit (HIR::ClosureExpr &expr)
2793{
699e7e86
PH
2794 TyTy::BaseType *closure_expr_ty = nullptr;
2795 if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
2796 &closure_expr_ty))
2797 {
2798 rust_fatal_error (expr.get_locus (),
2799 "did not resolve type for this ClosureExpr");
2800 return;
2801 }
2802 rust_assert (closure_expr_ty->get_kind () == TyTy::TypeKind::CLOSURE);
2803 TyTy::ClosureType *closure_tyty
2804 = static_cast<TyTy::ClosureType *> (closure_expr_ty);
2805 tree compiled_closure_tyty = TyTyResolveCompile::compile (ctx, closure_tyty);
2806
2807 // generate closure function
2808 generate_closure_function (expr, *closure_tyty, compiled_closure_tyty);
2809
2810 // lets ignore state capture for now we need to instantiate the struct anyway
2811 // then generate the function
699e7e86 2812 std::vector<tree> vals;
92389b46
PH
2813 for (const auto &capture : closure_tyty->get_captures ())
2814 {
2815 // lookup the HirId
2816 HirId ref = UNKNOWN_HIRID;
2817 bool ok = ctx->get_mappings ()->lookup_node_to_hir (capture, &ref);
2818 rust_assert (ok);
2819
2820 // lookup the var decl
2821 Bvariable *var = nullptr;
2822 bool found = ctx->lookup_var_decl (ref, &var);
2823 rust_assert (found);
2824
2825 // FIXME
2826 // this should bes based on the closure move-ability
2827 tree var_expr = var->get_tree (expr.get_locus ());
2828 tree val = address_expression (var_expr, expr.get_locus ());
2829 vals.push_back (val);
2830 }
699e7e86
PH
2831
2832 translated
2833 = ctx->get_backend ()->constructor_expression (compiled_closure_tyty, false,
2834 vals, -1, expr.get_locus ());
2835}
2836
2837tree
2838CompileExpr::generate_closure_function (HIR::ClosureExpr &expr,
2839 TyTy::ClosureType &closure_tyty,
2840 tree compiled_closure_tyty)
2841{
2842 TyTy::FnType *fn_tyty = nullptr;
2843 tree compiled_fn_type
2844 = generate_closure_fntype (expr, closure_tyty, compiled_closure_tyty,
2845 &fn_tyty);
2846 if (compiled_fn_type == error_mark_node)
2847 return error_mark_node;
2848
2849 const Resolver::CanonicalPath &parent_canonical_path
2850 = closure_tyty.get_ident ().path;
2851 Resolver::CanonicalPath path = parent_canonical_path.append (
2852 Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "{{closure}}"));
2853
2854 std::string ir_symbol_name = path.get ();
2855 std::string asm_name = ctx->mangle_item (&closure_tyty, path);
2856
2857 unsigned int flags = 0;
2858 tree fndecl
2859 = ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, asm_name,
2860 flags, expr.get_locus ());
2861
2862 // insert into the context
2863 ctx->insert_function_decl (fn_tyty, fndecl);
2864 ctx->insert_closure_decl (&closure_tyty, fndecl);
2865
2866 // setup the parameters
2867 std::vector<Bvariable *> param_vars;
2868
2869 // closure self
2870 Bvariable *self_param
2871 = ctx->get_backend ()->parameter_variable (fndecl, "$closure",
2872 compiled_closure_tyty,
2873 expr.get_locus ());
2874 DECL_ARTIFICIAL (self_param->get_decl ()) = 1;
2875 param_vars.push_back (self_param);
2876
92389b46
PH
2877 // push a new context
2878 ctx->push_closure_context (expr.get_mappings ().get_hirid ());
2879
699e7e86 2880 // setup the implicit argument captures
92389b46
PH
2881 size_t idx = 0;
2882 for (const auto &capture : closure_tyty.get_captures ())
2883 {
2884 // lookup the HirId
2885 HirId ref = UNKNOWN_HIRID;
2886 bool ok = ctx->get_mappings ()->lookup_node_to_hir (capture, &ref);
2887 rust_assert (ok);
2888
2889 // get the assessor
2890 tree binding = ctx->get_backend ()->struct_field_expression (
2891 self_param->get_tree (expr.get_locus ()), idx, expr.get_locus ());
2892 tree indirection = indirect_expression (binding, expr.get_locus ());
2893
2894 // insert bindings
2895 ctx->insert_closure_binding (ref, indirection);
2896
2897 // continue
2898 idx++;
2899 }
699e7e86
PH
2900
2901 // args tuple
2902 tree args_type
2903 = TyTyResolveCompile::compile (ctx, &closure_tyty.get_parameters ());
2904 Bvariable *args_param
2905 = ctx->get_backend ()->parameter_variable (fndecl, "args", args_type,
2906 expr.get_locus ());
2907 param_vars.push_back (args_param);
2908
2909 // setup the implicit mappings for the arguments. Since argument passing to
2910 // closure functions is done via passing a tuple but the closure body expects
2911 // just normal arguments this means we need to destructure them similar to
2912 // what we do in MatchExpr's. This means when we have a closure-param of a we
2913 // actually setup the destructure to take from the args tuple
2914
2915 tree args_param_expr = args_param->get_tree (expr.get_locus ());
2916 size_t i = 0;
2917 for (auto &closure_param : expr.get_params ())
2918 {
2919 tree compiled_param_var = ctx->get_backend ()->struct_field_expression (
2920 args_param_expr, i, closure_param.get_locus ());
2921
2922 const HIR::Pattern &param_pattern = *closure_param.get_pattern ();
2923 ctx->insert_pattern_binding (
2924 param_pattern.get_pattern_mappings ().get_hirid (), compiled_param_var);
2925 i++;
2926 }
2927
2928 if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
92389b46
PH
2929 {
2930 ctx->pop_closure_context ();
2931 return error_mark_node;
2932 }
699e7e86
PH
2933
2934 // lookup locals
2935 HIR::Expr *function_body = expr.get_expr ().get ();
2936 auto body_mappings = function_body->get_mappings ();
2937 Resolver::Rib *rib = nullptr;
2938 bool ok
2939 = ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (), &rib);
2940 rust_assert (ok);
2941
2942 std::vector<Bvariable *> locals
2943 = compile_locals_for_block (ctx, *rib, fndecl);
2944
2945 tree enclosing_scope = NULL_TREE;
2946 Location start_location = function_body->get_locus ();
2947 Location end_location = function_body->get_locus ();
2948 bool is_block_expr
2949 = function_body->get_expression_type () == HIR::Expr::ExprType::Block;
2950 if (is_block_expr)
2951 {
2952 HIR::BlockExpr *body = static_cast<HIR::BlockExpr *> (function_body);
2953 start_location = body->get_locus ();
2954 end_location = body->get_end_locus ();
2955 }
2956
2957 tree code_block = ctx->get_backend ()->block (fndecl, enclosing_scope, locals,
2958 start_location, end_location);
2959 ctx->push_block (code_block);
2960
2961 TyTy::BaseType *tyret = &closure_tyty.get_result_type ();
2962 bool function_has_return = !closure_tyty.get_result_type ().is_unit ();
2963 Bvariable *return_address = nullptr;
2964 if (function_has_return)
2965 {
2966 tree return_type = TyTyResolveCompile::compile (ctx, tyret);
2967
2968 bool address_is_taken = false;
2969 tree ret_var_stmt = NULL_TREE;
2970
2971 return_address = ctx->get_backend ()->temporary_variable (
2972 fndecl, code_block, return_type, NULL, address_is_taken,
2973 expr.get_locus (), &ret_var_stmt);
2974
2975 ctx->add_statement (ret_var_stmt);
2976 }
2977
2978 ctx->push_fn (fndecl, return_address);
2979
2980 if (is_block_expr)
2981 {
2982 HIR::BlockExpr *body = static_cast<HIR::BlockExpr *> (function_body);
2983 compile_function_body (ctx, fndecl, *body, true);
2984 }
2985 else
2986 {
2987 tree value = CompileExpr::Compile (function_body, ctx);
2988 tree return_expr
2989 = ctx->get_backend ()->return_statement (fndecl, {value},
2990 function_body->get_locus ());
2991 ctx->add_statement (return_expr);
2992 }
2993
2994 tree bind_tree = ctx->pop_block ();
2995
2996 gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
2997 DECL_SAVED_TREE (fndecl) = bind_tree;
2998
92389b46 2999 ctx->pop_closure_context ();
699e7e86
PH
3000 ctx->pop_fn ();
3001 ctx->push_function (fndecl);
3002
3003 return fndecl;
3004}
3005
3006tree
3007CompileExpr::generate_closure_fntype (HIR::ClosureExpr &expr,
3008 const TyTy::ClosureType &closure_tyty,
3009 tree compiled_closure_tyty,
3010 TyTy::FnType **fn_tyty)
3011{
3012 // grab the specified_bound
3013 rust_assert (closure_tyty.num_specified_bounds () == 1);
3014 const TyTy::TypeBoundPredicate &predicate
3015 = *closure_tyty.get_specified_bounds ().begin ();
3016
3017 // ensure the fn_once_output associated type is set
3018 closure_tyty.setup_fn_once_output ();
3019
3020 // the function signature is based on the trait bound that the closure
3021 // implements which is determined at the type resolution time
3022 //
3023 // https://github.com/rust-lang/rust/blob/7807a694c2f079fd3f395821bcc357eee8650071/library/core/src/ops/function.rs#L54-L71
3024
3025 TyTy::TypeBoundPredicateItem item = TyTy::TypeBoundPredicateItem::error ();
3026 if (predicate.get_name ().compare ("FnOnce") == 0)
3027 {
3028 item = predicate.lookup_associated_item ("call_once");
3029 }
3030 else if (predicate.get_name ().compare ("FnMut") == 0)
3031 {
3032 item = predicate.lookup_associated_item ("call_mut");
3033 }
3034 else if (predicate.get_name ().compare ("Fn") == 0)
3035 {
3036 item = predicate.lookup_associated_item ("call");
3037 }
3038 else
3039 {
3040 // FIXME error message?
3041 gcc_unreachable ();
3042 return error_mark_node;
3043 }
3044
3045 rust_assert (!item.is_error ());
3046
3047 TyTy::BaseType *item_tyty = item.get_tyty_for_receiver (&closure_tyty);
3048 rust_assert (item_tyty->get_kind () == TyTy::TypeKind::FNDEF);
3049 *fn_tyty = static_cast<TyTy::FnType *> (item_tyty);
3050 return TyTyResolveCompile::compile (ctx, item_tyty);
870dd9d5
PH
3051}
3052
21d19d2c
PH
3053bool
3054CompileExpr::generate_possible_fn_trait_call (HIR::CallExpr &expr,
3055 tree receiver, tree *result)
3056{
3057 TyTy::FnType *fn_sig = nullptr;
3058 bool found_overload = ctx->get_tyctx ()->lookup_operator_overload (
3059 expr.get_mappings ().get_hirid (), &fn_sig);
3060 if (!found_overload)
3061 return false;
3062
3063 auto id = fn_sig->get_ty_ref ();
3064 auto dId = fn_sig->get_id ();
3065
3066 tree function = error_mark_node;
3067 bool found_closure = ctx->lookup_function_decl (id, &function, dId, fn_sig);
3068 if (!found_closure)
3069 {
3070 // something went wrong we still return true as this was meant to be an fn
3071 // trait call
3072 *result = error_mark_node;
3073 return true;
3074 }
3075
3076 // need to apply any autoderef's to the self argument
3077 HirId autoderef_mappings_id = expr.get_mappings ().get_hirid ();
3078 std::vector<Resolver::Adjustment> *adjustments = nullptr;
3079 bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id,
3080 &adjustments);
3081 rust_assert (ok);
3082
3083 // apply adjustments for the fn call
3084 tree self = resolve_adjustements (*adjustments, receiver, expr.get_locus ());
3085
3086 // resolve the arguments
3087 std::vector<tree> tuple_arg_vals;
3088 for (auto &argument : expr.get_arguments ())
3089 {
3090 auto rvalue = CompileExpr::Compile (argument.get (), ctx);
3091 tuple_arg_vals.push_back (rvalue);
3092 }
3093
3094 // this is always the 2nd argument in the function signature
3095 tree fnty = TREE_TYPE (function);
3096 tree fn_arg_tys = TYPE_ARG_TYPES (fnty);
3097 tree tuple_args_tyty_chain = TREE_CHAIN (fn_arg_tys);
3098 tree tuple_args_tyty = TREE_VALUE (tuple_args_tyty_chain);
3099
3100 tree tuple_args
3101 = ctx->get_backend ()->constructor_expression (tuple_args_tyty, false,
3102 tuple_arg_vals, -1,
3103 expr.get_locus ());
3104
3105 // args are always self, and the tuple of the args we are passing where
3106 // self is the path of the call-expr in this case the fn_address
3107 std::vector<tree> args;
3108 args.push_back (self);
3109 args.push_back (tuple_args);
3110
3111 tree call_address = address_expression (function, expr.get_locus ());
3112 *result = ctx->get_backend ()->call_expression (call_address, args,
3113 nullptr /* static chain ?*/,
3114 expr.get_locus ());
3115 return true;
3116}
3117
019b2f15
PH
3118} // namespace Compile
3119} // namespace Rust