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

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.