LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-compile-proc-macro.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 0.0 % 158 0
Test Date: 2024-11-02 13:25:42 Functions: 0.0 % 14 0
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : #include "rust-compile.h"
       2                 :             : #include "libproc_macro_internal/proc_macro.h"
       3                 :             : #include "rust-compile-context.h"
       4                 :             : #include "rust-compile-base.h"
       5                 :             : 
       6                 :             : namespace Rust {
       7                 :             : namespace Compile {
       8                 :             : 
       9                 :             : const std::string GCCRS_PROC_MACRO_SYMBOL_PREFIX = "__gccrs_proc_macro_";
      10                 :             : 
      11                 :             : // This namespace brings multiple function to build and initialize multiple
      12                 :             : // structures that needs to get exposed in the final shared library for
      13                 :             : // procedural macro crates.
      14                 :             : //
      15                 :             : // The compiler needs some additional metadata to find which function correspond
      16                 :             : // to the desired macro. The library shall expose one entrypoint symbol leading
      17                 :             : // to those metadata which in turn lead to the correct function.
      18                 :             : // This namespace describes how to build and initialize those metadata
      19                 :             : // structures. Those structure should be kept in sync with the structures in
      20                 :             : // libproc_macro_internal/proc_macro.h describing how they should be read.
      21                 :             : namespace {
      22                 :             : 
      23                 :             : // Namespace containing all functions to build the different types.
      24                 :             : namespace build {
      25                 :             : 
      26                 :             : // Build an array of attribute type for derive procedural macros.
      27                 :             : tree
      28                 :           0 : attribute_array (std::vector<std::string> attributes)
      29                 :             : {
      30                 :           0 :   tree attribute_ptr = build_pointer_type (char_type_node);
      31                 :           0 :   tree attribute_type = build_qualified_type (attribute_ptr, TYPE_QUAL_CONST);
      32                 :           0 :   return build_array_type_nelts (attribute_type, attributes.size ());
      33                 :             : }
      34                 :             : 
      35                 :             : // We're constructing the following structure:
      36                 :             : //
      37                 :             : // struct {
      38                 :             : //     const char *trait_name;
      39                 :             : //     const char **attributes;
      40                 :             : //     std::uint64_t attr_size;
      41                 :             : //     TokenStream (fndecl*) (TokenStream);
      42                 :             : // }
      43                 :             : // The resulting structure should be the same as `CustomDerive` in proc_macro.h
      44                 :             : tree
      45                 :           0 : derive_proc_macro ()
      46                 :             : {
      47                 :           0 :   tree char_ptr = build_pointer_type (char_type_node);
      48                 :           0 :   tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
      49                 :           0 :   auto name_field = Backend::typed_identifier ("trait_name", const_char_type,
      50                 :           0 :                                                BUILTINS_LOCATION);
      51                 :             : 
      52                 :           0 :   tree handle_ptr = build_pointer_type (void_type_node);
      53                 :           0 :   auto fndecl_field
      54                 :           0 :     = Backend::typed_identifier ("fndecl", handle_ptr, BUILTINS_LOCATION);
      55                 :             : 
      56                 :           0 :   tree attribute_ptr = build_pointer_type (const_ptr_type_node);
      57                 :           0 :   auto attributes_field
      58                 :             :     = Backend::typed_identifier ("attributes", attribute_ptr,
      59                 :           0 :                                  BUILTINS_LOCATION);
      60                 :             : 
      61                 :           0 :   auto size_field = Backend::typed_identifier ("attr_size", unsigned_type_node,
      62                 :           0 :                                                BUILTINS_LOCATION);
      63                 :             : 
      64                 :           0 :   return Backend::struct_type (
      65                 :           0 :     {name_field, attributes_field, size_field, fndecl_field});
      66                 :           0 : }
      67                 :             : 
      68                 :             : // We're constructing the following structure:
      69                 :             : //
      70                 :             : // struct {
      71                 :             : //     const char *name;
      72                 :             : //     TokenStream (fndecl*) (TokenStream);
      73                 :             : // }
      74                 :             : // The resulting structure should be the same as `Bang` in proc_macro.h
      75                 :             : tree
      76                 :           0 : bang_proc_macro ()
      77                 :             : {
      78                 :           0 :   tree char_ptr = build_pointer_type (char_type_node);
      79                 :           0 :   tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
      80                 :           0 :   Backend::typed_identifier name_field
      81                 :           0 :     = Backend::typed_identifier ("name", const_char_type, BUILTINS_LOCATION);
      82                 :             : 
      83                 :           0 :   tree handle_ptr = ptr_type_node;
      84                 :           0 :   Backend::typed_identifier fndecl_field
      85                 :           0 :     = Backend::typed_identifier ("fndecl", handle_ptr, BUILTINS_LOCATION);
      86                 :             : 
      87                 :           0 :   return Backend::struct_type ({name_field, fndecl_field});
      88                 :           0 : }
      89                 :             : 
      90                 :             : // Bang proc macros and attribute proc macros almost have the same members
      91                 :             : // the function pointer type is not the same.
      92                 :             : //
      93                 :             : // We're constructing the following structure:
      94                 :             : //
      95                 :             : // struct {
      96                 :             : //     const char *name;
      97                 :             : //     TokenStream (fndecl*) (TokenStream, TokenStream);
      98                 :             : // }
      99                 :             : // The resulting structure should be the same as `Attribute` in proc_macro.h
     100                 :             : tree
     101                 :           0 : attribute_proc_macro ()
     102                 :             : {
     103                 :           0 :   return bang_proc_macro ();
     104                 :             : }
     105                 :             : 
     106                 :             : // Build the union of all macro types. The resulting type should have the exact
     107                 :             : // same representation as `ProcMacroPayload` in proc_macro.h
     108                 :             : tree
     109                 :           0 : proc_macro_payload ()
     110                 :             : {
     111                 :           0 :   tree bang = bang_proc_macro ();
     112                 :           0 :   tree attribute = attribute_proc_macro ();
     113                 :           0 :   tree derive = derive_proc_macro ();
     114                 :             : 
     115                 :           0 :   auto bang_field = Backend::typed_identifier ("bang", bang, BUILTINS_LOCATION);
     116                 :           0 :   auto attribute_field
     117                 :           0 :     = Backend::typed_identifier ("attribute", attribute, BUILTINS_LOCATION);
     118                 :           0 :   auto derive_field
     119                 :           0 :     = Backend::typed_identifier ("custom_derive", derive, BUILTINS_LOCATION);
     120                 :             : 
     121                 :             :   // We rely on the tag to represent the index of any union member. This means
     122                 :             :   // we should keep those fields in the same order as the tag representation for
     123                 :             :   // it to be kept in sync.
     124                 :             :   // Hence why the following code exist: to keep in sync the field vector and
     125                 :             :   // the tag enumeration.
     126                 :           0 :   std::vector<Backend::typed_identifier> fields;
     127                 :           0 :   fields.insert (fields.begin () + ProcMacro::CUSTOM_DERIVE, derive_field);
     128                 :           0 :   fields.insert (fields.begin () + ProcMacro::ATTR, attribute_field);
     129                 :           0 :   fields.insert (fields.begin () + ProcMacro::BANG, bang_field);
     130                 :             : 
     131                 :           0 :   return Backend::union_type (fields);
     132                 :           0 : }
     133                 :             : 
     134                 :             : // Build the tagged union proc macro type. This type contains a payload as well
     135                 :             : // as a tag to identify the contained member of the payload.
     136                 :             : //
     137                 :             : // struct {
     138                 :             : //     unsigned short tag;
     139                 :             : //     union { BangProcMacro , DeriveProcMacro, AttributeProcMacro} payload;
     140                 :             : // }
     141                 :             : tree
     142                 :           0 : proc_macro ()
     143                 :             : {
     144                 :           0 :   auto union_field = proc_macro_payload ();
     145                 :           0 :   auto payload_field
     146                 :           0 :     = Backend::typed_identifier ("payload", union_field, BUILTINS_LOCATION);
     147                 :             : 
     148                 :           0 :   auto tag_field = Backend::typed_identifier ("tag", short_unsigned_type_node,
     149                 :           0 :                                               BUILTINS_LOCATION);
     150                 :             : 
     151                 :           0 :   return Backend::struct_type ({tag_field, payload_field});
     152                 :           0 : }
     153                 :             : 
     154                 :             : // Build the `ProcmacroArray` structure
     155                 :             : //
     156                 :             : // struct {
     157                 :             : //     std::uint64_t length;
     158                 :             : //     Procmacro * macros;
     159                 :             : // }
     160                 :             : tree
     161                 :           0 : proc_macro_buffer (tree proc_macro_type, size_t total_macro)
     162                 :             : {
     163                 :           0 :   auto length_field = Backend::typed_identifier ("length", unsigned_type_node,
     164                 :           0 :                                                  BUILTINS_LOCATION);
     165                 :             : 
     166                 :           0 :   auto array_type = build_array_type_nelts (proc_macro_type, total_macro);
     167                 :           0 :   auto macros_field
     168                 :           0 :     = Backend::typed_identifier ("macros", array_type, BUILTINS_LOCATION);
     169                 :             : 
     170                 :           0 :   return Backend::struct_type ({length_field, macros_field});
     171                 :           0 : }
     172                 :             : 
     173                 :             : // The entrypoint of a proc macro crate is a reference to the proc macro buffer
     174                 :             : // `ProcmacroArray` defined in proc_macro.h
     175                 :             : tree
     176                 :           0 : entrypoint (tree proc_macro_buffer)
     177                 :             : {
     178                 :           0 :   return build_reference_type_for_mode (proc_macro_buffer, E_VOIDmode, false);
     179                 :             : }
     180                 :             : 
     181                 :             : } // namespace build
     182                 :             : 
     183                 :             : // Functions to init all proc macro trees with the correct values from some
     184                 :             : // macro information
     185                 :             : namespace init {
     186                 :             : 
     187                 :             : // Initialize a derive proc macro structure
     188                 :             : // - Store the trait name
     189                 :             : // - Initialize the attribute array
     190                 :             : // - Store the attribute array size
     191                 :             : // - Store the address of the function
     192                 :             : tree
     193                 :           0 : derive_proc_macro (Context *ctx, CustomDeriveInfo infos)
     194                 :             : {
     195                 :           0 :   tree derive_proc_macro_type = build::derive_proc_macro ();
     196                 :           0 :   tree trait_name = build_string_literal (infos.trait_name.c_str ());
     197                 :             : 
     198                 :           0 :   tree attribute_ptr;
     199                 :           0 :   if (infos.attributes.size () == 0)
     200                 :             :     {
     201                 :             :       // Set a null pointer if there is no attributes
     202                 :           0 :       attribute_ptr = HIRCompileBase::address_expression (null_pointer_node,
     203                 :             :                                                           BUILTINS_LOCATION);
     204                 :             :     }
     205                 :             :   else
     206                 :             :     {
     207                 :             :       // Initialize the attribute array
     208                 :           0 :       tree attribute_array_type = build::attribute_array (infos.attributes);
     209                 :             : 
     210                 :           0 :       std::vector<tree> attr_ctors;
     211                 :           0 :       std::vector<unsigned long> indices;
     212                 :             : 
     213                 :           0 :       size_t index = 0;
     214                 :           0 :       for (auto &attr : infos.attributes)
     215                 :             :         {
     216                 :           0 :           attr_ctors.push_back (build_string_literal (attr.c_str ()));
     217                 :           0 :           indices.push_back (index);
     218                 :           0 :           index++;
     219                 :             :         }
     220                 :             : 
     221                 :           0 :       tree attributes
     222                 :           0 :         = Backend::array_constructor_expression (attribute_array_type, indices,
     223                 :             :                                                  attr_ctors, BUILTINS_LOCATION);
     224                 :             : 
     225                 :           0 :       std::string attribute_var_name
     226                 :           0 :         = GCCRS_PROC_MACRO_SYMBOL_PREFIX + infos.trait_name;
     227                 :           0 :       Bvariable *attributes_var
     228                 :           0 :         = Backend::global_variable (attribute_var_name.c_str (),
     229                 :             :                                     attribute_var_name.c_str (),
     230                 :             :                                     attribute_array_type, false /* internal */,
     231                 :             :                                     true /* hidden */, false /* no gc */,
     232                 :             :                                     BUILTINS_LOCATION);
     233                 :           0 :       Backend::global_variable_set_init (attributes_var, attributes);
     234                 :           0 :       ctx->push_var (attributes_var);
     235                 :             : 
     236                 :           0 :       attribute_ptr
     237                 :           0 :         = HIRCompileBase::address_expression (attributes_var->get_decl (),
     238                 :             :                                               BUILTINS_LOCATION);
     239                 :           0 :     }
     240                 :             : 
     241                 :           0 :   tree attr_size = build_int_cst (unsigned_type_node, infos.attributes.size ());
     242                 :             : 
     243                 :           0 :   tree handle
     244                 :           0 :     = HIRCompileBase::address_expression (infos.fndecl, BUILTINS_LOCATION);
     245                 :             : 
     246                 :           0 :   return Backend::constructor_expression (derive_proc_macro_type, false,
     247                 :             :                                           {trait_name, attribute_ptr, attr_size,
     248                 :             :                                            handle},
     249                 :             :                                           -1 /* Structure: no index */,
     250                 :           0 :                                           BUILTINS_LOCATION);
     251                 :             : }
     252                 :             : 
     253                 :             : // Initialize an attribute proc macro structure.
     254                 :             : // - Store the name
     255                 :             : // - Store the address of the function
     256                 :             : tree
     257                 :           0 : attribute_proc_macro (tree macro)
     258                 :             : {
     259                 :           0 :   tree attribute_proc_macro_type = build::attribute_proc_macro ();
     260                 :           0 :   tree macro_name
     261                 :           0 :     = build_string_literal (IDENTIFIER_POINTER (DECL_NAME (macro)));
     262                 :           0 :   tree handle = HIRCompileBase::address_expression (macro, BUILTINS_LOCATION);
     263                 :             : 
     264                 :           0 :   return Backend::constructor_expression (attribute_proc_macro_type, false,
     265                 :             :                                           {macro_name, handle},
     266                 :             :                                           -1 /* Structure: No index */,
     267                 :           0 :                                           BUILTINS_LOCATION);
     268                 :             : }
     269                 :             : 
     270                 :             : // Initialize a bang proc macro structure.
     271                 :             : // - Store the name
     272                 :             : // - Store the address of the function
     273                 :             : tree
     274                 :           0 : bang_proc_macro (tree macro)
     275                 :             : {
     276                 :             :   // Attribute and bang proc macros have the same structure, they can be
     277                 :             :   // initialized with the same code.
     278                 :           0 :   return attribute_proc_macro (macro);
     279                 :             : }
     280                 :             : 
     281                 :             : // Initialize a proc macro structure from a given payload tree
     282                 :             : tree
     283                 :           0 : proc_macro (tree payload, tree proc_macro_type, ProcMacro::ProcmacroTag tag)
     284                 :             : {
     285                 :           0 :   auto discriminant = static_cast<int> (tag);
     286                 :             : 
     287                 :           0 :   tree macro_tag = build_int_cst (short_unsigned_type_node, discriminant);
     288                 :             : 
     289                 :           0 :   tree payload_union
     290                 :           0 :     = Backend::constructor_expression (build::proc_macro_payload (), false,
     291                 :             :                                        {payload},
     292                 :             :                                        discriminant /* Union: member index */,
     293                 :             :                                        BUILTINS_LOCATION);
     294                 :             : 
     295                 :           0 :   return Backend::constructor_expression (proc_macro_type,
     296                 :             :                                           false /* invariant */,
     297                 :             :                                           {macro_tag, payload_union},
     298                 :             :                                           -1 /* Structure: No index */,
     299                 :           0 :                                           BUILTINS_LOCATION);
     300                 :             : }
     301                 :             : 
     302                 :             : tree
     303                 :           0 : proc_macro_array (Context *ctx, tree proc_macro_buffer_type,
     304                 :             :                   tree proc_macro_type)
     305                 :             : {
     306                 :           0 :   std::vector<unsigned long> indexes;
     307                 :           0 :   std::vector<tree> ctors;
     308                 :           0 :   size_t index = 0;
     309                 :           0 :   for (auto &macro : ctx->get_derive_proc_macros ())
     310                 :             :     {
     311                 :           0 :       tree derive = derive_proc_macro (ctx, macro);
     312                 :           0 :       ctors.push_back (proc_macro (derive, proc_macro_type,
     313                 :             :                                    ProcMacro::ProcmacroTag::CUSTOM_DERIVE));
     314                 :           0 :       indexes.push_back (index);
     315                 :           0 :       index++;
     316                 :             :     }
     317                 :           0 :   for (auto &macro : ctx->get_attribute_proc_macros ())
     318                 :             :     {
     319                 :           0 :       tree attr = attribute_proc_macro (macro);
     320                 :             : 
     321                 :           0 :       ctors.push_back (
     322                 :           0 :         proc_macro (attr, proc_macro_type, ProcMacro::ProcmacroTag::ATTR));
     323                 :           0 :       indexes.push_back (index);
     324                 :           0 :       index++;
     325                 :             :     }
     326                 :           0 :   for (auto &macro : ctx->get_bang_proc_macros ())
     327                 :             :     {
     328                 :           0 :       tree bang = bang_proc_macro (macro);
     329                 :             : 
     330                 :           0 :       ctors.push_back (
     331                 :           0 :         proc_macro (bang, proc_macro_type, ProcMacro::ProcmacroTag::BANG));
     332                 :           0 :       indexes.push_back (index);
     333                 :           0 :       index++;
     334                 :             :     }
     335                 :             : 
     336                 :           0 :   auto length = build_int_cst (unsigned_type_node, ctors.size ());
     337                 :           0 :   auto array = Backend::array_constructor_expression (
     338                 :           0 :     build_array_type_nelts (proc_macro_type, ctors.size ()), indexes, ctors,
     339                 :             :     BUILTINS_LOCATION);
     340                 :           0 :   return Backend::constructor_expression (proc_macro_buffer_type,
     341                 :             :                                           false /* invariant */,
     342                 :             :                                           {length, array},
     343                 :             :                                           -1 /* Structure: No index */,
     344                 :           0 :                                           BUILTINS_LOCATION);
     345                 :           0 : }
     346                 :             : } // namespace init
     347                 :             : 
     348                 :             : } // namespace
     349                 :             : 
     350                 :             : // Gather procedural macros and generate the metadata as well as the entrypoint
     351                 :             : // for a procedural macro crate.
     352                 :             : void
     353                 :           0 : CompileCrate::add_proc_macro_symbols ()
     354                 :             : {
     355                 :           0 :   auto total_macros = ctx->get_attribute_proc_macros ().size ()
     356                 :           0 :                       + ctx->get_bang_proc_macros ().size ()
     357                 :           0 :                       + ctx->get_derive_proc_macros ().size ();
     358                 :             : 
     359                 :           0 :   tree pm_type = build::proc_macro ();
     360                 :           0 :   tree pm_buffer_type = build::proc_macro_buffer (pm_type, total_macros);
     361                 :           0 :   tree entrypoint_type = build::entrypoint (pm_buffer_type);
     362                 :             : 
     363                 :           0 :   std::string decl_symbol_name = generate_proc_macro_decls_symbol (
     364                 :           0 :     0 /* FIXME: Change to stable crate id */);
     365                 :             : 
     366                 :           0 :   Bvariable *macro_decls
     367                 :           0 :     = Backend::global_variable (decl_symbol_name.c_str (),
     368                 :             :                                 decl_symbol_name.c_str (), entrypoint_type,
     369                 :             :                                 false /* internal */, false /* not hidden */,
     370                 :             :                                 false /* no gc */, BUILTINS_LOCATION);
     371                 :             : 
     372                 :           0 :   std::string buffer_name
     373                 :           0 :     = GCCRS_PROC_MACRO_SYMBOL_PREFIX + "proc_macro_buffer";
     374                 :             : 
     375                 :           0 :   Bvariable *proc_macro_buffer
     376                 :           0 :     = Backend::global_variable (buffer_name.c_str (), buffer_name.c_str (),
     377                 :             :                                 pm_buffer_type, false /* internal */,
     378                 :             :                                 true /* hidden */, false /* no gc */,
     379                 :             :                                 BUILTINS_LOCATION);
     380                 :           0 :   Backend::global_variable_set_init (
     381                 :             :     proc_macro_buffer, init::proc_macro_array (ctx, pm_buffer_type, pm_type));
     382                 :           0 :   ctx->push_var (proc_macro_buffer);
     383                 :             : 
     384                 :           0 :   Backend::global_variable_set_init (
     385                 :             :     macro_decls,
     386                 :             :     HIRCompileBase::address_expression (proc_macro_buffer->get_decl (),
     387                 :             :                                         BUILTINS_LOCATION));
     388                 :             : 
     389                 :           0 :   ctx->push_var (macro_decls);
     390                 :           0 : }
     391                 :             : 
     392                 :             : } // namespace Compile
     393                 :             : } // namespace Rust
        

Generated by: LCOV version 2.1-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.