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 0 : = 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 : }
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 : }
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 : }
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 : }
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 0 : 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 0 : 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
|