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 : 12520 : bool inline should_mangle_item (const tree fndecl)
50 : : {
51 : 12520 : return lookup_attribute (Values::Attributes::NO_MANGLE,
52 : 12520 : DECL_ATTRIBUTES (fndecl))
53 : 12520 : == NULL_TREE;
54 : : }
55 : :
56 : : void
57 : 12520 : 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 : 12520 : bool is_pub = visibility.get_vis_type () == HIR::Visibility::VisType::PUBLIC;
65 : 12520 : if (is_main_entry_point || (is_pub && !is_generic_fn))
66 : : {
67 : 5493 : TREE_PUBLIC (fndecl) = 1;
68 : : }
69 : :
70 : : // is it a const fn
71 : 12520 : DECL_DECLARED_CONSTEXPR_P (fndecl) = qualifiers.is_const ();
72 : 12520 : if (qualifiers.is_const ())
73 : : {
74 : 656 : TREE_READONLY (fndecl) = 1;
75 : : }
76 : :
77 : : // is it inline?
78 : 28127 : for (const auto &attr : attrs)
79 : : {
80 : 15607 : bool is_inline
81 : 15607 : = attr.get_path ().as_string () == Values::Attributes::INLINE;
82 : 15607 : bool is_must_use
83 : 15607 : = attr.get_path ().as_string () == Values::Attributes::MUST_USE;
84 : 15607 : bool is_cold = attr.get_path ().as_string () == Values::Attributes::COLD;
85 : 15607 : bool is_link_section
86 : 15607 : = attr.get_path ().as_string () == Values::Attributes::LINK_SECTION;
87 : 15607 : bool no_mangle
88 : 15607 : = attr.get_path ().as_string () == Values::Attributes::NO_MANGLE;
89 : 15607 : bool is_deprecated
90 : 15607 : = attr.get_path ().as_string () == Values::Attributes::DEPRECATED;
91 : 15607 : bool is_proc_macro
92 : 15607 : = attr.get_path ().as_string () == Values::Attributes::PROC_MACRO;
93 : 15607 : bool is_proc_macro_attribute
94 : 31214 : = attr.get_path ().as_string ()
95 : 15607 : == Values::Attributes::PROC_MACRO_ATTRIBUTE;
96 : 31214 : bool is_proc_macro_derive = attr.get_path ().as_string ()
97 : 15607 : == Values::Attributes::PROC_MACRO_DERIVE;
98 : :
99 : 15607 : if (is_inline)
100 : : {
101 : 941 : handle_inline_attribute_on_fndecl (fndecl, attr);
102 : : }
103 : 14666 : else if (is_must_use)
104 : : {
105 : 1089 : handle_must_use_attribute_on_fndecl (fndecl, attr);
106 : : }
107 : 13577 : else if (is_cold)
108 : : {
109 : 1 : handle_cold_attribute_on_fndecl (fndecl, attr);
110 : : }
111 : 13576 : else if (is_link_section)
112 : : {
113 : 1 : handle_link_section_attribute_on_fndecl (fndecl, attr);
114 : : }
115 : 13575 : else if (is_deprecated)
116 : : {
117 : 5 : handle_deprecated_attribute_on_fndecl (fndecl, attr);
118 : : }
119 : 13570 : else if (no_mangle)
120 : : {
121 : 1 : handle_no_mangle_attribute_on_fndecl (fndecl, attr);
122 : : }
123 : 13569 : else if (is_proc_macro)
124 : : {
125 : 0 : handle_bang_proc_macro_attribute_on_fndecl (fndecl, attr);
126 : : }
127 : 13569 : else if (is_proc_macro_attribute)
128 : : {
129 : 0 : handle_attribute_proc_macro_attribute_on_fndecl (fndecl, attr);
130 : : }
131 : 13569 : else if (is_proc_macro_derive)
132 : : {
133 : 0 : handle_derive_proc_macro_attribute_on_fndecl (fndecl, attr);
134 : : }
135 : : }
136 : 12520 : }
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 : 1 : HIRCompileBase::handle_cold_attribute_on_fndecl (tree fndecl,
234 : : const AST::Attribute &attr)
235 : : {
236 : : // simple #[cold]
237 : 1 : if (!attr.has_attr_input ())
238 : : {
239 : 1 : tree cold = get_identifier (Values::Attributes::COLD);
240 : : // this will get handled by the GCC backend later
241 : 1 : DECL_ATTRIBUTES (fndecl)
242 : 1 : = tree_cons (cold, NULL_TREE, DECL_ATTRIBUTES (fndecl));
243 : 1 : 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 : 5 : HIRCompileBase::handle_deprecated_attribute_on_fndecl (
293 : : tree fndecl, const AST::Attribute &attr)
294 : : {
295 : 5 : tree value = NULL_TREE;
296 : 5 : TREE_DEPRECATED (fndecl) = 1;
297 : :
298 : : // simple #[deprecated]
299 : 5 : if (!attr.has_attr_input ())
300 : : return;
301 : :
302 : 4 : const AST::AttrInput &input = attr.get_attr_input ();
303 : 4 : auto input_type = input.get_attr_input_type ();
304 : :
305 : 4 : if (input_type == AST::AttrInput::AttrInputType::LITERAL)
306 : : {
307 : : // handle #[deprecated = "message"]
308 : 1 : auto &literal
309 : 1 : = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
310 : 1 : const auto &msg_str = literal.get_literal ().as_string ();
311 : 1 : value = build_string (msg_str.size (), msg_str.c_str ());
312 : 1 : }
313 : 3 : else if (input_type == AST::AttrInput::AttrInputType::TOKEN_TREE)
314 : : {
315 : : // handle #[deprecated(since = "...", note = "...")]
316 : 3 : const auto &option = static_cast<const AST::DelimTokenTree &> (input);
317 : 3 : AST::AttrInputMetaItemContainer *meta_item = option.parse_to_meta_item ();
318 : 7 : for (const auto &item : meta_item->get_items ())
319 : : {
320 : 4 : auto converted_item = item->to_meta_name_value_str ();
321 : 4 : if (!converted_item)
322 : 0 : continue;
323 : 4 : auto key_value = converted_item->get_name_value_pair ();
324 : 4 : 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 : 2 : continue;
329 : : }
330 : 2 : else if (key_value.first.as_string ().compare ("note") == 0)
331 : : {
332 : 1 : const auto &msg_str = key_value.second;
333 : 1 : if (value)
334 : 0 : rust_error_at (attr.get_locus (), "multiple %<note%> items");
335 : 1 : value = build_string (msg_str.size (), msg_str.c_str ());
336 : : }
337 : : else
338 : : {
339 : 1 : rust_error_at (attr.get_locus (), ErrorCode::E0541,
340 : : "unknown meta item %qs",
341 : 1 : key_value.first.as_string ().c_str ());
342 : : }
343 : 4 : }
344 : : }
345 : :
346 : 4 : if (value)
347 : : {
348 : 2 : tree attr_list = build_tree_list (NULL_TREE, value);
349 : 2 : DECL_ATTRIBUTES (fndecl)
350 : 4 : = tree_cons (get_identifier (Values::Attributes::DEPRECATED), attr_list,
351 : 2 : DECL_ATTRIBUTES (fndecl));
352 : : }
353 : : }
354 : :
355 : : void
356 : 941 : HIRCompileBase::handle_inline_attribute_on_fndecl (tree fndecl,
357 : : const AST::Attribute &attr)
358 : : {
359 : : // simple #[inline]
360 : 941 : if (!attr.has_attr_input ())
361 : : {
362 : 936 : DECL_DECLARED_INLINE_P (fndecl) = 1;
363 : 938 : return;
364 : : }
365 : :
366 : 5 : const AST::AttrInput &input = attr.get_attr_input ();
367 : 5 : bool is_token_tree
368 : 5 : = input.get_attr_input_type () == AST::AttrInput::AttrInputType::TOKEN_TREE;
369 : 5 : rust_assert (is_token_tree);
370 : 5 : const auto &option = static_cast<const AST::DelimTokenTree &> (input);
371 : 5 : AST::AttrInputMetaItemContainer *meta_item = option.parse_to_meta_item ();
372 : 5 : if (meta_item->get_items ().size () != 1)
373 : : {
374 : 2 : rich_location rich_locus (line_table, attr.get_locus ());
375 : 2 : rich_locus.add_fixit_replace ("expected one argument");
376 : 2 : rust_error_at (rich_locus, ErrorCode::E0534,
377 : : "invalid number of arguments");
378 : 2 : return;
379 : 2 : }
380 : :
381 : 3 : const std::string inline_option
382 : 3 : = meta_item->get_items ().at (0)->as_string ();
383 : :
384 : : // we only care about NEVER and ALWAYS else its an error
385 : 3 : bool is_always = inline_option.compare ("always") == 0;
386 : 3 : bool is_never = inline_option.compare ("never") == 0;
387 : :
388 : : // #[inline(never)]
389 : 3 : if (is_never)
390 : : {
391 : 1 : DECL_UNINLINABLE (fndecl) = 1;
392 : : }
393 : : // #[inline(always)]
394 : 2 : else if (is_always)
395 : : {
396 : 1 : DECL_DECLARED_INLINE_P (fndecl) = 1;
397 : 1 : DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("always_inline"),
398 : 1 : NULL, DECL_ATTRIBUTES (fndecl));
399 : : }
400 : : else
401 : : {
402 : 1 : rich_location rich_locus (line_table, attr.get_locus ());
403 : 1 : rich_locus.add_fixit_replace ("unknown inline option");
404 : 1 : rust_error_at (rich_locus, ErrorCode::E0535,
405 : : "invalid argument, %<inline%> attribute only accepts "
406 : : "%<always%> or %<never%>");
407 : 1 : }
408 : 3 : }
409 : :
410 : : void
411 : 1089 : HIRCompileBase::handle_must_use_attribute_on_fndecl (tree fndecl,
412 : : const AST::Attribute &attr)
413 : : {
414 : 1089 : tree nodiscard = get_identifier ("nodiscard");
415 : 1089 : tree value = NULL_TREE;
416 : :
417 : 1089 : if (attr.has_attr_input ())
418 : : {
419 : 15 : rust_assert (attr.get_attr_input ().get_attr_input_type ()
420 : : == AST::AttrInput::AttrInputType::LITERAL);
421 : :
422 : 15 : auto &literal
423 : 15 : = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
424 : 15 : const auto &msg_str = literal.get_literal ().as_string ();
425 : 15 : tree message = build_string (msg_str.size (), msg_str.c_str ());
426 : :
427 : 15 : value = tree_cons (nodiscard, message, NULL_TREE);
428 : 15 : }
429 : :
430 : 1089 : DECL_ATTRIBUTES (fndecl)
431 : 1089 : = tree_cons (nodiscard, value, DECL_ATTRIBUTES (fndecl));
432 : 1089 : }
433 : :
434 : : void
435 : 13551 : HIRCompileBase::setup_abi_options (tree fndecl, ABI abi)
436 : : {
437 : 13551 : tree abi_tree = NULL_TREE;
438 : :
439 : 13551 : switch (abi)
440 : : {
441 : 13550 : case Rust::ABI::RUST:
442 : 13550 : case Rust::ABI::INTRINSIC:
443 : 13550 : case Rust::ABI::C:
444 : 13550 : 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 : 13550 : DECL_ATTRIBUTES (fndecl)
452 : 13550 : = tree_cons (get_identifier ("cdecl"), NULL, DECL_ATTRIBUTES (fndecl));
453 : :
454 : 13550 : 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 : 36754 : HIRCompileBase::mark_addressable (tree exp, location_t locus)
494 : : {
495 : 36754 : tree x = exp;
496 : :
497 : 38698 : while (1)
498 : 38698 : 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 : 1944 : 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 : 1944 : case ADDR_EXPR:
517 : 1944 : case ARRAY_REF:
518 : 1944 : case REALPART_EXPR:
519 : 1944 : case IMAGPART_EXPR:
520 : 1944 : x = TREE_OPERAND (x, 0);
521 : 1944 : 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 : 252 : case CONSTRUCTOR:
529 : 252 : TREE_ADDRESSABLE (x) = 1;
530 : 252 : return true;
531 : :
532 : 26699 : case VAR_DECL:
533 : 26699 : case CONST_DECL:
534 : 26699 : case PARM_DECL:
535 : 26699 : case RESULT_DECL:
536 : : // (we don't have a concept of a "register" declaration)
537 : : // fallthrough */
538 : :
539 : : /* FALLTHRU */
540 : 26699 : case FUNCTION_DECL:
541 : 26699 : TREE_ADDRESSABLE (x) = 1;
542 : :
543 : : /* FALLTHRU */
544 : : default:
545 : : return true;
546 : : }
547 : :
548 : : return false;
549 : : }
550 : :
551 : : tree
552 : 36776 : HIRCompileBase::address_expression (tree expr, location_t location, tree ptrty)
553 : : {
554 : 36776 : if (expr == error_mark_node)
555 : : return error_mark_node;
556 : :
557 : 36754 : if (!mark_addressable (expr, location))
558 : 0 : return error_mark_node;
559 : :
560 : 36754 : if (ptrty == NULL || ptrty == error_mark_node)
561 : 35019 : ptrty = build_pointer_type (TREE_TYPE (expr));
562 : :
563 : 36754 : return build_fold_addr_expr_with_type_loc (location, expr, ptrty);
564 : : }
565 : :
566 : : tree
567 : 1064 : 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 : 1064 : HIRCompileBase c (ctx);
573 : 1064 : return c.compile_constant_item (coercion_id, resolved_type, expected_type,
574 : : canonical_path, const_value_expr, locus,
575 : 1064 : expr_locus);
576 : 1064 : }
577 : :
578 : : tree
579 : 1064 : HIRCompileBase::query_compile_const_expr (Context *ctx, TyTy::BaseType *expr_ty,
580 : : HIR::Expr &const_value_expr)
581 : : {
582 : 1064 : HIRCompileBase c (ctx);
583 : :
584 : 1064 : ctx->push_const_context ();
585 : :
586 : 1064 : HirId expr_id = const_value_expr.get_mappings ().get_hirid ();
587 : 1064 : location_t locus = const_value_expr.get_locus ();
588 : 1064 : tree capacity_expr = HIRCompileBase::compile_constant_expr (
589 : 1064 : ctx, expr_id, expr_ty, expr_ty, Resolver::CanonicalPath::create_empty (),
590 : : const_value_expr, locus, locus);
591 : :
592 : 1064 : ctx->pop_const_context ();
593 : :
594 : 1064 : return fold_expr (capacity_expr);
595 : 1064 : }
596 : :
597 : : tree
598 : 13977 : HIRCompileBase::indirect_expression (tree expr, location_t locus)
599 : : {
600 : 13977 : if (expr == error_mark_node)
601 : : return error_mark_node;
602 : :
603 : 13977 : return build_fold_indirect_ref_loc (locus, expr);
604 : : }
605 : :
606 : : void
607 : 12607 : HIRCompileBase::compile_function_body (tree fndecl,
608 : : HIR::BlockExpr &function_body,
609 : : TyTy::BaseType *fn_return_ty)
610 : : {
611 : 26137 : for (auto &s : function_body.get_statements ())
612 : : {
613 : 13530 : auto compiled_expr = CompileStmt::Compile (s.get (), ctx);
614 : 13530 : if (compiled_expr != nullptr)
615 : : {
616 : 4586 : tree s = convert_to_void (compiled_expr, ICV_STATEMENT);
617 : 4586 : ctx->add_statement (s);
618 : : }
619 : : }
620 : :
621 : 12607 : if (function_body.has_expr ())
622 : : {
623 : 10120 : location_t locus = function_body.get_final_expr ().get_locus ();
624 : 10120 : tree return_value
625 : 10120 : = CompileExpr::Compile (function_body.get_final_expr (), ctx);
626 : :
627 : : // we can only return this if non unit value return type
628 : 10120 : if (!fn_return_ty->is_unit ())
629 : : {
630 : 9026 : HirId id = function_body.get_mappings ().get_hirid ();
631 : 9026 : location_t lvalue_locus = function_body.get_locus ();
632 : 9026 : location_t rvalue_locus = locus;
633 : :
634 : 9026 : TyTy::BaseType *expected = fn_return_ty;
635 : 9026 : TyTy::BaseType *actual = nullptr;
636 : 9026 : bool ok = ctx->get_tyctx ()->lookup_type (
637 : 9026 : function_body.expr->get_mappings ().get_hirid (), &actual);
638 : 9026 : rust_assert (ok);
639 : :
640 : 9026 : return_value = coercion_site (id, return_value, actual, expected,
641 : : lvalue_locus, rvalue_locus);
642 : :
643 : 9026 : tree return_stmt
644 : 9026 : = Backend::return_statement (fndecl, return_value, locus);
645 : 9026 : ctx->add_statement (return_stmt);
646 : : }
647 : : else
648 : : {
649 : : // just add the stmt expression
650 : 1094 : ctx->add_statement (return_value);
651 : :
652 : : // now just return unit expression
653 : 1094 : tree unit_expr = unit_expression (locus);
654 : 1094 : tree return_stmt
655 : 1094 : = Backend::return_statement (fndecl, unit_expr, locus);
656 : 1094 : ctx->add_statement (return_stmt);
657 : : }
658 : : }
659 : 2487 : else if (fn_return_ty->is_unit ())
660 : : {
661 : : // we can only do this if the function is of unit type otherwise other
662 : : // errors should have occurred
663 : 2288 : location_t locus = function_body.get_locus ();
664 : 2288 : tree return_value = unit_expression (locus);
665 : 2288 : tree return_stmt
666 : 2288 : = Backend::return_statement (fndecl, return_value, locus);
667 : 2288 : ctx->add_statement (return_stmt);
668 : : }
669 : 12607 : }
670 : :
671 : : static ABI
672 : 12520 : get_abi (const AST::AttrVec &outer_attrs,
673 : : const HIR::FunctionQualifiers &qualifiers)
674 : : {
675 : 12520 : bool is_proc_macro = std::any_of (outer_attrs.cbegin (), outer_attrs.cend (),
676 : 15607 : [] (const AST::Attribute &attr) {
677 : 15607 : auto path = attr.get_path ().as_string ();
678 : 15607 : return path == "proc_macro"
679 : 15607 : || path == "proc_macro_derive"
680 : 31214 : || path == "proc_macro_attribute";
681 : 15607 : });
682 : :
683 : 12520 : return is_proc_macro ? ABI::CDECL : qualifiers.get_abi ();
684 : : }
685 : :
686 : : tree
687 : 12520 : HIRCompileBase::compile_function (
688 : : bool is_root_item, const std::string &fn_name,
689 : : tl::optional<HIR::SelfParam> &self_param,
690 : : std::vector<HIR::FunctionParam> &function_params,
691 : : const HIR::FunctionQualifiers &qualifiers, HIR::Visibility &visibility,
692 : : AST::AttrVec &outer_attrs, location_t locus, HIR::BlockExpr *function_body,
693 : : const Resolver::CanonicalPath &canonical_path, TyTy::FnType *fntype)
694 : : {
695 : 12520 : tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
696 : 12520 : std::string ir_symbol_name
697 : 12520 : = canonical_path.get () + fntype->subst_as_string ();
698 : :
699 : 12520 : rust_debug_loc (locus, "--> Compiling [%s] - %s", ir_symbol_name.c_str (),
700 : 12520 : fntype->get_name ().c_str ());
701 : :
702 : : // we don't mangle the main fn since we haven't implemented the main shim
703 : 3584 : bool is_main_fn = fn_name.compare ("main") == 0 && is_root_item
704 : 16102 : && canonical_path.size () <= 2;
705 : 3581 : if (is_main_fn)
706 : : {
707 : 3581 : rust_assert (!main_identifier_node);
708 : : /* So that 'MAIN_NAME_P' works. */
709 : 3581 : main_identifier_node = get_identifier (ir_symbol_name.c_str ());
710 : : }
711 : 12520 : std::string asm_name = fn_name;
712 : :
713 : 12520 : unsigned int flags = 0;
714 : 12520 : tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name,
715 : : tl::nullopt /* asm_name */, flags, locus);
716 : :
717 : 12520 : setup_fndecl (fndecl, is_main_fn, fntype->has_substitutions_defined (),
718 : : visibility, qualifiers, outer_attrs);
719 : 12520 : setup_abi_options (fndecl, get_abi (outer_attrs, qualifiers));
720 : :
721 : : // conditionally mangle the function name
722 : 12520 : bool should_mangle = should_mangle_item (fndecl);
723 : 12520 : if (!is_main_fn && should_mangle)
724 : 8938 : asm_name = ctx->mangle_item (fntype, canonical_path);
725 : 12520 : SET_DECL_ASSEMBLER_NAME (fndecl,
726 : : get_identifier_with_length (asm_name.data (),
727 : : asm_name.length ()));
728 : :
729 : : // insert into the context
730 : 12520 : ctx->insert_function_decl (fntype, fndecl);
731 : :
732 : : // setup the params
733 : 12520 : TyTy::BaseType *tyret = fntype->get_return_type ();
734 : 12520 : std::vector<Bvariable *> param_vars;
735 : 12520 : if (self_param)
736 : : {
737 : 10808 : rust_assert (fntype->is_method ());
738 : 5404 : TyTy::BaseType *self_tyty_lookup = fntype->get_self_type ();
739 : :
740 : 5404 : tree self_type = TyTyResolveCompile::compile (ctx, self_tyty_lookup);
741 : 5404 : Bvariable *compiled_self_param
742 : 5404 : = CompileSelfParam::compile (ctx, fndecl, self_param.value (),
743 : 5404 : self_type, self_param->get_locus ());
744 : :
745 : 5404 : param_vars.push_back (compiled_self_param);
746 : 5404 : ctx->insert_var_decl (self_param->get_mappings ().get_hirid (),
747 : : compiled_self_param);
748 : : }
749 : :
750 : : // offset from + 1 for the TyTy::FnType being used when this is a method to
751 : : // skip over Self on the FnType
752 : 12520 : bool is_method = self_param.has_value ();
753 : 12520 : size_t i = is_method ? 1 : 0;
754 : 18752 : for (auto &referenced_param : function_params)
755 : : {
756 : 6232 : auto &tyty_param = fntype->param_at (i++);
757 : 6232 : auto param_tyty = tyty_param.get_type ();
758 : 6232 : auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty);
759 : :
760 : 6232 : location_t param_locus = referenced_param.get_locus ();
761 : 6232 : Bvariable *compiled_param_var
762 : 6232 : = CompileFnParam::compile (ctx, fndecl, referenced_param,
763 : 6232 : compiled_param_type, param_locus);
764 : :
765 : 6232 : param_vars.push_back (compiled_param_var);
766 : :
767 : 6232 : const HIR::Pattern ¶m_pattern = referenced_param.get_param_name ();
768 : 6232 : ctx->insert_var_decl (param_pattern.get_mappings ().get_hirid (),
769 : : compiled_param_var);
770 : : }
771 : :
772 : 12520 : if (!Backend::function_set_parameters (fndecl, param_vars))
773 : 0 : return error_mark_node;
774 : :
775 : 12520 : tree enclosing_scope = NULL_TREE;
776 : 12520 : location_t start_location = function_body->get_locus ();
777 : 12520 : location_t end_location = function_body->get_end_locus ();
778 : :
779 : 12520 : tree code_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/,
780 : : start_location, end_location);
781 : 12520 : ctx->push_block (code_block);
782 : :
783 : 12520 : Bvariable *return_address = nullptr;
784 : 12520 : tree return_type = TyTyResolveCompile::compile (ctx, tyret);
785 : :
786 : 12520 : bool address_is_taken = false;
787 : 12520 : tree ret_var_stmt = NULL_TREE;
788 : 12520 : return_address
789 : 12520 : = Backend::temporary_variable (fndecl, code_block, return_type, NULL,
790 : : address_is_taken, locus, &ret_var_stmt);
791 : :
792 : 12520 : ctx->add_statement (ret_var_stmt);
793 : :
794 : 12520 : ctx->push_fn (fndecl, return_address, tyret);
795 : 12520 : compile_function_body (fndecl, *function_body, tyret);
796 : 12520 : tree bind_tree = ctx->pop_block ();
797 : :
798 : 12520 : gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
799 : 12520 : DECL_SAVED_TREE (fndecl) = bind_tree;
800 : :
801 : 12520 : ctx->pop_fn ();
802 : 12520 : ctx->push_function (fndecl);
803 : :
804 : 12520 : if (DECL_DECLARED_CONSTEXPR_P (fndecl))
805 : : {
806 : 656 : maybe_save_constexpr_fundef (fndecl);
807 : : }
808 : :
809 : : return fndecl;
810 : 12520 : }
811 : :
812 : : tree
813 : 1585 : HIRCompileBase::compile_constant_item (
814 : : HirId coercion_id, TyTy::BaseType *resolved_type,
815 : : TyTy::BaseType *expected_type, const Resolver::CanonicalPath &canonical_path,
816 : : HIR::Expr &const_value_expr, location_t locus, location_t expr_locus)
817 : : {
818 : 1585 : const std::string &ident = canonical_path.get ();
819 : :
820 : 1585 : tree type = TyTyResolveCompile::compile (ctx, resolved_type);
821 : 1585 : tree const_type = build_qualified_type (type, TYPE_QUAL_CONST);
822 : :
823 : 1585 : tree actual_type = TyTyResolveCompile::compile (ctx, expected_type);
824 : 1585 : tree actual_const_type = build_qualified_type (actual_type, TYPE_QUAL_CONST);
825 : :
826 : 1585 : bool is_block_expr
827 : 1585 : = const_value_expr.get_expression_type () == HIR::Expr::ExprType::Block;
828 : :
829 : : // in order to compile a block expr we want to reuse as much existing
830 : : // machineary that we already have. This means the best approach is to
831 : : // make a _fake_ function with a block so it can hold onto temps then
832 : : // use our constexpr code to fold it completely or error_mark_node
833 : 1585 : Backend::typed_identifier receiver ("", NULL_TREE, UNKNOWN_LOCATION);
834 : 1585 : tree compiled_fn_type = Backend::function_type (
835 : 1585 : receiver, {}, {Backend::typed_identifier ("_", const_type, locus)}, NULL,
836 : : locus);
837 : 1585 : tree fndecl
838 : 1585 : = Backend::function (compiled_fn_type, ident, tl::nullopt, 0, locus);
839 : 1585 : TREE_READONLY (fndecl) = 1;
840 : :
841 : 1585 : tree enclosing_scope = NULL_TREE;
842 : 1585 : location_t start_location = const_value_expr.get_locus ();
843 : 1585 : location_t end_location = const_value_expr.get_locus ();
844 : 1585 : if (is_block_expr)
845 : : {
846 : 36 : HIR::BlockExpr &function_body
847 : : = static_cast<HIR::BlockExpr &> (const_value_expr);
848 : 36 : start_location = function_body.get_locus ();
849 : 36 : end_location = function_body.get_end_locus ();
850 : : }
851 : :
852 : 1585 : tree code_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/,
853 : : start_location, end_location);
854 : 1585 : ctx->push_block (code_block);
855 : :
856 : 1585 : bool address_is_taken = false;
857 : 1585 : tree ret_var_stmt = NULL_TREE;
858 : 1585 : Bvariable *return_address
859 : 1585 : = Backend::temporary_variable (fndecl, code_block, const_type, NULL,
860 : : address_is_taken, locus, &ret_var_stmt);
861 : :
862 : 1585 : ctx->add_statement (ret_var_stmt);
863 : 1585 : ctx->push_fn (fndecl, return_address, resolved_type);
864 : :
865 : 1585 : if (is_block_expr)
866 : : {
867 : 36 : HIR::BlockExpr &function_body
868 : : = static_cast<HIR::BlockExpr &> (const_value_expr);
869 : 36 : compile_function_body (fndecl, function_body, resolved_type);
870 : : }
871 : : else
872 : : {
873 : 1549 : tree value = CompileExpr::Compile (const_value_expr, ctx);
874 : :
875 : 1549 : tree return_expr
876 : 1549 : = Backend::return_statement (fndecl, value,
877 : 1549 : const_value_expr.get_locus ());
878 : 1549 : ctx->add_statement (return_expr);
879 : : }
880 : :
881 : 1585 : tree bind_tree = ctx->pop_block ();
882 : :
883 : 1585 : gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
884 : 1585 : DECL_SAVED_TREE (fndecl) = bind_tree;
885 : 1585 : DECL_DECLARED_CONSTEXPR_P (fndecl) = 1;
886 : 1585 : maybe_save_constexpr_fundef (fndecl);
887 : :
888 : 1585 : ctx->pop_fn ();
889 : :
890 : : // lets fold it into a call expr
891 : 1585 : tree call = build_call_array_loc (locus, const_type, fndecl, 0, NULL);
892 : 1585 : tree folded_expr = fold_expr (call);
893 : :
894 : : // coercion site
895 : 1585 : tree coerced = coercion_site (coercion_id, folded_expr, resolved_type,
896 : : expected_type, locus, expr_locus);
897 : :
898 : 1585 : return named_constant_expression (actual_const_type, ident, coerced, locus);
899 : 1585 : }
900 : :
901 : : tree
902 : 1585 : HIRCompileBase::named_constant_expression (tree type_tree,
903 : : const std::string &name,
904 : : tree const_val, location_t location)
905 : : {
906 : 1585 : if (type_tree == error_mark_node || const_val == error_mark_node)
907 : : return error_mark_node;
908 : :
909 : 1575 : tree name_tree = get_identifier_with_length (name.data (), name.length ());
910 : 1575 : tree decl = build_decl (location, CONST_DECL, name_tree, type_tree);
911 : 1575 : DECL_INITIAL (decl) = const_val;
912 : 1575 : TREE_CONSTANT (decl) = 1;
913 : 1575 : TREE_READONLY (decl) = 1;
914 : :
915 : 1575 : rust_preserve_from_gc (decl);
916 : 1575 : return decl;
917 : : }
918 : :
919 : : tree
920 : 3910 : HIRCompileBase::resolve_method_address (TyTy::FnType *fntype,
921 : : TyTy::BaseType *receiver,
922 : : location_t expr_locus)
923 : : {
924 : 3910 : rust_debug_loc (expr_locus, "resolve_method_address for %s and receiver %s",
925 : 7820 : fntype->debug_str ().c_str (),
926 : 3910 : receiver->debug_str ().c_str ());
927 : :
928 : 3910 : DefId id = fntype->get_id ();
929 : 3910 : rust_assert (id != UNKNOWN_DEFID);
930 : :
931 : : // Now we can try and resolve the address since this might be a forward
932 : : // declared function, generic function which has not be compiled yet or
933 : : // its an not yet trait bound function
934 : 3910 : if (auto resolved_item = ctx->get_mappings ().lookup_defid (id))
935 : : {
936 : 2998 : if (!fntype->has_substitutions_defined ())
937 : 2998 : return CompileItem::compile (*resolved_item, ctx);
938 : :
939 : 735 : return CompileItem::compile (*resolved_item, ctx, fntype);
940 : : }
941 : :
942 : : // it might be resolved to a trait item
943 : 912 : HIR::TraitItem *trait_item
944 : 912 : = ctx->get_mappings ().lookup_trait_item_defid (id).value ();
945 : 912 : HIR::Trait *trait = ctx->get_mappings ().lookup_trait_item_mapping (
946 : 912 : trait_item->get_mappings ().get_hirid ());
947 : :
948 : 912 : Resolver::TraitReference *trait_ref
949 : 912 : = &Resolver::TraitReference::error_node ();
950 : 912 : bool ok = ctx->get_tyctx ()->lookup_trait_reference (
951 : 912 : trait->get_mappings ().get_defid (), &trait_ref);
952 : 912 : rust_assert (ok);
953 : :
954 : : // the type resolver can only resolve type bounds to their trait
955 : : // item so its up to us to figure out if this path should resolve
956 : : // to an trait-impl-block-item or if it can be defaulted to the
957 : : // trait-impl-item's definition
958 : 912 : const HIR::PathIdentSegment segment (trait_item->trait_identifier ());
959 : 912 : auto root = receiver->get_root ();
960 : 912 : auto candidates
961 : 912 : = Resolver::PathProbeImplTrait::Probe (root, segment, trait_ref);
962 : 912 : if (candidates.size () == 0)
963 : : {
964 : : // this means we are defaulting back to the trait_item if
965 : : // possible
966 : 131 : Resolver::TraitItemReference *trait_item_ref = nullptr;
967 : 131 : bool ok = trait_ref->lookup_hir_trait_item (*trait_item, &trait_item_ref);
968 : 131 : rust_assert (ok); // found
969 : 131 : rust_assert (trait_item_ref->is_optional ()); // has definition
970 : :
971 : : // FIXME tl::optional means it has a definition and an associated
972 : : // block which can be a default implementation, if it does not
973 : : // contain an implementation we should actually return
974 : : // error_mark_node
975 : :
976 : 131 : return CompileTraitItem::Compile (trait_item_ref->get_hir_trait_item (),
977 : : ctx, fntype, true, expr_locus);
978 : : }
979 : :
980 : 781 : const Resolver::PathProbeCandidate *selectedCandidate = nullptr;
981 : 781 : rust_debug_loc (expr_locus, "resolved to %lu candidates",
982 : 781 : (unsigned long) candidates.size ());
983 : :
984 : : // filter for the possible case of non fn type items
985 : 781 : std::set<Resolver::PathProbeCandidate> filteredFunctionCandidates;
986 : 1601 : for (auto &candidate : candidates)
987 : : {
988 : 820 : bool is_fntype = candidate.ty->get_kind () == TyTy::TypeKind::FNDEF;
989 : 820 : if (!is_fntype)
990 : 0 : continue;
991 : :
992 : 820 : filteredFunctionCandidates.insert (candidate);
993 : : }
994 : :
995 : : // look for the exact fntype
996 : 782 : for (auto &candidate : filteredFunctionCandidates)
997 : : {
998 : 782 : if (filteredFunctionCandidates.size () == 1)
999 : : {
1000 : : selectedCandidate = &candidate;
1001 : : break;
1002 : : }
1003 : :
1004 : 40 : bool compatable
1005 : 40 : = Resolver::types_compatable (TyTy::TyWithLocation (candidate.ty),
1006 : 40 : TyTy::TyWithLocation (fntype), expr_locus,
1007 : : false);
1008 : :
1009 : 80 : rust_debug_loc (candidate.locus, "candidate: %s vs %s compatable=%s",
1010 : 80 : candidate.ty->debug_str ().c_str (),
1011 : 40 : fntype->debug_str ().c_str (),
1012 : : compatable ? "true" : "false");
1013 : :
1014 : 40 : if (compatable)
1015 : : {
1016 : : selectedCandidate = &candidate;
1017 : : break;
1018 : : }
1019 : : }
1020 : :
1021 : : // FIXME eventually this should just return error mark node when we support
1022 : : // going through all the passes
1023 : 781 : rust_assert (selectedCandidate != nullptr);
1024 : :
1025 : : // lets compile it
1026 : 781 : const Resolver::PathProbeCandidate &candidate = *selectedCandidate;
1027 : 781 : rust_assert (candidate.is_impl_candidate ());
1028 : 781 : rust_assert (candidate.ty->get_kind () == TyTy::TypeKind::FNDEF);
1029 : 781 : TyTy::FnType *candidate_call = static_cast<TyTy::FnType *> (candidate.ty);
1030 : 781 : HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
1031 : :
1032 : 781 : TyTy::BaseType *monomorphized = candidate_call;
1033 : 781 : if (candidate_call->needs_generic_substitutions ())
1034 : : {
1035 : 102 : TyTy::BaseType *infer_impl_call
1036 : 102 : = candidate_call->infer_substitions (expr_locus);
1037 : 102 : monomorphized
1038 : 102 : = Resolver::unify_site (fntype->get_ref (),
1039 : 102 : TyTy::TyWithLocation (infer_impl_call),
1040 : 102 : TyTy::TyWithLocation (fntype), expr_locus);
1041 : : }
1042 : :
1043 : 781 : return CompileInherentImplItem::Compile (impl_item, ctx, monomorphized);
1044 : 1693 : }
1045 : :
1046 : : tree
1047 : 6463 : HIRCompileBase::unit_expression (location_t locus)
1048 : : {
1049 : 6463 : tree unit_type = TyTyResolveCompile::get_unit_type (ctx);
1050 : 6463 : return Backend::constructor_expression (unit_type, false, {}, -1, locus);
1051 : : }
1052 : :
1053 : : } // namespace Compile
1054 : : } // namespace Rust
|