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
|