Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 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 : 12673 : bool inline should_mangle_item (const tree fndecl)
51 : : {
52 : 12673 : return lookup_attribute (Values::Attributes::NO_MANGLE,
53 : 12673 : DECL_ATTRIBUTES (fndecl))
54 : 12673 : == NULL_TREE;
55 : : }
56 : :
57 : : void
58 : 12673 : 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 : 12673 : bool is_pub = visibility.get_vis_type () == HIR::Visibility::VisType::PUBLIC;
66 : 12673 : if (is_main_entry_point || (is_pub && !is_generic_fn))
67 : : {
68 : 5616 : TREE_PUBLIC (fndecl) = 1;
69 : : }
70 : :
71 : : // is it a const fn
72 : 12673 : DECL_DECLARED_CONSTEXPR_P (fndecl) = qualifiers.is_const ();
73 : 12673 : if (qualifiers.is_const ())
74 : : {
75 : 664 : TREE_READONLY (fndecl) = 1;
76 : : }
77 : :
78 : : // is it inline?
79 : 28282 : for (const auto &attr : attrs)
80 : : {
81 : 15609 : bool is_inline
82 : 15609 : = attr.get_path ().as_string () == Values::Attributes::INLINE;
83 : 15609 : bool is_must_use
84 : 15609 : = attr.get_path ().as_string () == Values::Attributes::MUST_USE;
85 : 15609 : bool is_cold = attr.get_path ().as_string () == Values::Attributes::COLD;
86 : 15609 : bool is_link_section
87 : 15609 : = attr.get_path ().as_string () == Values::Attributes::LINK_SECTION;
88 : 15609 : bool no_mangle
89 : 15609 : = attr.get_path ().as_string () == Values::Attributes::NO_MANGLE;
90 : 15609 : bool is_deprecated
91 : 15609 : = attr.get_path ().as_string () == Values::Attributes::DEPRECATED;
92 : 15609 : bool is_proc_macro
93 : 15609 : = attr.get_path ().as_string () == Values::Attributes::PROC_MACRO;
94 : 15609 : bool is_proc_macro_attribute
95 : 31218 : = attr.get_path ().as_string ()
96 : 15609 : == Values::Attributes::PROC_MACRO_ATTRIBUTE;
97 : 31218 : bool is_proc_macro_derive = attr.get_path ().as_string ()
98 : 15609 : == Values::Attributes::PROC_MACRO_DERIVE;
99 : :
100 : 15609 : if (is_inline)
101 : : {
102 : 943 : handle_inline_attribute_on_fndecl (fndecl, attr);
103 : : }
104 : 14666 : else if (is_must_use)
105 : : {
106 : 1089 : handle_must_use_attribute_on_fndecl (fndecl, attr);
107 : : }
108 : 13577 : else if (is_cold)
109 : : {
110 : 1 : handle_cold_attribute_on_fndecl (fndecl, attr);
111 : : }
112 : 13576 : else if (is_link_section)
113 : : {
114 : 1 : handle_link_section_attribute_on_fndecl (fndecl, attr);
115 : : }
116 : 13575 : else if (is_deprecated)
117 : : {
118 : 5 : handle_deprecated_attribute_on_fndecl (fndecl, attr);
119 : : }
120 : 13570 : else if (no_mangle)
121 : : {
122 : 1 : handle_no_mangle_attribute_on_fndecl (fndecl, attr);
123 : : }
124 : 13569 : else if (is_proc_macro)
125 : : {
126 : 0 : handle_bang_proc_macro_attribute_on_fndecl (fndecl, attr);
127 : : }
128 : 13569 : else if (is_proc_macro_attribute)
129 : : {
130 : 0 : handle_attribute_proc_macro_attribute_on_fndecl (fndecl, attr);
131 : : }
132 : 13569 : else if (is_proc_macro_derive)
133 : : {
134 : 0 : handle_derive_proc_macro_attribute_on_fndecl (fndecl, attr);
135 : : }
136 : : }
137 : 12673 : }
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 : 13739 : HIRCompileBase::setup_abi_options (tree fndecl, ABI abi)
430 : : {
431 : 13739 : tree abi_tree = NULL_TREE;
432 : :
433 : 13739 : switch (abi)
434 : : {
435 : 13738 : case Rust::ABI::RUST:
436 : 13738 : case Rust::ABI::INTRINSIC:
437 : 13738 : case Rust::ABI::C:
438 : 13738 : 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 : 13738 : DECL_ATTRIBUTES (fndecl)
446 : 13738 : = tree_cons (get_identifier ("cdecl"), NULL, DECL_ATTRIBUTES (fndecl));
447 : :
448 : 13738 : 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 : 37252 : HIRCompileBase::mark_addressable (tree exp, location_t locus)
488 : : {
489 : 37252 : tree x = exp;
490 : :
491 : 39201 : while (1)
492 : 39201 : 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 : 27010 : case VAR_DECL:
527 : 27010 : case CONST_DECL:
528 : 27010 : case PARM_DECL:
529 : 27010 : case RESULT_DECL:
530 : : // (we don't have a concept of a "register" declaration)
531 : : // fallthrough */
532 : :
533 : : /* FALLTHRU */
534 : 27010 : case FUNCTION_DECL:
535 : 27010 : TREE_ADDRESSABLE (x) = 1;
536 : :
537 : : /* FALLTHRU */
538 : : default:
539 : : return true;
540 : : }
541 : :
542 : : return false;
543 : : }
544 : :
545 : : tree
546 : 37274 : HIRCompileBase::address_expression (tree expr, location_t location, tree ptrty)
547 : : {
548 : 37274 : if (expr == error_mark_node)
549 : : return error_mark_node;
550 : :
551 : 37252 : if (!mark_addressable (expr, location))
552 : 0 : return error_mark_node;
553 : :
554 : 37252 : if (ptrty == NULL || ptrty == error_mark_node)
555 : 35506 : ptrty = build_pointer_type (TREE_TYPE (expr));
556 : :
557 : 37252 : 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 : 14079 : HIRCompileBase::indirect_expression (tree expr, location_t locus)
593 : : {
594 : 14079 : if (expr == error_mark_node)
595 : : return error_mark_node;
596 : :
597 : 14079 : return build_fold_indirect_ref_loc (locus, expr);
598 : : }
599 : :
600 : : void
601 : 12764 : HIRCompileBase::compile_function_body (tree fndecl,
602 : : HIR::BlockExpr &function_body,
603 : : TyTy::BaseType *fn_return_ty)
604 : : {
605 : 26599 : for (auto &s : function_body.get_statements ())
606 : : {
607 : 13835 : auto compiled_expr = CompileStmt::Compile (s.get (), ctx);
608 : 13835 : if (compiled_expr != nullptr)
609 : : {
610 : 4669 : tree s = convert_to_void (compiled_expr, ICV_STATEMENT);
611 : 4669 : ctx->add_statement (s);
612 : : }
613 : : }
614 : :
615 : 12764 : if (function_body.has_expr ())
616 : : {
617 : 10261 : location_t locus = function_body.get_final_expr ().get_locus ();
618 : 10261 : tree return_value
619 : 10261 : = CompileExpr::Compile (function_body.get_final_expr (), ctx);
620 : :
621 : : // we can only return this if non unit value return type
622 : 10261 : if (!fn_return_ty->is_unit ())
623 : : {
624 : 9159 : HirId id = function_body.get_mappings ().get_hirid ();
625 : 9159 : location_t lvalue_locus = function_body.get_locus ();
626 : 9159 : location_t rvalue_locus = locus;
627 : :
628 : 9159 : TyTy::BaseType *expected = fn_return_ty;
629 : 9159 : TyTy::BaseType *actual = nullptr;
630 : 9159 : bool ok = ctx->get_tyctx ()->lookup_type (
631 : 9159 : function_body.expr->get_mappings ().get_hirid (), &actual);
632 : 9159 : rust_assert (ok);
633 : :
634 : 9159 : return_value = coercion_site (id, return_value, actual, expected,
635 : : lvalue_locus, rvalue_locus);
636 : :
637 : 9159 : tree return_stmt
638 : 9159 : = Backend::return_statement (fndecl, return_value, locus);
639 : 9159 : ctx->add_statement (return_stmt);
640 : : }
641 : : else
642 : : {
643 : : // just add the stmt expression
644 : 1102 : ctx->add_statement (return_value);
645 : :
646 : : // now just return unit expression
647 : 1102 : tree unit_expr = unit_expression (locus);
648 : 1102 : tree return_stmt
649 : 1102 : = Backend::return_statement (fndecl, unit_expr, locus);
650 : 1102 : ctx->add_statement (return_stmt);
651 : : }
652 : : }
653 : 2503 : 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 : 2304 : location_t locus = function_body.get_locus ();
658 : 2304 : tree return_value = unit_expression (locus);
659 : 2304 : tree return_stmt
660 : 2304 : = Backend::return_statement (fndecl, return_value, locus);
661 : 2304 : ctx->add_statement (return_stmt);
662 : : }
663 : 12764 : }
664 : :
665 : : static ABI
666 : 12673 : get_abi (const AST::AttrVec &outer_attrs,
667 : : const HIR::FunctionQualifiers &qualifiers)
668 : : {
669 : 12673 : bool is_proc_macro = std::any_of (outer_attrs.cbegin (), outer_attrs.cend (),
670 : 15609 : [] (const AST::Attribute &attr) {
671 : 15609 : auto path = attr.get_path ().as_string ();
672 : 15609 : return path == "proc_macro"
673 : 15609 : || path == "proc_macro_derive"
674 : 31218 : || path == "proc_macro_attribute";
675 : 15609 : });
676 : :
677 : 12673 : return is_proc_macro ? ABI::CDECL : qualifiers.get_abi ();
678 : : }
679 : :
680 : : tree
681 : 12673 : 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 : 12673 : tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
690 : 12673 : std::string ir_symbol_name
691 : 12673 : = canonical_path.get () + fntype->subst_as_string ();
692 : :
693 : 12673 : rust_debug_loc (locus, "--> Compiling [%s] - %s", ir_symbol_name.c_str (),
694 : 12673 : fntype->get_name ().c_str ());
695 : :
696 : : // we don't mangle the main fn since we haven't implemented the main shim
697 : 3699 : bool is_main_fn = fn_name.compare ("main") == 0 && is_root_item
698 : 16370 : && canonical_path.size () <= 2;
699 : 3696 : if (is_main_fn)
700 : : {
701 : 3696 : rust_assert (!main_identifier_node);
702 : : /* So that 'MAIN_NAME_P' works. */
703 : 3696 : main_identifier_node = get_identifier (ir_symbol_name.c_str ());
704 : : }
705 : 12673 : std::string asm_name = fn_name;
706 : :
707 : 12673 : unsigned int flags = 0;
708 : 12673 : tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name,
709 : : tl::nullopt /* asm_name */, flags, locus);
710 : :
711 : 12673 : setup_fndecl (fndecl, is_main_fn, fntype->has_substitutions_defined (),
712 : : visibility, qualifiers, outer_attrs);
713 : 12673 : setup_abi_options (fndecl, get_abi (outer_attrs, qualifiers));
714 : :
715 : : // conditionally mangle the function name
716 : 12673 : bool should_mangle = should_mangle_item (fndecl);
717 : 12673 : if (!is_main_fn && should_mangle)
718 : 8976 : asm_name = ctx->mangle_item (fntype, canonical_path);
719 : 12673 : SET_DECL_ASSEMBLER_NAME (fndecl,
720 : : get_identifier_with_length (asm_name.data (),
721 : : asm_name.length ()));
722 : :
723 : : // insert into the context
724 : 12673 : ctx->insert_function_decl (fntype, fndecl);
725 : :
726 : : // setup the params
727 : 12673 : TyTy::BaseType *tyret = fntype->get_return_type ();
728 : 12673 : std::vector<Bvariable *> param_vars;
729 : 12673 : if (self_param)
730 : : {
731 : 10836 : rust_assert (fntype->is_method ());
732 : 5418 : TyTy::BaseType *self_tyty_lookup = fntype->get_self_type ();
733 : :
734 : 5418 : tree self_type = TyTyResolveCompile::compile (ctx, self_tyty_lookup);
735 : 5418 : Bvariable *compiled_self_param
736 : 5418 : = CompileSelfParam::compile (ctx, fndecl, self_param.value (),
737 : 5418 : self_type, self_param->get_locus ());
738 : :
739 : 5418 : param_vars.push_back (compiled_self_param);
740 : 5418 : ctx->insert_var_decl (self_param->get_mappings ().get_hirid (),
741 : : compiled_self_param);
742 : : }
743 : :
744 : : // offset from + 1 for the TyTy::FnType being used when this is a method to
745 : : // skip over Self on the FnType
746 : 12673 : bool is_method = self_param.has_value ();
747 : 12673 : size_t i = is_method ? 1 : 0;
748 : 18944 : for (auto &referenced_param : function_params)
749 : : {
750 : 6271 : auto &tyty_param = fntype->param_at (i++);
751 : 6271 : auto param_tyty = tyty_param.get_type ();
752 : 6271 : auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty);
753 : :
754 : 6271 : location_t param_locus = referenced_param.get_locus ();
755 : 6271 : Bvariable *compiled_param_var
756 : 6271 : = CompileFnParam::compile (ctx, fndecl, referenced_param,
757 : 6271 : compiled_param_type, param_locus);
758 : :
759 : 6271 : param_vars.push_back (compiled_param_var);
760 : :
761 : 6271 : const HIR::Pattern ¶m_pattern = referenced_param.get_param_name ();
762 : 6271 : ctx->insert_var_decl (param_pattern.get_mappings ().get_hirid (),
763 : : compiled_param_var);
764 : : }
765 : :
766 : 12673 : if (!Backend::function_set_parameters (fndecl, param_vars))
767 : 0 : return error_mark_node;
768 : :
769 : 12673 : tree enclosing_scope = NULL_TREE;
770 : 12673 : location_t start_location = function_body->get_locus ();
771 : 12673 : location_t end_location = function_body->get_end_locus ();
772 : :
773 : 12673 : tree code_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/,
774 : : start_location, end_location);
775 : 12673 : ctx->push_block (code_block);
776 : :
777 : 12673 : Bvariable *return_address = nullptr;
778 : 12673 : tree return_type = TyTyResolveCompile::compile (ctx, tyret);
779 : :
780 : 12673 : bool address_is_taken = false;
781 : 12673 : tree ret_var_stmt = NULL_TREE;
782 : 12673 : return_address
783 : 12673 : = Backend::temporary_variable (fndecl, code_block, return_type, NULL,
784 : : address_is_taken, locus, &ret_var_stmt);
785 : :
786 : 12673 : ctx->add_statement (ret_var_stmt);
787 : :
788 : 12673 : ctx->push_fn (fndecl, return_address, tyret);
789 : 12673 : compile_function_body (fndecl, *function_body, tyret);
790 : 12673 : tree bind_tree = ctx->pop_block ();
791 : :
792 : 12673 : gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
793 : 12673 : DECL_SAVED_TREE (fndecl) = bind_tree;
794 : :
795 : 12673 : ctx->pop_fn ();
796 : 12673 : ctx->push_function (fndecl);
797 : :
798 : 12673 : if (DECL_DECLARED_CONSTEXPR_P (fndecl))
799 : : {
800 : 664 : maybe_save_constexpr_fundef (fndecl);
801 : : }
802 : :
803 : : return fndecl;
804 : 12673 : }
805 : :
806 : : tree
807 : 1741 : HIRCompileBase::compile_constant_item (
808 : : HirId coercion_id, TyTy::BaseType *resolved_type,
809 : : TyTy::BaseType *expected_type, const Resolver::CanonicalPath &canonical_path,
810 : : HIR::Expr &const_value_expr, location_t locus, location_t expr_locus)
811 : : {
812 : 1741 : const std::string &ident = canonical_path.get ();
813 : :
814 : 1741 : tree type = TyTyResolveCompile::compile (ctx, resolved_type);
815 : 1741 : tree const_type = build_qualified_type (type, TYPE_QUAL_CONST);
816 : :
817 : 1741 : tree actual_type = TyTyResolveCompile::compile (ctx, expected_type);
818 : 1741 : tree actual_const_type = build_qualified_type (actual_type, TYPE_QUAL_CONST);
819 : :
820 : 1741 : bool is_block_expr
821 : 1741 : = const_value_expr.get_expression_type () == HIR::Expr::ExprType::Block;
822 : :
823 : : // in order to compile a block expr we want to reuse as much existing
824 : : // machineary that we already have. This means the best approach is to
825 : : // make a _fake_ function with a block so it can hold onto temps then
826 : : // use our constexpr code to fold it completely or error_mark_node
827 : 1741 : Backend::typed_identifier receiver ("", NULL_TREE, UNKNOWN_LOCATION);
828 : 1741 : tree compiled_fn_type = Backend::function_type (
829 : 1741 : receiver, {}, {Backend::typed_identifier ("_", const_type, locus)}, NULL,
830 : : locus);
831 : 1741 : tree fndecl
832 : 1741 : = Backend::function (compiled_fn_type, ident, tl::nullopt, 0, locus);
833 : 1741 : TREE_READONLY (fndecl) = 1;
834 : :
835 : 1741 : tree enclosing_scope = NULL_TREE;
836 : 1741 : location_t start_location = const_value_expr.get_locus ();
837 : 1741 : location_t end_location = const_value_expr.get_locus ();
838 : 1741 : if (is_block_expr)
839 : : {
840 : 39 : HIR::BlockExpr &function_body
841 : : = static_cast<HIR::BlockExpr &> (const_value_expr);
842 : 39 : start_location = function_body.get_locus ();
843 : 39 : end_location = function_body.get_end_locus ();
844 : : }
845 : :
846 : 1741 : tree code_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/,
847 : : start_location, end_location);
848 : 1741 : ctx->push_block (code_block);
849 : :
850 : 1741 : bool address_is_taken = false;
851 : 1741 : tree ret_var_stmt = NULL_TREE;
852 : 1741 : Bvariable *return_address
853 : 1741 : = Backend::temporary_variable (fndecl, code_block, const_type, NULL,
854 : : address_is_taken, locus, &ret_var_stmt);
855 : :
856 : 1741 : ctx->add_statement (ret_var_stmt);
857 : 1741 : ctx->push_fn (fndecl, return_address, resolved_type);
858 : :
859 : 1741 : if (is_block_expr)
860 : : {
861 : 39 : HIR::BlockExpr &function_body
862 : : = static_cast<HIR::BlockExpr &> (const_value_expr);
863 : 39 : compile_function_body (fndecl, function_body, resolved_type);
864 : : }
865 : : else
866 : : {
867 : 1702 : tree value = CompileExpr::Compile (const_value_expr, ctx);
868 : :
869 : 1702 : tree return_expr
870 : 1702 : = Backend::return_statement (fndecl, value,
871 : 1702 : const_value_expr.get_locus ());
872 : 1702 : ctx->add_statement (return_expr);
873 : : }
874 : :
875 : 1741 : tree bind_tree = ctx->pop_block ();
876 : :
877 : 1741 : gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
878 : 1741 : DECL_SAVED_TREE (fndecl) = bind_tree;
879 : 1741 : DECL_DECLARED_CONSTEXPR_P (fndecl) = 1;
880 : 1741 : maybe_save_constexpr_fundef (fndecl);
881 : :
882 : 1741 : ctx->pop_fn ();
883 : :
884 : : // lets fold it into a call expr
885 : 1741 : tree call = build_call_array_loc (locus, const_type, fndecl, 0, NULL);
886 : 1741 : tree folded_expr = fold_expr (call);
887 : :
888 : : // coercion site
889 : 1741 : tree coerced = coercion_site (coercion_id, folded_expr, resolved_type,
890 : : expected_type, locus, expr_locus);
891 : :
892 : 1741 : return named_constant_expression (actual_const_type, ident, coerced, locus);
893 : 1741 : }
894 : :
895 : : tree
896 : 1741 : HIRCompileBase::named_constant_expression (tree type_tree,
897 : : const std::string &name,
898 : : tree const_val, location_t location)
899 : : {
900 : 1741 : if (type_tree == error_mark_node || const_val == error_mark_node)
901 : : return error_mark_node;
902 : :
903 : 1729 : tree name_tree = get_identifier_with_length (name.data (), name.length ());
904 : 1729 : tree decl = build_decl (location, CONST_DECL, name_tree, type_tree);
905 : 1729 : DECL_INITIAL (decl) = const_val;
906 : 1729 : TREE_CONSTANT (decl) = 1;
907 : 1729 : TREE_READONLY (decl) = 1;
908 : :
909 : 1729 : rust_preserve_from_gc (decl);
910 : 1729 : return decl;
911 : : }
912 : :
913 : : tree
914 : 3920 : HIRCompileBase::resolve_method_address (TyTy::FnType *fntype,
915 : : TyTy::BaseType *receiver,
916 : : location_t expr_locus)
917 : : {
918 : 3920 : rust_debug_loc (expr_locus, "resolve_method_address for %s and receiver %s",
919 : 7840 : fntype->debug_str ().c_str (),
920 : 3920 : receiver->debug_str ().c_str ());
921 : :
922 : 3920 : DefId id = fntype->get_id ();
923 : 3920 : rust_assert (id != UNKNOWN_DEFID);
924 : :
925 : : // Now we can try and resolve the address since this might be a forward
926 : : // declared function, generic function which has not be compiled yet or
927 : : // its an not yet trait bound function
928 : 3920 : if (auto resolved_item = ctx->get_mappings ().lookup_defid (id))
929 : : {
930 : 3007 : if (!fntype->has_substitutions_defined ())
931 : 3007 : return CompileItem::compile (*resolved_item, ctx);
932 : :
933 : 744 : return CompileItem::compile (*resolved_item, ctx, fntype);
934 : : }
935 : :
936 : : // it might be resolved to a trait item
937 : 913 : HIR::TraitItem *trait_item
938 : 913 : = ctx->get_mappings ().lookup_trait_item_defid (id).value ();
939 : 913 : HIR::Trait *trait = ctx->get_mappings ().lookup_trait_item_mapping (
940 : 913 : trait_item->get_mappings ().get_hirid ());
941 : :
942 : 913 : Resolver::TraitReference *trait_ref
943 : 913 : = &Resolver::TraitReference::error_node ();
944 : 913 : bool ok = ctx->get_tyctx ()->lookup_trait_reference (
945 : 913 : trait->get_mappings ().get_defid (), &trait_ref);
946 : 913 : rust_assert (ok);
947 : :
948 : : // the type resolver can only resolve type bounds to their trait
949 : : // item so its up to us to figure out if this path should resolve
950 : : // to an trait-impl-block-item or if it can be defaulted to the
951 : : // trait-impl-item's definition
952 : 913 : const HIR::PathIdentSegment segment (trait_item->trait_identifier ());
953 : 913 : auto root = receiver->get_root ();
954 : 913 : auto candidates
955 : 913 : = Resolver::PathProbeImplTrait::Probe (root, segment, trait_ref);
956 : 913 : if (candidates.size () == 0)
957 : : {
958 : : // this means we are defaulting back to the trait_item if
959 : : // possible
960 : 131 : Resolver::TraitItemReference *trait_item_ref = nullptr;
961 : 131 : bool ok = trait_ref->lookup_hir_trait_item (*trait_item, &trait_item_ref);
962 : 131 : rust_assert (ok); // found
963 : 131 : rust_assert (trait_item_ref->is_optional ()); // has definition
964 : :
965 : : // FIXME tl::optional means it has a definition and an associated
966 : : // block which can be a default implementation, if it does not
967 : : // contain an implementation we should actually return
968 : : // error_mark_node
969 : :
970 : 131 : return CompileTraitItem::Compile (trait_item_ref->get_hir_trait_item (),
971 : : ctx, fntype, true, expr_locus);
972 : : }
973 : :
974 : 782 : const Resolver::PathProbeCandidate *selectedCandidate = nullptr;
975 : 782 : rust_debug_loc (expr_locus, "resolved to %lu candidates",
976 : 782 : (unsigned long) candidates.size ());
977 : :
978 : : // filter for the possible case of non fn type items
979 : 782 : std::set<Resolver::PathProbeCandidate> filteredFunctionCandidates;
980 : 1603 : for (auto &candidate : candidates)
981 : : {
982 : 821 : bool is_fntype = candidate.ty->get_kind () == TyTy::TypeKind::FNDEF;
983 : 821 : if (!is_fntype)
984 : 0 : continue;
985 : :
986 : 821 : filteredFunctionCandidates.insert (candidate);
987 : : }
988 : :
989 : : // look for the exact fntype
990 : 783 : for (auto &candidate : filteredFunctionCandidates)
991 : : {
992 : 783 : if (filteredFunctionCandidates.size () == 1)
993 : : {
994 : : selectedCandidate = &candidate;
995 : : break;
996 : : }
997 : :
998 : 40 : bool compatable
999 : 40 : = Resolver::types_compatable (TyTy::TyWithLocation (candidate.ty),
1000 : 40 : TyTy::TyWithLocation (fntype), expr_locus,
1001 : : false);
1002 : :
1003 : 80 : rust_debug_loc (candidate.locus, "candidate: %s vs %s compatable=%s",
1004 : 80 : candidate.ty->debug_str ().c_str (),
1005 : 40 : fntype->debug_str ().c_str (),
1006 : : compatable ? "true" : "false");
1007 : :
1008 : 40 : if (compatable)
1009 : : {
1010 : : selectedCandidate = &candidate;
1011 : : break;
1012 : : }
1013 : : }
1014 : :
1015 : : // FIXME eventually this should just return error mark node when we support
1016 : : // going through all the passes
1017 : 782 : rust_assert (selectedCandidate != nullptr);
1018 : :
1019 : : // lets compile it
1020 : 782 : const Resolver::PathProbeCandidate &candidate = *selectedCandidate;
1021 : 782 : rust_assert (candidate.is_impl_candidate ());
1022 : 782 : rust_assert (candidate.ty->get_kind () == TyTy::TypeKind::FNDEF);
1023 : 782 : TyTy::FnType *candidate_call = static_cast<TyTy::FnType *> (candidate.ty);
1024 : 782 : HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
1025 : :
1026 : 782 : TyTy::BaseType *monomorphized = candidate_call;
1027 : 782 : if (candidate_call->needs_generic_substitutions ())
1028 : : {
1029 : 102 : TyTy::BaseType *infer_impl_call
1030 : 102 : = candidate_call->infer_substitions (expr_locus);
1031 : 102 : monomorphized
1032 : 102 : = Resolver::unify_site (fntype->get_ref (),
1033 : 102 : TyTy::TyWithLocation (infer_impl_call),
1034 : 102 : TyTy::TyWithLocation (fntype), expr_locus);
1035 : : }
1036 : :
1037 : 782 : return CompileInherentImplItem::Compile (impl_item, ctx, monomorphized);
1038 : 1695 : }
1039 : :
1040 : : tree
1041 : 6563 : HIRCompileBase::unit_expression (location_t locus)
1042 : : {
1043 : 6563 : tree unit_type = TyTyResolveCompile::get_unit_type (ctx);
1044 : 6563 : return Backend::constructor_expression (unit_type, false, {}, -1, locus);
1045 : : }
1046 : :
1047 : : } // namespace Compile
1048 : : } // namespace Rust
|