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