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-base.h"
20 : #include "rust-abi.h"
21 : #include "rust-compile-stmt.h"
22 : #include "rust-compile-expr.h"
23 : #include "rust-compile-fnparam.h"
24 : #include "rust-compile-var-decl.h"
25 : #include "rust-compile-type.h"
26 : #include "rust-constexpr.h"
27 : #include "rust-diagnostics.h"
28 : #include "rust-expr.h" // for AST::AttrInputLiteral
29 : #include "rust-hir-map.h"
30 : #include "rust-macro.h" // for AST::MetaNameValueStr
31 : #include "rust-hir-path-probe.h"
32 : #include "rust-type-util.h"
33 : #include "rust-compile-implitem.h"
34 : #include "rust-attribute-values.h"
35 : #include "rust-attributes.h"
36 : #include "rust-immutable-name-resolution-context.h"
37 :
38 : #include "fold-const.h"
39 : #include "stringpool.h"
40 : #include "attribs.h"
41 : #include "tree.h"
42 : #include "print-tree.h"
43 :
44 : // rust-name-resolution-2.0
45 : #include "options.h"
46 :
47 : namespace Rust {
48 : namespace Compile {
49 :
50 12730 : bool inline should_mangle_item (const tree fndecl)
51 : {
52 12730 : return lookup_attribute (Values::Attributes::NO_MANGLE,
53 12730 : DECL_ATTRIBUTES (fndecl))
54 12730 : == NULL_TREE;
55 : }
56 :
57 : void
58 12730 : HIRCompileBase::setup_fndecl (tree fndecl, bool is_main_entry_point,
59 : bool is_generic_fn, HIR::Visibility &visibility,
60 : const HIR::FunctionQualifiers &qualifiers,
61 : const AST::AttrVec &attrs)
62 : {
63 : // if its the main fn or pub visibility mark its as DECL_PUBLIC
64 : // please see https://github.com/Rust-GCC/gccrs/pull/137
65 12730 : bool is_pub = visibility.get_vis_type () == HIR::Visibility::VisType::PUBLIC;
66 12730 : if (is_main_entry_point || (is_pub && !is_generic_fn))
67 : {
68 5657 : TREE_PUBLIC (fndecl) = 1;
69 : }
70 :
71 : // is it a const fn
72 12730 : DECL_DECLARED_CONSTEXPR_P (fndecl) = qualifiers.is_const ();
73 12730 : if (qualifiers.is_const ())
74 : {
75 664 : TREE_READONLY (fndecl) = 1;
76 : }
77 :
78 : // is it inline?
79 28340 : for (const auto &attr : attrs)
80 : {
81 15610 : bool is_inline
82 15610 : = attr.get_path ().as_string () == Values::Attributes::INLINE;
83 15610 : bool is_must_use
84 15610 : = attr.get_path ().as_string () == Values::Attributes::MUST_USE;
85 15610 : bool is_cold = attr.get_path ().as_string () == Values::Attributes::COLD;
86 15610 : bool is_link_section
87 15610 : = attr.get_path ().as_string () == Values::Attributes::LINK_SECTION;
88 15610 : bool no_mangle
89 15610 : = attr.get_path ().as_string () == Values::Attributes::NO_MANGLE;
90 15610 : bool is_deprecated
91 15610 : = attr.get_path ().as_string () == Values::Attributes::DEPRECATED;
92 15610 : bool is_proc_macro
93 15610 : = attr.get_path ().as_string () == Values::Attributes::PROC_MACRO;
94 15610 : bool is_proc_macro_attribute
95 31220 : = attr.get_path ().as_string ()
96 15610 : == Values::Attributes::PROC_MACRO_ATTRIBUTE;
97 31220 : bool is_proc_macro_derive = attr.get_path ().as_string ()
98 15610 : == Values::Attributes::PROC_MACRO_DERIVE;
99 :
100 15610 : if (is_inline)
101 : {
102 943 : handle_inline_attribute_on_fndecl (fndecl, attr);
103 : }
104 14667 : else if (is_must_use)
105 : {
106 1089 : handle_must_use_attribute_on_fndecl (fndecl, attr);
107 : }
108 13578 : else if (is_cold)
109 : {
110 1 : handle_cold_attribute_on_fndecl (fndecl, attr);
111 : }
112 13577 : else if (is_link_section)
113 : {
114 1 : handle_link_section_attribute_on_fndecl (fndecl, attr);
115 : }
116 13576 : else if (is_deprecated)
117 : {
118 5 : handle_deprecated_attribute_on_fndecl (fndecl, attr);
119 : }
120 13571 : else if (no_mangle)
121 : {
122 1 : handle_no_mangle_attribute_on_fndecl (fndecl, attr);
123 : }
124 13570 : else if (is_proc_macro)
125 : {
126 0 : handle_bang_proc_macro_attribute_on_fndecl (fndecl, attr);
127 : }
128 13570 : else if (is_proc_macro_attribute)
129 : {
130 0 : handle_attribute_proc_macro_attribute_on_fndecl (fndecl, attr);
131 : }
132 13570 : else if (is_proc_macro_derive)
133 : {
134 0 : handle_derive_proc_macro_attribute_on_fndecl (fndecl, attr);
135 : }
136 : }
137 12730 : }
138 :
139 : static void
140 0 : handle_proc_macro_common (tree fndecl, const AST::Attribute &attr)
141 : {
142 0 : DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("gccrs_proc_macro"),
143 0 : NULL, DECL_ATTRIBUTES (fndecl));
144 0 : }
145 :
146 : void
147 0 : HIRCompileBase::handle_bang_proc_macro_attribute_on_fndecl (
148 : tree fndecl, const AST::Attribute &attr)
149 : {
150 0 : handle_proc_macro_common (fndecl, attr);
151 0 : ctx->collect_bang_proc_macro (fndecl);
152 0 : }
153 :
154 : void
155 0 : HIRCompileBase::handle_attribute_proc_macro_attribute_on_fndecl (
156 : tree fndecl, const AST::Attribute &attr)
157 : {
158 0 : handle_proc_macro_common (fndecl, attr);
159 0 : ctx->collect_attribute_proc_macro (fndecl);
160 0 : }
161 :
162 : static std::vector<std::string>
163 0 : get_attributes (const AST::Attribute &attr)
164 : {
165 0 : std::vector<std::string> result;
166 :
167 0 : rust_assert (attr.get_attr_input ().get_attr_input_type ()
168 : == Rust::AST::AttrInput::TOKEN_TREE);
169 0 : const auto &tt
170 0 : = static_cast<const AST::DelimTokenTree &> (attr.get_attr_input ());
171 :
172 : // TODO: Should we rely on fixed index ? Should we search for the
173 : // attribute tokentree instead ?
174 :
175 : // Derive proc macros have the following format:
176 : // #[proc_macro_derive(TraitName, attributes(attr1, attr2, attr3))]
177 : // -~~~~~~~~ - ~~~~~~~~~~---------------------
178 : // ^0 ^1 ^2 ^3 ^4
179 : // - "attributes" is stored at position 3 in the token tree
180 : // - attribute are stored in the delimited token tree in position 4
181 0 : constexpr size_t attr_kw_pos = 3;
182 0 : constexpr size_t attribute_list_pos = 4;
183 :
184 0 : if (tt.get_token_trees ().size () > attr_kw_pos)
185 : {
186 0 : rust_assert (tt.get_token_trees ()[attr_kw_pos]->as_string ()
187 : == "attributes");
188 :
189 0 : auto attributes = static_cast<const AST::DelimTokenTree *> (
190 0 : tt.get_token_trees ()[attribute_list_pos].get ());
191 :
192 0 : auto &token_trees = attributes->get_token_trees ();
193 :
194 0 : for (auto i = token_trees.cbegin () + 1; // Skip opening parenthesis
195 0 : i < token_trees.cend ();
196 0 : i += 2) // Skip comma and closing parenthesis
197 : {
198 0 : result.push_back ((*i)->as_string ());
199 : }
200 : }
201 0 : return result;
202 : }
203 :
204 : static std::string
205 0 : get_trait_name (const AST::Attribute &attr)
206 : {
207 : // Derive proc macros have the following format:
208 : // #[proc_macro_derive(TraitName, attributes(attr1, attr2, attr3))]
209 : // -~~~~~~~~ - ~~~~~~~~~~---------------------
210 : // ^0 ^1 ^2 ^3 ^4
211 : // - The trait name is stored at position 1
212 0 : constexpr size_t trait_name_pos = 1;
213 :
214 0 : rust_assert (attr.get_attr_input ().get_attr_input_type ()
215 : == Rust::AST::AttrInput::TOKEN_TREE);
216 0 : const auto &tt
217 0 : = static_cast<const AST::DelimTokenTree &> (attr.get_attr_input ());
218 0 : return tt.get_token_trees ()[trait_name_pos]->as_string ();
219 : }
220 :
221 : void
222 0 : HIRCompileBase::handle_derive_proc_macro_attribute_on_fndecl (
223 : tree fndecl, const AST::Attribute &attr)
224 : {
225 0 : handle_proc_macro_common (fndecl, attr);
226 :
227 0 : attr.get_attr_input ().parse_to_meta_item ();
228 0 : CustomDeriveInfo macro
229 0 : = {fndecl, get_trait_name (attr), get_attributes (attr)};
230 0 : ctx->collect_derive_proc_macro (macro);
231 0 : }
232 :
233 : void
234 1 : HIRCompileBase::handle_cold_attribute_on_fndecl (tree fndecl,
235 : const AST::Attribute &attr)
236 : {
237 : // simple #[cold]
238 1 : if (!attr.has_attr_input ())
239 : {
240 1 : tree cold = get_identifier (Values::Attributes::COLD);
241 : // this will get handled by the GCC backend later
242 1 : DECL_ATTRIBUTES (fndecl)
243 1 : = tree_cons (cold, NULL_TREE, DECL_ATTRIBUTES (fndecl));
244 1 : return;
245 : }
246 :
247 0 : rust_error_at (attr.get_locus (),
248 : "attribute %<cold%> does not accept any arguments");
249 : }
250 :
251 : void
252 1 : HIRCompileBase::handle_link_section_attribute_on_fndecl (
253 : tree fndecl, const AST::Attribute &attr)
254 : {
255 1 : auto msg_str = Analysis::Attributes::extract_string_literal (attr);
256 :
257 1 : if (!msg_str.has_value ())
258 : {
259 0 : rust_error_at (attr.get_locus (),
260 : "malformed %<link_section%> attribute input");
261 0 : return;
262 : }
263 :
264 1 : if (decl_section_name (fndecl))
265 : {
266 0 : rust_warning_at (attr.get_locus (), 0, "section name redefined");
267 : }
268 :
269 1 : set_decl_section_name (fndecl, msg_str->c_str ());
270 1 : }
271 :
272 : void
273 1 : HIRCompileBase::handle_no_mangle_attribute_on_fndecl (
274 : tree fndecl, const AST::Attribute &attr)
275 : {
276 1 : if (attr.has_attr_input ())
277 : {
278 0 : rust_error_at (attr.get_locus (),
279 : "attribute %<no_mangle%> does not accept any arguments");
280 0 : return;
281 : }
282 :
283 1 : DECL_ATTRIBUTES (fndecl)
284 2 : = tree_cons (get_identifier (Values::Attributes::NO_MANGLE), NULL_TREE,
285 1 : DECL_ATTRIBUTES (fndecl));
286 : }
287 :
288 : void
289 5 : HIRCompileBase::handle_deprecated_attribute_on_fndecl (
290 : tree fndecl, const AST::Attribute &attr)
291 : {
292 5 : tree value = NULL_TREE;
293 5 : TREE_DEPRECATED (fndecl) = 1;
294 :
295 : // simple #[deprecated]
296 5 : if (!attr.has_attr_input ())
297 : return;
298 :
299 4 : const AST::AttrInput &input = attr.get_attr_input ();
300 4 : auto input_type = input.get_attr_input_type ();
301 :
302 4 : if (input_type == AST::AttrInput::AttrInputType::LITERAL)
303 : {
304 : // handle #[deprecated = "message"]
305 1 : auto &literal
306 1 : = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
307 1 : const auto &msg_str = literal.get_literal ().as_string ();
308 1 : value = build_string (msg_str.size (), msg_str.c_str ());
309 1 : }
310 3 : else if (input_type == AST::AttrInput::AttrInputType::TOKEN_TREE)
311 : {
312 : // handle #[deprecated(since = "...", note = "...")]
313 3 : const auto &option = static_cast<const AST::DelimTokenTree &> (input);
314 3 : AST::AttrInputMetaItemContainer *meta_item = option.parse_to_meta_item ();
315 7 : for (const auto &item : meta_item->get_items ())
316 : {
317 4 : auto converted_item = item->to_meta_name_value_str ();
318 4 : if (!converted_item)
319 0 : continue;
320 4 : auto key_value = converted_item->get_name_value_pair ();
321 4 : if (key_value.first.as_string ().compare ("since") == 0)
322 : {
323 : // valid, but this is handled by Cargo and some third-party
324 : // audit tools
325 2 : continue;
326 : }
327 2 : else if (key_value.first.as_string ().compare ("note") == 0)
328 : {
329 1 : const auto &msg_str = key_value.second;
330 1 : if (value)
331 0 : rust_error_at (attr.get_locus (), "multiple %<note%> items");
332 1 : value = build_string (msg_str.size (), msg_str.c_str ());
333 : }
334 : else
335 : {
336 1 : rust_error_at (attr.get_locus (), ErrorCode::E0541,
337 : "unknown meta item %qs",
338 1 : key_value.first.as_string ().c_str ());
339 : }
340 4 : }
341 : }
342 :
343 4 : if (value)
344 : {
345 2 : tree attr_list = build_tree_list (NULL_TREE, value);
346 2 : DECL_ATTRIBUTES (fndecl)
347 4 : = tree_cons (get_identifier (Values::Attributes::DEPRECATED), attr_list,
348 2 : DECL_ATTRIBUTES (fndecl));
349 : }
350 : }
351 :
352 : void
353 943 : HIRCompileBase::handle_inline_attribute_on_fndecl (tree fndecl,
354 : const AST::Attribute &attr)
355 : {
356 : // simple #[inline]
357 943 : if (!attr.has_attr_input ())
358 : {
359 938 : DECL_DECLARED_INLINE_P (fndecl) = 1;
360 940 : return;
361 : }
362 :
363 5 : const AST::AttrInput &input = attr.get_attr_input ();
364 5 : bool is_token_tree
365 5 : = input.get_attr_input_type () == AST::AttrInput::AttrInputType::TOKEN_TREE;
366 5 : rust_assert (is_token_tree);
367 5 : const auto &option = static_cast<const AST::DelimTokenTree &> (input);
368 5 : AST::AttrInputMetaItemContainer *meta_item = option.parse_to_meta_item ();
369 5 : if (meta_item->get_items ().size () != 1)
370 : {
371 2 : rich_location rich_locus (line_table, attr.get_locus ());
372 2 : rich_locus.add_fixit_replace ("expected one argument");
373 2 : rust_error_at (rich_locus, ErrorCode::E0534,
374 : "invalid number of arguments");
375 2 : return;
376 2 : }
377 :
378 3 : const std::string inline_option
379 3 : = meta_item->get_items ().at (0)->as_string ();
380 :
381 : // we only care about NEVER and ALWAYS else its an error
382 3 : bool is_always = inline_option.compare ("always") == 0;
383 3 : bool is_never = inline_option.compare ("never") == 0;
384 :
385 : // #[inline(never)]
386 3 : if (is_never)
387 : {
388 1 : DECL_UNINLINABLE (fndecl) = 1;
389 : }
390 : // #[inline(always)]
391 2 : else if (is_always)
392 : {
393 1 : DECL_DECLARED_INLINE_P (fndecl) = 1;
394 1 : DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("always_inline"),
395 1 : NULL, DECL_ATTRIBUTES (fndecl));
396 : }
397 : else
398 : {
399 1 : rich_location rich_locus (line_table, attr.get_locus ());
400 1 : rich_locus.add_fixit_replace ("unknown inline option");
401 1 : rust_error_at (rich_locus, ErrorCode::E0535,
402 : "invalid argument, %<inline%> attribute only accepts "
403 : "%<always%> or %<never%>");
404 1 : }
405 3 : }
406 :
407 : void
408 1089 : HIRCompileBase::handle_must_use_attribute_on_fndecl (tree fndecl,
409 : const AST::Attribute &attr)
410 : {
411 1089 : tree nodiscard = get_identifier ("nodiscard");
412 1089 : tree value = NULL_TREE;
413 :
414 1089 : if (attr.has_attr_input ())
415 : {
416 15 : auto msg_str = Analysis::Attributes::extract_string_literal (attr);
417 15 : rust_assert (msg_str.has_value ());
418 :
419 15 : tree message = build_string (msg_str->size (), msg_str->c_str ());
420 :
421 15 : value = tree_cons (nodiscard, message, NULL_TREE);
422 15 : }
423 :
424 1089 : DECL_ATTRIBUTES (fndecl)
425 1089 : = tree_cons (nodiscard, value, DECL_ATTRIBUTES (fndecl));
426 1089 : }
427 :
428 : void
429 13797 : HIRCompileBase::setup_abi_options (tree fndecl, ABI abi)
430 : {
431 13797 : tree abi_tree = NULL_TREE;
432 :
433 13797 : switch (abi)
434 : {
435 13796 : case Rust::ABI::RUST:
436 13796 : case Rust::ABI::INTRINSIC:
437 13796 : case Rust::ABI::C:
438 13796 : case Rust::ABI::CDECL:
439 : // `decl_attributes` function (not the macro) has the side-effect of
440 : // actually switching the codegen backend to use the ABI we annotated.
441 : // However, since `cdecl` is the default ABI GCC will be using,
442 : // explicitly specifying that ABI will cause GCC to emit a warning
443 : // saying the attribute is useless (which is confusing to the user as
444 : // the attribute is added by us).
445 13796 : DECL_ATTRIBUTES (fndecl)
446 13796 : = tree_cons (get_identifier ("cdecl"), NULL, DECL_ATTRIBUTES (fndecl));
447 :
448 13796 : return;
449 :
450 0 : case Rust::ABI::STDCALL:
451 0 : abi_tree = get_identifier ("stdcall");
452 :
453 0 : break;
454 :
455 0 : case Rust::ABI::FASTCALL:
456 0 : abi_tree = get_identifier ("fastcall");
457 :
458 0 : break;
459 :
460 0 : case Rust::ABI::SYSV64:
461 0 : abi_tree = get_identifier ("sysv_abi");
462 :
463 0 : break;
464 :
465 1 : case Rust::ABI::WIN_64:
466 1 : abi_tree = get_identifier ("ms_abi");
467 :
468 1 : break;
469 :
470 : default:
471 : break;
472 : }
473 :
474 1 : decl_attributes (&fndecl, build_tree_list (abi_tree, NULL_TREE), 0);
475 : }
476 :
477 : // ported from gcc/c/c-typecheck.c
478 : //
479 : // Mark EXP saying that we need to be able to take the
480 : // address of it; it should not be allocated in a register.
481 : // Returns true if successful. ARRAY_REF_P is true if this
482 : // is for ARRAY_REF construction - in that case we don't want
483 : // to look through VIEW_CONVERT_EXPR from VECTOR_TYPE to ARRAY_TYPE,
484 : // it is fine to use ARRAY_REFs for vector subscripts on vector
485 : // register variables.
486 : bool
487 37335 : HIRCompileBase::mark_addressable (tree exp, location_t locus)
488 : {
489 37335 : tree x = exp;
490 :
491 39284 : while (1)
492 39284 : switch (TREE_CODE (x))
493 : {
494 0 : case VIEW_CONVERT_EXPR:
495 0 : if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
496 0 : && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))))
497 : return true;
498 0 : x = TREE_OPERAND (x, 0);
499 0 : break;
500 :
501 1949 : case COMPONENT_REF:
502 : // TODO
503 : // if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
504 : // {
505 : // error ("cannot take address of bit-field %qD", TREE_OPERAND (x,
506 : // 1)); return false;
507 : // }
508 :
509 : /* FALLTHRU */
510 1949 : case ADDR_EXPR:
511 1949 : case ARRAY_REF:
512 1949 : case REALPART_EXPR:
513 1949 : case IMAGPART_EXPR:
514 1949 : x = TREE_OPERAND (x, 0);
515 1949 : break;
516 :
517 0 : case COMPOUND_LITERAL_EXPR:
518 0 : TREE_ADDRESSABLE (x) = 1;
519 0 : TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (x)) = 1;
520 0 : return true;
521 :
522 253 : case CONSTRUCTOR:
523 253 : TREE_ADDRESSABLE (x) = 1;
524 253 : return true;
525 :
526 27086 : case VAR_DECL:
527 27086 : case CONST_DECL:
528 27086 : case PARM_DECL:
529 27086 : case RESULT_DECL:
530 : // (we don't have a concept of a "register" declaration)
531 : // fallthrough */
532 :
533 : /* FALLTHRU */
534 27086 : case FUNCTION_DECL:
535 27086 : TREE_ADDRESSABLE (x) = 1;
536 :
537 : /* FALLTHRU */
538 : default:
539 : return true;
540 : }
541 :
542 : return false;
543 : }
544 :
545 : tree
546 37357 : HIRCompileBase::address_expression (tree expr, location_t location, tree ptrty)
547 : {
548 37357 : if (expr == error_mark_node)
549 : return error_mark_node;
550 :
551 37335 : if (!mark_addressable (expr, location))
552 0 : return error_mark_node;
553 :
554 37335 : if (ptrty == NULL || ptrty == error_mark_node)
555 35589 : ptrty = build_pointer_type (TREE_TYPE (expr));
556 :
557 37335 : return build_fold_addr_expr_with_type_loc (location, expr, ptrty);
558 : }
559 :
560 : tree
561 1187 : HIRCompileBase::compile_constant_expr (
562 : Context *ctx, HirId coercion_id, TyTy::BaseType *resolved_type,
563 : TyTy::BaseType *expected_type, const Resolver::CanonicalPath &canonical_path,
564 : HIR::Expr &const_value_expr, location_t locus, location_t expr_locus)
565 : {
566 1187 : HIRCompileBase c (ctx);
567 1187 : return c.compile_constant_item (coercion_id, resolved_type, expected_type,
568 : canonical_path, const_value_expr, locus,
569 1187 : expr_locus);
570 1187 : }
571 :
572 : tree
573 1187 : HIRCompileBase::query_compile_const_expr (Context *ctx, TyTy::BaseType *expr_ty,
574 : HIR::Expr &const_value_expr)
575 : {
576 1187 : HIRCompileBase c (ctx);
577 :
578 1187 : ctx->push_const_context ();
579 :
580 1187 : HirId expr_id = const_value_expr.get_mappings ().get_hirid ();
581 1187 : location_t locus = const_value_expr.get_locus ();
582 1187 : tree capacity_expr = HIRCompileBase::compile_constant_expr (
583 1187 : ctx, expr_id, expr_ty, expr_ty, Resolver::CanonicalPath::create_empty (),
584 : const_value_expr, locus, locus);
585 :
586 1187 : ctx->pop_const_context ();
587 :
588 1187 : return fold_expr (capacity_expr);
589 1187 : }
590 :
591 : tree
592 14084 : HIRCompileBase::indirect_expression (tree expr, location_t locus)
593 : {
594 14084 : if (expr == error_mark_node)
595 : return error_mark_node;
596 :
597 14084 : return build_fold_indirect_ref_loc (locus, expr);
598 : }
599 :
600 : void
601 12821 : HIRCompileBase::compile_function_body (tree fndecl,
602 : HIR::BlockExpr &function_body,
603 : TyTy::BaseType *fn_return_ty)
604 : {
605 26713 : for (auto &s : function_body.get_statements ())
606 : {
607 13892 : auto compiled_expr = CompileStmt::Compile (s.get (), ctx);
608 13892 : if (compiled_expr != nullptr)
609 : {
610 4695 : tree s = convert_to_void (compiled_expr, ICV_STATEMENT);
611 4695 : ctx->add_statement (s);
612 : }
613 : }
614 :
615 12821 : if (function_body.has_expr ())
616 : {
617 10304 : location_t locus = function_body.get_final_expr ().get_locus ();
618 10304 : tree return_value
619 10304 : = CompileExpr::Compile (function_body.get_final_expr (), ctx);
620 :
621 : // we can only return this if non unit value return type
622 10304 : if (!fn_return_ty->is_unit ())
623 : {
624 9187 : HirId id = function_body.get_mappings ().get_hirid ();
625 9187 : location_t lvalue_locus = function_body.get_locus ();
626 9187 : location_t rvalue_locus = locus;
627 :
628 9187 : TyTy::BaseType *expected = fn_return_ty;
629 9187 : TyTy::BaseType *actual = nullptr;
630 9187 : bool ok = ctx->get_tyctx ()->lookup_type (
631 9187 : function_body.expr->get_mappings ().get_hirid (), &actual);
632 9187 : rust_assert (ok);
633 :
634 9187 : return_value = coercion_site (id, return_value, actual, expected,
635 : lvalue_locus, rvalue_locus);
636 :
637 9187 : tree return_stmt
638 9187 : = Backend::return_statement (fndecl, return_value, locus);
639 9187 : ctx->add_statement (return_stmt);
640 : }
641 : else
642 : {
643 : // just add the stmt expression
644 1117 : ctx->add_statement (return_value);
645 :
646 : // now just return unit expression
647 1117 : tree unit_expr = unit_expression (locus);
648 1117 : tree return_stmt
649 1117 : = Backend::return_statement (fndecl, unit_expr, locus);
650 1117 : ctx->add_statement (return_stmt);
651 : }
652 : }
653 2517 : else if (fn_return_ty->is_unit ())
654 : {
655 : // we can only do this if the function is of unit type otherwise other
656 : // errors should have occurred
657 2317 : location_t locus = function_body.get_locus ();
658 2317 : tree return_value = unit_expression (locus);
659 2317 : tree return_stmt
660 2317 : = Backend::return_statement (fndecl, return_value, locus);
661 2317 : ctx->add_statement (return_stmt);
662 : }
663 12821 : }
664 :
665 : static ABI
666 12730 : get_abi (const AST::AttrVec &outer_attrs,
667 : const HIR::FunctionQualifiers &qualifiers)
668 : {
669 12730 : bool is_proc_macro = std::any_of (outer_attrs.cbegin (), outer_attrs.cend (),
670 15610 : [] (const AST::Attribute &attr) {
671 15610 : auto path = attr.get_path ().as_string ();
672 15610 : return path == "proc_macro"
673 15610 : || path == "proc_macro_derive"
674 31220 : || path == "proc_macro_attribute";
675 15610 : });
676 :
677 12730 : return is_proc_macro ? ABI::CDECL : qualifiers.get_abi ();
678 : }
679 :
680 : tree
681 12730 : HIRCompileBase::compile_function (
682 : bool is_root_item, const std::string &fn_name,
683 : tl::optional<HIR::SelfParam> &self_param,
684 : std::vector<HIR::FunctionParam> &function_params,
685 : const HIR::FunctionQualifiers &qualifiers, HIR::Visibility &visibility,
686 : AST::AttrVec &outer_attrs, location_t locus, HIR::BlockExpr *function_body,
687 : const Resolver::CanonicalPath &canonical_path, TyTy::FnType *fntype)
688 : {
689 12730 : tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
690 12730 : std::string ir_symbol_name
691 12730 : = canonical_path.get () + fntype->subst_as_string ();
692 :
693 12730 : rust_debug_loc (locus, "--> Compiling [%s] - %s", ir_symbol_name.c_str (),
694 12730 : fntype->get_name ().c_str ());
695 :
696 : // we don't mangle the main fn since we haven't implemented the main shim
697 3727 : bool is_main_fn = fn_name.compare ("main") == 0 && is_root_item
698 16455 : && canonical_path.size () <= 2;
699 3724 : if (is_main_fn)
700 : {
701 3724 : rust_assert (!main_identifier_node);
702 : /* So that 'MAIN_NAME_P' works. */
703 3724 : main_identifier_node = get_identifier (ir_symbol_name.c_str ());
704 : }
705 : // Local name because fn_name is not mutable.
706 12730 : std::string asm_name = fn_name;
707 :
708 : // conditionally mangle the function name
709 12730 : bool should_mangle = true;
710 :
711 28340 : auto get_export_name = [] (AST::Attribute &attr) {
712 15610 : return attr.get_path ().as_string () == Values::Attributes::EXPORT_NAME;
713 : };
714 12730 : auto export_name_attr
715 12730 : = std::find_if (outer_attrs.begin (), outer_attrs.end (), get_export_name);
716 :
717 12730 : tl::optional<std::string> backend_asm_name = tl::nullopt;
718 :
719 12730 : if (export_name_attr != outer_attrs.end ())
720 : {
721 1 : asm_name
722 1 : = Analysis::Attributes::extract_string_literal (*export_name_attr)
723 1 : .value (); // Checked within attribute checker
724 1 : backend_asm_name = asm_name;
725 1 : should_mangle = false;
726 : }
727 :
728 12730 : unsigned int flags = 0;
729 12730 : tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name,
730 12730 : backend_asm_name, flags, locus);
731 :
732 12730 : setup_fndecl (fndecl, is_main_fn, fntype->has_substitutions_defined (),
733 : visibility, qualifiers, outer_attrs);
734 12730 : setup_abi_options (fndecl, get_abi (outer_attrs, qualifiers));
735 :
736 12730 : should_mangle &= should_mangle_item (fndecl);
737 12730 : if (!is_main_fn && should_mangle)
738 9004 : asm_name = ctx->mangle_item (fntype, canonical_path);
739 12730 : SET_DECL_ASSEMBLER_NAME (fndecl,
740 : get_identifier_with_length (asm_name.data (),
741 : asm_name.length ()));
742 :
743 : // insert into the context
744 12730 : ctx->insert_function_decl (fntype, fndecl);
745 :
746 : // setup the params
747 12730 : TyTy::BaseType *tyret = fntype->get_return_type ();
748 12730 : std::vector<Bvariable *> param_vars;
749 12730 : if (self_param)
750 : {
751 10836 : rust_assert (fntype->is_method ());
752 5418 : TyTy::BaseType *self_tyty_lookup = fntype->get_self_type ();
753 :
754 5418 : tree self_type = TyTyResolveCompile::compile (ctx, self_tyty_lookup);
755 5418 : Bvariable *compiled_self_param
756 5418 : = CompileSelfParam::compile (ctx, fndecl, self_param.value (),
757 5418 : self_type, self_param->get_locus ());
758 :
759 5418 : param_vars.push_back (compiled_self_param);
760 5418 : ctx->insert_var_decl (self_param->get_mappings ().get_hirid (),
761 : compiled_self_param);
762 : }
763 :
764 : // offset from + 1 for the TyTy::FnType being used when this is a method to
765 : // skip over Self on the FnType
766 12730 : bool is_method = self_param.has_value ();
767 12730 : size_t i = is_method ? 1 : 0;
768 19009 : for (auto &referenced_param : function_params)
769 : {
770 6279 : auto &tyty_param = fntype->param_at (i++);
771 6279 : auto param_tyty = tyty_param.get_type ();
772 6279 : auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty);
773 :
774 6279 : location_t param_locus = referenced_param.get_locus ();
775 6279 : Bvariable *compiled_param_var
776 6279 : = CompileFnParam::compile (ctx, fndecl, referenced_param,
777 6279 : compiled_param_type, param_locus);
778 :
779 6279 : param_vars.push_back (compiled_param_var);
780 :
781 6279 : const HIR::Pattern ¶m_pattern = referenced_param.get_param_name ();
782 6279 : ctx->insert_var_decl (param_pattern.get_mappings ().get_hirid (),
783 : compiled_param_var);
784 : }
785 :
786 12730 : if (!Backend::function_set_parameters (fndecl, param_vars))
787 0 : return error_mark_node;
788 :
789 12730 : tree enclosing_scope = NULL_TREE;
790 12730 : location_t start_location = function_body->get_locus ();
791 12730 : location_t end_location = function_body->get_end_locus ();
792 :
793 12730 : tree code_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/,
794 : start_location, end_location);
795 12730 : ctx->push_block (code_block);
796 :
797 12730 : Bvariable *return_address = nullptr;
798 12730 : tree return_type = TyTyResolveCompile::compile (ctx, tyret);
799 :
800 12730 : bool address_is_taken = false;
801 12730 : tree ret_var_stmt = NULL_TREE;
802 12730 : return_address
803 12730 : = Backend::temporary_variable (fndecl, code_block, return_type, NULL,
804 : address_is_taken, locus, &ret_var_stmt);
805 :
806 12730 : ctx->add_statement (ret_var_stmt);
807 :
808 12730 : ctx->push_fn (fndecl, return_address, tyret);
809 12730 : compile_function_body (fndecl, *function_body, tyret);
810 12730 : tree bind_tree = ctx->pop_block ();
811 :
812 12730 : gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
813 12730 : DECL_SAVED_TREE (fndecl) = bind_tree;
814 :
815 12730 : ctx->pop_fn ();
816 12730 : ctx->push_function (fndecl);
817 :
818 12730 : if (DECL_DECLARED_CONSTEXPR_P (fndecl))
819 : {
820 664 : maybe_save_constexpr_fundef (fndecl);
821 : }
822 :
823 : return fndecl;
824 12731 : }
825 :
826 : tree
827 1743 : HIRCompileBase::compile_constant_item (
828 : HirId coercion_id, TyTy::BaseType *resolved_type,
829 : TyTy::BaseType *expected_type, const Resolver::CanonicalPath &canonical_path,
830 : HIR::Expr &const_value_expr, location_t locus, location_t expr_locus)
831 : {
832 1743 : const std::string &ident = canonical_path.get ();
833 :
834 1743 : tree type = TyTyResolveCompile::compile (ctx, resolved_type);
835 1743 : tree const_type = build_qualified_type (type, TYPE_QUAL_CONST);
836 :
837 1743 : tree actual_type = TyTyResolveCompile::compile (ctx, expected_type);
838 1743 : tree actual_const_type = build_qualified_type (actual_type, TYPE_QUAL_CONST);
839 :
840 1743 : bool is_block_expr
841 1743 : = const_value_expr.get_expression_type () == HIR::Expr::ExprType::Block;
842 :
843 : // in order to compile a block expr we want to reuse as much existing
844 : // machineary that we already have. This means the best approach is to
845 : // make a _fake_ function with a block so it can hold onto temps then
846 : // use our constexpr code to fold it completely or error_mark_node
847 1743 : Backend::typed_identifier receiver ("", NULL_TREE, UNKNOWN_LOCATION);
848 1743 : tree compiled_fn_type = Backend::function_type (
849 1743 : receiver, {}, {Backend::typed_identifier ("_", const_type, locus)}, NULL,
850 : locus);
851 1743 : tree fndecl
852 1743 : = Backend::function (compiled_fn_type, ident, tl::nullopt, 0, locus);
853 1743 : TREE_READONLY (fndecl) = 1;
854 :
855 1743 : tree enclosing_scope = NULL_TREE;
856 1743 : location_t start_location = const_value_expr.get_locus ();
857 1743 : location_t end_location = const_value_expr.get_locus ();
858 1743 : if (is_block_expr)
859 : {
860 39 : HIR::BlockExpr &function_body
861 : = static_cast<HIR::BlockExpr &> (const_value_expr);
862 39 : start_location = function_body.get_locus ();
863 39 : end_location = function_body.get_end_locus ();
864 : }
865 :
866 1743 : tree code_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/,
867 : start_location, end_location);
868 1743 : ctx->push_block (code_block);
869 :
870 1743 : bool address_is_taken = false;
871 1743 : tree ret_var_stmt = NULL_TREE;
872 1743 : Bvariable *return_address
873 1743 : = Backend::temporary_variable (fndecl, code_block, const_type, NULL,
874 : address_is_taken, locus, &ret_var_stmt);
875 :
876 1743 : ctx->add_statement (ret_var_stmt);
877 1743 : ctx->push_fn (fndecl, return_address, resolved_type);
878 :
879 1743 : if (is_block_expr)
880 : {
881 39 : HIR::BlockExpr &function_body
882 : = static_cast<HIR::BlockExpr &> (const_value_expr);
883 39 : compile_function_body (fndecl, function_body, resolved_type);
884 : }
885 : else
886 : {
887 1704 : tree value = CompileExpr::Compile (const_value_expr, ctx);
888 :
889 1704 : tree return_expr
890 1704 : = Backend::return_statement (fndecl, value,
891 1704 : const_value_expr.get_locus ());
892 1704 : ctx->add_statement (return_expr);
893 : }
894 :
895 1743 : tree bind_tree = ctx->pop_block ();
896 :
897 1743 : gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
898 1743 : DECL_SAVED_TREE (fndecl) = bind_tree;
899 1743 : DECL_DECLARED_CONSTEXPR_P (fndecl) = 1;
900 1743 : maybe_save_constexpr_fundef (fndecl);
901 :
902 1743 : ctx->pop_fn ();
903 :
904 : // lets fold it into a call expr
905 1743 : tree call = build_call_array_loc (locus, const_type, fndecl, 0, NULL);
906 1743 : tree folded_expr = fold_expr (call);
907 :
908 : // coercion site
909 1743 : tree coerced = coercion_site (coercion_id, folded_expr, resolved_type,
910 : expected_type, locus, expr_locus);
911 :
912 1743 : return named_constant_expression (actual_const_type, ident, coerced, locus);
913 1743 : }
914 :
915 : tree
916 1743 : HIRCompileBase::named_constant_expression (tree type_tree,
917 : const std::string &name,
918 : tree const_val, location_t location)
919 : {
920 1743 : if (type_tree == error_mark_node || const_val == error_mark_node)
921 : return error_mark_node;
922 :
923 1731 : tree name_tree = get_identifier_with_length (name.data (), name.length ());
924 1731 : tree decl = build_decl (location, CONST_DECL, name_tree, type_tree);
925 1731 : DECL_INITIAL (decl) = const_val;
926 1731 : TREE_CONSTANT (decl) = 1;
927 1731 : TREE_READONLY (decl) = 1;
928 :
929 1731 : rust_preserve_from_gc (decl);
930 1731 : return decl;
931 : }
932 :
933 : tree
934 3920 : HIRCompileBase::resolve_method_address (TyTy::FnType *fntype,
935 : TyTy::BaseType *receiver,
936 : location_t expr_locus)
937 : {
938 3920 : rust_debug_loc (expr_locus, "resolve_method_address for %s and receiver %s",
939 7840 : fntype->debug_str ().c_str (),
940 3920 : receiver->debug_str ().c_str ());
941 :
942 3920 : DefId id = fntype->get_id ();
943 3920 : rust_assert (id != UNKNOWN_DEFID);
944 :
945 : // Now we can try and resolve the address since this might be a forward
946 : // declared function, generic function which has not be compiled yet or
947 : // its an not yet trait bound function
948 3920 : if (auto resolved_item = ctx->get_mappings ().lookup_defid (id))
949 : {
950 3007 : if (!fntype->has_substitutions_defined ())
951 3007 : return CompileItem::compile (*resolved_item, ctx);
952 :
953 744 : return CompileItem::compile (*resolved_item, ctx, fntype);
954 : }
955 :
956 : // it might be resolved to a trait item
957 913 : HIR::TraitItem *trait_item
958 913 : = ctx->get_mappings ().lookup_trait_item_defid (id).value ();
959 913 : HIR::Trait *trait = ctx->get_mappings ().lookup_trait_item_mapping (
960 913 : trait_item->get_mappings ().get_hirid ());
961 :
962 913 : Resolver::TraitReference *trait_ref
963 913 : = &Resolver::TraitReference::error_node ();
964 913 : bool ok = ctx->get_tyctx ()->lookup_trait_reference (
965 913 : trait->get_mappings ().get_defid (), &trait_ref);
966 913 : rust_assert (ok);
967 :
968 : // the type resolver can only resolve type bounds to their trait
969 : // item so its up to us to figure out if this path should resolve
970 : // to an trait-impl-block-item or if it can be defaulted to the
971 : // trait-impl-item's definition
972 913 : const HIR::PathIdentSegment segment (trait_item->trait_identifier ());
973 913 : auto root = receiver->get_root ();
974 913 : auto candidates
975 913 : = Resolver::PathProbeImplTrait::Probe (root, segment, trait_ref);
976 913 : if (candidates.size () == 0)
977 : {
978 : // this means we are defaulting back to the trait_item if
979 : // possible
980 131 : Resolver::TraitItemReference *trait_item_ref = nullptr;
981 131 : bool ok = trait_ref->lookup_hir_trait_item (*trait_item, &trait_item_ref);
982 131 : rust_assert (ok); // found
983 131 : rust_assert (trait_item_ref->is_optional ()); // has definition
984 :
985 : // FIXME tl::optional means it has a definition and an associated
986 : // block which can be a default implementation, if it does not
987 : // contain an implementation we should actually return
988 : // error_mark_node
989 :
990 131 : return CompileTraitItem::Compile (trait_item_ref->get_hir_trait_item (),
991 : ctx, fntype, true, expr_locus);
992 : }
993 :
994 782 : const Resolver::PathProbeCandidate *selectedCandidate = nullptr;
995 782 : rust_debug_loc (expr_locus, "resolved to %lu candidates",
996 782 : (unsigned long) candidates.size ());
997 :
998 : // filter for the possible case of non fn type items
999 782 : std::set<Resolver::PathProbeCandidate> filteredFunctionCandidates;
1000 1603 : for (auto &candidate : candidates)
1001 : {
1002 821 : bool is_fntype = candidate.ty->get_kind () == TyTy::TypeKind::FNDEF;
1003 821 : if (!is_fntype)
1004 0 : continue;
1005 :
1006 821 : filteredFunctionCandidates.insert (candidate);
1007 : }
1008 :
1009 : // look for the exact fntype
1010 783 : for (auto &candidate : filteredFunctionCandidates)
1011 : {
1012 783 : if (filteredFunctionCandidates.size () == 1)
1013 : {
1014 : selectedCandidate = &candidate;
1015 : break;
1016 : }
1017 :
1018 40 : bool compatable
1019 40 : = Resolver::types_compatable (TyTy::TyWithLocation (candidate.ty),
1020 40 : TyTy::TyWithLocation (fntype), expr_locus,
1021 : false);
1022 :
1023 80 : rust_debug_loc (candidate.locus, "candidate: %s vs %s compatable=%s",
1024 80 : candidate.ty->debug_str ().c_str (),
1025 40 : fntype->debug_str ().c_str (),
1026 : compatable ? "true" : "false");
1027 :
1028 40 : if (compatable)
1029 : {
1030 : selectedCandidate = &candidate;
1031 : break;
1032 : }
1033 : }
1034 :
1035 : // FIXME eventually this should just return error mark node when we support
1036 : // going through all the passes
1037 782 : rust_assert (selectedCandidate != nullptr);
1038 :
1039 : // lets compile it
1040 782 : const Resolver::PathProbeCandidate &candidate = *selectedCandidate;
1041 782 : rust_assert (candidate.is_impl_candidate ());
1042 782 : rust_assert (candidate.ty->get_kind () == TyTy::TypeKind::FNDEF);
1043 782 : TyTy::FnType *candidate_call = static_cast<TyTy::FnType *> (candidate.ty);
1044 782 : HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
1045 :
1046 782 : TyTy::BaseType *monomorphized = candidate_call;
1047 782 : if (candidate_call->needs_generic_substitutions ())
1048 : {
1049 102 : TyTy::BaseType *infer_impl_call
1050 102 : = candidate_call->infer_substitions (expr_locus);
1051 102 : monomorphized
1052 102 : = Resolver::unify_site (fntype->get_ref (),
1053 102 : TyTy::TyWithLocation (infer_impl_call),
1054 102 : TyTy::TyWithLocation (fntype), expr_locus);
1055 : }
1056 :
1057 782 : return CompileInherentImplItem::Compile (impl_item, ctx, monomorphized);
1058 1695 : }
1059 :
1060 : tree
1061 6613 : HIRCompileBase::unit_expression (location_t locus)
1062 : {
1063 6613 : tree unit_type = TyTyResolveCompile::get_unit_type (ctx);
1064 6613 : return Backend::constructor_expression (unit_type, false, {}, -1, locus);
1065 : }
1066 :
1067 : } // namespace Compile
1068 : } // namespace Rust
|