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 % 157 0
Test Date: 2026-02-28 14:20:25 Functions: 0.0 % 14 0
Legend: Lines:     hit not hit

            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            0 :     = 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              : }
      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              : }
      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              : }
     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              : }
     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            0 :                                     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            0 :                                 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.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.