LCOV - code coverage report
Current view: top level - gcc/rust/parse - rust-parse-impl-macro.hxx (source / functions) Coverage Total Hit
Test: gcc.info Lines: 79.3 % 271 215
Test Date: 2026-08-22 16:33:35 Functions: 93.8 % 16 15
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2025-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : /* DO NOT INCLUDE ANYWHERE - this is automatically included
      20              :  *   by rust-parse-impl.h
      21              :  * This is also the reason why there are no include guards. */
      22              : 
      23              : #include "rust-parse.h"
      24              : 
      25              : namespace Rust {
      26              : 
      27              : // Parses a semi-coloned (except for full block) macro invocation item.
      28              : template <typename ManagedTokenSource>
      29              : std::unique_ptr<AST::MacroInvocation>
      30         4993 : Parser<ManagedTokenSource>::parse_macro_invocation_semi (
      31              :   AST::AttrVec outer_attrs)
      32              : {
      33         4993 :   location_t macro_locus = lexer.peek_token ()->get_locus ();
      34         4993 :   auto path = parse_simple_path ();
      35         4993 :   if (!path)
      36            0 :     return nullptr;
      37              : 
      38         4993 :   if (!skip_token (EXCLAM))
      39              :     {
      40              :       // skip after somewhere?
      41            0 :       return nullptr;
      42              :     }
      43              : 
      44              :   // save delim type to ensure it is reused later
      45         4993 :   AST::DelimType delim_type = AST::PARENS;
      46              : 
      47              :   // Map tokens to DelimType
      48         4993 :   const_TokenPtr t = lexer.peek_token ();
      49         4993 :   switch (t->get_id ())
      50              :     {
      51              :     case LEFT_PAREN:
      52              :       delim_type = AST::PARENS;
      53              :       break;
      54            0 :     case LEFT_SQUARE:
      55            0 :       delim_type = AST::SQUARE;
      56            0 :       break;
      57         3521 :     case LEFT_CURLY:
      58         3521 :       delim_type = AST::CURLY;
      59         3521 :       break;
      60            0 :     default:
      61            0 :       add_error (Error (t->get_locus (),
      62              :                         "unexpected token %qs - expecting delimiters (for a "
      63              :                         "macro invocation semi body)",
      64              :                         t->get_token_description ()));
      65              : 
      66            0 :       return nullptr;
      67              :     }
      68         4993 :   location_t tok_tree_locus = t->get_locus ();
      69         4993 :   lexer.skip_token ();
      70              : 
      71              :   // parse actual token trees
      72         4993 :   std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
      73         4993 :   auto delim_open
      74         4993 :     = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
      75         4993 :   token_trees.push_back (std::move (delim_open));
      76              : 
      77         4993 :   t = lexer.peek_token ();
      78              :   // parse token trees until the initial delimiter token is found again
      79        64092 :   while (!Parse::Utils::token_id_matches_delims (t->get_id (), delim_type)
      80        64091 :          && t->get_id () != END_OF_FILE)
      81              :     {
      82        59099 :       auto tree = parse_token_tree ();
      83        59099 :       if (!tree)
      84            1 :         return nullptr;
      85              : 
      86        59098 :       token_trees.push_back (std::move (tree.value ()));
      87              : 
      88        59098 :       t = lexer.peek_token ();
      89              :     }
      90         4992 :   auto delim_close
      91         4992 :     = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
      92         4992 :   token_trees.push_back (std::move (delim_close));
      93              : 
      94         4992 :   AST::DelimTokenTree delim_tok_tree (delim_type, std::move (token_trees),
      95              :                                       tok_tree_locus);
      96         4992 :   AST::MacroInvocData invoc_data (std::move (path.value ()),
      97              :                                   std::move (delim_tok_tree));
      98              : 
      99              :   // parse end delimiters
     100         4992 :   t = lexer.peek_token ();
     101         4992 :   if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
     102              :     {
     103              :       // tokens match opening delimiter, so skip.
     104         4992 :       lexer.skip_token ();
     105              : 
     106         4992 :       if (delim_type != AST::CURLY)
     107              :         {
     108              :           // skip semicolon at end of non-curly macro invocation semis
     109         1471 :           if (!skip_token (SEMICOLON))
     110              :             {
     111              :               // as this is the end, allow recovery (probably) - may change
     112              : 
     113            0 :               return AST::MacroInvocation::Regular (std::move (invoc_data),
     114              :                                                     std::move (outer_attrs),
     115            0 :                                                     macro_locus, true);
     116              :             }
     117              :         }
     118              : 
     119              :       // DEBUG:
     120         9984 :       rust_debug ("skipped token is '%s', next token (current peek) is '%s'",
     121              :                   t->get_token_description (),
     122              :                   lexer.peek_token ()->get_token_description ());
     123              : 
     124         9984 :       return AST::MacroInvocation::Regular (std::move (invoc_data),
     125              :                                             std::move (outer_attrs),
     126         4992 :                                             macro_locus, true);
     127              :     }
     128              :   else
     129              :     {
     130              :       // tokens don't match opening delimiters, so produce error
     131            0 :       Error error (t->get_locus (),
     132              :                    "unexpected token %qs - expecting closing delimiter %qs "
     133              :                    "(for a macro invocation semi)",
     134              :                    t->get_token_description (),
     135              :                    (delim_type == AST::PARENS
     136              :                       ? ")"
     137              :                       : (delim_type == AST::SQUARE ? "]" : "}")));
     138            0 :       add_error (std::move (error));
     139              : 
     140              :       /* return empty macro invocation despite possibly parsing mostly valid one
     141              :        * - TODO is this a good idea? */
     142            0 :       return nullptr;
     143            0 :     }
     144         9986 : }
     145              : 
     146              : // Parses a non-semicoloned macro invocation (i.e. as pattern or expression).
     147              : template <typename ManagedTokenSource>
     148              : std::unique_ptr<AST::MacroInvocation>
     149         9790 : Parser<ManagedTokenSource>::parse_macro_invocation (AST::AttrVec outer_attrs)
     150              : {
     151              :   // parse macro path
     152         9790 :   auto macro_path = parse_simple_path ();
     153         9790 :   if (!macro_path)
     154              :     {
     155         7550 :       Error error (lexer.peek_token ()->get_locus (),
     156              :                    "failed to parse macro invocation path");
     157         7550 :       add_error (std::move (error));
     158              : 
     159              :       // skip?
     160         7550 :       return nullptr;
     161         7550 :     }
     162              : 
     163         2240 :   if (!skip_token (EXCLAM))
     164              :     {
     165              :       // skip after somewhere?
     166            3 :       return nullptr;
     167              :     }
     168              : 
     169              :   // parse internal delim token tree
     170         2237 :   auto delim_tok_tree = parse_delim_token_tree ();
     171         2237 :   if (!delim_tok_tree)
     172            0 :     return nullptr;
     173              : 
     174         2237 :   location_t macro_locus = macro_path->get_locus ();
     175              : 
     176         2237 :   return AST::MacroInvocation::Regular (
     177         4474 :     AST::MacroInvocData (std::move (macro_path.value ()),
     178         2237 :                          std::move (delim_tok_tree.value ())),
     179         2237 :     std::move (outer_attrs), macro_locus);
     180         2237 : }
     181              : 
     182              : // Parses a macro rule definition - does not parse semicolons.
     183              : template <typename ManagedTokenSource>
     184              : AST::MacroRule
     185         1862 : Parser<ManagedTokenSource>::parse_macro_rule ()
     186              : {
     187         1862 :   location_t locus = lexer.peek_token ()->get_locus ();
     188              : 
     189              :   // parse macro matcher
     190         1862 :   AST::MacroMatcher matcher = parse_macro_matcher ();
     191              : 
     192         1862 :   if (matcher.is_error ())
     193           13 :     return AST::MacroRule::create_error (locus);
     194              : 
     195         1849 :   if (!skip_token (MATCH_ARROW))
     196              :     {
     197              :       // skip after somewhere?
     198            0 :       return AST::MacroRule::create_error (locus);
     199              :     }
     200              : 
     201              :   // parse transcriber (this is just a delim token tree)
     202         1849 :   location_t token_tree_loc = lexer.peek_token ()->get_locus ();
     203         1849 :   auto delim_token_tree = parse_delim_token_tree ();
     204         1849 :   if (!delim_token_tree)
     205            0 :     return AST::MacroRule::create_error (token_tree_loc);
     206              : 
     207         1849 :   AST::MacroTranscriber transcriber (delim_token_tree.value (), token_tree_loc);
     208              : 
     209         1849 :   return AST::MacroRule (std::move (matcher), std::move (transcriber), locus);
     210         1849 : }
     211              : 
     212              : // Parses a macro matcher (part of a macro rule definition).
     213              : template <typename ManagedTokenSource>
     214              : AST::MacroMatcher
     215         2009 : Parser<ManagedTokenSource>::parse_macro_matcher ()
     216              : {
     217              :   // save delim type to ensure it is reused later
     218         2009 :   AST::DelimType delim_type = AST::PARENS;
     219              : 
     220              :   // DEBUG
     221         2009 :   rust_debug ("begun parsing macro matcher");
     222              : 
     223              :   // Map tokens to DelimType
     224         2009 :   const_TokenPtr t = lexer.peek_token ();
     225         2009 :   location_t locus = t->get_locus ();
     226         2009 :   switch (t->get_id ())
     227              :     {
     228              :     case LEFT_PAREN:
     229              :       delim_type = AST::PARENS;
     230              :       break;
     231           65 :     case LEFT_SQUARE:
     232           65 :       delim_type = AST::SQUARE;
     233           65 :       break;
     234           25 :     case LEFT_CURLY:
     235           25 :       delim_type = AST::CURLY;
     236           25 :       break;
     237            1 :     default:
     238            1 :       add_error (Error (
     239              :         t->get_locus (),
     240              :         "unexpected token %qs - expecting delimiters (for a macro matcher)",
     241              :         t->get_token_description ()));
     242              : 
     243            1 :       return AST::MacroMatcher::create_error (t->get_locus ());
     244              :     }
     245         2008 :   lexer.skip_token ();
     246              : 
     247              :   // parse actual macro matches
     248         2008 :   std::vector<std::unique_ptr<AST::MacroMatch>> matches;
     249              :   // Set of possible preceding macro matches to make sure follow-set
     250              :   // restrictions are respected.
     251              :   // TODO: Consider using std::reference_wrapper instead of raw pointers?
     252         2008 :   std::vector<const AST::MacroMatch *> last_matches;
     253              : 
     254         2008 :   t = lexer.peek_token ();
     255              :   // parse token trees until the initial delimiter token is found again
     256         6404 :   while (!Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
     257              :     {
     258         4396 :       std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
     259              : 
     260         4396 :       if (match == nullptr)
     261              :         {
     262            1 :           Error error (
     263              :             t->get_locus (),
     264              :             "failed to parse macro match for macro matcher - found %qs",
     265              :             t->get_token_description ());
     266            1 :           add_error (std::move (error));
     267              : 
     268            1 :           return AST::MacroMatcher::create_error (t->get_locus ());
     269            1 :         }
     270              : 
     271         4395 :       if (matches.size () > 0)
     272              :         {
     273         2769 :           const auto *last_match = matches.back ().get ();
     274              : 
     275              :           // We want to check if we are dealing with a zeroable repetition
     276         2769 :           bool zeroable = false;
     277         2769 :           if (last_match->get_macro_match_type ()
     278              :               == AST::MacroMatch::MacroMatchType::Repetition)
     279              :             {
     280           43 :               auto repetition
     281              :                 = static_cast<const AST::MacroMatchRepetition *> (last_match);
     282              : 
     283           43 :               if (repetition->get_op ()
     284              :                   != AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE)
     285              :                 zeroable = true;
     286              :             }
     287              : 
     288              :           if (!zeroable)
     289         2769 :             last_matches.clear ();
     290              : 
     291         2769 :           last_matches.emplace_back (last_match);
     292              : 
     293         5541 :           for (auto last : last_matches)
     294         2784 :             if (!is_match_compatible (*last, *match))
     295              :               return AST::MacroMatcher::create_error (
     296           12 :                 match->get_match_locus ());
     297              :         }
     298              : 
     299         4383 :       matches.push_back (std::move (match));
     300              : 
     301              :       // DEBUG
     302         4383 :       rust_debug ("pushed back a match in macro matcher");
     303              : 
     304         4383 :       t = lexer.peek_token ();
     305              :     }
     306              : 
     307              :   // parse end delimiters
     308         1995 :   t = lexer.peek_token ();
     309         1995 :   if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
     310              :     {
     311              :       // tokens match opening delimiter, so skip.
     312         1995 :       lexer.skip_token ();
     313              : 
     314         1995 :       return AST::MacroMatcher (delim_type, std::move (matches), locus);
     315              :     }
     316              :   else
     317              :     {
     318              :       // tokens don't match opening delimiters, so produce error
     319            0 :       Error error (t->get_locus (),
     320              :                    "unexpected token %qs - expecting closing delimiter %qs "
     321              :                    "(for a macro matcher)",
     322              :                    t->get_token_description (),
     323              :                    (delim_type == AST::PARENS
     324              :                       ? ")"
     325              :                       : (delim_type == AST::SQUARE ? "]" : "}")));
     326            0 :       add_error (std::move (error));
     327              : 
     328              :       /* return error macro matcher despite possibly parsing mostly correct one?
     329              :        * TODO is this the best idea? */
     330            0 :       return AST::MacroMatcher::create_error (t->get_locus ());
     331            0 :     }
     332         2008 : }
     333              : 
     334              : // Parses a macro match (syntax match inside a matcher in a macro rule).
     335              : template <typename ManagedTokenSource>
     336              : std::unique_ptr<AST::MacroMatch>
     337         5291 : Parser<ManagedTokenSource>::parse_macro_match ()
     338              : {
     339              :   // branch based on token available
     340         5291 :   const_TokenPtr t = lexer.peek_token ();
     341         5291 :   switch (t->get_id ())
     342              :     {
     343          108 :     case LEFT_PAREN:
     344              :     case LEFT_SQUARE:
     345              :     case LEFT_CURLY:
     346              :       {
     347              :         // must be macro matcher as delimited
     348          108 :         AST::MacroMatcher matcher = parse_macro_matcher ();
     349          108 :         if (matcher.is_error ())
     350              :           {
     351            1 :             Error error (lexer.peek_token ()->get_locus (),
     352              :                          "failed to parse macro matcher in macro match");
     353            1 :             add_error (std::move (error));
     354              : 
     355            1 :             return nullptr;
     356            1 :           }
     357          107 :         return std::unique_ptr<AST::MacroMatcher> (
     358          107 :           new AST::MacroMatcher (std::move (matcher)));
     359          108 :       }
     360         3463 :     case DOLLAR_SIGN:
     361              :       {
     362              :         // have to do more lookahead to determine if fragment or repetition
     363         3463 :         const_TokenPtr t2 = lexer.peek_token (1);
     364         3463 :         switch (t2->get_id ())
     365              :           {
     366         2766 :           case IDENTIFIER:
     367              :           case UNDERSCORE:
     368              :             // macro fragment
     369         2766 :             return parse_macro_match_fragment ();
     370          683 :           case LEFT_PAREN:
     371              :             // macro repetition
     372          683 :             return parse_macro_match_repetition ();
     373           14 :           default:
     374           14 :             if (token_id_is_keyword (t2->get_id ()) && t2->get_id () != CRATE)
     375              :               {
     376              :                 // keyword as macro fragment
     377           14 :                 return parse_macro_match_fragment ();
     378              :               }
     379              :             else
     380              :               {
     381              :                 // error: unrecognised
     382            0 :                 add_error (Error (
     383              :                   t2->get_locus (),
     384              :                   "unrecognised token combination %<$%s%> at start of "
     385              :                   "macro match - did you mean %<$identifier%> or %<$(%>?",
     386              :                   t2->get_token_description ()));
     387              : 
     388              :                 // skip somewhere?
     389            0 :                 return nullptr;
     390              :               }
     391              :           }
     392         3463 :       }
     393            0 :     case RIGHT_PAREN:
     394              :     case RIGHT_SQUARE:
     395              :     case RIGHT_CURLY:
     396              :       // not allowed
     397            0 :       add_error (Error (
     398              :         t->get_locus (),
     399              :         "closing delimiters like %qs are not allowed at the start of a macro "
     400              :         "match",
     401              :         t->get_token_description ()));
     402              : 
     403              :       // skip somewhere?
     404            0 :       return nullptr;
     405         1720 :     default:
     406              :       // just the token
     407         1720 :       lexer.skip_token ();
     408         1720 :       return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
     409              :     }
     410         5291 : }
     411              : 
     412              : // Parses a fragment macro match.
     413              : template <typename ManagedTokenSource>
     414              : std::unique_ptr<AST::MacroMatchFragment>
     415         2780 : Parser<ManagedTokenSource>::parse_macro_match_fragment ()
     416              : {
     417         2780 :   location_t fragment_locus = lexer.peek_token ()->get_locus ();
     418         2780 :   skip_token (DOLLAR_SIGN);
     419              : 
     420         2780 :   Identifier ident;
     421         2780 :   auto identifier = lexer.peek_token ();
     422         2780 :   if (identifier->get_id () == UNDERSCORE)
     423            6 :     ident = {Values::Keywords::UNDERSCORE, identifier->get_locus ()};
     424              :   else
     425         5554 :     ident = {identifier};
     426              : 
     427         2780 :   if (ident.empty ())
     428              :     {
     429            0 :       Error error (lexer.peek_token ()->get_locus (),
     430              :                    "missing identifier in macro match fragment");
     431            0 :       add_error (std::move (error));
     432              : 
     433            0 :       return nullptr;
     434            0 :     }
     435         2780 :   skip_token (identifier->get_id ());
     436              : 
     437         2780 :   if (!skip_token (COLON))
     438              :     {
     439              :       // skip after somewhere?
     440            0 :       return nullptr;
     441              :     }
     442              : 
     443              :   // get MacroFragSpec for macro
     444         2780 :   const_TokenPtr t = expect_token (IDENTIFIER);
     445         2780 :   if (t == nullptr)
     446            0 :     return nullptr;
     447              : 
     448         2780 :   AST::MacroFragSpec frag
     449         2780 :     = AST::MacroFragSpec::get_frag_spec_from_str (t->get_str ());
     450         2780 :   if (frag.is_error ())
     451              :     {
     452            0 :       Error error (t->get_locus (),
     453              :                    "invalid fragment specifier %qs in fragment macro match",
     454            0 :                    t->get_str ().c_str ());
     455            0 :       add_error (std::move (error));
     456              : 
     457            0 :       return nullptr;
     458            0 :     }
     459              : 
     460              :   return std::unique_ptr<AST::MacroMatchFragment> (
     461         2780 :     new AST::MacroMatchFragment (std::move (ident), frag, fragment_locus));
     462         5560 : }
     463              : 
     464              : // Parses a repetition macro match.
     465              : template <typename ManagedTokenSource>
     466              : std::unique_ptr<AST::MacroMatchRepetition>
     467          683 : Parser<ManagedTokenSource>::parse_macro_match_repetition ()
     468              : {
     469          683 :   skip_token (DOLLAR_SIGN);
     470          683 :   skip_token (LEFT_PAREN);
     471              : 
     472          683 :   std::vector<std::unique_ptr<AST::MacroMatch>> matches;
     473              : 
     474              :   // parse required first macro match
     475          683 :   std::unique_ptr<AST::MacroMatch> initial_match = parse_macro_match ();
     476          683 :   if (initial_match == nullptr)
     477              :     {
     478            0 :       Error error (
     479            0 :         lexer.peek_token ()->get_locus (),
     480              :         "could not parse required first macro match in macro match repetition");
     481            0 :       add_error (std::move (error));
     482              : 
     483              :       // skip after somewhere?
     484            0 :       return nullptr;
     485            0 :     }
     486          683 :   matches.push_back (std::move (initial_match));
     487              : 
     488              :   // parse optional later macro matches
     489          683 :   const_TokenPtr t = lexer.peek_token ();
     490          895 :   while (t->get_id () != RIGHT_PAREN)
     491              :     {
     492          212 :       std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
     493              : 
     494          212 :       if (match == nullptr)
     495              :         {
     496            0 :           Error error (lexer.peek_token ()->get_locus (),
     497              :                        "failed to parse macro match in macro match repetition");
     498            0 :           add_error (std::move (error));
     499              : 
     500            0 :           return nullptr;
     501            0 :         }
     502              : 
     503          212 :       matches.push_back (std::move (match));
     504              : 
     505          212 :       t = lexer.peek_token ();
     506              :     }
     507              : 
     508          683 :   if (!skip_token (RIGHT_PAREN))
     509              :     {
     510              :       // skip after somewhere?
     511            0 :       return nullptr;
     512              :     }
     513              : 
     514          683 :   t = lexer.peek_token ();
     515              :   // see if separator token exists
     516          683 :   std::unique_ptr<AST::Token> separator = nullptr;
     517          683 :   switch (t->get_id ())
     518              :     {
     519              :     // repetition operators
     520              :     case ASTERISK:
     521              :     case PLUS:
     522              :     case QUESTION_MARK:
     523              :     // delimiters
     524              :     case LEFT_PAREN:
     525              :     case LEFT_CURLY:
     526              :     case LEFT_SQUARE:
     527              :     case RIGHT_PAREN:
     528              :     case RIGHT_CURLY:
     529              :     case RIGHT_SQUARE:
     530              :       // separator does not exist, so still null and don't skip token
     531              :       break;
     532          166 :     default:
     533              :       // separator does exist
     534          166 :       separator = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
     535          166 :       lexer.skip_token ();
     536          166 :       break;
     537              :     }
     538              : 
     539              :   // parse repetition operator
     540          683 :   t = lexer.peek_token ();
     541          683 :   AST::MacroMatchRepetition::MacroRepOp op = AST::MacroMatchRepetition::NONE;
     542          683 :   switch (t->get_id ())
     543              :     {
     544          539 :     case ASTERISK:
     545          539 :       op = AST::MacroMatchRepetition::ANY;
     546          539 :       lexer.skip_token ();
     547          539 :       break;
     548           82 :     case PLUS:
     549           82 :       op = AST::MacroMatchRepetition::ONE_OR_MORE;
     550           82 :       lexer.skip_token ();
     551           82 :       break;
     552           62 :     case QUESTION_MARK:
     553           62 :       op = AST::MacroMatchRepetition::ZERO_OR_ONE;
     554           62 :       lexer.skip_token ();
     555              : 
     556           62 :       if (separator != nullptr)
     557              :         {
     558            1 :           add_error (
     559            2 :             Error (separator->get_locus (),
     560              :                    "the %<?%> macro repetition operator does not take a "
     561              :                    "separator"));
     562          683 :           separator = nullptr;
     563              :         }
     564              : 
     565              :       break;
     566            0 :     default:
     567            0 :       add_error (
     568            0 :         Error (t->get_locus (),
     569              :                "expected macro repetition operator (%<*%>, %<+%>, or %<?%>) in "
     570              :                "macro match - found %qs",
     571              :                t->get_token_description ()));
     572              : 
     573              :       // skip after somewhere?
     574            0 :       return nullptr;
     575              :     }
     576              : 
     577              :   return std::unique_ptr<AST::MacroMatchRepetition> (
     578          683 :     new AST::MacroMatchRepetition (std::move (matches), op,
     579          683 :                                    std::move (separator), t->get_locus ()));
     580         1366 : }
     581              : 
     582              : /* Parses a macro invocation with a path in expression already parsed (but not
     583              :  * '!' token). */
     584              : template <typename ManagedTokenSource>
     585              : std::unique_ptr<AST::MacroInvocation>
     586        53264 : Parser<ManagedTokenSource>::parse_macro_invocation_partial (
     587              :   AST::PathInExpression path, AST::AttrVec outer_attrs,
     588              :   ParseRestrictions restrictions)
     589              : {
     590              :   // macro invocation
     591        53264 :   if (!skip_token (EXCLAM))
     592              :     {
     593            0 :       return nullptr;
     594              :     }
     595              : 
     596              :   // convert PathInExpression to SimplePath - if this isn't possible, error
     597        53264 :   AST::SimplePath converted_path = path.as_simple_path ();
     598        53264 :   if (converted_path.is_empty ())
     599              :     {
     600            0 :       Error error (lexer.peek_token ()->get_locus (),
     601              :                    "failed to parse simple path in macro invocation");
     602            0 :       add_error (std::move (error));
     603              : 
     604            0 :       return nullptr;
     605            0 :     }
     606              : 
     607        53264 :   auto tok_tree = parse_delim_token_tree ();
     608        53264 :   if (!tok_tree)
     609            3 :     return nullptr;
     610              : 
     611        53261 :   rust_debug ("successfully parsed macro invocation (via partial)");
     612              : 
     613        53261 :   location_t macro_locus = converted_path.get_locus ();
     614              : 
     615        53261 :   return AST::MacroInvocation::Regular (
     616       106522 :     AST::MacroInvocData (std::move (converted_path),
     617        53261 :                          std::move (tok_tree.value ())),
     618        53261 :     std::move (outer_attrs), macro_locus);
     619        53264 : }
     620              : 
     621              : } // namespace Rust
        

Generated by: LCOV version 2.4-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.