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-impl-trait.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 14223 : bool inline should_mangle_item (const tree fndecl)
53 : {
54 14223 : return lookup_attribute (Values::Attributes::NO_MANGLE,
55 14223 : DECL_ATTRIBUTES (fndecl))
56 : == NULL_TREE
57 28445 : && lookup_attribute (Values::Attributes::RUSTC_STD_INTERNAL_SYMBOL,
58 14222 : DECL_ATTRIBUTES (fndecl))
59 14223 : == NULL_TREE;
60 : }
61 :
62 : void
63 14223 : 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 14223 : bool is_pub = visibility.get_vis_type () == HIR::Visibility::VisType::Public;
71 14223 : if (is_main_entry_point || (is_pub && !is_generic_fn))
72 : {
73 6398 : TREE_PUBLIC (fndecl) = 1;
74 : }
75 :
76 : // is it a const fn
77 14223 : DECL_DECLARED_CONSTEXPR_P (fndecl) = qualifiers.is_const ();
78 14223 : if (qualifiers.is_const ())
79 : {
80 817 : TREE_READONLY (fndecl) = 1;
81 : }
82 :
83 : // is it inline?
84 30126 : for (const auto &attr : attrs)
85 : {
86 15903 : std::string attr_str = attr.get_path ().as_string ();
87 :
88 15903 : bool is_inline = attr_str == Values::Attributes::INLINE;
89 15903 : bool is_must_use = attr_str == Values::Attributes::MUST_USE;
90 15903 : bool is_cold = attr_str == Values::Attributes::COLD;
91 15903 : bool is_link_section = attr_str == Values::Attributes::LINK_SECTION;
92 15903 : bool no_mangle = attr_str == Values::Attributes::NO_MANGLE;
93 15903 : bool is_std_internal
94 15903 : = attr_str == Values::Attributes::RUSTC_STD_INTERNAL_SYMBOL;
95 15903 : bool is_deprecated = attr_str == Values::Attributes::DEPRECATED;
96 15903 : bool is_proc_macro = attr_str == Values::Attributes::PROC_MACRO;
97 15903 : bool is_proc_macro_attribute
98 15903 : = attr_str == Values::Attributes::PROC_MACRO_ATTRIBUTE;
99 15903 : bool is_proc_macro_derive
100 15903 : = attr_str == Values::Attributes::PROC_MACRO_DERIVE;
101 15903 : bool is_allocator = attr_str == Values::Attributes::RUSTC_ALLOCATOR;
102 15903 : bool is_allocator_nounwind
103 15903 : = attr_str == Values::Attributes::RUSTC_ALLOCATOR_NOUNWIND;
104 :
105 15903 : if (is_inline)
106 : {
107 1048 : handle_inline_attribute_on_fndecl (fndecl, attr);
108 : }
109 14855 : else if (is_must_use)
110 : {
111 1089 : handle_must_use_attribute_on_fndecl (fndecl, attr);
112 : }
113 13766 : else if (is_cold)
114 : {
115 1 : handle_cold_attribute_on_fndecl (fndecl, attr);
116 : }
117 13765 : else if (is_link_section)
118 : {
119 1 : handle_link_section_attribute_on_fndecl (fndecl, attr);
120 : }
121 13764 : else if (is_deprecated)
122 : {
123 5 : handle_deprecated_attribute_on_fndecl (fndecl, attr);
124 : }
125 13759 : else if (no_mangle)
126 : {
127 1 : handle_no_mangle_attribute_on_fndecl (fndecl, attr);
128 : }
129 13758 : else if (is_std_internal)
130 : {
131 1 : handle_rustc_std_internal_symbol_attribute_on_fndecl (fndecl, attr);
132 : }
133 13757 : else if (is_proc_macro)
134 : {
135 0 : handle_bang_proc_macro_attribute_on_fndecl (fndecl, attr);
136 : }
137 13757 : else if (is_proc_macro_attribute)
138 : {
139 0 : handle_attribute_proc_macro_attribute_on_fndecl (fndecl, attr);
140 : }
141 13757 : else if (is_proc_macro_derive)
142 : {
143 0 : handle_derive_proc_macro_attribute_on_fndecl (fndecl, attr);
144 : }
145 13757 : else if (is_allocator)
146 : {
147 2 : handle_rustc_allocator_on_fndecl (fndecl, attr);
148 : }
149 13755 : else if (is_allocator_nounwind)
150 : {
151 1 : handle_rustc_allocator_nounwind_on_fndecl (fndecl, attr);
152 : }
153 15903 : }
154 14223 : }
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 1048 : HIRCompileBase::handle_inline_attribute_on_fndecl (tree fndecl,
429 : const AST::Attribute &attr)
430 : {
431 : // simple #[inline]
432 1048 : if (!attr.has_attr_input ())
433 : {
434 1043 : DECL_DECLARED_INLINE_P (fndecl) = 1;
435 1045 : 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 15363 : HIRCompileBase::setup_abi_options (tree fndecl, ABI abi)
505 : {
506 15363 : tree abi_tree = NULL_TREE;
507 :
508 15363 : switch (abi)
509 : {
510 15362 : case Rust::ABI::RUST:
511 15362 : case Rust::ABI::INTRINSIC:
512 15362 : case Rust::ABI::PLATFORM_INTRINSIC:
513 15362 : case Rust::ABI::C:
514 15362 : case Rust::ABI::CDECL:
515 : // `decl_attributes` function (not the macro) has the side-effect of
516 : // actually switching the codegen backend to use the ABI we annotated.
517 : // However, since `cdecl` is the default ABI GCC will be using,
518 : // explicitly specifying that ABI will cause GCC to emit a warning
519 : // saying the attribute is useless (which is confusing to the user as
520 : // the attribute is added by us).
521 15362 : DECL_ATTRIBUTES (fndecl)
522 15362 : = tree_cons (get_identifier ("cdecl"), NULL, DECL_ATTRIBUTES (fndecl));
523 :
524 15362 : return;
525 :
526 0 : case Rust::ABI::STDCALL:
527 0 : abi_tree = get_identifier ("stdcall");
528 :
529 0 : break;
530 :
531 0 : case Rust::ABI::FASTCALL:
532 0 : abi_tree = get_identifier ("fastcall");
533 :
534 0 : break;
535 :
536 0 : case Rust::ABI::SYSV64:
537 0 : abi_tree = get_identifier ("sysv_abi");
538 :
539 0 : break;
540 :
541 1 : case Rust::ABI::WIN_64:
542 1 : abi_tree = get_identifier ("ms_abi");
543 :
544 1 : break;
545 :
546 : default:
547 : break;
548 : }
549 :
550 1 : decl_attributes (&fndecl, build_tree_list (abi_tree, NULL_TREE), 0);
551 : }
552 :
553 : // ported from gcc/c/c-typecheck.c
554 : //
555 : // Mark EXP saying that we need to be able to take the
556 : // address of it; it should not be allocated in a register.
557 : // Returns true if successful. ARRAY_REF_P is true if this
558 : // is for ARRAY_REF construction - in that case we don't want
559 : // to look through VIEW_CONVERT_EXPR from VECTOR_TYPE to ARRAY_TYPE,
560 : // it is fine to use ARRAY_REFs for vector subscripts on vector
561 : // register variables.
562 : bool
563 42424 : HIRCompileBase::mark_addressable (tree exp, location_t locus)
564 : {
565 42424 : tree x = exp;
566 :
567 44485 : while (1)
568 44485 : switch (TREE_CODE (x))
569 : {
570 2 : case VIEW_CONVERT_EXPR:
571 2 : if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
572 2 : && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))))
573 : return true;
574 2 : x = TREE_OPERAND (x, 0);
575 2 : break;
576 :
577 2059 : case COMPONENT_REF:
578 : // TODO
579 : // if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
580 : // {
581 : // error ("cannot take address of bit-field %qD", TREE_OPERAND (x,
582 : // 1)); return false;
583 : // }
584 :
585 : /* FALLTHRU */
586 2059 : case ADDR_EXPR:
587 2059 : case ARRAY_REF:
588 2059 : case REALPART_EXPR:
589 2059 : case IMAGPART_EXPR:
590 2059 : x = TREE_OPERAND (x, 0);
591 2059 : break;
592 :
593 0 : case COMPOUND_LITERAL_EXPR:
594 0 : TREE_ADDRESSABLE (x) = 1;
595 0 : TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (x)) = 1;
596 0 : return true;
597 :
598 253 : case CONSTRUCTOR:
599 253 : TREE_ADDRESSABLE (x) = 1;
600 253 : return true;
601 :
602 31511 : case VAR_DECL:
603 31511 : case CONST_DECL:
604 31511 : case PARM_DECL:
605 31511 : case RESULT_DECL:
606 : // (we don't have a concept of a "register" declaration)
607 : // fallthrough */
608 :
609 : /* FALLTHRU */
610 31511 : case FUNCTION_DECL:
611 31511 : TREE_ADDRESSABLE (x) = 1;
612 :
613 : /* FALLTHRU */
614 : default:
615 : return true;
616 : }
617 :
618 : return false;
619 : }
620 :
621 : tree
622 42444 : HIRCompileBase::address_expression (tree expr, location_t location, tree ptrty)
623 : {
624 42444 : if (expr == error_mark_node)
625 : return error_mark_node;
626 :
627 42424 : if (!mark_addressable (expr, location))
628 0 : return error_mark_node;
629 :
630 42424 : if (ptrty == NULL || ptrty == error_mark_node)
631 40511 : ptrty = build_pointer_type (TREE_TYPE (expr));
632 :
633 42424 : return build_fold_addr_expr_with_type_loc (location, expr, ptrty);
634 : }
635 :
636 : tree
637 1340 : HIRCompileBase::compile_constant_expr (
638 : Context *ctx, HirId coercion_id, TyTy::BaseType *resolved_type,
639 : TyTy::BaseType *expected_type, const Resolver::CanonicalPath &canonical_path,
640 : HIR::Expr &const_value_expr, location_t locus, location_t expr_locus)
641 : {
642 1340 : HIRCompileBase c (ctx);
643 1340 : return c.compile_constant_item (coercion_id, resolved_type, expected_type,
644 : canonical_path, const_value_expr, locus,
645 1340 : expr_locus);
646 1340 : }
647 :
648 : tree
649 1340 : HIRCompileBase::query_compile_const_expr (Context *ctx, TyTy::BaseType *expr_ty,
650 : HIR::Expr &const_value_expr)
651 : {
652 1340 : HIRCompileBase c (ctx);
653 :
654 1340 : ctx->push_const_context ();
655 :
656 1340 : HirId expr_id = const_value_expr.get_mappings ().get_hirid ();
657 1340 : location_t locus = const_value_expr.get_locus ();
658 1340 : tree capacity_expr = HIRCompileBase::compile_constant_expr (
659 1340 : ctx, expr_id, expr_ty, expr_ty, Resolver::CanonicalPath::create_empty (),
660 : const_value_expr, locus, locus);
661 :
662 1340 : ctx->pop_const_context ();
663 :
664 1340 : return fold_expr (capacity_expr);
665 1340 : }
666 :
667 : tree
668 15119 : HIRCompileBase::indirect_expression (tree expr, location_t locus)
669 : {
670 15119 : if (expr == error_mark_node)
671 : return error_mark_node;
672 :
673 15119 : return build_fold_indirect_ref_loc (locus, expr);
674 : }
675 :
676 : void
677 14317 : HIRCompileBase::compile_function_body (tree fndecl,
678 : HIR::BlockExpr &function_body,
679 : TyTy::BaseType *fn_return_ty)
680 : {
681 29550 : for (auto &s : function_body.get_statements ())
682 : {
683 15233 : auto compiled_expr = CompileStmt::Compile (s.get (), ctx);
684 15233 : if (compiled_expr != nullptr)
685 : {
686 5403 : tree s = convert_to_void (compiled_expr, ICV_STATEMENT);
687 5403 : ctx->add_statement (s);
688 : }
689 : }
690 :
691 14317 : if (function_body.has_expr ())
692 : {
693 11661 : location_t locus = function_body.get_final_expr ().get_locus ();
694 11661 : tree return_value
695 11661 : = CompileExpr::Compile (function_body.get_final_expr (), ctx);
696 :
697 : // we can only return this if non unit value return type
698 11661 : if (!fn_return_ty->is_unit ())
699 : {
700 10420 : HirId id = function_body.get_mappings ().get_hirid ();
701 10420 : location_t lvalue_locus = function_body.get_locus ();
702 10420 : location_t rvalue_locus = locus;
703 :
704 10420 : TyTy::BaseType *expected = fn_return_ty;
705 10420 : TyTy::BaseType *actual = nullptr;
706 10420 : bool ok = ctx->get_tyctx ()->lookup_type (
707 10420 : function_body.expr->get_mappings ().get_hirid (), &actual);
708 10420 : rust_assert (ok);
709 :
710 10420 : return_value = coercion_site (id, return_value, actual, expected,
711 : lvalue_locus, rvalue_locus);
712 :
713 : /* Save the non-unit tail expression result before emitting scope
714 : drops, so a tail call like foo() is evaluated before locals are
715 : dropped. Conceptually, this changes lowering from:
716 :
717 : drop (_x);
718 : return foo ();
719 :
720 : to:
721 :
722 : ret_slot = foo ();
723 : drop (_x);
724 : return ret_slot; */
725 10420 : fncontext fnctx = ctx->peek_fn ();
726 10420 : tree result_reference
727 10420 : = Backend::var_expression (fnctx.ret_addr, lvalue_locus);
728 10420 : tree assignment = Backend::assignment_statement (result_reference,
729 : return_value, locus);
730 10420 : ctx->add_statement (assignment);
731 :
732 10420 : result_reference = Backend::var_expression (fnctx.ret_addr, locus);
733 10420 : tree return_stmt
734 10420 : = Backend::return_statement (fndecl, result_reference, locus);
735 10420 : ctx->add_statement (return_stmt);
736 : }
737 : else
738 : {
739 : // just add the stmt expression
740 1241 : ctx->add_statement (return_value);
741 :
742 : // now just return unit expression
743 1241 : tree unit_expr = unit_expression (locus);
744 1241 : tree return_stmt
745 1241 : = Backend::return_statement (fndecl, unit_expr, locus);
746 1241 : ctx->add_statement (return_stmt);
747 : }
748 : }
749 2656 : else if (fn_return_ty->is_unit ())
750 : {
751 : // we can only do this if the function is of unit type otherwise other
752 : // errors should have occurred
753 2438 : location_t locus = function_body.get_locus ();
754 2438 : tree return_value = unit_expression (locus);
755 :
756 2438 : tree return_stmt
757 2438 : = Backend::return_statement (fndecl, return_value, locus);
758 2438 : ctx->add_statement (return_stmt);
759 : }
760 14317 : }
761 :
762 : static ABI
763 14223 : get_abi (const AST::AttrVec &outer_attrs,
764 : const HIR::FunctionQualifiers &qualifiers)
765 : {
766 14223 : bool is_proc_macro = std::any_of (outer_attrs.cbegin (), outer_attrs.cend (),
767 15903 : [] (const AST::Attribute &attr) {
768 15903 : auto path = attr.get_path ().as_string ();
769 15903 : return path == "proc_macro"
770 15903 : || path == "proc_macro_derive"
771 31806 : || path == "proc_macro_attribute";
772 15903 : });
773 :
774 14223 : return is_proc_macro ? ABI::CDECL : qualifiers.get_abi ();
775 : }
776 :
777 : tree
778 14223 : HIRCompileBase::compile_function (
779 : bool is_root_item, const std::string &fn_name,
780 : tl::optional<HIR::SelfParam> &self_param,
781 : std::vector<HIR::FunctionParam> &function_params,
782 : const HIR::FunctionQualifiers &qualifiers, HIR::Visibility &visibility,
783 : AST::AttrVec &outer_attrs, location_t locus, HIR::BlockExpr *function_body,
784 : const Resolver::CanonicalPath &canonical_path, TyTy::FnType *fntype)
785 : {
786 14223 : tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
787 14223 : std::string ir_symbol_name
788 14223 : = canonical_path.get () + fntype->subst_as_string ();
789 :
790 14223 : rust_debug_loc (locus, "--> Compiling [%s] - %s", ir_symbol_name.c_str (),
791 : fntype->get_name ().c_str ());
792 :
793 : // we don't mangle the main fn since we haven't implemented the main shim
794 4027 : bool is_main_fn = fn_name.compare ("main") == 0 && is_root_item
795 18248 : && canonical_path.size () <= 2;
796 4024 : if (is_main_fn)
797 : {
798 4024 : rust_assert (!main_identifier_node);
799 : /* So that 'MAIN_NAME_P' works. */
800 4024 : main_identifier_node = get_identifier (ir_symbol_name.c_str ());
801 : }
802 : // Local name because fn_name is not mutable.
803 14223 : std::string asm_name = fn_name;
804 :
805 : // conditionally mangle the function name
806 14223 : bool should_mangle = true;
807 :
808 30126 : auto get_export_name = [] (AST::Attribute &attr) {
809 15903 : return attr.get_path ().as_string () == Values::Attributes::EXPORT_NAME;
810 : };
811 14223 : auto export_name_attr
812 14223 : = std::find_if (outer_attrs.begin (), outer_attrs.end (), get_export_name);
813 :
814 14223 : tl::optional<std::string> backend_asm_name = tl::nullopt;
815 :
816 14223 : if (export_name_attr != outer_attrs.end ())
817 : {
818 1 : asm_name
819 1 : = Analysis::Attributes::extract_string_literal (*export_name_attr)
820 1 : .value (); // Checked within attribute checker
821 1 : backend_asm_name = asm_name;
822 1 : should_mangle = false;
823 : }
824 :
825 14223 : unsigned int flags = 0;
826 14223 : tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name,
827 14223 : backend_asm_name, flags, locus);
828 :
829 14223 : setup_fndecl (fndecl, is_main_fn, fntype->has_substitutions_defined (),
830 : visibility, qualifiers, outer_attrs);
831 14223 : setup_abi_options (fndecl, get_abi (outer_attrs, qualifiers));
832 :
833 14223 : should_mangle &= should_mangle_item (fndecl);
834 14223 : if (!is_main_fn && should_mangle)
835 10196 : asm_name = ctx->mangle_item (fntype, canonical_path);
836 14223 : SET_DECL_ASSEMBLER_NAME (fndecl,
837 : get_identifier_with_length (asm_name.data (),
838 : asm_name.length ()));
839 :
840 : // insert into the context
841 14223 : ctx->insert_function_decl (fntype, fndecl);
842 :
843 : // setup the params
844 14223 : TyTy::BaseType *tyret = fntype->get_return_type ();
845 14223 : std::vector<Bvariable *> param_vars;
846 :
847 14223 : tree enclosing_scope = NULL_TREE;
848 14223 : location_t start_location = function_body->get_locus ();
849 14223 : location_t end_location = function_body->get_end_locus ();
850 :
851 14223 : tree arg_scope_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/,
852 : start_location, end_location);
853 14223 : ctx->push_block (arg_scope_block);
854 :
855 14223 : DropBuilder drop_builder (*ctx);
856 :
857 14223 : if (self_param)
858 : {
859 12434 : rust_assert (fntype->is_method ());
860 6217 : TyTy::BaseType *self_tyty_lookup = fntype->get_self_type ();
861 :
862 6217 : tree self_type = TyTyResolveCompile::compile (ctx, self_tyty_lookup);
863 6217 : Bvariable *compiled_self_param
864 6217 : = CompileSelfParam::compile (ctx, fndecl, self_param.value (),
865 6217 : self_type, self_param->get_locus ());
866 :
867 6217 : param_vars.push_back (compiled_self_param);
868 6217 : ctx->insert_var_decl (self_param->get_mappings ().get_hirid (),
869 : compiled_self_param);
870 : }
871 :
872 : // offset from + 1 for the TyTy::FnType being used when this is a method to
873 : // skip over Self on the FnType
874 14223 : bool is_method = self_param.has_value ();
875 14223 : size_t i = is_method ? 1 : 0;
876 21393 : for (auto &referenced_param : function_params)
877 : {
878 7171 : auto &tyty_param = fntype->param_at (i++);
879 7171 : auto param_tyty = tyty_param.get_type ();
880 7171 : auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty);
881 :
882 7171 : location_t param_locus = referenced_param.get_locus ();
883 7171 : Bvariable *compiled_param_var
884 7171 : = CompileFnParam::compile (ctx, fndecl, referenced_param,
885 7170 : compiled_param_type, param_locus);
886 :
887 7170 : param_vars.push_back (compiled_param_var);
888 :
889 7170 : const HIR::Pattern ¶m_pattern = referenced_param.get_param_name ();
890 7170 : ctx->insert_var_decl (param_pattern.get_mappings ().get_hirid (),
891 : compiled_param_var);
892 :
893 7170 : if (CompileDrop (ctx).type_has_drop_impl (param_tyty))
894 8 : drop_builder.note_simple_drop_candidate (
895 8 : param_pattern.get_mappings ().get_hirid (),
896 8 : param_pattern.get_locus ());
897 : }
898 :
899 14222 : if (!Backend::function_set_parameters (fndecl, param_vars))
900 : {
901 0 : ctx->pop_block ();
902 0 : return error_mark_node;
903 : }
904 :
905 14221 : Bvariable *return_address = nullptr;
906 14221 : tree return_type = TyTyResolveCompile::compile (ctx, tyret);
907 :
908 14221 : bool address_is_taken = false;
909 14221 : tree ret_var_stmt = NULL_TREE;
910 14221 : return_address
911 14221 : = Backend::temporary_variable (fndecl, arg_scope_block, return_type, NULL,
912 : address_is_taken, locus, &ret_var_stmt);
913 :
914 14221 : ctx->add_statement (ret_var_stmt);
915 :
916 14221 : ctx->push_fn (fndecl, return_address, tyret);
917 14221 : tree body_scope_block
918 14221 : = Backend::block (fndecl, arg_scope_block, {} /*locals*/, start_location,
919 : end_location);
920 14221 : ctx->push_block (body_scope_block);
921 :
922 14221 : compile_function_body (fndecl, *function_body, tyret);
923 :
924 14221 : tree body_cleanup = CompileDrop (ctx).build_current_scope_drop_cleanup ();
925 14221 : tree body_bind_tree
926 14221 : = ctx->pop_block_with_cleanup (body_cleanup, function_body->get_locus ());
927 14221 : ctx->add_statement (body_bind_tree);
928 :
929 14221 : tree arg_cleanup = CompileDrop (ctx).build_current_scope_drop_cleanup ();
930 14221 : tree bind_tree
931 14221 : = ctx->pop_block_with_cleanup (arg_cleanup, function_body->get_locus ());
932 :
933 14221 : gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
934 14221 : DECL_SAVED_TREE (fndecl) = bind_tree;
935 :
936 14221 : ctx->pop_fn ();
937 14221 : ctx->push_function (fndecl);
938 :
939 14221 : if (DECL_DECLARED_CONSTEXPR_P (fndecl))
940 : {
941 817 : maybe_save_constexpr_fundef (fndecl);
942 : }
943 :
944 : return fndecl;
945 14222 : }
946 :
947 : tree
948 1929 : HIRCompileBase::compile_constant_item (
949 : HirId coercion_id, TyTy::BaseType *resolved_type,
950 : TyTy::BaseType *expected_type, const Resolver::CanonicalPath &canonical_path,
951 : HIR::Expr &const_value_expr, location_t locus, location_t expr_locus)
952 : {
953 1929 : const std::string &ident = canonical_path.get ();
954 :
955 1929 : tree type = TyTyResolveCompile::compile (ctx, resolved_type);
956 1929 : tree const_type = build_qualified_type (type, TYPE_QUAL_CONST);
957 :
958 1929 : tree actual_type = TyTyResolveCompile::compile (ctx, expected_type);
959 1929 : tree actual_const_type = build_qualified_type (actual_type, TYPE_QUAL_CONST);
960 :
961 1929 : bool is_block_expr
962 1929 : = const_value_expr.get_expression_type () == HIR::Expr::ExprType::Block;
963 :
964 : // in order to compile a block expr we want to reuse as much existing
965 : // machineary that we already have. This means the best approach is to
966 : // make a _fake_ function with a block so it can hold onto temps then
967 : // use our constexpr code to fold it completely or error_mark_node
968 1929 : Backend::typed_identifier receiver ("", NULL_TREE, UNKNOWN_LOCATION);
969 1929 : tree compiled_fn_type = Backend::function_type (
970 1929 : receiver, {}, {Backend::typed_identifier ("_", const_type, locus)}, NULL,
971 : locus);
972 1929 : tree fndecl
973 1929 : = Backend::function (compiled_fn_type, ident, tl::nullopt, 0, locus);
974 1929 : TREE_READONLY (fndecl) = 1;
975 :
976 1929 : tree enclosing_scope = NULL_TREE;
977 1929 : location_t start_location = const_value_expr.get_locus ();
978 1929 : location_t end_location = const_value_expr.get_locus ();
979 1929 : if (is_block_expr)
980 : {
981 44 : HIR::BlockExpr &function_body
982 : = static_cast<HIR::BlockExpr &> (const_value_expr);
983 44 : start_location = function_body.get_locus ();
984 44 : end_location = function_body.get_end_locus ();
985 : }
986 :
987 1929 : tree code_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/,
988 : start_location, end_location);
989 1929 : ctx->push_block (code_block);
990 :
991 1929 : bool address_is_taken = false;
992 1929 : tree ret_var_stmt = NULL_TREE;
993 1929 : Bvariable *return_address
994 1929 : = Backend::temporary_variable (fndecl, code_block, const_type, NULL,
995 : address_is_taken, locus, &ret_var_stmt);
996 :
997 1929 : ctx->add_statement (ret_var_stmt);
998 1929 : ctx->push_fn (fndecl, return_address, resolved_type);
999 :
1000 1929 : if (is_block_expr)
1001 : {
1002 44 : HIR::BlockExpr &function_body
1003 : = static_cast<HIR::BlockExpr &> (const_value_expr);
1004 44 : compile_function_body (fndecl, function_body, resolved_type);
1005 : }
1006 : else
1007 : {
1008 1885 : tree value = CompileExpr::Compile (const_value_expr, ctx);
1009 :
1010 1885 : tree return_expr
1011 1885 : = Backend::return_statement (fndecl, value,
1012 1885 : const_value_expr.get_locus ());
1013 1885 : ctx->add_statement (return_expr);
1014 : }
1015 :
1016 1929 : tree cleanup = CompileDrop (ctx).build_current_scope_drop_cleanup ();
1017 1929 : tree bind_tree
1018 1929 : = ctx->pop_block_with_cleanup (cleanup, const_value_expr.get_locus ());
1019 :
1020 1929 : gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
1021 1929 : DECL_SAVED_TREE (fndecl) = bind_tree;
1022 1929 : DECL_DECLARED_CONSTEXPR_P (fndecl) = 1;
1023 1929 : maybe_save_constexpr_fundef (fndecl);
1024 :
1025 1929 : ctx->pop_fn ();
1026 :
1027 : // lets fold it into a call expr
1028 1929 : tree call = build_call_array_loc (locus, const_type, fndecl, 0, NULL);
1029 1929 : tree folded_expr = fold_expr (call);
1030 :
1031 : // coercion site
1032 1929 : tree coerced = coercion_site (coercion_id, folded_expr, resolved_type,
1033 : expected_type, locus, expr_locus);
1034 :
1035 1929 : return named_constant_expression (actual_const_type, ident, coerced, locus);
1036 1929 : }
1037 :
1038 : tree
1039 1929 : HIRCompileBase::named_constant_expression (tree type_tree,
1040 : const std::string &name,
1041 : tree const_val, location_t location)
1042 : {
1043 1929 : if (type_tree == error_mark_node || const_val == error_mark_node)
1044 : return error_mark_node;
1045 :
1046 1915 : tree name_tree = get_identifier_with_length (name.data (), name.length ());
1047 1915 : tree decl = build_decl (location, CONST_DECL, name_tree, type_tree);
1048 1915 : DECL_INITIAL (decl) = const_val;
1049 1915 : TREE_CONSTANT (decl) = 1;
1050 1915 : TREE_READONLY (decl) = 1;
1051 :
1052 1915 : rust_preserve_from_gc (decl);
1053 1915 : return decl;
1054 : }
1055 :
1056 : tree
1057 4149 : HIRCompileBase::resolve_method_address (TyTy::FnType *fntype,
1058 : TyTy::BaseType *receiver,
1059 : location_t expr_locus)
1060 : {
1061 4149 : rust_debug_loc (expr_locus, "resolve_method_address for %s and receiver %s",
1062 : fntype->debug_str ().c_str (),
1063 : receiver->debug_str ().c_str ());
1064 :
1065 4149 : DefId id = fntype->get_id ();
1066 4149 : rust_assert (id != UNKNOWN_DEFID);
1067 :
1068 : // Now we can try and resolve the address since this might be a forward
1069 : // declared function, generic function which has not be compiled yet or
1070 : // its an not yet trait bound function
1071 4149 : if (auto resolved_item = ctx->get_mappings ().lookup_defid (id))
1072 : {
1073 3178 : if (!fntype->has_substitutions_defined ())
1074 3178 : return CompileItem::compile (*resolved_item, ctx);
1075 :
1076 808 : return CompileItem::compile (*resolved_item, ctx, fntype);
1077 : }
1078 :
1079 : // it might be resolved to a trait item
1080 971 : HIR::TraitItem *trait_item
1081 971 : = ctx->get_mappings ().lookup_trait_item_defid (id).value ();
1082 971 : HIR::Trait *trait = ctx->get_mappings ().lookup_trait_item_mapping (
1083 971 : trait_item->get_mappings ().get_hirid ());
1084 :
1085 971 : Resolver::TraitReference *trait_ref
1086 971 : = &Resolver::TraitReference::error_node ();
1087 971 : bool ok = ctx->get_tyctx ()->lookup_trait_reference (
1088 971 : trait->get_mappings ().get_defid (), &trait_ref);
1089 971 : rust_assert (ok);
1090 :
1091 : // the type resolver can only resolve type bounds to their trait
1092 : // item so its up to us to figure out if this path should resolve
1093 : // to an trait-impl-block-item or if it can be defaulted to the
1094 : // trait-impl-item's definition
1095 971 : const HIR::PathIdentSegment segment (trait_item->trait_identifier ());
1096 971 : auto root = receiver->get_root ();
1097 971 : auto candidates
1098 971 : = Resolver::PathProbeImplTrait::Probe (root, segment, trait_ref);
1099 971 : if (candidates.size () == 0)
1100 : {
1101 : // this means we are defaulting back to the trait_item if
1102 : // possible
1103 131 : Resolver::TraitItemReference *trait_item_ref = nullptr;
1104 131 : bool ok = trait_ref->lookup_hir_trait_item (*trait_item, &trait_item_ref);
1105 131 : rust_assert (ok); // found
1106 131 : rust_assert (trait_item_ref->is_optional ()); // has definition
1107 :
1108 : // FIXME tl::optional means it has a definition and an associated
1109 : // block which can be a default implementation, if it does not
1110 : // contain an implementation we should actually return
1111 : // error_mark_node
1112 :
1113 131 : return CompileTraitItem::Compile (trait_item_ref->get_hir_trait_item (),
1114 : ctx, fntype, true, expr_locus);
1115 : }
1116 :
1117 840 : const Resolver::PathProbeCandidate *selectedCandidate = nullptr;
1118 840 : rust_debug_loc (expr_locus, "resolved to %lu candidates",
1119 : (unsigned long) candidates.size ());
1120 :
1121 : // filter for the possible case of non fn type items
1122 840 : std::set<Resolver::PathProbeCandidate> filteredFunctionCandidates;
1123 1720 : for (auto &candidate : candidates)
1124 : {
1125 880 : bool is_fntype = candidate.ty->get_kind () == TyTy::TypeKind::FNDEF;
1126 880 : if (!is_fntype)
1127 0 : continue;
1128 :
1129 880 : filteredFunctionCandidates.insert (candidate);
1130 : }
1131 :
1132 : // look for the exact fntype
1133 841 : for (auto &candidate : filteredFunctionCandidates)
1134 : {
1135 841 : if (filteredFunctionCandidates.size () == 1)
1136 : {
1137 : selectedCandidate = &candidate;
1138 : break;
1139 : }
1140 :
1141 41 : bool compatable
1142 41 : = Resolver::types_compatable (TyTy::TyWithLocation (candidate.ty),
1143 41 : TyTy::TyWithLocation (fntype), expr_locus,
1144 : false);
1145 :
1146 41 : rust_debug_loc (candidate.locus, "candidate: %s vs %s compatable=%s",
1147 : candidate.ty->debug_str ().c_str (),
1148 : fntype->debug_str ().c_str (),
1149 : compatable ? "true" : "false");
1150 :
1151 41 : if (compatable)
1152 : {
1153 : selectedCandidate = &candidate;
1154 : break;
1155 : }
1156 : }
1157 :
1158 : // FIXME eventually this should just return error mark node when we support
1159 : // going through all the passes
1160 840 : rust_assert (selectedCandidate != nullptr);
1161 :
1162 : // lets compile it
1163 840 : const Resolver::PathProbeCandidate &candidate = *selectedCandidate;
1164 840 : rust_assert (candidate.is_impl_candidate ());
1165 840 : rust_assert (candidate.ty->get_kind () == TyTy::TypeKind::FNDEF);
1166 840 : TyTy::FnType *candidate_call = static_cast<TyTy::FnType *> (candidate.ty);
1167 840 : HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
1168 :
1169 840 : TyTy::BaseType *monomorphized = candidate_call;
1170 840 : if (candidate_call->needs_generic_substitutions ())
1171 : {
1172 116 : TyTy::BaseType *infer_impl_call
1173 116 : = candidate_call->infer_substitions (expr_locus);
1174 116 : monomorphized
1175 116 : = Resolver::unify_site (fntype->get_ref (),
1176 116 : TyTy::TyWithLocation (infer_impl_call),
1177 116 : TyTy::TyWithLocation (fntype), expr_locus);
1178 : }
1179 :
1180 840 : return CompileInherentImplItem::Compile (impl_item, ctx, monomorphized);
1181 1811 : }
1182 :
1183 : tree
1184 11762 : HIRCompileBase::unit_expression (location_t locus)
1185 : {
1186 11762 : tree unit_type = TyTyResolveCompile::get_unit_type (ctx);
1187 11762 : return Backend::constructor_expression (unit_type, false, {}, -1, locus);
1188 : }
1189 :
1190 : } // namespace Compile
1191 : } // namespace Rust
|