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