libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / rust / expand / rust-proc-macro.cc
blob09680733e988fa4c9cc30634502b8c15bfc4fb1a
1 // This file is part of GCC.
3 // GCC is free software; you can redistribute it and/or modify it under
4 // the terms of the GNU General Public License as published by the Free
5 // Software Foundation; either version 3, or (at your option) any later
6 // version.
8 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
9 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 // for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with GCC; see the file COPYING3. If not see
15 // <http://www.gnu.org/licenses/>.
17 #include "rust-system.h"
18 #include "rust-diagnostics.h"
19 #include "rust-proc-macro.h"
20 #include "rust-session-manager.h"
21 #include "rust-lex.h"
22 #include "rust-token-converter.h"
23 #include "rust-attributes.h"
25 #ifndef _WIN32
26 #include <dlfcn.h>
27 #endif
29 namespace Rust {
31 BangProcMacro::BangProcMacro (ProcMacro::Bang macro)
32 : name (macro.name),
33 node_id (Analysis::Mappings::get ()->get_next_node_id ()),
34 macro (macro.macro)
37 AttributeProcMacro::AttributeProcMacro (ProcMacro::Attribute macro)
38 : name (macro.name),
39 node_id (Analysis::Mappings::get ()->get_next_node_id ()),
40 macro (macro.macro)
43 CustomDeriveProcMacro::CustomDeriveProcMacro (ProcMacro::CustomDerive macro)
44 : trait_name (macro.trait_name),
45 attributes (macro.attributes, macro.attributes + macro.attr_size),
46 node_id (Analysis::Mappings::get ()->get_next_node_id ()),
47 macro (macro.macro)
50 namespace {
52 ProcMacro::Literal
53 literal_from_string (const std::string &data, bool &error)
55 Lexer lex (data, nullptr);
56 const_TokenPtr output = lex.build_token ();
57 if (output == nullptr || !output->is_literal ())
59 error = true;
60 // We should probably rework this
61 return ProcMacro::Literal::make_usize (0);
64 error = false;
65 return convert_literal (output);
68 ProcMacro::TokenStream
69 tokenstream_from_string (std::string &data, bool &lex_error)
71 // FIXME: Insert location pointing to call site in tokens
72 Lexer lex (data, Session::get_instance ().linemap);
74 std::vector<const_TokenPtr> tokens;
75 TokenPtr ptr;
76 for (ptr = lex.build_token ();
77 ptr != nullptr && ptr->get_id () != END_OF_FILE;
78 ptr = lex.build_token ())
80 tokens.emplace_back (ptr);
83 if (ptr == nullptr)
85 lex_error = true;
86 return ProcMacro::TokenStream::make_tokenstream ();
89 lex_error = false;
90 return convert (tokens);
93 static_assert (
94 std::is_same<decltype (tokenstream_from_string) *,
95 ProcMacro::ts_from_str_fn_t>::value,
96 "Registration callback signature not synced, check proc macro internals.");
98 static_assert (
99 std::is_same<decltype (literal_from_string) *,
100 ProcMacro::lit_from_str_fn_t>::value,
101 "Registration callback signature not synced, check proc macro internals.");
103 } // namespace
105 template <typename Symbol, typename Callback>
106 bool
107 register_callback (void *handle, Symbol, std::string symbol_name,
108 Callback callback)
110 void *addr = dlsym (handle, symbol_name.c_str ());
111 if (addr == nullptr)
113 rust_error_at (UNDEF_LOCATION,
114 "Callback registration symbol (%s) missing from "
115 "proc macro, wrong version?",
116 symbol_name.c_str ());
117 return false;
120 auto storage = reinterpret_cast<Symbol *> (addr);
121 *storage = callback;
123 return true;
126 #define REGISTER_CALLBACK(HANDLE, SYMBOL, CALLBACK) \
127 register_callback (HANDLE, SYMBOL, #SYMBOL, CALLBACK)
129 const ProcMacro::ProcmacroArray *
130 load_macros_array (std::string path)
132 #ifndef _WIN32
133 void *handle = dlopen (path.c_str (), RTLD_LAZY | RTLD_LOCAL);
134 // We're leaking the handle since we can't ever unload it
135 if (!handle)
137 rust_debug ("Error whilst opening procedural macro: %s", dlerror ());
138 return nullptr;
141 if (!REGISTER_CALLBACK (handle, __gccrs_proc_macro_ts_from_str_,
142 tokenstream_from_string))
143 return nullptr;
144 if (!REGISTER_CALLBACK (handle, __gccrs_proc_macro_lit_from_str_,
145 literal_from_string))
146 return nullptr;
147 if (!REGISTER_CALLBACK (handle, __gccrs_proc_macro_is_available_,
148 ProcMacro::BridgeState::Available))
149 return nullptr;
151 // FIXME: Add CrateStableId handling, right now all versions may be loaded,
152 // even incompatible ones.
153 auto symbol_name = generate_proc_macro_decls_symbol (0 /* FIXME */);
155 return *reinterpret_cast<const ProcMacro::ProcmacroArray **> (
156 dlsym (handle, symbol_name.c_str ()));
157 #else
158 rust_sorry_at (UNDEF_LOCATION,
159 "Procedural macros are not yet supported on windows host");
160 rust_unreachable ();
161 #endif
164 #undef REGISTER_CALLBACK
166 const std::vector<ProcMacro::Procmacro>
167 load_macros (std::string path)
169 const ProcMacro::ProcmacroArray *array = load_macros_array (path);
170 // Did not load the proc macro
171 if (array == nullptr)
172 return {};
174 rust_debug ("Found %lu procedural macros", (unsigned long) array->length);
176 return std::vector<ProcMacro::Procmacro> (array->macros,
177 array->macros + array->length);
180 std::string
181 generate_proc_macro_decls_symbol (std::uint32_t stable_crate_id)
183 std::ostringstream stream;
184 stream << "__gccrs_proc_macro_decls_" << std::setfill ('0') << std::hex
185 << std::setw (8) << stable_crate_id << "__";
187 return stream.str ();
190 } // namespace Rust