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