LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-compile-base.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 86.4 % 546 472
Test Date: 2026-07-11 15:47:05 Functions: 81.2 % 32 26
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.