aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>2023-10-17 16:00:30 +0200
committerArthur Cohen <arthur.cohen@embecosm.com>2024-01-16 19:09:34 +0100
commit0f04ac6eecd1214fe7403945874e125f92d58d9c (patch)
tree0b980d91a8d897f5001d25f0114e8c0733b1925c /gcc
parent068bdc3c6141833d533fd99234578c86658c0576 (diff)
downloadgcc-0f04ac6eecd1214fe7403945874e125f92d58d9c.zip
gcc-0f04ac6eecd1214fe7403945874e125f92d58d9c.tar.gz
gcc-0f04ac6eecd1214fe7403945874e125f92d58d9c.tar.bz2
gccrs: Move proc macro builders to their own file
The code to build the required procedural macro symbols is rather long and could be placed in it's own file. gcc/rust/ChangeLog: * Make-lang.in: Add gcc/rust/backend/rust-compile-proc-macro.cc to the list of file to compile. * backend/rust-compile.cc (attribute_array): Move to rust-compile-proc-macro.cc (derive_proc_macro): Likewise. (bang_proc_macro): Likewise. (attribute_proc_macro): Likewise. (proc_macro_payload): Likewise. (proc_macro): Likewise. (proc_macro_buffer): Likewise. (entrypoint): Likewise. (proc_macro_array): Likewise. (CompileCrate::add_proc_macro_symbols): Likewise. * backend/rust-compile-proc-macro.cc: New file. Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/Make-lang.in1
-rw-r--r--gcc/rust/backend/rust-compile-proc-macro.cc393
-rw-r--r--gcc/rust/backend/rust-compile.cc384
3 files changed, 394 insertions, 384 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index d3cbe27..1cba946 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -169,6 +169,7 @@ GRS_OBJS = \
rust/rust-compile-intrinsic.o \
rust/rust-compile-pattern.o \
rust/rust-compile-fnparam.o \
+ rust/rust-compile-proc-macro.o \
rust/rust-base62.o \
rust/rust-compile-item.o \
rust/rust-compile-implitem.o \
diff --git a/gcc/rust/backend/rust-compile-proc-macro.cc b/gcc/rust/backend/rust-compile-proc-macro.cc
new file mode 100644
index 0000000..91b38ef
--- /dev/null
+++ b/gcc/rust/backend/rust-compile-proc-macro.cc
@@ -0,0 +1,393 @@
+#include "rust-compile.h"
+#include "libproc_macro_internal/proc_macro.h"
+#include "rust-compile-context.h"
+#include "rust-compile-base.h"
+
+namespace Rust {
+namespace Compile {
+
+const std::string GCCRS_PROC_MACRO_SYMBOL_PREFIX = "__gccrs_proc_macro_";
+
+// This namespace brings multiple function to build and initialize multiple
+// structures that needs to get exposed in the final shared library for
+// procedural macro crates.
+//
+// The compiler needs some additional metadata to find which function correspond
+// to the desired macro. The library shall expose one entrypoint symbol leading
+// to those metadata which in turn lead to the correct function.
+// This namespace describes how to build and initialize those metadata
+// structures. Those structure should be kept in sync with the structures in
+// libproc_macro_internal/proc_macro.h describing how they should be read.
+namespace {
+
+// Namespace containing all functions to build the different types.
+namespace build {
+
+// Build an array of attribute type for derive procedural macros.
+tree
+attribute_array (std::vector<std::string> attributes)
+{
+ tree attribute_ptr = build_pointer_type (char_type_node);
+ tree attribute_type = build_qualified_type (attribute_ptr, TYPE_QUAL_CONST);
+ return build_array_type_nelts (attribute_type, attributes.size ());
+}
+
+// We're constructing the following structure:
+//
+// struct {
+// const char *trait_name;
+// const char **attributes;
+// std::uint64_t attr_size;
+// TokenStream (fndecl*) (TokenStream);
+// }
+// The resulting structure should be the same as `CustomDerive` in proc_macro.h
+tree
+derive_proc_macro ()
+{
+ tree char_ptr = build_pointer_type (char_type_node);
+ tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
+ auto name_field = Backend::typed_identifier ("trait_name", const_char_type,
+ BUILTINS_LOCATION);
+
+ tree handle_ptr = build_pointer_type (void_type_node);
+ auto fndecl_field
+ = Backend::typed_identifier ("fndecl", handle_ptr, BUILTINS_LOCATION);
+
+ tree attribute_ptr = build_pointer_type (const_ptr_type_node);
+ auto attributes_field
+ = Backend::typed_identifier ("attributes", attribute_ptr,
+ BUILTINS_LOCATION);
+
+ auto size_field = Backend::typed_identifier ("attr_size", unsigned_type_node,
+ BUILTINS_LOCATION);
+
+ return Backend::struct_type (
+ {name_field, attributes_field, size_field, fndecl_field});
+}
+
+// We're constructing the following structure:
+//
+// struct {
+// const char *name;
+// TokenStream (fndecl*) (TokenStream);
+// }
+// The resulting structure should be the same as `Bang` in proc_macro.h
+tree
+bang_proc_macro ()
+{
+ tree char_ptr = build_pointer_type (char_type_node);
+ tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
+ Backend::typed_identifier name_field
+ = Backend::typed_identifier ("name", const_char_type, BUILTINS_LOCATION);
+
+ tree handle_ptr = ptr_type_node;
+ Backend::typed_identifier fndecl_field
+ = Backend::typed_identifier ("fndecl", handle_ptr, BUILTINS_LOCATION);
+
+ return Backend::struct_type ({name_field, fndecl_field});
+}
+
+// Bang proc macros and attribute proc macros almost have the same members
+// the function pointer type is not the same.
+//
+// We're constructing the following structure:
+//
+// struct {
+// const char *name;
+// TokenStream (fndecl*) (TokenStream, TokenStream);
+// }
+// The resulting structure should be the same as `Attribute` in proc_macro.h
+tree
+attribute_proc_macro ()
+{
+ return bang_proc_macro ();
+}
+
+// Build the union of all macro types. The resulting type should have the exact
+// same representation as `ProcMacroPayload` in proc_macro.h
+tree
+proc_macro_payload ()
+{
+ tree bang = bang_proc_macro ();
+ tree attribute = attribute_proc_macro ();
+ tree derive = derive_proc_macro ();
+
+ auto bang_field = Backend::typed_identifier ("bang", bang, BUILTINS_LOCATION);
+ auto attribute_field
+ = Backend::typed_identifier ("attribute", attribute, BUILTINS_LOCATION);
+ auto derive_field
+ = Backend::typed_identifier ("custom_derive", derive, BUILTINS_LOCATION);
+
+ // We rely on the tag to represent the index of any union member. This means
+ // we should keep those fields in the same order as the tag representation for
+ // it to be kept in sync.
+ // Hence why the following code exist: to keep in sync the field vector and
+ // the tag enumeration.
+ std::vector<Backend::typed_identifier> fields;
+ fields.insert (fields.begin () + ProcMacro::CUSTOM_DERIVE, derive_field);
+ fields.insert (fields.begin () + ProcMacro::ATTR, attribute_field);
+ fields.insert (fields.begin () + ProcMacro::BANG, bang_field);
+
+ return Backend::union_type (fields);
+}
+
+// Build the tagged union proc macro type. This type contains a payload as well
+// as a tag to identify the contained member of the payload.
+//
+// struct {
+// unsigned short tag;
+// union { BangProcMacro , DeriveProcMacro, AttributeProcMacro} payload;
+// }
+tree
+proc_macro ()
+{
+ auto union_field = proc_macro_payload ();
+ auto payload_field
+ = Backend::typed_identifier ("payload", union_field, BUILTINS_LOCATION);
+
+ auto tag_field = Backend::typed_identifier ("tag", short_unsigned_type_node,
+ BUILTINS_LOCATION);
+
+ return Backend::struct_type ({tag_field, payload_field});
+}
+
+// Build the `ProcmacroArray` structure
+//
+// struct {
+// std::uint64_t length;
+// Procmacro * macros;
+// }
+tree
+proc_macro_buffer (tree proc_macro_type, size_t total_macro)
+{
+ auto length_field = Backend::typed_identifier ("length", unsigned_type_node,
+ BUILTINS_LOCATION);
+
+ auto array_type = build_array_type_nelts (proc_macro_type, total_macro);
+ auto macros_field
+ = Backend::typed_identifier ("macros", array_type, BUILTINS_LOCATION);
+
+ return Backend::struct_type ({length_field, macros_field});
+}
+
+// The entrypoint of a proc macro crate is a reference to the proc macro buffer
+// `ProcmacroArray` defined in proc_macro.h
+tree
+entrypoint (tree proc_macro_buffer)
+{
+ return build_reference_type_for_mode (proc_macro_buffer, E_VOIDmode, false);
+}
+
+} // namespace build
+
+// Functions to init all proc macro trees with the correct values from some
+// macro information
+namespace init {
+
+// Initialize a derive proc macro structure
+// - Store the trait name
+// - Initialize the attribute array
+// - Store the attribute array size
+// - Store the address of the function
+tree
+derive_proc_macro (Context *ctx, CustomDeriveInfo infos)
+{
+ tree derive_proc_macro_type = build::derive_proc_macro ();
+ tree trait_name = build_string_literal (infos.trait_name.c_str ());
+
+ tree attribute_ptr;
+ if (infos.attributes.size () == 0)
+ {
+ // Set a null pointer if there is no attributes
+ attribute_ptr = HIRCompileBase::address_expression (null_pointer_node,
+ BUILTINS_LOCATION);
+ }
+ else
+ {
+ // Initialize the attribute array
+ tree attribute_array_type = build::attribute_array (infos.attributes);
+
+ std::vector<tree> attr_ctors;
+ std::vector<unsigned long> indices;
+
+ size_t index = 0;
+ for (auto &attr : infos.attributes)
+ {
+ attr_ctors.push_back (build_string_literal (attr.c_str ()));
+ indices.push_back (index);
+ index++;
+ }
+
+ tree attributes
+ = Backend::array_constructor_expression (attribute_array_type, indices,
+ attr_ctors, BUILTINS_LOCATION);
+
+ std::string attribute_var_name
+ = GCCRS_PROC_MACRO_SYMBOL_PREFIX + infos.trait_name;
+ Bvariable *attributes_var
+ = Backend::global_variable (attribute_var_name.c_str (),
+ attribute_var_name.c_str (),
+ attribute_array_type, false /* internal */,
+ true /* hidden */, false /* no gc */,
+ BUILTINS_LOCATION);
+ Backend::global_variable_set_init (attributes_var, attributes);
+ ctx->push_var (attributes_var);
+
+ attribute_ptr
+ = HIRCompileBase::address_expression (attributes_var->get_decl (),
+ BUILTINS_LOCATION);
+ }
+
+ tree attr_size = build_int_cst (unsigned_type_node, infos.attributes.size ());
+
+ tree handle
+ = HIRCompileBase::address_expression (infos.fndecl, BUILTINS_LOCATION);
+
+ return Backend::constructor_expression (derive_proc_macro_type, false,
+ {trait_name, attribute_ptr, attr_size,
+ handle},
+ -1 /* Structure: no index */,
+ BUILTINS_LOCATION);
+}
+
+// Initialize an attribute proc macro structure.
+// - Store the name
+// - Store the address of the function
+tree
+attribute_proc_macro (tree macro)
+{
+ tree attribute_proc_macro_type = build::attribute_proc_macro ();
+ tree macro_name
+ = build_string_literal (IDENTIFIER_POINTER (DECL_NAME (macro)));
+ tree handle = HIRCompileBase::address_expression (macro, BUILTINS_LOCATION);
+
+ return Backend::constructor_expression (attribute_proc_macro_type, false,
+ {macro_name, handle},
+ -1 /* Structure: No index */,
+ BUILTINS_LOCATION);
+}
+
+// Initialize a bang proc macro structure.
+// - Store the name
+// - Store the address of the function
+tree
+bang_proc_macro (tree macro)
+{
+ // Attribute and bang proc macros have the same structure, they can be
+ // initialized with the same code.
+ return attribute_proc_macro (macro);
+}
+
+// Initialize a proc macro structure from a given payload tree
+tree
+proc_macro (tree payload, tree proc_macro_type, ProcMacro::ProcmacroTag tag)
+{
+ auto discriminant = static_cast<int> (tag);
+
+ tree macro_tag = build_int_cst (short_unsigned_type_node, discriminant);
+
+ tree payload_union
+ = Backend::constructor_expression (build::proc_macro_payload (), false,
+ {payload},
+ discriminant /* Union: member index */,
+ BUILTINS_LOCATION);
+
+ return Backend::constructor_expression (proc_macro_type,
+ false /* invariant */,
+ {macro_tag, payload_union},
+ -1 /* Structure: No index */,
+ BUILTINS_LOCATION);
+}
+
+tree
+proc_macro_array (Context *ctx, tree proc_macro_buffer_type,
+ tree proc_macro_type)
+{
+ std::vector<unsigned long> indexes;
+ std::vector<tree> ctors;
+ size_t index = 0;
+ for (auto &macro : ctx->get_derive_proc_macros ())
+ {
+ tree derive = derive_proc_macro (ctx, macro);
+ ctors.push_back (proc_macro (derive, proc_macro_type,
+ ProcMacro::ProcmacroTag::CUSTOM_DERIVE));
+ indexes.push_back (index);
+ index++;
+ }
+ for (auto &macro : ctx->get_attribute_proc_macros ())
+ {
+ tree attr = attribute_proc_macro (macro);
+
+ ctors.push_back (
+ proc_macro (attr, proc_macro_type, ProcMacro::ProcmacroTag::ATTR));
+ indexes.push_back (index);
+ index++;
+ }
+ for (auto &macro : ctx->get_bang_proc_macros ())
+ {
+ tree bang = bang_proc_macro (macro);
+
+ ctors.push_back (
+ proc_macro (bang, proc_macro_type, ProcMacro::ProcmacroTag::BANG));
+ indexes.push_back (index);
+ index++;
+ }
+
+ auto length = build_int_cst (unsigned_type_node, ctors.size ());
+ auto array = Backend::array_constructor_expression (
+ build_array_type_nelts (proc_macro_type, ctors.size ()), indexes, ctors,
+ BUILTINS_LOCATION);
+ return Backend::constructor_expression (proc_macro_buffer_type,
+ false /* invariant */,
+ {length, array},
+ -1 /* Structure: No index */,
+ BUILTINS_LOCATION);
+}
+} // namespace init
+
+} // namespace
+
+// Gather procedural macros and generate the metadata as well as the entrypoint
+// for a procedural macro crate.
+void
+CompileCrate::add_proc_macro_symbols ()
+{
+ auto total_macros = ctx->get_attribute_proc_macros ().size ()
+ + ctx->get_bang_proc_macros ().size ()
+ + ctx->get_derive_proc_macros ().size ();
+
+ tree pm_type = build::proc_macro ();
+ tree pm_buffer_type = build::proc_macro_buffer (pm_type, total_macros);
+ tree entrypoint_type = build::entrypoint (pm_buffer_type);
+
+ std::string decl_symbol_name = generate_proc_macro_decls_symbol (
+ 0 /* FIXME: Change to stable crate id */);
+
+ Bvariable *macro_decls
+ = Backend::global_variable (decl_symbol_name.c_str (),
+ decl_symbol_name.c_str (), entrypoint_type,
+ false /* internal */, false /* not hidden */,
+ false /* no gc */, BUILTINS_LOCATION);
+
+ std::string buffer_name
+ = GCCRS_PROC_MACRO_SYMBOL_PREFIX + "proc_macro_buffer";
+
+ Bvariable *proc_macro_buffer
+ = Backend::global_variable (buffer_name.c_str (), buffer_name.c_str (),
+ pm_buffer_type, false /* internal */,
+ true /* hidden */, false /* no gc */,
+ BUILTINS_LOCATION);
+ Backend::global_variable_set_init (
+ proc_macro_buffer, init::proc_macro_array (ctx, pm_buffer_type, pm_type));
+ ctx->push_var (proc_macro_buffer);
+
+ Backend::global_variable_set_init (
+ macro_decls,
+ HIRCompileBase::address_expression (proc_macro_buffer->get_decl (),
+ BUILTINS_LOCATION));
+
+ ctx->push_var (macro_decls);
+}
+
+} // namespace Compile
+} // namespace Rust
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index d0052fe..5b07d79 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -17,7 +17,6 @@
// <http://www.gnu.org/licenses/>.
#include "rust-compile.h"
-#include "libproc_macro_internal/proc_macro.h"
#include "rust-compile-item.h"
#include "rust-compile-implitem.h"
#include "rust-hir-type-bounds.h"
@@ -29,8 +28,6 @@
namespace Rust {
namespace Compile {
-const std::string GCCRS_PROC_MACRO_SYMBOL_PREFIX = "__gccrs_proc_macro_";
-
CompileCrate::CompileCrate (HIR::Crate &crate, Context *ctx)
: crate (crate), ctx (ctx)
{}
@@ -55,387 +52,6 @@ CompileCrate::go ()
add_proc_macro_symbols ();
}
-// This namespace brings multiple function to build and initialize multiple
-// structures that needs to get exposed in the final shared library for
-// procedural macro crates.
-//
-// The compiler needs some additional metadata to find which function correspond
-// to the desired macro. The library shall expose one entrypoint symbol leading
-// to those metadata which in turn lead to the correct function.
-// This namespace describes how to build and initialize those metadata
-// structures. Those structure should be kept in sync with the structures in
-// libproc_macro_internal/proc_macro.h describing how they should be read.
-namespace {
-
-// Namespace containing all functions to build the different types.
-namespace build {
-
-// Build an array of attribute type for derive procedural macros.
-tree
-attribute_array (std::vector<std::string> attributes)
-{
- tree attribute_ptr = build_pointer_type (char_type_node);
- tree attribute_type = build_qualified_type (attribute_ptr, TYPE_QUAL_CONST);
- return build_array_type_nelts (attribute_type, attributes.size ());
-}
-
-// We're constructing the following structure:
-//
-// struct {
-// const char *trait_name;
-// const char **attributes;
-// std::uint64_t attr_size;
-// TokenStream (fndecl*) (TokenStream);
-// }
-// The resulting structure should be the same as `CustomDerive` in proc_macro.h
-tree
-derive_proc_macro ()
-{
- tree char_ptr = build_pointer_type (char_type_node);
- tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
- auto name_field = Backend::typed_identifier ("trait_name", const_char_type,
- BUILTINS_LOCATION);
-
- tree handle_ptr = build_pointer_type (void_type_node);
- auto fndecl_field
- = Backend::typed_identifier ("fndecl", handle_ptr, BUILTINS_LOCATION);
-
- tree attribute_ptr = build_pointer_type (const_ptr_type_node);
- auto attributes_field
- = Backend::typed_identifier ("attributes", attribute_ptr,
- BUILTINS_LOCATION);
-
- auto size_field = Backend::typed_identifier ("attr_size", unsigned_type_node,
- BUILTINS_LOCATION);
-
- return Backend::struct_type (
- {name_field, attributes_field, size_field, fndecl_field});
-}
-
-// We're constructing the following structure:
-//
-// struct {
-// const char *name;
-// TokenStream (fndecl*) (TokenStream);
-// }
-// The resulting structure should be the same as `Bang` in proc_macro.h
-tree
-bang_proc_macro ()
-{
- tree char_ptr = build_pointer_type (char_type_node);
- tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
- Backend::typed_identifier name_field
- = Backend::typed_identifier ("name", const_char_type, BUILTINS_LOCATION);
-
- tree handle_ptr = ptr_type_node;
- Backend::typed_identifier fndecl_field
- = Backend::typed_identifier ("fndecl", handle_ptr, BUILTINS_LOCATION);
-
- return Backend::struct_type ({name_field, fndecl_field});
-}
-
-// Bang proc macros and attribute proc macros almost have the same members
-// the function pointer type is not the same.
-//
-// We're constructing the following structure:
-//
-// struct {
-// const char *name;
-// TokenStream (fndecl*) (TokenStream, TokenStream);
-// }
-// The resulting structure should be the same as `Attribute` in proc_macro.h
-tree
-attribute_proc_macro ()
-{
- return bang_proc_macro ();
-}
-
-// Build the union of all macro types. The resulting type should have the exact
-// same representation as `ProcMacroPayload` in proc_macro.h
-tree
-proc_macro_payload ()
-{
- tree bang = bang_proc_macro ();
- tree attribute = attribute_proc_macro ();
- tree derive = derive_proc_macro ();
-
- auto bang_field = Backend::typed_identifier ("bang", bang, BUILTINS_LOCATION);
- auto attribute_field
- = Backend::typed_identifier ("attribute", attribute, BUILTINS_LOCATION);
- auto derive_field
- = Backend::typed_identifier ("custom_derive", derive, BUILTINS_LOCATION);
-
- // We rely on the tag to represent the index of any union member. This means
- // we should keep those fields in the same order as the tag representation for
- // it to be kept in sync.
- // Hence why the following code exist: to keep in sync the field vector and
- // the tag enumeration.
- std::vector<Backend::typed_identifier> fields;
- fields.insert (fields.begin () + ProcMacro::CUSTOM_DERIVE, derive_field);
- fields.insert (fields.begin () + ProcMacro::ATTR, attribute_field);
- fields.insert (fields.begin () + ProcMacro::BANG, bang_field);
-
- return Backend::union_type (fields);
-}
-
-// Build the tagged union proc macro type. This type contains a payload as well
-// as a tag to identify the contained member of the payload.
-//
-// struct {
-// unsigned short tag;
-// union { BangProcMacro , DeriveProcMacro, AttributeProcMacro} payload;
-// }
-tree
-proc_macro ()
-{
- auto union_field = proc_macro_payload ();
- auto payload_field
- = Backend::typed_identifier ("payload", union_field, BUILTINS_LOCATION);
-
- auto tag_field = Backend::typed_identifier ("tag", short_unsigned_type_node,
- BUILTINS_LOCATION);
-
- return Backend::struct_type ({tag_field, payload_field});
-}
-
-// Build the `ProcmacroArray` structure
-//
-// struct {
-// std::uint64_t length;
-// Procmacro * macros;
-// }
-tree
-proc_macro_buffer (tree proc_macro_type, size_t total_macro)
-{
- auto length_field = Backend::typed_identifier ("length", unsigned_type_node,
- BUILTINS_LOCATION);
-
- auto array_type = build_array_type_nelts (proc_macro_type, total_macro);
- auto macros_field
- = Backend::typed_identifier ("macros", array_type, BUILTINS_LOCATION);
-
- return Backend::struct_type ({length_field, macros_field});
-}
-
-// The entrypoint of a proc macro crate is a reference to the proc macro buffer
-// `ProcmacroArray` defined in proc_macro.h
-tree
-entrypoint (tree proc_macro_buffer)
-{
- return build_reference_type_for_mode (proc_macro_buffer, E_VOIDmode, false);
-}
-
-} // namespace build
-
-// Functions to init all proc macro trees with the correct values from some
-// macro information
-namespace init {
-
-// Initialize a derive proc macro structure
-// - Store the trait name
-// - Initialize the attribute array
-// - Store the attribute array size
-// - Store the address of the function
-tree
-derive_proc_macro (Context *ctx, CustomDeriveInfo infos)
-{
- tree derive_proc_macro_type = build::derive_proc_macro ();
- tree trait_name = build_string_literal (infos.trait_name.c_str ());
-
- tree attribute_ptr;
- if (infos.attributes.size () == 0)
- {
- // Set a null pointer if there is no attributes
- attribute_ptr = HIRCompileBase::address_expression (null_pointer_node,
- BUILTINS_LOCATION);
- }
- else
- {
- // Initialize the attribute array
- tree attribute_array_type = build::attribute_array (infos.attributes);
-
- std::vector<tree> attr_ctors;
- std::vector<unsigned long> indices;
-
- size_t index = 0;
- for (auto &attr : infos.attributes)
- {
- attr_ctors.push_back (build_string_literal (attr.c_str ()));
- indices.push_back (index);
- index++;
- }
-
- tree attributes
- = Backend::array_constructor_expression (attribute_array_type, indices,
- attr_ctors, BUILTINS_LOCATION);
-
- std::string attribute_var_name
- = GCCRS_PROC_MACRO_SYMBOL_PREFIX + infos.trait_name;
- Bvariable *attributes_var
- = Backend::global_variable (attribute_var_name.c_str (),
- attribute_var_name.c_str (),
- attribute_array_type, false /* internal */,
- true /* hidden */, false /* no gc */,
- BUILTINS_LOCATION);
- Backend::global_variable_set_init (attributes_var, attributes);
- ctx->push_var (attributes_var);
-
- attribute_ptr
- = HIRCompileBase::address_expression (attributes_var->get_decl (),
- BUILTINS_LOCATION);
- }
-
- tree attr_size = build_int_cst (unsigned_type_node, infos.attributes.size ());
-
- tree handle
- = HIRCompileBase::address_expression (infos.fndecl, BUILTINS_LOCATION);
-
- return Backend::constructor_expression (derive_proc_macro_type, false,
- {trait_name, attribute_ptr, attr_size,
- handle},
- -1 /* Structure: no index */,
- BUILTINS_LOCATION);
-}
-
-// Initialize an attribute proc macro structure.
-// - Store the name
-// - Store the address of the function
-tree
-attribute_proc_macro (tree macro)
-{
- tree attribute_proc_macro_type = build::attribute_proc_macro ();
- tree macro_name
- = build_string_literal (IDENTIFIER_POINTER (DECL_NAME (macro)));
- tree handle = HIRCompileBase::address_expression (macro, BUILTINS_LOCATION);
-
- return Backend::constructor_expression (attribute_proc_macro_type, false,
- {macro_name, handle},
- -1 /* Structure: No index */,
- BUILTINS_LOCATION);
-}
-
-// Initialize a bang proc macro structure.
-// - Store the name
-// - Store the address of the function
-tree
-bang_proc_macro (tree macro)
-{
- // Attribute and bang proc macros have the same structure, they can be
- // initialized with the same code.
- return attribute_proc_macro (macro);
-}
-
-// Initialize a proc macro structure from a given payload tree
-tree
-proc_macro (tree payload, tree proc_macro_type, ProcMacro::ProcmacroTag tag)
-{
- auto discriminant = static_cast<int> (tag);
-
- tree macro_tag = build_int_cst (short_unsigned_type_node, discriminant);
-
- tree payload_union
- = Backend::constructor_expression (build::proc_macro_payload (), false,
- {payload},
- discriminant /* Union: member index */,
- BUILTINS_LOCATION);
-
- return Backend::constructor_expression (proc_macro_type,
- false /* invariant */,
- {macro_tag, payload_union},
- -1 /* Structure: No index */,
- BUILTINS_LOCATION);
-}
-
-tree
-proc_macro_array (Context *ctx, tree proc_macro_buffer_type,
- tree proc_macro_type)
-{
- std::vector<unsigned long> indexes;
- std::vector<tree> ctors;
- size_t index = 0;
- for (auto &macro : ctx->get_derive_proc_macros ())
- {
- tree derive = derive_proc_macro (ctx, macro);
- ctors.push_back (proc_macro (derive, proc_macro_type,
- ProcMacro::ProcmacroTag::CUSTOM_DERIVE));
- indexes.push_back (index);
- index++;
- }
- for (auto &macro : ctx->get_attribute_proc_macros ())
- {
- tree attr = attribute_proc_macro (macro);
-
- ctors.push_back (
- proc_macro (attr, proc_macro_type, ProcMacro::ProcmacroTag::ATTR));
- indexes.push_back (index);
- index++;
- }
- for (auto &macro : ctx->get_bang_proc_macros ())
- {
- tree bang = bang_proc_macro (macro);
-
- ctors.push_back (
- proc_macro (bang, proc_macro_type, ProcMacro::ProcmacroTag::BANG));
- indexes.push_back (index);
- index++;
- }
-
- auto length = build_int_cst (unsigned_type_node, ctors.size ());
- auto array = Backend::array_constructor_expression (
- build_array_type_nelts (proc_macro_type, ctors.size ()), indexes, ctors,
- BUILTINS_LOCATION);
- return Backend::constructor_expression (proc_macro_buffer_type,
- false /* invariant */,
- {length, array},
- -1 /* Structure: No index */,
- BUILTINS_LOCATION);
-}
-} // namespace init
-
-} // namespace
-
-// Gather procedural macros and generate the metadata as well as the entrypoint
-// for a procedural macro crate.
-void
-CompileCrate::add_proc_macro_symbols ()
-{
- auto total_macros = ctx->get_attribute_proc_macros ().size ()
- + ctx->get_bang_proc_macros ().size ()
- + ctx->get_derive_proc_macros ().size ();
-
- tree pm_type = build::proc_macro ();
- tree pm_buffer_type = build::proc_macro_buffer (pm_type, total_macros);
- tree entrypoint_type = build::entrypoint (pm_buffer_type);
-
- std::string decl_symbol_name = generate_proc_macro_decls_symbol (
- 0 /* FIXME: Change to stable crate id */);
-
- Bvariable *macro_decls
- = Backend::global_variable (decl_symbol_name.c_str (),
- decl_symbol_name.c_str (), entrypoint_type,
- false /* internal */, false /* not hidden */,
- false /* no gc */, BUILTINS_LOCATION);
-
- std::string buffer_name
- = GCCRS_PROC_MACRO_SYMBOL_PREFIX + "proc_macro_buffer";
-
- Bvariable *proc_macro_buffer
- = Backend::global_variable (buffer_name.c_str (), buffer_name.c_str (),
- pm_buffer_type, false /* internal */,
- true /* hidden */, false /* no gc */,
- BUILTINS_LOCATION);
- Backend::global_variable_set_init (
- proc_macro_buffer, init::proc_macro_array (ctx, pm_buffer_type, pm_type));
- ctx->push_var (proc_macro_buffer);
-
- Backend::global_variable_set_init (
- macro_decls,
- HIRCompileBase::address_expression (proc_macro_buffer->get_decl (),
- BUILTINS_LOCATION));
-
- ctx->push_var (macro_decls);
-}
-
// Shared methods in compilation
tree