Branch data Line data Source code
1 : : // This file is part of GCC.
2 : :
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.
7 : :
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.
12 : :
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/>.
16 : :
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"
24 : :
25 : : #ifdef _WIN32
26 : : #define WIN32_LEAN_AND_MEAN
27 : : #include <windows.h>
28 : : #else
29 : : #include <dlfcn.h>
30 : : #endif
31 : :
32 : : namespace Rust {
33 : :
34 : 0 : BangProcMacro::BangProcMacro (ProcMacro::Bang macro)
35 : 0 : : name (macro.name), node_id (Analysis::Mappings::get ().get_next_node_id ()),
36 : 0 : macro (macro.macro)
37 : 0 : {}
38 : :
39 : 0 : AttributeProcMacro::AttributeProcMacro (ProcMacro::Attribute macro)
40 : 0 : : name (macro.name), node_id (Analysis::Mappings::get ().get_next_node_id ()),
41 : 0 : macro (macro.macro)
42 : 0 : {}
43 : :
44 : 0 : CustomDeriveProcMacro::CustomDeriveProcMacro (ProcMacro::CustomDerive macro)
45 : 0 : : trait_name (macro.trait_name),
46 : 0 : attributes (macro.attributes, macro.attributes + macro.attr_size),
47 : 0 : node_id (Analysis::Mappings::get ().get_next_node_id ()),
48 : 0 : macro (macro.macro)
49 : 0 : {}
50 : :
51 : : namespace {
52 : :
53 : : ProcMacro::Literal
54 : 0 : literal_from_string (const std::string &data, bool &error)
55 : : {
56 : 0 : Lexer lex (data, nullptr);
57 : 0 : const_TokenPtr output = lex.build_token ();
58 : 0 : if (output == nullptr || !output->is_literal ())
59 : : {
60 : 0 : error = true;
61 : : // We should probably rework this
62 : 0 : return ProcMacro::Literal::make_usize (0);
63 : : }
64 : :
65 : 0 : error = false;
66 : 0 : return convert_literal (output);
67 : 0 : }
68 : :
69 : : ProcMacro::TokenStream
70 : 0 : tokenstream_from_string (std::string &data, bool &lex_error)
71 : : {
72 : : // FIXME: Insert location pointing to call site in tokens
73 : 0 : Lexer lex (data, Session::get_instance ().linemap);
74 : :
75 : 0 : std::vector<const_TokenPtr> tokens;
76 : 0 : TokenPtr ptr;
77 : 0 : for (ptr = lex.build_token ();
78 : 0 : ptr != nullptr && ptr->get_id () != END_OF_FILE;
79 : 0 : ptr = lex.build_token ())
80 : : {
81 : 0 : tokens.emplace_back (ptr);
82 : : }
83 : :
84 : 0 : if (ptr == nullptr)
85 : : {
86 : 0 : lex_error = true;
87 : 0 : return ProcMacro::TokenStream::make_tokenstream ();
88 : : }
89 : :
90 : 0 : lex_error = false;
91 : 0 : return convert (tokens);
92 : 0 : }
93 : :
94 : : static_assert (
95 : : std::is_same<decltype (tokenstream_from_string) *,
96 : : ProcMacro::ts_from_str_fn_t>::value,
97 : : "Registration callback signature not synced, check proc macro internals.");
98 : :
99 : : static_assert (
100 : : std::is_same<decltype (literal_from_string) *,
101 : : ProcMacro::lit_from_str_fn_t>::value,
102 : : "Registration callback signature not synced, check proc macro internals.");
103 : :
104 : : } // namespace
105 : :
106 : : template <typename Handle, typename Symbol, typename Callback>
107 : : bool
108 : 0 : register_callback (Handle handle, Symbol, std::string symbol_name,
109 : : Callback callback)
110 : : {
111 : : #ifdef _WIN32
112 : : FARPROC addr = GetProcAddress (handle, symbol_name.c_str ());
113 : : #else
114 : 0 : void *addr = dlsym (handle, symbol_name.c_str ());
115 : : #endif
116 : 0 : if (addr == nullptr)
117 : : {
118 : 0 : rust_error_at (UNDEF_LOCATION,
119 : : "Callback registration symbol (%s) missing from "
120 : : "proc macro, wrong version?",
121 : : symbol_name.c_str ());
122 : 0 : return false;
123 : : }
124 : :
125 : 0 : auto storage = reinterpret_cast<Symbol *> (addr);
126 : 0 : *storage = callback;
127 : :
128 : 0 : return true;
129 : : }
130 : :
131 : : #define REGISTER_CALLBACK(HANDLE, SYMBOL, CALLBACK) \
132 : : register_callback (HANDLE, SYMBOL, #SYMBOL, CALLBACK)
133 : :
134 : : const ProcMacro::ProcmacroArray *
135 : 24 : load_macros_array (std::string path)
136 : : {
137 : : #ifdef _WIN32
138 : : HMODULE handle = LoadLibraryA (path.c_str ());
139 : : // We're leaking the handle since we can't ever unload it
140 : : if (!handle)
141 : : {
142 : : char msg[300];
143 : : FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM
144 : : | FORMAT_MESSAGE_IGNORE_INSERTS,
145 : : nullptr, GetLastError (), 0, msg, sizeof msg, nullptr);
146 : : rust_debug ("Error whilst opening procedural macro: %s", msg);
147 : : return nullptr;
148 : : }
149 : : #else
150 : 24 : void *handle = dlopen (path.c_str (), RTLD_LAZY | RTLD_LOCAL);
151 : : // We're leaking the handle since we can't ever unload it
152 : 24 : if (!handle)
153 : : {
154 : 24 : rust_debug ("Error whilst opening procedural macro: %s", dlerror ());
155 : 24 : return nullptr;
156 : : }
157 : : #endif
158 : :
159 : 0 : if (!REGISTER_CALLBACK (handle, __gccrs_proc_macro_ts_from_str_,
160 : : tokenstream_from_string))
161 : : return nullptr;
162 : 0 : if (!REGISTER_CALLBACK (handle, __gccrs_proc_macro_lit_from_str_,
163 : : literal_from_string))
164 : : return nullptr;
165 : 0 : if (!REGISTER_CALLBACK (handle, __gccrs_proc_macro_is_available_,
166 : : ProcMacro::BridgeState::Available))
167 : : return nullptr;
168 : :
169 : : // FIXME: Add CrateStableId handling, right now all versions may be loaded,
170 : : // even incompatible ones.
171 : 0 : auto symbol_name = generate_proc_macro_decls_symbol (0 /* FIXME */);
172 : :
173 : 0 : return *reinterpret_cast<const ProcMacro::ProcmacroArray **> (
174 : : #ifdef _WIN32
175 : : GetProcAddress (handle, symbol_name.c_str ())
176 : : #else
177 : 0 : dlsym (handle, symbol_name.c_str ())
178 : : #endif
179 : 0 : );
180 : 0 : }
181 : :
182 : : #undef REGISTER_CALLBACK
183 : :
184 : : const std::vector<ProcMacro::Procmacro>
185 : 24 : load_macros (std::string path)
186 : : {
187 : 48 : const ProcMacro::ProcmacroArray *array = load_macros_array (path);
188 : : // Did not load the proc macro
189 : 24 : if (array == nullptr)
190 : 24 : return {};
191 : :
192 : 0 : rust_debug ("Found %lu procedural macros", (unsigned long) array->length);
193 : :
194 : 0 : return std::vector<ProcMacro::Procmacro> (array->macros,
195 : 0 : array->macros + array->length);
196 : : }
197 : :
198 : : std::string
199 : 0 : generate_proc_macro_decls_symbol (std::uint32_t stable_crate_id)
200 : : {
201 : 0 : std::ostringstream stream;
202 : 0 : stream << "__gccrs_proc_macro_decls_" << std::setfill ('0') << std::hex
203 : 0 : << std::setw (8) << stable_crate_id << "__";
204 : :
205 : 0 : return stream.str ();
206 : 0 : }
207 : :
208 : : } // namespace Rust
|