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