Branch data Line data Source code
1 : : #include "rust-compile.h"
2 : : #include "libproc_macro_internal/proc_macro.h"
3 : : #include "rust-compile-context.h"
4 : : #include "rust-compile-base.h"
5 : :
6 : : namespace Rust {
7 : : namespace Compile {
8 : :
9 : : const std::string GCCRS_PROC_MACRO_SYMBOL_PREFIX = "__gccrs_proc_macro_";
10 : :
11 : : // This namespace brings multiple function to build and initialize multiple
12 : : // structures that needs to get exposed in the final shared library for
13 : : // procedural macro crates.
14 : : //
15 : : // The compiler needs some additional metadata to find which function correspond
16 : : // to the desired macro. The library shall expose one entrypoint symbol leading
17 : : // to those metadata which in turn lead to the correct function.
18 : : // This namespace describes how to build and initialize those metadata
19 : : // structures. Those structure should be kept in sync with the structures in
20 : : // libproc_macro_internal/proc_macro.h describing how they should be read.
21 : : namespace {
22 : :
23 : : // Namespace containing all functions to build the different types.
24 : : namespace build {
25 : :
26 : : // Build an array of attribute type for derive procedural macros.
27 : : tree
28 : 0 : attribute_array (std::vector<std::string> attributes)
29 : : {
30 : 0 : tree attribute_ptr = build_pointer_type (char_type_node);
31 : 0 : tree attribute_type = build_qualified_type (attribute_ptr, TYPE_QUAL_CONST);
32 : 0 : return build_array_type_nelts (attribute_type, attributes.size ());
33 : : }
34 : :
35 : : // We're constructing the following structure:
36 : : //
37 : : // struct {
38 : : // const char *trait_name;
39 : : // const char **attributes;
40 : : // std::uint64_t attr_size;
41 : : // TokenStream (fndecl*) (TokenStream);
42 : : // }
43 : : // The resulting structure should be the same as `CustomDerive` in proc_macro.h
44 : : tree
45 : 0 : derive_proc_macro ()
46 : : {
47 : 0 : tree char_ptr = build_pointer_type (char_type_node);
48 : 0 : tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
49 : 0 : auto name_field = Backend::typed_identifier ("trait_name", const_char_type,
50 : 0 : BUILTINS_LOCATION);
51 : :
52 : 0 : tree handle_ptr = build_pointer_type (void_type_node);
53 : 0 : auto fndecl_field
54 : 0 : = Backend::typed_identifier ("fndecl", handle_ptr, BUILTINS_LOCATION);
55 : :
56 : 0 : tree attribute_ptr = build_pointer_type (const_ptr_type_node);
57 : 0 : auto attributes_field
58 : : = Backend::typed_identifier ("attributes", attribute_ptr,
59 : 0 : BUILTINS_LOCATION);
60 : :
61 : 0 : auto size_field = Backend::typed_identifier ("attr_size", unsigned_type_node,
62 : 0 : BUILTINS_LOCATION);
63 : :
64 : 0 : return Backend::struct_type (
65 : 0 : {name_field, attributes_field, size_field, fndecl_field});
66 : 0 : }
67 : :
68 : : // We're constructing the following structure:
69 : : //
70 : : // struct {
71 : : // const char *name;
72 : : // TokenStream (fndecl*) (TokenStream);
73 : : // }
74 : : // The resulting structure should be the same as `Bang` in proc_macro.h
75 : : tree
76 : 0 : bang_proc_macro ()
77 : : {
78 : 0 : tree char_ptr = build_pointer_type (char_type_node);
79 : 0 : tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST);
80 : 0 : Backend::typed_identifier name_field
81 : 0 : = Backend::typed_identifier ("name", const_char_type, BUILTINS_LOCATION);
82 : :
83 : 0 : tree handle_ptr = ptr_type_node;
84 : 0 : Backend::typed_identifier fndecl_field
85 : 0 : = Backend::typed_identifier ("fndecl", handle_ptr, BUILTINS_LOCATION);
86 : :
87 : 0 : return Backend::struct_type ({name_field, fndecl_field});
88 : 0 : }
89 : :
90 : : // Bang proc macros and attribute proc macros almost have the same members
91 : : // the function pointer type is not the same.
92 : : //
93 : : // We're constructing the following structure:
94 : : //
95 : : // struct {
96 : : // const char *name;
97 : : // TokenStream (fndecl*) (TokenStream, TokenStream);
98 : : // }
99 : : // The resulting structure should be the same as `Attribute` in proc_macro.h
100 : : tree
101 : 0 : attribute_proc_macro ()
102 : : {
103 : 0 : return bang_proc_macro ();
104 : : }
105 : :
106 : : // Build the union of all macro types. The resulting type should have the exact
107 : : // same representation as `ProcMacroPayload` in proc_macro.h
108 : : tree
109 : 0 : proc_macro_payload ()
110 : : {
111 : 0 : tree bang = bang_proc_macro ();
112 : 0 : tree attribute = attribute_proc_macro ();
113 : 0 : tree derive = derive_proc_macro ();
114 : :
115 : 0 : auto bang_field = Backend::typed_identifier ("bang", bang, BUILTINS_LOCATION);
116 : 0 : auto attribute_field
117 : 0 : = Backend::typed_identifier ("attribute", attribute, BUILTINS_LOCATION);
118 : 0 : auto derive_field
119 : 0 : = Backend::typed_identifier ("custom_derive", derive, BUILTINS_LOCATION);
120 : :
121 : : // We rely on the tag to represent the index of any union member. This means
122 : : // we should keep those fields in the same order as the tag representation for
123 : : // it to be kept in sync.
124 : : // Hence why the following code exist: to keep in sync the field vector and
125 : : // the tag enumeration.
126 : 0 : std::vector<Backend::typed_identifier> fields;
127 : 0 : fields.insert (fields.begin () + ProcMacro::CUSTOM_DERIVE, derive_field);
128 : 0 : fields.insert (fields.begin () + ProcMacro::ATTR, attribute_field);
129 : 0 : fields.insert (fields.begin () + ProcMacro::BANG, bang_field);
130 : :
131 : 0 : return Backend::union_type (fields);
132 : 0 : }
133 : :
134 : : // Build the tagged union proc macro type. This type contains a payload as well
135 : : // as a tag to identify the contained member of the payload.
136 : : //
137 : : // struct {
138 : : // unsigned short tag;
139 : : // union { BangProcMacro , DeriveProcMacro, AttributeProcMacro} payload;
140 : : // }
141 : : tree
142 : 0 : proc_macro ()
143 : : {
144 : 0 : auto union_field = proc_macro_payload ();
145 : 0 : auto payload_field
146 : 0 : = Backend::typed_identifier ("payload", union_field, BUILTINS_LOCATION);
147 : :
148 : 0 : auto tag_field = Backend::typed_identifier ("tag", short_unsigned_type_node,
149 : 0 : BUILTINS_LOCATION);
150 : :
151 : 0 : return Backend::struct_type ({tag_field, payload_field});
152 : 0 : }
153 : :
154 : : // Build the `ProcmacroArray` structure
155 : : //
156 : : // struct {
157 : : // std::uint64_t length;
158 : : // Procmacro * macros;
159 : : // }
160 : : tree
161 : 0 : proc_macro_buffer (tree proc_macro_type, size_t total_macro)
162 : : {
163 : 0 : auto length_field = Backend::typed_identifier ("length", unsigned_type_node,
164 : 0 : BUILTINS_LOCATION);
165 : :
166 : 0 : auto array_type = build_array_type_nelts (proc_macro_type, total_macro);
167 : 0 : auto macros_field
168 : 0 : = Backend::typed_identifier ("macros", array_type, BUILTINS_LOCATION);
169 : :
170 : 0 : return Backend::struct_type ({length_field, macros_field});
171 : 0 : }
172 : :
173 : : // The entrypoint of a proc macro crate is a reference to the proc macro buffer
174 : : // `ProcmacroArray` defined in proc_macro.h
175 : : tree
176 : 0 : entrypoint (tree proc_macro_buffer)
177 : : {
178 : 0 : return build_reference_type_for_mode (proc_macro_buffer, E_VOIDmode, false);
179 : : }
180 : :
181 : : } // namespace build
182 : :
183 : : // Functions to init all proc macro trees with the correct values from some
184 : : // macro information
185 : : namespace init {
186 : :
187 : : // Initialize a derive proc macro structure
188 : : // - Store the trait name
189 : : // - Initialize the attribute array
190 : : // - Store the attribute array size
191 : : // - Store the address of the function
192 : : tree
193 : 0 : derive_proc_macro (Context *ctx, CustomDeriveInfo infos)
194 : : {
195 : 0 : tree derive_proc_macro_type = build::derive_proc_macro ();
196 : 0 : tree trait_name = build_string_literal (infos.trait_name.c_str ());
197 : :
198 : 0 : tree attribute_ptr;
199 : 0 : if (infos.attributes.size () == 0)
200 : : {
201 : : // Set a null pointer if there is no attributes
202 : 0 : attribute_ptr = HIRCompileBase::address_expression (null_pointer_node,
203 : : BUILTINS_LOCATION);
204 : : }
205 : : else
206 : : {
207 : : // Initialize the attribute array
208 : 0 : tree attribute_array_type = build::attribute_array (infos.attributes);
209 : :
210 : 0 : std::vector<tree> attr_ctors;
211 : 0 : std::vector<unsigned long> indices;
212 : :
213 : 0 : size_t index = 0;
214 : 0 : for (auto &attr : infos.attributes)
215 : : {
216 : 0 : attr_ctors.push_back (build_string_literal (attr.c_str ()));
217 : 0 : indices.push_back (index);
218 : 0 : index++;
219 : : }
220 : :
221 : 0 : tree attributes
222 : 0 : = Backend::array_constructor_expression (attribute_array_type, indices,
223 : : attr_ctors, BUILTINS_LOCATION);
224 : :
225 : 0 : std::string attribute_var_name
226 : 0 : = GCCRS_PROC_MACRO_SYMBOL_PREFIX + infos.trait_name;
227 : 0 : Bvariable *attributes_var
228 : 0 : = Backend::global_variable (attribute_var_name.c_str (),
229 : : attribute_var_name.c_str (),
230 : : attribute_array_type, false /* internal */,
231 : : true /* hidden */, false /* no gc */,
232 : : BUILTINS_LOCATION);
233 : 0 : Backend::global_variable_set_init (attributes_var, attributes);
234 : 0 : ctx->push_var (attributes_var);
235 : :
236 : 0 : attribute_ptr
237 : 0 : = HIRCompileBase::address_expression (attributes_var->get_decl (),
238 : : BUILTINS_LOCATION);
239 : 0 : }
240 : :
241 : 0 : tree attr_size = build_int_cst (unsigned_type_node, infos.attributes.size ());
242 : :
243 : 0 : tree handle
244 : 0 : = HIRCompileBase::address_expression (infos.fndecl, BUILTINS_LOCATION);
245 : :
246 : 0 : return Backend::constructor_expression (derive_proc_macro_type, false,
247 : : {trait_name, attribute_ptr, attr_size,
248 : : handle},
249 : : -1 /* Structure: no index */,
250 : 0 : BUILTINS_LOCATION);
251 : : }
252 : :
253 : : // Initialize an attribute proc macro structure.
254 : : // - Store the name
255 : : // - Store the address of the function
256 : : tree
257 : 0 : attribute_proc_macro (tree macro)
258 : : {
259 : 0 : tree attribute_proc_macro_type = build::attribute_proc_macro ();
260 : 0 : tree macro_name
261 : 0 : = build_string_literal (IDENTIFIER_POINTER (DECL_NAME (macro)));
262 : 0 : tree handle = HIRCompileBase::address_expression (macro, BUILTINS_LOCATION);
263 : :
264 : 0 : return Backend::constructor_expression (attribute_proc_macro_type, false,
265 : : {macro_name, handle},
266 : : -1 /* Structure: No index */,
267 : 0 : BUILTINS_LOCATION);
268 : : }
269 : :
270 : : // Initialize a bang proc macro structure.
271 : : // - Store the name
272 : : // - Store the address of the function
273 : : tree
274 : 0 : bang_proc_macro (tree macro)
275 : : {
276 : : // Attribute and bang proc macros have the same structure, they can be
277 : : // initialized with the same code.
278 : 0 : return attribute_proc_macro (macro);
279 : : }
280 : :
281 : : // Initialize a proc macro structure from a given payload tree
282 : : tree
283 : 0 : proc_macro (tree payload, tree proc_macro_type, ProcMacro::ProcmacroTag tag)
284 : : {
285 : 0 : auto discriminant = static_cast<int> (tag);
286 : :
287 : 0 : tree macro_tag = build_int_cst (short_unsigned_type_node, discriminant);
288 : :
289 : 0 : tree payload_union
290 : 0 : = Backend::constructor_expression (build::proc_macro_payload (), false,
291 : : {payload},
292 : : discriminant /* Union: member index */,
293 : : BUILTINS_LOCATION);
294 : :
295 : 0 : return Backend::constructor_expression (proc_macro_type,
296 : : false /* invariant */,
297 : : {macro_tag, payload_union},
298 : : -1 /* Structure: No index */,
299 : 0 : BUILTINS_LOCATION);
300 : : }
301 : :
302 : : tree
303 : 0 : proc_macro_array (Context *ctx, tree proc_macro_buffer_type,
304 : : tree proc_macro_type)
305 : : {
306 : 0 : std::vector<unsigned long> indexes;
307 : 0 : std::vector<tree> ctors;
308 : 0 : size_t index = 0;
309 : 0 : for (auto ¯o : ctx->get_derive_proc_macros ())
310 : : {
311 : 0 : tree derive = derive_proc_macro (ctx, macro);
312 : 0 : ctors.push_back (proc_macro (derive, proc_macro_type,
313 : : ProcMacro::ProcmacroTag::CUSTOM_DERIVE));
314 : 0 : indexes.push_back (index);
315 : 0 : index++;
316 : : }
317 : 0 : for (auto ¯o : ctx->get_attribute_proc_macros ())
318 : : {
319 : 0 : tree attr = attribute_proc_macro (macro);
320 : :
321 : 0 : ctors.push_back (
322 : 0 : proc_macro (attr, proc_macro_type, ProcMacro::ProcmacroTag::ATTR));
323 : 0 : indexes.push_back (index);
324 : 0 : index++;
325 : : }
326 : 0 : for (auto ¯o : ctx->get_bang_proc_macros ())
327 : : {
328 : 0 : tree bang = bang_proc_macro (macro);
329 : :
330 : 0 : ctors.push_back (
331 : 0 : proc_macro (bang, proc_macro_type, ProcMacro::ProcmacroTag::BANG));
332 : 0 : indexes.push_back (index);
333 : 0 : index++;
334 : : }
335 : :
336 : 0 : auto length = build_int_cst (unsigned_type_node, ctors.size ());
337 : 0 : auto array = Backend::array_constructor_expression (
338 : 0 : build_array_type_nelts (proc_macro_type, ctors.size ()), indexes, ctors,
339 : : BUILTINS_LOCATION);
340 : 0 : return Backend::constructor_expression (proc_macro_buffer_type,
341 : : false /* invariant */,
342 : : {length, array},
343 : : -1 /* Structure: No index */,
344 : 0 : BUILTINS_LOCATION);
345 : 0 : }
346 : : } // namespace init
347 : :
348 : : } // namespace
349 : :
350 : : // Gather procedural macros and generate the metadata as well as the entrypoint
351 : : // for a procedural macro crate.
352 : : void
353 : 0 : CompileCrate::add_proc_macro_symbols ()
354 : : {
355 : 0 : auto total_macros = ctx->get_attribute_proc_macros ().size ()
356 : 0 : + ctx->get_bang_proc_macros ().size ()
357 : 0 : + ctx->get_derive_proc_macros ().size ();
358 : :
359 : 0 : tree pm_type = build::proc_macro ();
360 : 0 : tree pm_buffer_type = build::proc_macro_buffer (pm_type, total_macros);
361 : 0 : tree entrypoint_type = build::entrypoint (pm_buffer_type);
362 : :
363 : 0 : std::string decl_symbol_name = generate_proc_macro_decls_symbol (
364 : 0 : 0 /* FIXME: Change to stable crate id */);
365 : :
366 : 0 : Bvariable *macro_decls
367 : 0 : = Backend::global_variable (decl_symbol_name.c_str (),
368 : : decl_symbol_name.c_str (), entrypoint_type,
369 : : false /* internal */, false /* not hidden */,
370 : : false /* no gc */, BUILTINS_LOCATION);
371 : :
372 : 0 : std::string buffer_name
373 : 0 : = GCCRS_PROC_MACRO_SYMBOL_PREFIX + "proc_macro_buffer";
374 : :
375 : 0 : Bvariable *proc_macro_buffer
376 : 0 : = Backend::global_variable (buffer_name.c_str (), buffer_name.c_str (),
377 : : pm_buffer_type, false /* internal */,
378 : : true /* hidden */, false /* no gc */,
379 : : BUILTINS_LOCATION);
380 : 0 : Backend::global_variable_set_init (
381 : : proc_macro_buffer, init::proc_macro_array (ctx, pm_buffer_type, pm_type));
382 : 0 : ctx->push_var (proc_macro_buffer);
383 : :
384 : 0 : Backend::global_variable_set_init (
385 : : macro_decls,
386 : : HIRCompileBase::address_expression (proc_macro_buffer->get_decl (),
387 : : BUILTINS_LOCATION));
388 : :
389 : 0 : ctx->push_var (macro_decls);
390 : 0 : }
391 : :
392 : : } // namespace Compile
393 : : } // namespace Rust
|