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

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.