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