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