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