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.0 % 267 211
Test Date: 2026-02-28 14:20:25 Functions: 81.2 % 16 13
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          384 : Parser<ManagedTokenSource>::parse_macro_invocation_semi (
      31              :   AST::AttrVec outer_attrs)
      32              : {
      33          384 :   location_t macro_locus = lexer.peek_token ()->get_locus ();
      34          384 :   auto path = parse_simple_path ();
      35          384 :   if (!path)
      36            0 :     return nullptr;
      37              : 
      38          384 :   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          384 :   AST::DelimType delim_type = AST::PARENS;
      46              : 
      47              :   // Map tokens to DelimType
      48          384 :   const_TokenPtr t = lexer.peek_token ();
      49          384 :   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          231 :     case LEFT_CURLY:
      58          231 :       delim_type = AST::CURLY;
      59          231 :       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          384 :   location_t tok_tree_locus = t->get_locus ();
      69          384 :   lexer.skip_token ();
      70              : 
      71              :   // parse actual token trees
      72          384 :   std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
      73          384 :   auto delim_open
      74          384 :     = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
      75          384 :   token_trees.push_back (std::move (delim_open));
      76              : 
      77          384 :   t = lexer.peek_token ();
      78              :   // parse token trees until the initial delimiter token is found again
      79         4094 :   while (!Parse::Utils::token_id_matches_delims (t->get_id (), delim_type)
      80         4093 :          && t->get_id () != END_OF_FILE)
      81              :     {
      82         3710 :       auto tree = parse_token_tree ();
      83         3710 :       if (!tree)
      84            1 :         return nullptr;
      85              : 
      86         3709 :       token_trees.push_back (std::move (tree.value ()));
      87              : 
      88         3709 :       t = lexer.peek_token ();
      89              :     }
      90          383 :   auto delim_close
      91          383 :     = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
      92          383 :   token_trees.push_back (std::move (delim_close));
      93              : 
      94          383 :   AST::DelimTokenTree delim_tok_tree (delim_type, std::move (token_trees),
      95              :                                       tok_tree_locus);
      96          383 :   AST::MacroInvocData invoc_data (std::move (path.value ()),
      97              :                                   std::move (delim_tok_tree));
      98              : 
      99              :   // parse end delimiters
     100          383 :   t = lexer.peek_token ();
     101          383 :   if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
     102              :     {
     103              :       // tokens match opening delimiter, so skip.
     104          383 :       lexer.skip_token ();
     105              : 
     106          383 :       if (delim_type != AST::CURLY)
     107              :         {
     108              :           // skip semicolon at end of non-curly macro invocation semis
     109          152 :           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          766 :       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          766 :       return AST::MacroInvocation::Regular (std::move (invoc_data),
     125              :                                             std::move (outer_attrs),
     126          383 :                                             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          768 : }
     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          360 : Parser<ManagedTokenSource>::parse_macro_invocation (AST::AttrVec outer_attrs)
     150              : {
     151              :   // parse macro path
     152          360 :   auto macro_path = parse_simple_path ();
     153          360 :   if (!macro_path)
     154              :     {
     155          272 :       Error error (lexer.peek_token ()->get_locus (),
     156              :                    "failed to parse macro invocation path");
     157          272 :       add_error (std::move (error));
     158              : 
     159              :       // skip?
     160          272 :       return nullptr;
     161          272 :     }
     162              : 
     163           88 :   if (!skip_token (EXCLAM))
     164              :     {
     165              :       // skip after somewhere?
     166            3 :       return nullptr;
     167              :     }
     168              : 
     169              :   // parse internal delim token tree
     170           85 :   auto delim_tok_tree = parse_delim_token_tree ();
     171           85 :   if (!delim_tok_tree)
     172            0 :     return nullptr;
     173              : 
     174           85 :   location_t macro_locus = macro_path->get_locus ();
     175              : 
     176           85 :   return AST::MacroInvocation::Regular (
     177          170 :     AST::MacroInvocData (std::move (macro_path.value ()),
     178           85 :                          std::move (delim_tok_tree.value ())),
     179           85 :     std::move (outer_attrs), macro_locus);
     180           85 : }
     181              : 
     182              : // Parses a macro rule definition - does not parse semicolons.
     183              : template <typename ManagedTokenSource>
     184              : AST::MacroRule
     185         1105 : Parser<ManagedTokenSource>::parse_macro_rule ()
     186              : {
     187         1105 :   location_t locus = lexer.peek_token ()->get_locus ();
     188              : 
     189              :   // parse macro matcher
     190         1105 :   AST::MacroMatcher matcher = parse_macro_matcher ();
     191              : 
     192         1105 :   if (matcher.is_error ())
     193           13 :     return AST::MacroRule::create_error (locus);
     194              : 
     195         1092 :   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         1092 :   location_t token_tree_loc = lexer.peek_token ()->get_locus ();
     203         1092 :   auto delim_token_tree = parse_delim_token_tree ();
     204         1092 :   if (!delim_token_tree)
     205            0 :     return AST::MacroRule::create_error (token_tree_loc);
     206              : 
     207         1092 :   AST::MacroTranscriber transcriber (delim_token_tree.value (), token_tree_loc);
     208              : 
     209         1092 :   return AST::MacroRule (std::move (matcher), std::move (transcriber), locus);
     210         1092 : }
     211              : 
     212              : // Parses a macro matcher (part of a macro rule definition).
     213              : template <typename ManagedTokenSource>
     214              : AST::MacroMatcher
     215         1192 : Parser<ManagedTokenSource>::parse_macro_matcher ()
     216              : {
     217              :   // save delim type to ensure it is reused later
     218         1192 :   AST::DelimType delim_type = AST::PARENS;
     219              : 
     220              :   // DEBUG
     221         1192 :   rust_debug ("begun parsing macro matcher");
     222              : 
     223              :   // Map tokens to DelimType
     224         1192 :   const_TokenPtr t = lexer.peek_token ();
     225         1192 :   location_t locus = t->get_locus ();
     226         1192 :   switch (t->get_id ())
     227              :     {
     228              :     case LEFT_PAREN:
     229              :       delim_type = AST::PARENS;
     230              :       break;
     231           39 :     case LEFT_SQUARE:
     232           39 :       delim_type = AST::SQUARE;
     233           39 :       break;
     234           15 :     case LEFT_CURLY:
     235           15 :       delim_type = AST::CURLY;
     236           15 :       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         1191 :   lexer.skip_token ();
     246              : 
     247              :   // parse actual macro matches
     248         1191 :   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         1191 :   std::vector<const AST::MacroMatch *> last_matches;
     253              : 
     254         1191 :   t = lexer.peek_token ();
     255              :   // parse token trees until the initial delimiter token is found again
     256         2606 :   while (!Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
     257              :     {
     258         1415 :       std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
     259              : 
     260         1415 :       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         1414 :       if (matches.size () > 0)
     272              :         {
     273          580 :           const auto *last_match = matches.back ().get ();
     274              : 
     275              :           // We want to check if we are dealing with a zeroable repetition
     276          580 :           bool zeroable = false;
     277          580 :           if (last_match->get_macro_match_type ()
     278              :               == AST::MacroMatch::MacroMatchType::Repetition)
     279              :             {
     280           23 :               auto repetition
     281              :                 = static_cast<const AST::MacroMatchRepetition *> (last_match);
     282              : 
     283           23 :               if (repetition->get_op ()
     284              :                   != AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE)
     285              :                 zeroable = true;
     286              :             }
     287              : 
     288              :           if (!zeroable)
     289          580 :             last_matches.clear ();
     290              : 
     291          580 :           last_matches.emplace_back (last_match);
     292              : 
     293         1151 :           for (auto last : last_matches)
     294          583 :             if (!is_match_compatible (*last, *match))
     295              :               return AST::MacroMatcher::create_error (
     296           12 :                 match->get_match_locus ());
     297              :         }
     298              : 
     299         1402 :       matches.push_back (std::move (match));
     300              : 
     301              :       // DEBUG
     302         1402 :       rust_debug ("pushed back a match in macro matcher");
     303              : 
     304         1402 :       t = lexer.peek_token ();
     305              :     }
     306              : 
     307              :   // parse end delimiters
     308         1178 :   t = lexer.peek_token ();
     309         1178 :   if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
     310              :     {
     311              :       // tokens match opening delimiter, so skip.
     312         1178 :       lexer.skip_token ();
     313              : 
     314         1178 :       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         1191 : }
     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         2071 : Parser<ManagedTokenSource>::parse_macro_match ()
     338              : {
     339              :   // branch based on token available
     340         2071 :   const_TokenPtr t = lexer.peek_token ();
     341         2071 :   switch (t->get_id ())
     342              :     {
     343           67 :     case LEFT_PAREN:
     344              :     case LEFT_SQUARE:
     345              :     case LEFT_CURLY:
     346              :       {
     347              :         // must be macro matcher as delimited
     348           67 :         AST::MacroMatcher matcher = parse_macro_matcher ();
     349           67 :         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           66 :         return std::unique_ptr<AST::MacroMatcher> (
     358           66 :           new AST::MacroMatcher (std::move (matcher)));
     359           67 :       }
     360         1484 :     case DOLLAR_SIGN:
     361              :       {
     362              :         // have to do more lookahead to determine if fragment or repetition
     363         1484 :         const_TokenPtr t2 = lexer.peek_token (1);
     364         1484 :         switch (t2->get_id ())
     365              :           {
     366          967 :           case IDENTIFIER:
     367              :           case UNDERSCORE:
     368              :             // macro fragment
     369          967 :             return parse_macro_match_fragment ();
     370          516 :           case LEFT_PAREN:
     371              :             // macro repetition
     372          516 :             return parse_macro_match_repetition ();
     373            1 :           default:
     374            1 :             if (token_id_is_keyword (t2->get_id ()) && t2->get_id () != CRATE)
     375              :               {
     376              :                 // keyword as macro fragment
     377            1 :                 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         1484 :       }
     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          520 :     default:
     406              :       // just the token
     407          520 :       lexer.skip_token ();
     408          520 :       return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
     409              :     }
     410         2071 : }
     411              : 
     412              : // Parses a fragment macro match.
     413              : template <typename ManagedTokenSource>
     414              : std::unique_ptr<AST::MacroMatchFragment>
     415          968 : Parser<ManagedTokenSource>::parse_macro_match_fragment ()
     416              : {
     417          968 :   location_t fragment_locus = lexer.peek_token ()->get_locus ();
     418          968 :   skip_token (DOLLAR_SIGN);
     419              : 
     420          968 :   Identifier ident;
     421          968 :   auto identifier = lexer.peek_token ();
     422          968 :   if (identifier->get_id () == UNDERSCORE)
     423            4 :     ident = {Values::Keywords::UNDERSCORE, identifier->get_locus ()};
     424              :   else
     425         1932 :     ident = {identifier};
     426              : 
     427          968 :   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          968 :   skip_token (identifier->get_id ());
     436              : 
     437          968 :   if (!skip_token (COLON))
     438              :     {
     439              :       // skip after somewhere?
     440            0 :       return nullptr;
     441              :     }
     442              : 
     443              :   // get MacroFragSpec for macro
     444          968 :   const_TokenPtr t = expect_token (IDENTIFIER);
     445          968 :   if (t == nullptr)
     446            0 :     return nullptr;
     447              : 
     448              :   AST::MacroFragSpec frag
     449          968 :     = AST::MacroFragSpec::get_frag_spec_from_str (t->get_str ());
     450          968 :   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          968 :     new AST::MacroMatchFragment (std::move (ident), frag, fragment_locus));
     462         1936 : }
     463              : 
     464              : // Parses a repetition macro match.
     465              : template <typename ManagedTokenSource>
     466              : std::unique_ptr<AST::MacroMatchRepetition>
     467          516 : Parser<ManagedTokenSource>::parse_macro_match_repetition ()
     468              : {
     469          516 :   skip_token (DOLLAR_SIGN);
     470          516 :   skip_token (LEFT_PAREN);
     471              : 
     472          516 :   std::vector<std::unique_ptr<AST::MacroMatch>> matches;
     473              : 
     474              :   // parse required first macro match
     475          516 :   std::unique_ptr<AST::MacroMatch> initial_match = parse_macro_match ();
     476          516 :   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          516 :   matches.push_back (std::move (initial_match));
     487              : 
     488              :   // parse optional later macro matches
     489          516 :   const_TokenPtr t = lexer.peek_token ();
     490          656 :   while (t->get_id () != RIGHT_PAREN)
     491              :     {
     492          140 :       std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
     493              : 
     494          140 :       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          140 :       matches.push_back (std::move (match));
     504              : 
     505          140 :       t = lexer.peek_token ();
     506              :     }
     507              : 
     508          516 :   if (!skip_token (RIGHT_PAREN))
     509              :     {
     510              :       // skip after somewhere?
     511            0 :       return nullptr;
     512              :     }
     513              : 
     514          516 :   t = lexer.peek_token ();
     515              :   // see if separator token exists
     516          516 :   std::unique_ptr<AST::Token> separator = nullptr;
     517          516 :   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          135 :     default:
     533              :       // separator does exist
     534          135 :       separator = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
     535          135 :       lexer.skip_token ();
     536              :       break;
     537              :     }
     538              : 
     539              :   // parse repetition operator
     540          516 :   t = lexer.peek_token ();
     541          516 :   AST::MacroMatchRepetition::MacroRepOp op = AST::MacroMatchRepetition::NONE;
     542          516 :   switch (t->get_id ())
     543              :     {
     544          440 :     case ASTERISK:
     545          440 :       op = AST::MacroMatchRepetition::ANY;
     546          440 :       lexer.skip_token ();
     547              :       break;
     548           39 :     case PLUS:
     549           39 :       op = AST::MacroMatchRepetition::ONE_OR_MORE;
     550           39 :       lexer.skip_token ();
     551              :       break;
     552           37 :     case QUESTION_MARK:
     553           37 :       op = AST::MacroMatchRepetition::ZERO_OR_ONE;
     554           37 :       lexer.skip_token ();
     555              : 
     556           37 :       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            1 :           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          516 :     new AST::MacroMatchRepetition (std::move (matches), op,
     579          516 :                                    std::move (separator), t->get_locus ()));
     580         1032 : }
     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         2457 : Parser<ManagedTokenSource>::parse_macro_invocation_partial (
     587              :   AST::PathInExpression path, AST::AttrVec outer_attrs,
     588              :   ParseRestrictions restrictions)
     589              : {
     590              :   // macro invocation
     591         2457 :   if (!skip_token (EXCLAM))
     592              :     {
     593            0 :       return nullptr;
     594              :     }
     595              : 
     596              :   // convert PathInExpression to SimplePath - if this isn't possible, error
     597         2457 :   AST::SimplePath converted_path = path.as_simple_path ();
     598         2457 :   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         2457 :   auto tok_tree = parse_delim_token_tree ();
     608         2457 :   if (!tok_tree)
     609            2 :     return nullptr;
     610              : 
     611         2455 :   rust_debug ("successfully parsed macro invocation (via partial)");
     612              : 
     613         2455 :   location_t macro_locus = converted_path.get_locus ();
     614              : 
     615         2455 :   return AST::MacroInvocation::Regular (
     616         4910 :     AST::MacroInvocData (std::move (converted_path),
     617         2455 :                          std::move (tok_tree.value ())),
     618         2455 :     std::move (outer_attrs), macro_locus);
     619         4914 : }
     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.