LCOV - code coverage report
Current view: top level - gcc/rust/expand - rust-macro-expand.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 87.2 % 562 490
Test Date: 2025-11-22 14:42:49 Functions: 92.7 % 41 38
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             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                 :             : #include "rust-macro-expand.h"
      20                 :             : #include "optional.h"
      21                 :             : #include "rust-ast-fragment.h"
      22                 :             : #include "rust-macro-builtins.h"
      23                 :             : #include "rust-macro-substitute-ctx.h"
      24                 :             : #include "rust-ast-full.h"
      25                 :             : #include "rust-ast-visitor.h"
      26                 :             : #include "rust-diagnostics.h"
      27                 :             : #include "rust-macro.h"
      28                 :             : #include "rust-parse.h"
      29                 :             : #include "rust-cfg-strip.h"
      30                 :             : #include "rust-proc-macro.h"
      31                 :             : #include "rust-token-tree-desugar.h"
      32                 :             : 
      33                 :             : namespace Rust {
      34                 :             : 
      35                 :             : AST::Fragment
      36                 :       55198 : MacroExpander::expand_decl_macro (location_t invoc_locus,
      37                 :             :                                   AST::MacroInvocData &invoc,
      38                 :             :                                   AST::MacroRulesDefinition &rules_def,
      39                 :             :                                   AST::InvocKind semicolon)
      40                 :             : {
      41                 :             :   // ensure that both invocation and rules are in a valid state
      42                 :       55198 :   rust_assert (!invoc.is_marked_for_strip ());
      43                 :       55198 :   rust_assert (!rules_def.is_marked_for_strip ());
      44                 :       55198 :   rust_assert (rules_def.get_macro_rules ().size () > 0);
      45                 :             : 
      46                 :             :   /* probably something here about parsing invoc and rules def token trees to
      47                 :             :    * token stream. if not, how would parser handle the captures of exprs and
      48                 :             :    * stuff? on the other hand, token trees may be kind of useful in rules def
      49                 :             :    * as creating a point where recursion can occur (like having
      50                 :             :    * "compare_macro_match" and then it calling itself when it finds
      51                 :             :    * delimiters)
      52                 :             :    */
      53                 :             : 
      54                 :             :   /* find matching rule to invoc token tree, based on macro rule's matcher. if
      55                 :             :    * none exist, error.
      56                 :             :    * - specifically, check each matcher in order. if one fails to match, move
      57                 :             :    * onto next. */
      58                 :             :   /* TODO: does doing this require parsing expressions and whatever in the
      59                 :             :    * invoc? if so, might as well save the results if referenced using $ or
      60                 :             :    * whatever. If not, do another pass saving them. Except this is probably
      61                 :             :    * useless as different rules could have different starting points for exprs
      62                 :             :    * or whatever. Decision trees could avoid this, but they have their own
      63                 :             :    * issues. */
      64                 :             :   /* TODO: will need to modify the parser so that it can essentially "catch"
      65                 :             :    * errors - maybe "try_parse_expr" or whatever methods. */
      66                 :             :   // this technically creates a back-tracking parser - this will be the
      67                 :             :   // implementation style
      68                 :             : 
      69                 :             :   /* then, after results are saved, generate the macro output from the
      70                 :             :    * transcriber token tree. if i understand this correctly, the macro
      71                 :             :    * invocation gets replaced by the transcriber tokens, except with
      72                 :             :    * substitutions made (e.g. for $i variables) */
      73                 :             : 
      74                 :             :   /* TODO: it is probably better to modify AST::Token to store a pointer to a
      75                 :             :    * Lexer::Token (rather than being converted) - i.e. not so much have
      76                 :             :    * AST::Token as a Token but rather a TokenContainer (as it is another type
      77                 :             :    * of TokenTree). This will prevent re-conversion of Tokens between each
      78                 :             :    * type all the time, while still allowing the heterogenous storage of token
      79                 :             :    * trees.
      80                 :             :    */
      81                 :             : 
      82                 :       55198 :   AST::DelimTokenTree &invoc_token_tree_sugar = invoc.get_delim_tok_tree ();
      83                 :             : 
      84                 :             :   // We must first desugar doc comments into proper attributes
      85                 :       55198 :   auto invoc_token_tree = AST::TokenTreeDesugar ().go (invoc_token_tree_sugar);
      86                 :             : 
      87                 :             :   // find matching arm
      88                 :       55198 :   AST::MacroRule *matched_rule = nullptr;
      89                 :       55198 :   std::map<std::string, std::unique_ptr<MatchedFragmentContainer>>
      90                 :       55198 :     matched_fragments;
      91                 :       58955 :   for (auto &rule : rules_def.get_rules ())
      92                 :             :     {
      93                 :       58948 :       sub_stack.push ();
      94                 :       58948 :       bool did_match_rule = try_match_rule (rule, invoc_token_tree);
      95                 :      117896 :       matched_fragments = sub_stack.pop ();
      96                 :             : 
      97                 :       58948 :       if (did_match_rule)
      98                 :             :         {
      99                 :             :           //  // Debugging
     100                 :             :           //  for (auto &kv : matched_fragments)
     101                 :             :           //    rust_debug ("[fragment]: %s (%ld - %s)", kv.first.c_str (),
     102                 :             :           //            kv.second.get_fragments ().size (),
     103                 :             :           //            kv.second.get_kind ()
     104                 :             :           //                == MatchedFragmentContainer::Kind::Repetition
     105                 :             :           //              ? "repetition"
     106                 :             :           //              : "metavar");
     107                 :             : 
     108                 :             :           matched_rule = &rule;
     109                 :             :           break;
     110                 :             :         }
     111                 :             :     }
     112                 :             : 
     113                 :       55198 :   if (matched_rule == nullptr)
     114                 :             :     {
     115                 :           7 :       rich_location r (line_table, invoc_locus);
     116                 :           7 :       r.add_range (rules_def.get_locus ());
     117                 :           7 :       rust_error_at (r, "Failed to match any rule within macro");
     118                 :           7 :       return AST::Fragment::create_error ();
     119                 :           7 :     }
     120                 :             : 
     121                 :       55191 :   std::map<std::string, MatchedFragmentContainer *> matched_fragments_ptr;
     122                 :             : 
     123                 :      227772 :   for (auto &ent : matched_fragments)
     124                 :      172581 :     matched_fragments_ptr.emplace (ent.first, ent.second.get ());
     125                 :             : 
     126                 :       55191 :   return transcribe_rule (rules_def, *matched_rule, invoc_token_tree,
     127                 :       55191 :                           matched_fragments_ptr, semicolon, peek_context ());
     128                 :      110389 : }
     129                 :             : 
     130                 :             : void
     131                 :          45 : MacroExpander::expand_eager_invocations (AST::MacroInvocation &invoc)
     132                 :             : {
     133                 :          45 :   if (invoc.get_pending_eager_invocations ().empty ())
     134                 :           0 :     return;
     135                 :             : 
     136                 :             :   // We have to basically create a new delimited token tree which contains the
     137                 :             :   // result of one step of expansion. In the case of builtin macros called with
     138                 :             :   // other macro invocations, such as `concat!("h", 'a', a!())`, we need to
     139                 :             :   // expand `a!()` before expanding the concat macro.
     140                 :             :   // This will, ideally, give us a new token tree containing the various
     141                 :             :   // existing tokens + the result of the expansion of a!().
     142                 :             :   // To do this, we "parse" the given token tree to find anything that "looks
     143                 :             :   // like a macro invocation". Then, we get the corresponding macro invocation
     144                 :             :   // from the `pending_eager_invocations` vector and expand it.
     145                 :             :   // Because the `pending_eager_invocations` vector is created in the same order
     146                 :             :   // that the DelimTokenTree is parsed, we know that the first macro invocation
     147                 :             :   // within the DelimTokenTree corresponds to the first element in
     148                 :             :   // `pending_eager_invocations`. The idea is thus to:
     149                 :             :   // 1. Find a macro invocation in the token tree, noting the index of the start
     150                 :             :   //    token and of the end token
     151                 :             :   // 2. Get its associated invocation in `pending_eager_invocations`
     152                 :             :   // 3. Expand that element
     153                 :             :   // 4. Get the token tree associated with that AST fragment
     154                 :             :   // 5. Replace the original tokens corresponding to the invocation with the new
     155                 :             :   //    tokens from the fragment
     156                 :             :   // pseudo-code:
     157                 :             :   //
     158                 :             :   // i = 0;
     159                 :             :   // for tok in dtt:
     160                 :             :   //   if tok is identifier && tok->next() is !:
     161                 :             :   //     start = index(tok);
     162                 :             :   //     l_delim = tok->next()->next();
     163                 :             :   //     tok = skip_until_r_delim();
     164                 :             :   //     end = index(tok);
     165                 :             :   //
     166                 :             :   //     new_tt = expand_eager_invoc(eagers[i++]);
     167                 :             :   //     old_tt[start..end] = new_tt;
     168                 :             : 
     169                 :          45 :   auto dtt = invoc.get_invoc_data ().get_delim_tok_tree ();
     170                 :          45 :   auto stream = dtt.to_token_stream ();
     171                 :          45 :   std::vector<std::unique_ptr<AST::TokenTree>> new_stream;
     172                 :          45 :   size_t current_pending = 0;
     173                 :             : 
     174                 :             :   // we need to create a clone of the delimited token tree as the lexer
     175                 :             :   // expects ownership of the tokens
     176                 :          45 :   std::vector<std::unique_ptr<Rust::AST::Token>> dtt_clone;
     177                 :         389 :   for (auto &tok : stream)
     178                 :         344 :     dtt_clone.emplace_back (tok->clone_token ());
     179                 :             : 
     180                 :          45 :   MacroInvocLexer lex (std::move (dtt_clone));
     181                 :          45 :   Parser<MacroInvocLexer> parser (lex);
     182                 :             : 
     183                 :             :   // we want to build a substitution map - basically, associating a `start` and
     184                 :             :   // `end` index for each of the pending macro invocations
     185                 :          45 :   std::map<std::pair<size_t, size_t>, std::unique_ptr<AST::MacroInvocation> &>
     186                 :          45 :     substitution_map;
     187                 :             : 
     188                 :         389 :   for (size_t i = 0; i < stream.size (); i++)
     189                 :             :     {
     190                 :             :       // FIXME: Can't these offsets be figure out when we actually parse the
     191                 :             :       // pending_eager_invocation in the first place?
     192                 :         344 :       auto invocation = parser.parse_macro_invocation ({});
     193                 :             : 
     194                 :             :       // if we've managed to parse a macro invocation, we look at the current
     195                 :             :       // offset and store them in the substitution map. Otherwise, we skip one
     196                 :             :       // token and try parsing again
     197                 :         344 :       if (invocation)
     198                 :          48 :         substitution_map.insert (
     199                 :          48 :           {{i, parser.get_token_source ().get_offs ()},
     200                 :          48 :            invoc.get_pending_eager_invocations ()[current_pending++]});
     201                 :             :       else
     202                 :         296 :         parser.skip_token (stream[i]->get_id ());
     203                 :         344 :     }
     204                 :             : 
     205                 :          45 :   size_t current_idx = 0;
     206                 :          93 :   for (auto kv : substitution_map)
     207                 :             :     {
     208                 :          48 :       auto &to_expand = kv.second;
     209                 :          48 :       expand_invoc (*to_expand, AST::InvocKind::Expr);
     210                 :             : 
     211                 :          48 :       auto fragment = take_expanded_fragment ();
     212                 :          48 :       auto &new_tokens = fragment.get_tokens ();
     213                 :             : 
     214                 :          48 :       auto start = kv.first.first;
     215                 :          48 :       auto end = kv.first.second;
     216                 :             : 
     217                 :             :       // We're now going to re-add the tokens to the invocation's token tree.
     218                 :             :       // 1. Basically, what we want to do is insert all tokens up until the
     219                 :             :       //    beginning of the macro invocation (start).
     220                 :             :       // 2. Then, we'll insert all of the tokens resulting from the macro
     221                 :             :       //    expansion: These are in `new_tokens`.
     222                 :             :       // 3. Finally, we'll do that again from
     223                 :             :       //    the end of macro and go back to 1.
     224                 :             : 
     225                 :         102 :       for (size_t i = current_idx; i < start; i++)
     226                 :          54 :         new_stream.emplace_back (stream[i]->clone_token ());
     227                 :             : 
     228                 :          96 :       for (auto &tok : new_tokens)
     229                 :          48 :         new_stream.emplace_back (tok->clone_token ());
     230                 :             : 
     231                 :          48 :       current_idx = end;
     232                 :          48 :     }
     233                 :             : 
     234                 :             :   // Once all of that is done, we copy the last remaining tokens from the
     235                 :             :   // original stream
     236                 :         121 :   for (size_t i = current_idx; i < stream.size (); i++)
     237                 :          76 :     new_stream.emplace_back (stream[i]->clone_token ());
     238                 :             : 
     239                 :          45 :   auto new_dtt
     240                 :          45 :     = AST::DelimTokenTree (dtt.get_delim_type (), std::move (new_stream));
     241                 :             : 
     242                 :          45 :   invoc.get_pending_eager_invocations ().clear ();
     243                 :          45 :   invoc.get_invoc_data ().set_delim_tok_tree (new_dtt);
     244                 :          90 : }
     245                 :             : 
     246                 :             : void
     247                 :       61715 : MacroExpander::expand_invoc (AST::MacroInvocation &invoc,
     248                 :             :                              AST::InvocKind semicolon)
     249                 :             : {
     250                 :       61715 :   if (depth_exceeds_recursion_limit ())
     251                 :             :     {
     252                 :           0 :       rust_error_at (invoc.get_locus (), "reached recursion limit");
     253                 :          39 :       return;
     254                 :             :     }
     255                 :             : 
     256                 :       61715 :   if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
     257                 :             :     {
     258                 :             :       // Eager expansions are always expressions
     259                 :          45 :       push_context (ContextType::EXPR);
     260                 :          45 :       expand_eager_invocations (invoc);
     261                 :          45 :       pop_context ();
     262                 :             :     }
     263                 :             : 
     264                 :       61715 :   AST::MacroInvocData &invoc_data = invoc.get_invoc_data ();
     265                 :             : 
     266                 :             :   // ??
     267                 :             :   // switch on type of macro:
     268                 :             :   //  - '!' syntax macro (inner switch)
     269                 :             :   //      - procedural macro - "A token-based function-like macro"
     270                 :             :   //      - 'macro_rules' (by example/pattern-match) macro? or not? "an
     271                 :             :   // AST-based function-like macro"
     272                 :             :   //      - else is unreachable
     273                 :             :   //  - attribute syntax macro (inner switch)
     274                 :             :   //  - procedural macro attribute syntax - "A token-based attribute
     275                 :             :   // macro"
     276                 :             :   //      - legacy macro attribute syntax? - "an AST-based attribute macro"
     277                 :             :   //      - non-macro attribute: mark known
     278                 :             :   //      - else is unreachable
     279                 :             :   //  - derive macro (inner switch)
     280                 :             :   //      - derive or legacy derive - "token-based" vs "AST-based"
     281                 :             :   //      - else is unreachable
     282                 :             :   //  - derive container macro - unreachable
     283                 :             : 
     284                 :       61715 :   auto fragment = AST::Fragment::create_error ();
     285                 :       61715 :   invoc_data.set_expander (this);
     286                 :             : 
     287                 :             :   // lookup the rules
     288                 :       61715 :   auto rules_def = mappings.lookup_macro_invocation (invoc);
     289                 :             : 
     290                 :             :   // We special case the `offset_of!()` macro if the flag is here and manually
     291                 :             :   // resolve to the builtin transcriber we have specified
     292                 :       61715 :   auto assume_builtin_offset_of
     293                 :       61715 :     = flag_assume_builtin_offset_of
     294                 :          36 :       && (invoc.get_invoc_data ().get_path ().as_string () == "offset_of")
     295                 :       61733 :       && !rules_def;
     296                 :             : 
     297                 :             :   // TODO: This is *massive hack* which should be removed as we progress to
     298                 :             :   // Rust 1.71 when offset_of gets added to core
     299                 :       61715 :   if (assume_builtin_offset_of)
     300                 :             :     {
     301                 :          18 :       fragment = MacroBuiltin::offset_of_handler (invoc.get_locus (),
     302                 :             :                                                   invoc_data, semicolon)
     303                 :          54 :                    .value_or (AST::Fragment::create_empty ());
     304                 :             : 
     305                 :          18 :       set_expanded_fragment (std::move (fragment));
     306                 :             : 
     307                 :          18 :       return;
     308                 :             :     }
     309                 :             : 
     310                 :             :   // If there's no rule associated with the invocation, we can simply return
     311                 :             :   // early. The early name resolver will have already emitted an error.
     312                 :       61697 :   if (!rules_def)
     313                 :             :     return;
     314                 :             : 
     315                 :       61676 :   auto rdef = rules_def.value ();
     316                 :             : 
     317                 :             :   // We store the last expanded invocation and macro definition for error
     318                 :             :   // reporting in case the recursion limit is reached
     319                 :       61676 :   last_invoc = *invoc.clone_macro_invocation_impl ();
     320                 :       61676 :   last_def = *rdef;
     321                 :             : 
     322                 :       61676 :   if (rdef->is_builtin ())
     323                 :        6478 :     fragment = rdef
     324                 :        6478 :                  ->get_builtin_transcriber () (invoc.get_locus (), invoc_data,
     325                 :             :                                                semicolon)
     326                 :       19434 :                  .value_or (AST::Fragment::create_empty ());
     327                 :             :   else
     328                 :       55198 :     fragment
     329                 :      110396 :       = expand_decl_macro (invoc.get_locus (), invoc_data, *rdef, semicolon);
     330                 :             : 
     331                 :       61676 :   set_expanded_fragment (std::move (fragment));
     332                 :       61715 : }
     333                 :             : 
     334                 :             : void
     335                 :           0 : MacroExpander::expand_crate ()
     336                 :             : {
     337                 :           0 :   NodeId scope_node_id = crate.get_node_id ();
     338                 :           0 :   resolver->get_macro_scope ().push (scope_node_id);
     339                 :             : 
     340                 :             :   /* fill macro/decorator map from init list? not sure where init list comes
     341                 :             :    * from? */
     342                 :             : 
     343                 :             :   // TODO: does cfg apply for inner attributes? research.
     344                 :             :   // the apparent answer (from playground test) is yes
     345                 :             : 
     346                 :           0 :   push_context (ContextType::ITEM);
     347                 :             : 
     348                 :             :   // expand attributes recursively and strip items if required
     349                 :             :   //  AttrVisitor attr_visitor (*this);
     350                 :           0 :   auto &items = crate.items;
     351                 :           0 :   for (auto it = items.begin (); it != items.end ();)
     352                 :             :     {
     353                 :           0 :       auto &item = *it;
     354                 :             : 
     355                 :           0 :       auto fragment = take_expanded_fragment ();
     356                 :           0 :       if (fragment.should_expand ())
     357                 :             :         {
     358                 :             :           // Remove the current expanded invocation
     359                 :           0 :           it = items.erase (it);
     360                 :           0 :           for (auto &node : fragment.get_nodes ())
     361                 :             :             {
     362                 :           0 :               it = items.insert (it, node.take_item ());
     363                 :           0 :               it++;
     364                 :             :             }
     365                 :             :         }
     366                 :           0 :       else if (item->is_marked_for_strip ())
     367                 :           0 :         it = items.erase (it);
     368                 :             :       else
     369                 :           0 :         it++;
     370                 :           0 :     }
     371                 :             : 
     372                 :           0 :   pop_context ();
     373                 :             : 
     374                 :             :   // TODO: should recursive attribute and macro expansion be done in the same
     375                 :             :   // transversal? Or in separate ones like currently?
     376                 :             : 
     377                 :             :   // expand module tree recursively
     378                 :             : 
     379                 :             :   // post-process
     380                 :             : 
     381                 :             :   // extract exported macros?
     382                 :           0 : }
     383                 :             : 
     384                 :             : bool
     385                 :      122755 : MacroExpander::depth_exceeds_recursion_limit () const
     386                 :             : {
     387                 :      122755 :   return expansion_depth >= cfg.recursion_limit;
     388                 :             : }
     389                 :             : 
     390                 :             : bool
     391                 :       58948 : MacroExpander::try_match_rule (AST::MacroRule &match_rule,
     392                 :             :                                AST::DelimTokenTree &invoc_token_tree)
     393                 :             : {
     394                 :       58948 :   MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
     395                 :       58948 :   Parser<MacroInvocLexer> parser (lex);
     396                 :             : 
     397                 :       58948 :   AST::MacroMatcher &matcher = match_rule.get_matcher ();
     398                 :             : 
     399                 :       58948 :   expansion_depth++;
     400                 :       58948 :   if (!match_matcher (parser, matcher, false, false))
     401                 :             :     {
     402                 :        3757 :       expansion_depth--;
     403                 :        3757 :       return false;
     404                 :             :     }
     405                 :       55191 :   expansion_depth--;
     406                 :             : 
     407                 :       55191 :   bool used_all_input_tokens = parser.skip_token (END_OF_FILE);
     408                 :       55191 :   return used_all_input_tokens;
     409                 :       58948 : }
     410                 :             : 
     411                 :             : bool
     412                 :      206269 : MacroExpander::match_fragment (Parser<MacroInvocLexer> &parser,
     413                 :             :                                AST::MacroMatchFragment &fragment)
     414                 :             : {
     415                 :      206269 :   switch (fragment.get_frag_spec ().get_kind ())
     416                 :             :     {
     417                 :      157460 :     case AST::MacroFragSpec::EXPR:
     418                 :      157460 :       parser.parse_expr ();
     419                 :      157460 :       break;
     420                 :             : 
     421                 :          11 :     case AST::MacroFragSpec::BLOCK:
     422                 :          11 :       parser.parse_block_expr ();
     423                 :          11 :       break;
     424                 :             : 
     425                 :       13318 :     case AST::MacroFragSpec::IDENT:
     426                 :       13318 :       parser.parse_identifier_or_keyword_token ();
     427                 :       13318 :       break;
     428                 :             : 
     429                 :        3768 :     case AST::MacroFragSpec::LITERAL:
     430                 :        3768 :       parser.parse_literal_expr ();
     431                 :        3768 :       break;
     432                 :             : 
     433                 :           1 :     case AST::MacroFragSpec::ITEM:
     434                 :           1 :       parser.parse_item (false);
     435                 :           1 :       break;
     436                 :             : 
     437                 :       11386 :     case AST::MacroFragSpec::TY:
     438                 :       11386 :       parser.parse_type ();
     439                 :       11386 :       break;
     440                 :             : 
     441                 :          56 :     case AST::MacroFragSpec::PAT:
     442                 :          56 :       parser.parse_pattern ();
     443                 :          56 :       break;
     444                 :             : 
     445                 :           3 :     case AST::MacroFragSpec::PATH:
     446                 :           3 :       parser.parse_path_in_expression ();
     447                 :           3 :       break;
     448                 :             : 
     449                 :           0 :     case AST::MacroFragSpec::VIS:
     450                 :           0 :       parser.parse_visibility ();
     451                 :           0 :       break;
     452                 :             : 
     453                 :         301 :     case AST::MacroFragSpec::STMT:
     454                 :         301 :       {
     455                 :         301 :         auto restrictions = ParseRestrictions ();
     456                 :         301 :         restrictions.consume_semi = false;
     457                 :         301 :         parser.parse_stmt (restrictions);
     458                 :         301 :         break;
     459                 :             :       }
     460                 :             : 
     461                 :          17 :     case AST::MacroFragSpec::LIFETIME:
     462                 :          17 :       parser.parse_lifetime_params ();
     463                 :          17 :       break;
     464                 :             : 
     465                 :             :       // is meta attributes?
     466                 :        1786 :     case AST::MacroFragSpec::META:
     467                 :        1786 :       parser.parse_attribute_body ();
     468                 :        1786 :       break;
     469                 :             : 
     470                 :       18162 :     case AST::MacroFragSpec::TT:
     471                 :       18162 :       parser.parse_token_tree ();
     472                 :       18162 :       break;
     473                 :             : 
     474                 :             :       // i guess we just ignore invalid and just error out
     475                 :             :     case AST::MacroFragSpec::INVALID:
     476                 :             :       return false;
     477                 :             :     }
     478                 :             : 
     479                 :             :   // it matches if the parser did not produce errors trying to parse that type
     480                 :             :   // of item
     481                 :      206269 :   return !parser.has_errors ();
     482                 :             : }
     483                 :             : 
     484                 :             : bool
     485                 :       61040 : MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
     486                 :             :                               AST::MacroMatcher &matcher, bool in_repetition,
     487                 :             :                               bool match_delim)
     488                 :             : {
     489                 :       61040 :   if (depth_exceeds_recursion_limit ())
     490                 :             :     {
     491                 :           0 :       rust_error_at (matcher.get_match_locus (), "reached recursion limit");
     492                 :           0 :       return false;
     493                 :             :     }
     494                 :             : 
     495                 :       61040 :   auto delimiter = parser.peek_current_token ();
     496                 :             : 
     497                 :      122038 :   auto check_delim = [&matcher, match_delim] (AST::DelimType delim) {
     498                 :        2050 :     return !match_delim || matcher.get_delim_type () == delim;
     499                 :       61040 :   };
     500                 :             : 
     501                 :             :   // this is used so we can check that we delimit the stream correctly.
     502                 :       61040 :   switch (delimiter->get_id ())
     503                 :             :     {
     504                 :       55340 :     case LEFT_PAREN:
     505                 :       55340 :       {
     506                 :       55340 :         if (!check_delim (AST::DelimType::PARENS))
     507                 :             :           return false;
     508                 :             :       }
     509                 :             :       break;
     510                 :             : 
     511                 :        1855 :     case LEFT_SQUARE:
     512                 :        1855 :       {
     513                 :        1855 :         if (!check_delim (AST::DelimType::SQUARE))
     514                 :             :           return false;
     515                 :             :       }
     516                 :             :       break;
     517                 :             : 
     518                 :        3803 :     case LEFT_CURLY:
     519                 :        3803 :       {
     520                 :        7603 :         if (!check_delim (AST::DelimType::CURLY))
     521                 :             :           return false;
     522                 :             :       }
     523                 :             :       break;
     524                 :             :     default:
     525                 :             :       return false;
     526                 :             :     }
     527                 :       60997 :   parser.skip_token ();
     528                 :             : 
     529                 :       60997 :   const MacroInvocLexer &source = parser.get_token_source ();
     530                 :             : 
     531                 :      368607 :   for (auto &match : matcher.get_matches ())
     532                 :             :     {
     533                 :      308107 :       size_t offs_begin = source.get_offs ();
     534                 :             : 
     535                 :      308107 :       switch (match->get_macro_match_type ())
     536                 :             :         {
     537                 :      175828 :         case AST::MacroMatch::MacroMatchType::Fragment:
     538                 :      175828 :           {
     539                 :      175828 :             AST::MacroMatchFragment *fragment
     540                 :      175828 :               = static_cast<AST::MacroMatchFragment *> (match.get ());
     541                 :      175828 :             if (!match_fragment (parser, *fragment))
     542                 :       61040 :               return false;
     543                 :             : 
     544                 :             :             // matched fragment get the offset in the token stream
     545                 :      175823 :             size_t offs_end = source.get_offs ();
     546                 :      351646 :             sub_stack.insert_metavar (
     547                 :      351646 :               MatchedFragment (fragment->get_ident ().as_string (), offs_begin,
     548                 :      527469 :                                offs_end));
     549                 :             :           }
     550                 :      175823 :           break;
     551                 :             : 
     552                 :      126026 :         case AST::MacroMatch::MacroMatchType::Tok:
     553                 :      126026 :           {
     554                 :      126026 :             AST::Token *tok = static_cast<AST::Token *> (match.get ());
     555                 :      126026 :             if (!match_token (parser, *tok))
     556                 :             :               return false;
     557                 :             :           }
     558                 :             :           break;
     559                 :             : 
     560                 :        4718 :         case AST::MacroMatch::MacroMatchType::Repetition:
     561                 :        4718 :           {
     562                 :        4718 :             AST::MacroMatchRepetition *rep
     563                 :        4718 :               = static_cast<AST::MacroMatchRepetition *> (match.get ());
     564                 :        4718 :             if (!match_repetition (parser, *rep))
     565                 :             :               return false;
     566                 :             :           }
     567                 :             :           break;
     568                 :             : 
     569                 :        1535 :         case AST::MacroMatch::MacroMatchType::Matcher:
     570                 :        1535 :           {
     571                 :        1535 :             AST::MacroMatcher *m
     572                 :        1535 :               = static_cast<AST::MacroMatcher *> (match.get ());
     573                 :        1535 :             expansion_depth++;
     574                 :        1535 :             if (!match_matcher (parser, *m, in_repetition))
     575                 :             :               {
     576                 :           3 :                 expansion_depth--;
     577                 :           3 :                 return false;
     578                 :             :               }
     579                 :        1532 :             expansion_depth--;
     580                 :             :           }
     581                 :        1532 :           break;
     582                 :             :         }
     583                 :             :     }
     584                 :             : 
     585                 :       60500 :   switch (delimiter->get_id ())
     586                 :             :     {
     587                 :       54951 :     case LEFT_PAREN:
     588                 :       54951 :       {
     589                 :       54951 :         if (!parser.skip_token (RIGHT_PAREN))
     590                 :             :           return false;
     591                 :             :       }
     592                 :             :       break;
     593                 :             : 
     594                 :        1855 :     case LEFT_SQUARE:
     595                 :        1855 :       {
     596                 :        1855 :         if (!parser.skip_token (RIGHT_SQUARE))
     597                 :             :           return false;
     598                 :             :       }
     599                 :             :       break;
     600                 :             : 
     601                 :        3694 :     case LEFT_CURLY:
     602                 :        3694 :       {
     603                 :        3694 :         if (!parser.skip_token (RIGHT_CURLY))
     604                 :             :           return false;
     605                 :             :       }
     606                 :             :       break;
     607                 :           0 :     default:
     608                 :           0 :       rust_unreachable ();
     609                 :             :     }
     610                 :             : 
     611                 :             :   return true;
     612                 :       61040 : }
     613                 :             : 
     614                 :             : bool
     615                 :      134761 : MacroExpander::match_token (Parser<MacroInvocLexer> &parser, AST::Token &token)
     616                 :             : {
     617                 :      269522 :   return parser.skip_token (token.get_tok_ptr ());
     618                 :             : }
     619                 :             : 
     620                 :             : bool
     621                 :        4781 : MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser,
     622                 :             :                                 AST::MacroMatchRepetition &rep,
     623                 :             :                                 size_t &match_amount, size_t lo_bound,
     624                 :             :                                 size_t hi_bound)
     625                 :             : {
     626                 :        4781 :   match_amount = 0;
     627                 :        4781 :   auto &matches = rep.get_matches ();
     628                 :             : 
     629                 :        4781 :   const MacroInvocLexer &source = parser.get_token_source ();
     630                 :       62597 :   while (true)
     631                 :             :     {
     632                 :             :       // If the current token is a closing macro delimiter, break away.
     633                 :             :       // TODO: Is this correct?
     634                 :       33689 :       auto t_id = parser.peek_current_token ()->get_id ();
     635                 :       33689 :       if (t_id == RIGHT_PAREN || t_id == RIGHT_SQUARE || t_id == RIGHT_CURLY)
     636                 :             :         break;
     637                 :             : 
     638                 :             :       // Skip parsing a separator on the first match, otherwise consume it.
     639                 :             :       // If it isn't present, this is an error
     640                 :       29149 :       if (rep.has_sep () && match_amount > 0)
     641                 :        3046 :         if (!match_token (parser, *rep.get_sep ()))
     642                 :             :           break;
     643                 :             : 
     644                 :       29071 :       sub_stack.push ();
     645                 :       29071 :       bool valid_current_match = false;
     646                 :       65821 :       for (auto &match : matches)
     647                 :             :         {
     648                 :       36750 :           size_t offs_begin = source.get_offs ();
     649                 :       36750 :           switch (match->get_macro_match_type ())
     650                 :             :             {
     651                 :       30441 :             case AST::MacroMatch::MacroMatchType::Fragment:
     652                 :       30441 :               {
     653                 :       30441 :                 AST::MacroMatchFragment *fragment
     654                 :       30441 :                   = static_cast<AST::MacroMatchFragment *> (match.get ());
     655                 :       30441 :                 valid_current_match = match_fragment (parser, *fragment);
     656                 :             : 
     657                 :             :                 // matched fragment get the offset in the token stream
     658                 :       30441 :                 size_t offs_end = source.get_offs ();
     659                 :             : 
     660                 :       30441 :                 if (valid_current_match)
     661                 :       60852 :                   sub_stack.insert_metavar (
     662                 :       60852 :                     MatchedFragment (fragment->get_ident ().as_string (),
     663                 :       91278 :                                      offs_begin, offs_end));
     664                 :             :               }
     665                 :             :               break;
     666                 :             : 
     667                 :        5689 :             case AST::MacroMatch::MacroMatchType::Tok:
     668                 :        5689 :               {
     669                 :        5689 :                 AST::Token *tok = static_cast<AST::Token *> (match.get ());
     670                 :        5689 :                 valid_current_match = match_token (parser, *tok);
     671                 :             :               }
     672                 :        5689 :               break;
     673                 :             : 
     674                 :          63 :             case AST::MacroMatch::MacroMatchType::Repetition:
     675                 :          63 :               {
     676                 :          63 :                 AST::MacroMatchRepetition *rep
     677                 :          63 :                   = static_cast<AST::MacroMatchRepetition *> (match.get ());
     678                 :          63 :                 valid_current_match = match_repetition (parser, *rep);
     679                 :             :               }
     680                 :          63 :               break;
     681                 :             : 
     682                 :         557 :             case AST::MacroMatch::MacroMatchType::Matcher:
     683                 :         557 :               {
     684                 :         557 :                 AST::MacroMatcher *m
     685                 :         557 :                   = static_cast<AST::MacroMatcher *> (match.get ());
     686                 :         557 :                 valid_current_match = match_matcher (parser, *m, true);
     687                 :             :               }
     688                 :         557 :               break;
     689                 :             :             }
     690                 :             :         }
     691                 :       29071 :       auto old_stack = sub_stack.pop ();
     692                 :             : 
     693                 :             :       // If we've encountered an error once, stop trying to match more
     694                 :             :       // repetitions
     695                 :       29071 :       if (!valid_current_match)
     696                 :             :         break;
     697                 :             : 
     698                 :             :       // nest metavars into repetitions
     699                 :       59924 :       for (auto &ent : old_stack)
     700                 :       62030 :         sub_stack.append_fragment (ent.first, std::move (ent.second));
     701                 :             : 
     702                 :       28909 :       match_amount++;
     703                 :             : 
     704                 :             :       // Break early if we notice there's too many expressions already
     705                 :       28909 :       if (hi_bound && match_amount > hi_bound)
     706                 :             :         break;
     707                 :       29071 :     }
     708                 :             : 
     709                 :             :   // Check if the amount of matches we got is valid: Is it more than the lower
     710                 :             :   // bound and less than the higher bound?
     711                 :        4781 :   bool did_meet_lo_bound = match_amount >= lo_bound;
     712                 :        4781 :   bool did_meet_hi_bound = hi_bound ? match_amount <= hi_bound : true;
     713                 :             : 
     714                 :             :   // If the end-result is valid, then we can clear the parse errors: Since
     715                 :             :   // repetitions are parsed eagerly, it is okay to fail in some cases
     716                 :        9561 :   auto res = did_meet_lo_bound && did_meet_hi_bound;
     717                 :        4780 :   if (res)
     718                 :        4766 :     parser.clear_errors ();
     719                 :             : 
     720                 :        4781 :   return res;
     721                 :             : }
     722                 :             : 
     723                 :             : /*
     724                 :             :  * Helper function for defining unmatched repetition metavars
     725                 :             :  */
     726                 :             : void
     727                 :        7457 : MacroExpander::match_repetition_skipped_metavars (AST::MacroMatch &match)
     728                 :             : {
     729                 :             :   // We have to handle zero fragments differently: They will not have been
     730                 :             :   // "matched" but they are still valid and should be inserted as a special
     731                 :             :   // case. So we go through the stack map, and for every fragment which doesn't
     732                 :             :   // exist, insert a zero-matched fragment.
     733                 :        7457 :   switch (match.get_macro_match_type ())
     734                 :             :     {
     735                 :        4871 :     case AST::MacroMatch::MacroMatchType::Fragment:
     736                 :        4871 :       match_repetition_skipped_metavars (
     737                 :             :         static_cast<AST::MacroMatchFragment &> (match));
     738                 :        4871 :       break;
     739                 :          29 :     case AST::MacroMatch::MacroMatchType::Repetition:
     740                 :          29 :       match_repetition_skipped_metavars (
     741                 :             :         static_cast<AST::MacroMatchRepetition &> (match));
     742                 :          29 :       break;
     743                 :          76 :     case AST::MacroMatch::MacroMatchType::Matcher:
     744                 :          76 :       match_repetition_skipped_metavars (
     745                 :             :         static_cast<AST::MacroMatcher &> (match));
     746                 :          76 :       break;
     747                 :             :     case AST::MacroMatch::MacroMatchType::Tok:
     748                 :             :       break;
     749                 :             :     }
     750                 :        7457 : }
     751                 :             : 
     752                 :             : void
     753                 :        4871 : MacroExpander::match_repetition_skipped_metavars (
     754                 :             :   AST::MacroMatchFragment &fragment)
     755                 :             : {
     756                 :        4871 :   auto &stack_map = sub_stack.peek ();
     757                 :        4871 :   auto it = stack_map.find (fragment.get_ident ().as_string ());
     758                 :             : 
     759                 :        4871 :   if (it == stack_map.end ())
     760                 :         256 :     sub_stack.insert_matches (fragment.get_ident ().as_string (),
     761                 :         256 :                               MatchedFragmentContainer::zero ());
     762                 :        4871 : }
     763                 :             : 
     764                 :             : void
     765                 :        4810 : MacroExpander::match_repetition_skipped_metavars (
     766                 :             :   AST::MacroMatchRepetition &rep)
     767                 :             : {
     768                 :       12194 :   for (auto &match : rep.get_matches ())
     769                 :        7384 :     match_repetition_skipped_metavars (*match);
     770                 :        4810 : }
     771                 :             : 
     772                 :             : void
     773                 :          76 : MacroExpander::match_repetition_skipped_metavars (AST::MacroMatcher &rep)
     774                 :             : {
     775                 :         149 :   for (auto &match : rep.get_matches ())
     776                 :          73 :     match_repetition_skipped_metavars (*match);
     777                 :          76 : }
     778                 :             : 
     779                 :             : bool
     780                 :        4781 : MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser,
     781                 :             :                                  AST::MacroMatchRepetition &rep)
     782                 :             : {
     783                 :        4781 :   size_t match_amount = 0;
     784                 :        4781 :   bool res = false;
     785                 :             : 
     786                 :        4781 :   std::string lo_str;
     787                 :        4781 :   std::string hi_str;
     788                 :        4781 :   switch (rep.get_op ())
     789                 :             :     {
     790                 :        3191 :     case AST::MacroMatchRepetition::MacroRepOp::ANY:
     791                 :        3191 :       lo_str = "0";
     792                 :        3191 :       hi_str = "+inf";
     793                 :        3191 :       res = match_n_matches (parser, rep, match_amount);
     794                 :        3191 :       break;
     795                 :        1102 :     case AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE:
     796                 :        1102 :       lo_str = "1";
     797                 :        1102 :       hi_str = "+inf";
     798                 :        1102 :       res = match_n_matches (parser, rep, match_amount, 1);
     799                 :        1102 :       break;
     800                 :         488 :     case AST::MacroMatchRepetition::MacroRepOp::ZERO_OR_ONE:
     801                 :         488 :       lo_str = "0";
     802                 :         488 :       hi_str = "1";
     803                 :         488 :       res = match_n_matches (parser, rep, match_amount, 0, 1);
     804                 :         488 :       break;
     805                 :           0 :     default:
     806                 :           0 :       rust_unreachable ();
     807                 :             :     }
     808                 :             : 
     809                 :        4796 :   rust_debug_loc (rep.get_match_locus (), "%s matched %lu times",
     810                 :             :                   res ? "successfully" : "unsuccessfully",
     811                 :             :                   (unsigned long) match_amount);
     812                 :             : 
     813                 :        4781 :   match_repetition_skipped_metavars (rep);
     814                 :             : 
     815                 :        4781 :   return res;
     816                 :        4781 : }
     817                 :             : 
     818                 :             : /**
     819                 :             :  * Helper function to refactor calling a parsing function 0 or more times
     820                 :             :  */
     821                 :             : static AST::Fragment
     822                 :        5432 : parse_many (Parser<MacroInvocLexer> &parser, TokenId delimiter,
     823                 :             :             std::function<AST::SingleASTNode ()> parse_fn)
     824                 :             : {
     825                 :        5432 :   auto &lexer = parser.get_token_source ();
     826                 :        5432 :   auto start = lexer.get_offs ();
     827                 :             : 
     828                 :        5432 :   std::vector<AST::SingleASTNode> nodes;
     829                 :       13594 :   while (true)
     830                 :             :     {
     831                 :       38052 :       if (parser.peek_current_token ()->get_id () == delimiter)
     832                 :             :         break;
     833                 :             : 
     834                 :       13598 :       auto node = parse_fn ();
     835                 :       13598 :       if (node.is_error ())
     836                 :             :         {
     837                 :           9 :           for (auto err : parser.get_errors ())
     838                 :           5 :             err.emit ();
     839                 :             : 
     840                 :           4 :           return AST::Fragment::create_error ();
     841                 :             :         }
     842                 :             : 
     843                 :       13594 :       nodes.emplace_back (std::move (node));
     844                 :       13598 :     }
     845                 :        5428 :   auto end = lexer.get_offs ();
     846                 :             : 
     847                 :        5428 :   return AST::Fragment (std::move (nodes), lexer.get_token_slice (start, end));
     848                 :        5432 : }
     849                 :             : 
     850                 :             : /**
     851                 :             :  * Transcribe 0 or more items from a macro invocation
     852                 :             :  *
     853                 :             :  * @param parser Parser to extract items from
     854                 :             :  * @param delimiter Id of the token on which parsing should stop
     855                 :             :  */
     856                 :             : static AST::Fragment
     857                 :        3755 : transcribe_many_items (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
     858                 :             : {
     859                 :        3755 :   return parse_many (parser, delimiter, [&parser] () {
     860                 :       10768 :     auto item = parser.parse_item (true);
     861                 :       10768 :     return AST::SingleASTNode (std::move (item));
     862                 :       14523 :   });
     863                 :             : }
     864                 :             : 
     865                 :             : /**
     866                 :             :  * Transcribe 0 or more external items from a macro invocation
     867                 :             :  *
     868                 :             :  * @param parser Parser to extract items from
     869                 :             :  * @param delimiter Id of the token on which parsing should stop
     870                 :             :  */
     871                 :             : static AST::Fragment
     872                 :           2 : transcribe_many_ext (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
     873                 :             : {
     874                 :           2 :   return parse_many (parser, delimiter, [&parser] () {
     875                 :           3 :     auto item = parser.parse_external_item ();
     876                 :           3 :     return AST::SingleASTNode (std::move (item));
     877                 :           5 :   });
     878                 :             : }
     879                 :             : 
     880                 :             : /**
     881                 :             :  * Transcribe 0 or more trait items from a macro invocation
     882                 :             :  *
     883                 :             :  * @param parser Parser to extract items from
     884                 :             :  * @param delimiter Id of the token on which parsing should stop
     885                 :             :  */
     886                 :             : static AST::Fragment
     887                 :           1 : transcribe_many_trait_items (Parser<MacroInvocLexer> &parser,
     888                 :             :                              TokenId &delimiter)
     889                 :             : {
     890                 :           1 :   return parse_many (parser, delimiter, [&parser] () {
     891                 :           2 :     auto item = parser.parse_trait_item ();
     892                 :           2 :     return AST::SingleASTNode (std::move (item));
     893                 :           3 :   });
     894                 :             : }
     895                 :             : 
     896                 :             : /**
     897                 :             :  * Transcribe 0 or more impl items from a macro invocation
     898                 :             :  *
     899                 :             :  * @param parser Parser to extract items from
     900                 :             :  * @param delimiter Id of the token on which parsing should stop
     901                 :             :  */
     902                 :             : static AST::Fragment
     903                 :        1087 : transcribe_many_impl_items (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
     904                 :             : {
     905                 :        1087 :   return parse_many (parser, delimiter, [&parser] () {
     906                 :        2006 :     auto item = parser.parse_inherent_impl_item ();
     907                 :        2006 :     return AST::SingleASTNode (std::move (item));
     908                 :        3093 :   });
     909                 :             : }
     910                 :             : 
     911                 :             : /**
     912                 :             :  * Transcribe 0 or more trait impl items from a macro invocation
     913                 :             :  *
     914                 :             :  * @param parser Parser to extract items from
     915                 :             :  * @param delimiter Id of the token on which parsing should stop
     916                 :             :  */
     917                 :             : static AST::Fragment
     918                 :          64 : transcribe_many_trait_impl_items (Parser<MacroInvocLexer> &parser,
     919                 :             :                                   TokenId &delimiter)
     920                 :             : {
     921                 :          64 :   return parse_many (parser, delimiter, [&parser] () {
     922                 :         220 :     auto item = parser.parse_trait_impl_item ();
     923                 :         220 :     return AST::SingleASTNode (std::move (item));
     924                 :         284 :   });
     925                 :             : }
     926                 :             : 
     927                 :             : /**
     928                 :             :  * Transcribe 0 or more statements from a macro invocation
     929                 :             :  *
     930                 :             :  * @param parser Parser to extract statements from
     931                 :             :  * @param delimiter Id of the token on which parsing should stop
     932                 :             :  */
     933                 :             : static AST::Fragment
     934                 :         523 : transcribe_many_stmts (Parser<MacroInvocLexer> &parser, TokenId delimiter,
     935                 :             :                        bool semicolon)
     936                 :             : {
     937                 :         523 :   auto restrictions = ParseRestrictions ();
     938                 :         523 :   restrictions.allow_close_after_expr_stmt = true;
     939                 :             : 
     940                 :         523 :   return parse_many (parser, delimiter,
     941                 :         523 :                      [&parser, restrictions, delimiter, semicolon] () {
     942                 :         599 :                        auto stmt = parser.parse_stmt (restrictions);
     943                 :         591 :                        if (semicolon && stmt
     944                 :        1778 :                            && parser.peek_current_token ()->get_id ()
     945                 :         588 :                                 == delimiter)
     946                 :         494 :                          stmt->add_semicolon ();
     947                 :             : 
     948                 :         599 :                        return AST::SingleASTNode (std::move (stmt));
     949                 :        1122 :                      });
     950                 :             : }
     951                 :             : 
     952                 :             : /**
     953                 :             :  * Transcribe one expression from a macro invocation
     954                 :             :  *
     955                 :             :  * @param parser Parser to extract statements from
     956                 :             :  */
     957                 :             : static AST::Fragment
     958                 :       49261 : transcribe_expression (Parser<MacroInvocLexer> &parser)
     959                 :             : {
     960                 :       49261 :   auto &lexer = parser.get_token_source ();
     961                 :       49261 :   auto start = lexer.get_offs ();
     962                 :             : 
     963                 :       49261 :   auto attrs = parser.parse_outer_attributes ();
     964                 :       49261 :   auto expr = parser.parse_expr (std::move (attrs));
     965                 :       49261 :   if (expr == nullptr)
     966                 :             :     {
     967                 :           2 :       for (auto error : parser.get_errors ())
     968                 :           1 :         error.emit ();
     969                 :           1 :       return AST::Fragment::create_error ();
     970                 :             :     }
     971                 :             : 
     972                 :             :   // FIXME: make this an error for some edititons
     973                 :       98520 :   if (parser.peek_current_token ()->get_id () == SEMICOLON)
     974                 :             :     {
     975                 :        6994 :       rust_warning_at (
     976                 :        6994 :         parser.peek_current_token ()->get_locus (), 0,
     977                 :             :         "trailing semicolon in macro used in expression context");
     978                 :        6994 :       parser.skip_token ();
     979                 :             :     }
     980                 :             : 
     981                 :       49260 :   auto end = lexer.get_offs ();
     982                 :             : 
     983                 :       98520 :   return AST::Fragment ({std::move (expr)}, lexer.get_token_slice (start, end));
     984                 :       49261 : }
     985                 :             : 
     986                 :             : /**
     987                 :             :  * Transcribe one type from a macro invocation
     988                 :             :  *
     989                 :             :  * @param parser Parser to extract statements from
     990                 :             :  */
     991                 :             : static AST::Fragment
     992                 :         497 : transcribe_type (Parser<MacroInvocLexer> &parser)
     993                 :             : {
     994                 :         497 :   auto &lexer = parser.get_token_source ();
     995                 :         497 :   auto start = lexer.get_offs ();
     996                 :             : 
     997                 :         497 :   auto type = parser.parse_type (true);
     998                 :         497 :   for (auto err : parser.get_errors ())
     999                 :           0 :     err.emit ();
    1000                 :             : 
    1001                 :         497 :   auto end = lexer.get_offs ();
    1002                 :             : 
    1003                 :         994 :   return AST::Fragment ({std::move (type)}, lexer.get_token_slice (start, end));
    1004                 :         497 : }
    1005                 :             : 
    1006                 :             : /**
    1007                 :             :  * Transcribe one pattern from a macro invocation
    1008                 :             :  *
    1009                 :             :  * @param parser Parser to extract statements from
    1010                 :             :  */
    1011                 :             : static AST::Fragment
    1012                 :           1 : transcribe_pattern (Parser<MacroInvocLexer> &parser)
    1013                 :             : {
    1014                 :           1 :   auto &lexer = parser.get_token_source ();
    1015                 :           1 :   auto start = lexer.get_offs ();
    1016                 :             : 
    1017                 :           1 :   auto pattern = parser.parse_pattern ();
    1018                 :           1 :   for (auto err : parser.get_errors ())
    1019                 :           0 :     err.emit ();
    1020                 :             : 
    1021                 :           1 :   auto end = lexer.get_offs ();
    1022                 :             : 
    1023                 :           2 :   return AST::Fragment ({std::move (pattern)},
    1024                 :           3 :                         lexer.get_token_slice (start, end));
    1025                 :           1 : }
    1026                 :             : 
    1027                 :             : static AST::Fragment
    1028                 :       55191 : transcribe_context (MacroExpander::ContextType ctx,
    1029                 :             :                     Parser<MacroInvocLexer> &parser, bool semicolon,
    1030                 :             :                     AST::DelimType delimiter, TokenId last_token_id)
    1031                 :             : {
    1032                 :             :   // The flow-chart in order to choose a parsing function is as follows:
    1033                 :             :   //
    1034                 :             :   // [switch special context]
    1035                 :             :   //     -- Item --> parser.parse_item();
    1036                 :             :   //     -- Trait --> parser.parse_trait_item();
    1037                 :             :   //     -- Impl --> parser.parse_impl_item();
    1038                 :             :   //     -- Extern --> parser.parse_extern_item();
    1039                 :             :   //     -- Pattern --> parser.parse_pattern();
    1040                 :             :   //     -- None --> [has semicolon?]
    1041                 :             :   //                 -- Yes --> parser.parse_stmt();
    1042                 :             :   //                 -- No --> [switch invocation.delimiter()]
    1043                 :             :   //                             -- { } --> parser.parse_stmt();
    1044                 :             :   //                             -- _ --> parser.parse_expr(); // once!
    1045                 :             : 
    1046                 :             :   // If there is a semicolon OR we are expanding a MacroInvocationSemi, then
    1047                 :             :   // we can parse multiple items. Otherwise, parse *one* expression
    1048                 :             : 
    1049                 :       55191 :   switch (ctx)
    1050                 :             :     {
    1051                 :        3755 :     case MacroExpander::ContextType::ITEM:
    1052                 :        3755 :       return transcribe_many_items (parser, last_token_id);
    1053                 :           1 :       break;
    1054                 :           1 :     case MacroExpander::ContextType::TRAIT:
    1055                 :           1 :       return transcribe_many_trait_items (parser, last_token_id);
    1056                 :        1087 :       break;
    1057                 :        1087 :     case MacroExpander::ContextType::IMPL:
    1058                 :        1087 :       return transcribe_many_impl_items (parser, last_token_id);
    1059                 :          64 :       break;
    1060                 :          64 :     case MacroExpander::ContextType::TRAIT_IMPL:
    1061                 :          64 :       return transcribe_many_trait_impl_items (parser, last_token_id);
    1062                 :           2 :       break;
    1063                 :           2 :     case MacroExpander::ContextType::EXTERN:
    1064                 :           2 :       return transcribe_many_ext (parser, last_token_id);
    1065                 :         497 :       break;
    1066                 :         497 :     case MacroExpander::ContextType::TYPE:
    1067                 :         497 :       return transcribe_type (parser);
    1068                 :           1 :     case MacroExpander::ContextType::PATTERN:
    1069                 :           1 :       return transcribe_pattern (parser);
    1070                 :         523 :       break;
    1071                 :         523 :     case MacroExpander::ContextType::STMT:
    1072                 :         523 :       return transcribe_many_stmts (parser, last_token_id, semicolon);
    1073                 :       49261 :     case MacroExpander::ContextType::EXPR:
    1074                 :       49261 :       return transcribe_expression (parser);
    1075                 :           0 :     default:
    1076                 :           0 :       rust_unreachable ();
    1077                 :             :     }
    1078                 :             : }
    1079                 :             : 
    1080                 :             : static std::string
    1081                 :       55191 : tokens_to_str (std::vector<std::unique_ptr<AST::Token>> &tokens)
    1082                 :             : {
    1083                 :       55191 :   std::string str;
    1084                 :       55191 :   if (!tokens.empty ())
    1085                 :             :     {
    1086                 :      110382 :       str += tokens[0]->as_string ();
    1087                 :     2265411 :       for (size_t i = 1; i < tokens.size (); i++)
    1088                 :     4420440 :         str += " " + tokens[i]->as_string ();
    1089                 :             :     }
    1090                 :             : 
    1091                 :       55191 :   return str;
    1092                 :             : }
    1093                 :             : 
    1094                 :             : AST::Fragment
    1095                 :       55191 : MacroExpander::transcribe_rule (
    1096                 :             :   AST::MacroRulesDefinition &definition, AST::MacroRule &match_rule,
    1097                 :             :   AST::DelimTokenTree &invoc_token_tree,
    1098                 :             :   std::map<std::string, MatchedFragmentContainer *> &matched_fragments,
    1099                 :             :   AST::InvocKind invoc_kind, ContextType ctx)
    1100                 :             : {
    1101                 :       55191 :   bool semicolon = invoc_kind == AST::InvocKind::Semicoloned;
    1102                 :             : 
    1103                 :             :   // we can manipulate the token tree to substitute the dollar identifiers so
    1104                 :             :   // that when we call parse its already substituted for us
    1105                 :       55191 :   AST::MacroTranscriber &transcriber = match_rule.get_transcriber ();
    1106                 :       55191 :   AST::DelimTokenTree &transcribe_tree = transcriber.get_token_tree ();
    1107                 :             : 
    1108                 :       55191 :   auto invoc_stream = invoc_token_tree.to_token_stream ();
    1109                 :       55191 :   auto macro_rule_tokens = transcribe_tree.to_token_stream ();
    1110                 :             : 
    1111                 :       55191 :   auto substitute_context
    1112                 :             :     = SubstituteCtx (invoc_stream, macro_rule_tokens, matched_fragments,
    1113                 :       55191 :                      definition, invoc_token_tree.get_locus ());
    1114                 :       55191 :   std::vector<std::unique_ptr<AST::Token>> substituted_tokens
    1115                 :       55191 :     = substitute_context.substitute_tokens ();
    1116                 :             : 
    1117                 :       55191 :   rust_debug ("substituted tokens: %s",
    1118                 :             :               tokens_to_str (substituted_tokens).c_str ());
    1119                 :             : 
    1120                 :             :   // parse it to an Fragment
    1121                 :       55191 :   MacroInvocLexer lex (std::move (substituted_tokens));
    1122                 :       55191 :   Parser<MacroInvocLexer> parser (lex);
    1123                 :             : 
    1124                 :       55191 :   auto last_token_id = TokenId::RIGHT_CURLY;
    1125                 :             : 
    1126                 :             :   // this is used so we can check that we delimit the stream correctly.
    1127                 :       55191 :   switch (transcribe_tree.get_delim_type ())
    1128                 :             :     {
    1129                 :         655 :     case AST::DelimType::PARENS:
    1130                 :         655 :       last_token_id = TokenId::RIGHT_PAREN;
    1131                 :         655 :       rust_assert (parser.skip_token (LEFT_PAREN));
    1132                 :             :       break;
    1133                 :             : 
    1134                 :       54536 :     case AST::DelimType::CURLY:
    1135                 :       54536 :       rust_assert (parser.skip_token (LEFT_CURLY));
    1136                 :             :       break;
    1137                 :             : 
    1138                 :           0 :     case AST::DelimType::SQUARE:
    1139                 :           0 :       last_token_id = TokenId::RIGHT_SQUARE;
    1140                 :           0 :       rust_assert (parser.skip_token (LEFT_SQUARE));
    1141                 :             :       break;
    1142                 :             :     }
    1143                 :             : 
    1144                 :             :   // see https://github.com/Rust-GCC/gccrs/issues/22
    1145                 :             :   // TL;DR:
    1146                 :             :   //   - Treat all macro invocations with parentheses, (), or square brackets,
    1147                 :             :   //   [], as expressions.
    1148                 :             :   //   - If the macro invocation has curly brackets, {}, it may be parsed as a
    1149                 :             :   //   statement depending on the context.
    1150                 :             :   //   - If the macro invocation has a semicolon at the end, it must be parsed
    1151                 :             :   //   as a statement (either via ExpressionStatement or
    1152                 :             :   //   MacroInvocationWithSemi)
    1153                 :             : 
    1154                 :       55191 :   auto fragment
    1155                 :             :     = transcribe_context (ctx, parser, semicolon,
    1156                 :       55191 :                           invoc_token_tree.get_delim_type (), last_token_id);
    1157                 :             : 
    1158                 :             :   // emit any errors
    1159                 :       55191 :   if (parser.has_errors ())
    1160                 :           5 :     return AST::Fragment::create_error ();
    1161                 :             : 
    1162                 :             :   // are all the tokens used?
    1163                 :       55186 :   bool did_delimit = parser.skip_token (last_token_id);
    1164                 :             : 
    1165                 :       55186 :   bool reached_end_of_stream = did_delimit && parser.skip_token (END_OF_FILE);
    1166                 :           0 :   if (!reached_end_of_stream)
    1167                 :             :     {
    1168                 :             :       // FIXME: rustc has some cases it accepts this with a warning due to
    1169                 :             :       // backwards compatibility.
    1170                 :           0 :       const_TokenPtr current_token = parser.peek_current_token ();
    1171                 :           0 :       rust_error_at (current_token->get_locus (),
    1172                 :             :                      "tokens here and after are unparsed");
    1173                 :           0 :     }
    1174                 :             : 
    1175                 :       55186 :   return fragment;
    1176                 :      110382 : }
    1177                 :             : 
    1178                 :             : AST::Fragment
    1179                 :           0 : MacroExpander::parse_proc_macro_output (ProcMacro::TokenStream ts)
    1180                 :             : {
    1181                 :           0 :   ProcMacroInvocLexer lex (convert (ts));
    1182                 :           0 :   Parser<ProcMacroInvocLexer> parser (lex);
    1183                 :             : 
    1184                 :           0 :   std::vector<AST::SingleASTNode> nodes;
    1185                 :           0 :   switch (peek_context ())
    1186                 :             :     {
    1187                 :             :     case ContextType::ITEM:
    1188                 :           0 :       while (lex.peek_token ()->get_id () != END_OF_FILE)
    1189                 :             :         {
    1190                 :           0 :           auto result = parser.parse_item (false);
    1191                 :           0 :           if (result == nullptr)
    1192                 :             :             break;
    1193                 :           0 :           nodes.emplace_back (std::move (result));
    1194                 :           0 :         }
    1195                 :             :       break;
    1196                 :             :     case ContextType::STMT:
    1197                 :           0 :       while (lex.peek_token ()->get_id () != END_OF_FILE)
    1198                 :             :         {
    1199                 :           0 :           auto result = parser.parse_stmt ();
    1200                 :           0 :           if (result == nullptr)
    1201                 :             :             break;
    1202                 :           0 :           nodes.emplace_back (std::move (result));
    1203                 :           0 :         }
    1204                 :             :       break;
    1205                 :           0 :     case ContextType::TRAIT:
    1206                 :           0 :     case ContextType::IMPL:
    1207                 :           0 :     case ContextType::TRAIT_IMPL:
    1208                 :           0 :     case ContextType::EXTERN:
    1209                 :           0 :     case ContextType::TYPE:
    1210                 :           0 :     case ContextType::EXPR:
    1211                 :           0 :     default:
    1212                 :           0 :       rust_unreachable ();
    1213                 :             :     }
    1214                 :             : 
    1215                 :           0 :   if (parser.has_errors ())
    1216                 :           0 :     return AST::Fragment::create_error ();
    1217                 :             :   else
    1218                 :           0 :     return {nodes, std::vector<std::unique_ptr<AST::Token>> ()};
    1219                 :           0 : }
    1220                 :             : 
    1221                 :             : MatchedFragment &
    1222                 :      344417 : MatchedFragmentContainer::get_single_fragment ()
    1223                 :             : {
    1224                 :      344417 :   rust_assert (is_single_fragment ());
    1225                 :             : 
    1226                 :      344417 :   return static_cast<MatchedFragmentContainerMetaVar &> (*this).get_fragment ();
    1227                 :             : }
    1228                 :             : 
    1229                 :             : std::vector<std::unique_ptr<MatchedFragmentContainer>> &
    1230                 :       87674 : MatchedFragmentContainer::get_fragments ()
    1231                 :             : {
    1232                 :       87674 :   rust_assert (!is_single_fragment ());
    1233                 :             : 
    1234                 :       87674 :   return static_cast<MatchedFragmentContainerRepetition &> (*this)
    1235                 :       87674 :     .get_fragments ();
    1236                 :             : }
    1237                 :             : 
    1238                 :             : void
    1239                 :           0 : MatchedFragmentContainer::add_fragment (MatchedFragment fragment)
    1240                 :             : {
    1241                 :           0 :   rust_assert (!is_single_fragment ());
    1242                 :             : 
    1243                 :           0 :   return static_cast<MatchedFragmentContainerRepetition &> (*this)
    1244                 :           0 :     .add_fragment (fragment);
    1245                 :             : }
    1246                 :             : 
    1247                 :             : void
    1248                 :       31015 : MatchedFragmentContainer::add_fragment (
    1249                 :             :   std::unique_ptr<MatchedFragmentContainer> fragment)
    1250                 :             : {
    1251                 :       31015 :   rust_assert (!is_single_fragment ());
    1252                 :             : 
    1253                 :       31015 :   return static_cast<MatchedFragmentContainerRepetition &> (*this)
    1254                 :       31015 :     .add_fragment (std::move (fragment));
    1255                 :             : }
    1256                 :             : 
    1257                 :             : std::unique_ptr<MatchedFragmentContainer>
    1258                 :         128 : MatchedFragmentContainer::zero ()
    1259                 :             : {
    1260                 :         128 :   return std::unique_ptr<MatchedFragmentContainer> (
    1261                 :         128 :     new MatchedFragmentContainerRepetition ());
    1262                 :             : }
    1263                 :             : 
    1264                 :             : std::unique_ptr<MatchedFragmentContainer>
    1265                 :      206249 : MatchedFragmentContainer::metavar (MatchedFragment fragment)
    1266                 :             : {
    1267                 :      206249 :   return std::unique_ptr<MatchedFragmentContainer> (
    1268                 :      206249 :     new MatchedFragmentContainerMetaVar (fragment));
    1269                 :             : }
    1270                 :             : 
    1271                 :             : } // namespace Rust
        

Generated by: LCOV version 2.1-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.