Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 Free Software Foundation, Inc.
2 : :
3 : : // This file is part of GCC.
4 : :
5 : : // GCC is free software; you can redistribute it and/or modify it under
6 : : // the terms of the GNU General Public License as published by the Free
7 : : // Software Foundation; either version 3, or (at your option) any later
8 : : // version.
9 : :
10 : : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : : // for more details.
14 : :
15 : : // You should have received a copy of the GNU General Public License
16 : : // along with GCC; see the file COPYING3. If not see
17 : : // <http://www.gnu.org/licenses/>.
18 : :
19 : : #ifndef RUST_MACRO_EXPAND_H
20 : : #define RUST_MACRO_EXPAND_H
21 : :
22 : : #include "optional.h"
23 : : #include "rust-ast-fragment.h"
24 : : #include "rust-buffered-queue.h"
25 : : #include "rust-parse.h"
26 : : #include "rust-token.h"
27 : : #include "rust-ast.h"
28 : : #include "rust-macro.h"
29 : : #include "rust-hir-map.h"
30 : : #include "rust-early-name-resolver.h"
31 : : #include "rust-name-resolver.h"
32 : : #include "rust-macro-invoc-lexer.h"
33 : : #include "rust-proc-macro-invoc-lexer.h"
34 : : #include "rust-token-converter.h"
35 : : #include "rust-ast-collector.h"
36 : : #include "rust-system.h"
37 : : #include "libproc_macro_internal/proc_macro.h"
38 : :
39 : : // Provides objects and method prototypes for macro expansion
40 : :
41 : : namespace Rust {
42 : : // forward decls for AST
43 : : namespace AST {
44 : : class MacroInvocation;
45 : : }
46 : :
47 : : // Object used to store configuration data for macro expansion.
48 : : // NOTE: Keep all these items complying with the latest rustc.
49 : 9878 : struct ExpansionCfg
50 : : {
51 : : // features?
52 : : // TODO: Add `features' when we have it.
53 : : unsigned int recursion_limit = 1024;
54 : : bool trace_mac = false; // trace macro
55 : : bool should_test = false; // strip #[test] nodes if false
56 : : bool keep_macs = false; // keep macro definitions
57 : : std::string crate_name = "";
58 : : };
59 : :
60 : 11388 : struct MatchedFragment
61 : : {
62 : : std::string fragment_ident;
63 : : size_t token_offset_begin;
64 : : size_t token_offset_end;
65 : :
66 : 11388 : MatchedFragment (std::string identifier, size_t token_offset_begin,
67 : : size_t token_offset_end)
68 : 11388 : : fragment_ident (identifier), token_offset_begin (token_offset_begin),
69 : 11388 : token_offset_end (token_offset_end)
70 : : {}
71 : :
72 : : /**
73 : : * Empty constructor for uninitialized fragments
74 : : */
75 : : MatchedFragment () : MatchedFragment ("", 0, 0) {}
76 : :
77 : 0 : std::string as_string () const
78 : : {
79 : 0 : return fragment_ident + "=" + std::to_string (token_offset_begin) + ":"
80 : 0 : + std::to_string (token_offset_end);
81 : : }
82 : : };
83 : :
84 : 14274 : class MatchedFragmentContainer
85 : : {
86 : : public:
87 : : // Does the container refer to a simple metavariable, different from a
88 : : // repetition repeated once
89 : : enum class Kind
90 : : {
91 : : MetaVar,
92 : : Repetition,
93 : : };
94 : :
95 : : virtual ~MatchedFragmentContainer () = default;
96 : :
97 : : virtual Kind get_kind () const = 0;
98 : :
99 : : virtual std::string as_string () const = 0;
100 : :
101 : : /**
102 : : * Create a valid fragment matched zero times. This is useful for repetitions
103 : : * which allow the absence of a fragment, such as * and ?
104 : : */
105 : : static std::unique_ptr<MatchedFragmentContainer> zero ();
106 : :
107 : : /**
108 : : * Create a valid fragment matched one time
109 : : */
110 : : static std::unique_ptr<MatchedFragmentContainer>
111 : : metavar (MatchedFragment fragment);
112 : :
113 : : /**
114 : : * Add a matched fragment to the container
115 : : */
116 : : void add_fragment (MatchedFragment fragment);
117 : :
118 : : /**
119 : : * Add a matched fragment to the container
120 : : */
121 : : void add_fragment (std::unique_ptr<MatchedFragmentContainer> fragment);
122 : :
123 : : // const std::string &get_fragment_name () const { return fragment_name; }
124 : :
125 : 53806 : bool is_single_fragment () const { return get_kind () == Kind::MetaVar; }
126 : :
127 : : MatchedFragment &get_single_fragment ();
128 : :
129 : : std::vector<std::unique_ptr<MatchedFragmentContainer>> &get_fragments ();
130 : : };
131 : :
132 : : class MatchedFragmentContainerMetaVar : public MatchedFragmentContainer
133 : : {
134 : : MatchedFragment fragment;
135 : :
136 : : public:
137 : 11388 : MatchedFragmentContainerMetaVar (const MatchedFragment &fragment)
138 : 11388 : : fragment (fragment)
139 : : {}
140 : :
141 : 12276 : MatchedFragment &get_fragment () { return fragment; }
142 : :
143 : 27401 : virtual Kind get_kind () const { return Kind::MetaVar; }
144 : :
145 : 0 : virtual std::string as_string () const { return fragment.as_string (); }
146 : : };
147 : :
148 : : class MatchedFragmentContainerRepetition : public MatchedFragmentContainer
149 : : {
150 : : std::vector<std::unique_ptr<MatchedFragmentContainer>> fragments;
151 : :
152 : : public:
153 : 2886 : MatchedFragmentContainerRepetition () {}
154 : :
155 : 3184 : size_t get_match_amount () const { return fragments.size (); }
156 : :
157 : 11630 : std::vector<std::unique_ptr<MatchedFragmentContainer>> &get_fragments ()
158 : : {
159 : 11630 : return fragments;
160 : : }
161 : :
162 : : /**
163 : : * Add a matched fragment to the container
164 : : */
165 : 0 : void add_fragment (MatchedFragment fragment)
166 : : {
167 : 0 : add_fragment (metavar (fragment));
168 : 0 : }
169 : :
170 : : /**
171 : : * Add a matched fragment to the container
172 : : */
173 : 5763 : void add_fragment (std::unique_ptr<MatchedFragmentContainer> fragment)
174 : : {
175 : 5763 : fragments.emplace_back (std::move (fragment));
176 : : }
177 : :
178 : 26405 : virtual Kind get_kind () const { return Kind::Repetition; }
179 : :
180 : 0 : virtual std::string as_string () const
181 : : {
182 : 0 : std::string acc = "[";
183 : 0 : for (size_t i = 0; i < fragments.size (); i++)
184 : : {
185 : 0 : if (i)
186 : 0 : acc += " ";
187 : 0 : acc += fragments[i]->as_string ();
188 : : }
189 : 0 : acc += "]";
190 : 0 : return acc;
191 : : }
192 : : };
193 : :
194 : 9878 : class SubstitutionScope
195 : : {
196 : : public:
197 : 4939 : SubstitutionScope () : stack () {}
198 : :
199 : 11429 : void push () { stack.push_back ({}); }
200 : :
201 : 11429 : std::map<std::string, std::unique_ptr<MatchedFragmentContainer>> pop ()
202 : : {
203 : 11429 : auto top = std::move (stack.back ());
204 : 11429 : stack.pop_back ();
205 : 11429 : return top;
206 : : }
207 : :
208 : 2886 : std::map<std::string, std::unique_ptr<MatchedFragmentContainer>> &peek ()
209 : : {
210 : 2886 : return stack.back ();
211 : : }
212 : :
213 : : /**
214 : : * Insert a new matched metavar into the current substitution map
215 : : */
216 : 11388 : void insert_metavar (MatchedFragment fragment)
217 : : {
218 : 11388 : auto ¤t_map = stack.back ();
219 : 11388 : auto it = current_map.find (fragment.fragment_ident);
220 : :
221 : 11388 : if (it == current_map.end ())
222 : 11388 : current_map.emplace (fragment.fragment_ident,
223 : 22776 : MatchedFragmentContainer::metavar (fragment));
224 : : else
225 : 0 : rust_unreachable ();
226 : 11388 : }
227 : :
228 : : /**
229 : : * Append a new matched fragment to a repetition into the current substitution
230 : : * map
231 : : */
232 : : void append_fragment (MatchedFragment fragment)
233 : : {
234 : : auto ¤t_map = stack.back ();
235 : : auto it = current_map.find (fragment.fragment_ident);
236 : :
237 : : if (it == current_map.end ())
238 : : it = current_map
239 : : .emplace (fragment.fragment_ident,
240 : : std::unique_ptr<MatchedFragmentContainer> (
241 : : new MatchedFragmentContainerRepetition ()))
242 : : .first;
243 : :
244 : : it->second->add_fragment (fragment);
245 : : }
246 : :
247 : : /**
248 : : * Append a new matched fragment to a repetition into the current substitution
249 : : * map
250 : : */
251 : 5763 : void append_fragment (std::string ident,
252 : : std::unique_ptr<MatchedFragmentContainer> fragment)
253 : : {
254 : 5763 : auto ¤t_map = stack.back ();
255 : 5763 : auto it = current_map.find (ident);
256 : :
257 : 5763 : if (it == current_map.end ())
258 : 5648 : it = current_map
259 : 2824 : .emplace (ident, std::unique_ptr<MatchedFragmentContainer> (
260 : 2824 : new MatchedFragmentContainerRepetition ()))
261 : : .first;
262 : :
263 : 5763 : it->second->add_fragment (std::move (fragment));
264 : 5763 : }
265 : :
266 : 62 : void insert_matches (std::string key,
267 : : std::unique_ptr<MatchedFragmentContainer> matches)
268 : : {
269 : 62 : auto ¤t_map = stack.back ();
270 : 62 : auto it = current_map.find (key);
271 : 62 : rust_assert (it == current_map.end ());
272 : :
273 : 62 : current_map.emplace (std::move (key), std::move (matches));
274 : 62 : }
275 : :
276 : : private:
277 : : std::vector<std::map<std::string, std::unique_ptr<MatchedFragmentContainer>>>
278 : : stack;
279 : : };
280 : :
281 : : // Object used to store shared data (between functions) for macro expansion.
282 : : struct MacroExpander
283 : : {
284 : : enum class ContextType
285 : : {
286 : : ITEM,
287 : : STMT,
288 : : EXPR,
289 : : EXTERN,
290 : : TYPE,
291 : : TRAIT,
292 : : IMPL,
293 : : TRAIT_IMPL,
294 : : };
295 : :
296 : : ExpansionCfg cfg;
297 : : unsigned int expansion_depth = 0;
298 : :
299 : 4939 : MacroExpander (AST::Crate &crate, ExpansionCfg cfg, Session &session)
300 : 4939 : : cfg (cfg), crate (crate), session (session),
301 : 4939 : sub_stack (SubstitutionScope ()),
302 : 4939 : expanded_fragment (AST::Fragment::create_error ()),
303 : 9878 : has_changed_flag (false), resolver (Resolver::Resolver::get ()),
304 : 4939 : mappings (Analysis::Mappings::get ())
305 : 4939 : {}
306 : :
307 : 9878 : ~MacroExpander () = default;
308 : :
309 : : // Expands all macros in the crate passed in.
310 : : void expand_crate ();
311 : :
312 : : /**
313 : : * Expand the eager invocations contained within a builtin macro invocation.
314 : : * Called by `expand_invoc` when expanding builtin invocations.
315 : : */
316 : : void expand_eager_invocations (AST::MacroInvocation &invoc);
317 : :
318 : : /* Expands a macro invocation - possibly make both
319 : : * have similar duck-typed interface and use templates?*/
320 : : // should this be public or private?
321 : : void expand_invoc (AST::MacroInvocation &invoc, AST::InvocKind semicolon);
322 : :
323 : : // Expands a single declarative macro.
324 : : AST::Fragment expand_decl_macro (location_t locus, AST::MacroInvocData &invoc,
325 : : AST::MacroRulesDefinition &rules_def,
326 : : AST::InvocKind semicolon);
327 : :
328 : : bool depth_exceeds_recursion_limit () const;
329 : :
330 : : bool try_match_rule (AST::MacroRule &match_rule,
331 : : AST::DelimTokenTree &invoc_token_tree);
332 : :
333 : : AST::Fragment transcribe_rule (
334 : : AST::MacroRulesDefinition &definition, AST::MacroRule &match_rule,
335 : : AST::DelimTokenTree &invoc_token_tree,
336 : : std::map<std::string, MatchedFragmentContainer *> &matched_fragments,
337 : : AST::InvocKind invoc_kind, ContextType ctx);
338 : :
339 : : bool match_fragment (Parser<MacroInvocLexer> &parser,
340 : : AST::MacroMatchFragment &fragment);
341 : :
342 : : bool match_token (Parser<MacroInvocLexer> &parser, AST::Token &token);
343 : :
344 : : void match_repetition_skipped_metavars (AST::MacroMatch &);
345 : : void match_repetition_skipped_metavars (AST::MacroMatchFragment &);
346 : : void match_repetition_skipped_metavars (AST::MacroMatchRepetition &);
347 : : void match_repetition_skipped_metavars (AST::MacroMatcher &);
348 : :
349 : : bool match_repetition (Parser<MacroInvocLexer> &parser,
350 : : AST::MacroMatchRepetition &rep);
351 : :
352 : : bool match_matcher (Parser<MacroInvocLexer> &parser,
353 : : AST::MacroMatcher &matcher, bool in_repetition = false,
354 : : bool match_delim = true);
355 : :
356 : : /**
357 : : * Match any amount of matches
358 : : *
359 : : * @param parser Parser to use for matching
360 : : * @param rep Repetition to try and match
361 : : * @param match_amount Reference in which to store the ammount of succesful
362 : : * and valid matches
363 : : *
364 : : * @param lo_bound Lower bound of the matcher. When specified, the matcher
365 : : * will only succeed if it parses at *least* `lo_bound` fragments. If
366 : : * unspecified, the matcher could succeed when parsing 0 fragments.
367 : : *
368 : : * @param hi_bound Higher bound of the matcher. When specified, the matcher
369 : : * will only succeed if it parses *less than* `hi_bound` fragments. If
370 : : * unspecified, the matcher could succeed when parsing an infinity of
371 : : * fragments.
372 : : *
373 : : * @return true if matching was successful and within the given limits, false
374 : : * otherwise
375 : : */
376 : : bool match_n_matches (Parser<MacroInvocLexer> &parser,
377 : : AST::MacroMatchRepetition &rep, size_t &match_amount,
378 : : size_t lo_bound = 0, size_t hi_bound = 0);
379 : :
380 : 2312397 : void push_context (ContextType t) { context.push_back (t); }
381 : :
382 : 2312397 : ContextType pop_context ()
383 : : {
384 : 2312397 : rust_assert (!context.empty ());
385 : :
386 : 2312397 : ContextType t = context.back ();
387 : 2312397 : context.pop_back ();
388 : :
389 : 2312397 : return t;
390 : : }
391 : :
392 : 3468 : ContextType peek_context () { return context.back (); }
393 : :
394 : 3935 : void set_expanded_fragment (AST::Fragment &&fragment)
395 : : {
396 : 3935 : if (!fragment.is_error ())
397 : 3839 : has_changed_flag = true;
398 : :
399 : 3935 : expanded_fragment = std::move (fragment);
400 : 3935 : }
401 : :
402 : 2329297 : AST::Fragment take_expanded_fragment ()
403 : : {
404 : 2329297 : auto fragment = std::move (expanded_fragment);
405 : 2329297 : expanded_fragment = AST::Fragment::create_error ();
406 : :
407 : 2329297 : return fragment;
408 : : }
409 : :
410 : : void import_proc_macros (std::string extern_crate);
411 : :
412 : : template <typename T>
413 : 0 : AST::Fragment expand_derive_proc_macro (T &item, AST::SimplePath &path)
414 : : {
415 : : tl::optional<CustomDeriveProcMacro &> macro
416 : 0 : = mappings.lookup_derive_proc_macro_invocation (path);
417 : 0 : if (!macro.has_value ())
418 : : {
419 : 0 : rust_error_at (path.get_locus (), "macro not found");
420 : 0 : return AST::Fragment::create_error ();
421 : : }
422 : :
423 : 0 : AST::TokenCollector collector;
424 : :
425 : 0 : collector.visit (item);
426 : :
427 : 0 : auto c = collector.collect_tokens ();
428 : 0 : std::vector<const_TokenPtr> vec (c.cbegin (), c.cend ());
429 : :
430 : : return parse_proc_macro_output (
431 : 0 : macro.value ().get_handle () (convert (vec)));
432 : 0 : }
433 : :
434 : : template <typename T>
435 : : AST::Fragment expand_bang_proc_macro (T &item,
436 : : AST::MacroInvocation &invocation)
437 : : {
438 : : tl::optional<BangProcMacro &> macro
439 : : = mappings.lookup_bang_proc_macro_invocation (invocation);
440 : : if (!macro.has_value ())
441 : : {
442 : : rust_error_at (invocation.get_locus (), "macro not found");
443 : : return AST::Fragment::create_error ();
444 : : }
445 : :
446 : : AST::TokenCollector collector;
447 : :
448 : : collector.visit (item);
449 : :
450 : : auto c = collector.collect_tokens ();
451 : : std::vector<const_TokenPtr> vec (c.cbegin (), c.cend ());
452 : :
453 : : return parse_proc_macro_output (
454 : : macro.value ().get_handle () (convert (vec)));
455 : : }
456 : :
457 : : template <typename T>
458 : 0 : AST::Fragment expand_attribute_proc_macro (T &item, AST::SimplePath &path)
459 : : {
460 : : tl::optional<AttributeProcMacro &> macro
461 : 0 : = mappings.lookup_attribute_proc_macro_invocation (path);
462 : 0 : if (!macro.has_value ())
463 : : {
464 : 0 : rust_error_at (path.get_locus (), "macro not found");
465 : 0 : return AST::Fragment::create_error ();
466 : : }
467 : :
468 : 0 : AST::TokenCollector collector;
469 : :
470 : 0 : collector.visit (item);
471 : :
472 : 0 : auto c = collector.collect_tokens ();
473 : 0 : std::vector<const_TokenPtr> vec (c.cbegin (), c.cend ());
474 : :
475 : : // FIXME: Handle attributes
476 : : return parse_proc_macro_output (
477 : 0 : macro.value ().get_handle () (ProcMacro::TokenStream::make_tokenstream (),
478 : 0 : convert (vec)));
479 : 0 : }
480 : :
481 : : /**
482 : : * Has the MacroExpander expanded a macro since its state was last reset?
483 : : */
484 : 8686 : bool has_changed () const { return has_changed_flag; }
485 : :
486 : : /**
487 : : * Reset the expander's "changed" state. This function should be executed at
488 : : * each iteration in a fixed point loop
489 : : */
490 : 8686 : void reset_changed_state () { has_changed_flag = false; }
491 : :
492 : 2 : tl::optional<AST::MacroRulesDefinition &> &get_last_definition ()
493 : : {
494 : 2 : return last_def;
495 : : }
496 : :
497 : 2 : tl::optional<AST::MacroInvocation &> &get_last_invocation ()
498 : : {
499 : 2 : return last_invoc;
500 : : }
501 : :
502 : : private:
503 : : AST::Fragment parse_proc_macro_output (ProcMacro::TokenStream ts);
504 : :
505 : : AST::Crate &crate;
506 : : Session &session;
507 : : SubstitutionScope sub_stack;
508 : : std::vector<ContextType> context;
509 : : AST::Fragment expanded_fragment;
510 : : bool has_changed_flag;
511 : :
512 : : tl::optional<AST::MacroRulesDefinition &> last_def;
513 : : tl::optional<AST::MacroInvocation &> last_invoc;
514 : :
515 : : public:
516 : : Resolver::Resolver *resolver;
517 : : Analysis::Mappings &mappings;
518 : : };
519 : :
520 : : } // namespace Rust
521 : :
522 : : #endif
|