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 9020 : 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 8151 : struct MatchedFragment
59 : {
60 : std::string fragment_ident;
61 : size_t token_offset_begin;
62 : size_t token_offset_end;
63 :
64 8151 : MatchedFragment (std::string identifier, size_t token_offset_begin,
65 : size_t token_offset_end)
66 8151 : : fragment_ident (identifier), token_offset_begin (token_offset_begin),
67 8151 : 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 9920 : 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 44151 : 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 8151 : MatchedFragmentContainerMetaVar (const MatchedFragment &fragment)
136 8151 : : fragment (fragment)
137 : {}
138 :
139 11366 : MatchedFragment &get_fragment () { return fragment; }
140 :
141 24394 : 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 1769 : MatchedFragmentContainerRepetition () {}
152 :
153 2014 : size_t get_match_amount () const { return fragments.size (); }
154 :
155 8862 : std::vector<std::unique_ptr<MatchedFragmentContainer>> &get_fragments ()
156 : {
157 8862 : 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 4440 : void add_fragment (std::unique_ptr<MatchedFragmentContainer> fragment)
172 : {
173 4440 : fragments.emplace_back (std::move (fragment));
174 : }
175 :
176 19757 : 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 9020 : class SubstitutionScope
193 : {
194 : public:
195 4510 : SubstitutionScope () : stack () {}
196 :
197 8055 : void push () { stack.push_back ({}); }
198 :
199 8055 : std::map<std::string, std::unique_ptr<MatchedFragmentContainer>> pop ()
200 : {
201 8055 : auto top = std::move (stack.back ());
202 8055 : stack.pop_back ();
203 8055 : return top;
204 : }
205 :
206 1769 : std::map<std::string, std::unique_ptr<MatchedFragmentContainer>> &peek ()
207 : {
208 1769 : return stack.back ();
209 : }
210 :
211 : /**
212 : * Insert a new matched metavar into the current substitution map
213 : */
214 8151 : void insert_metavar (MatchedFragment fragment)
215 : {
216 8151 : auto ¤t_map = stack.back ();
217 8151 : auto it = current_map.find (fragment.fragment_ident);
218 :
219 8151 : if (it == current_map.end ())
220 8151 : current_map.emplace (fragment.fragment_ident,
221 16302 : MatchedFragmentContainer::metavar (fragment));
222 : else
223 0 : rust_unreachable ();
224 8151 : }
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 4440 : void append_fragment (std::string ident,
250 : std::unique_ptr<MatchedFragmentContainer> fragment)
251 : {
252 4440 : auto ¤t_map = stack.back ();
253 4440 : auto it = current_map.find (ident);
254 :
255 4440 : if (it == current_map.end ())
256 3424 : it = current_map
257 1712 : .emplace (ident, std::unique_ptr<MatchedFragmentContainer> (
258 1712 : new MatchedFragmentContainerRepetition ()))
259 : .first;
260 :
261 4440 : it->second->add_fragment (std::move (fragment));
262 4440 : }
263 :
264 57 : void insert_matches (std::string key,
265 : std::unique_ptr<MatchedFragmentContainer> matches)
266 : {
267 57 : auto ¤t_map = stack.back ();
268 57 : auto it = current_map.find (key);
269 57 : rust_assert (it == current_map.end ());
270 :
271 57 : current_map.emplace (std::move (key), std::move (matches));
272 57 : }
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 4510 : MacroExpander (AST::Crate &crate, ExpansionCfg cfg, Session &session)
299 4510 : : cfg (cfg), crate (crate), session (session),
300 4510 : sub_stack (SubstitutionScope ()),
301 4510 : expanded_fragment (AST::Fragment::create_error ()),
302 4510 : has_changed_flag (false), had_duplicate_error (false),
303 4510 : resolver (Resolver::Resolver::get ()),
304 4510 : mappings (Analysis::Mappings::get ())
305 4510 : {}
306 :
307 9020 : ~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 amount of successful
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 1610378 : void push_context (ContextType t) { context.push_back (t); }
381 :
382 1610378 : ContextType pop_context ()
383 : {
384 1610378 : rust_assert (!context.empty ());
385 :
386 1610378 : ContextType t = context.back ();
387 1610378 : context.pop_back ();
388 :
389 1610378 : return t;
390 : }
391 :
392 2436 : ContextType peek_context () { return context.back (); }
393 :
394 2818 : void set_expanded_fragment (AST::Fragment &&fragment)
395 : {
396 2818 : if (!fragment.is_error ())
397 2818 : has_changed_flag = true;
398 :
399 2818 : expanded_fragment = std::move (fragment);
400 2818 : }
401 :
402 1635515 : AST::Fragment take_expanded_fragment ()
403 : {
404 1635515 : auto fragment = std::move (expanded_fragment);
405 1635515 : expanded_fragment = AST::Fragment::create_error ();
406 :
407 1635515 : 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 1 : AST::Fragment expand_attribute_proc_macro (T &item, AST::SimplePath &path)
459 : {
460 : tl::optional<AttributeProcMacro &> macro
461 1 : = mappings.lookup_attribute_proc_macro_invocation (path);
462 1 : if (!macro.has_value ())
463 : {
464 1 : rust_error_at (path.get_locus (), "macro not found");
465 1 : 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 10347 : 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 10347 : void reset_changed_state () { has_changed_flag = false; }
491 :
492 1 : tl::optional<AST::MacroRulesDefinition &> &get_last_definition ()
493 : {
494 1 : return last_def;
495 : }
496 :
497 1 : tl::optional<AST::MacroInvocation &> &get_last_invocation ()
498 : {
499 1 : 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 : // used to avoid emitting excess errors
516 : bool had_duplicate_error;
517 :
518 : public:
519 : Resolver::Resolver *resolver;
520 : Analysis::Mappings &mappings;
521 : };
522 :
523 : } // namespace Rust
524 :
525 : #endif
|