LCOV - code coverage report
Current view: top level - gcc/rust/ast - rust-macro.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 73.7 % 334 246
Test Date: 2026-02-28 14:20:25 Functions: 66.3 % 83 55
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #ifndef RUST_AST_MACRO_H
      20              : #define RUST_AST_MACRO_H
      21              : 
      22              : #include "rust-system.h"
      23              : #include "rust-ast.h"
      24              : #include "rust-ast-fragment.h"
      25              : #include "rust-location.h"
      26              : #include "rust-item.h"
      27              : #include "rust-macro-builtins.h"
      28              : 
      29              : namespace Rust {
      30              : 
      31              : // forward declarations for AttributeParser
      32              : class MacroInvocLexer;
      33              : template <typename ManagedTokenSource> class Parser;
      34              : 
      35              : namespace AST {
      36              : 
      37              : class MacroFragSpec
      38              : {
      39              : public:
      40              :   enum Kind
      41              :   {
      42              :     BLOCK,
      43              :     EXPR,
      44              :     IDENT,
      45              :     ITEM,
      46              :     LIFETIME,
      47              :     LITERAL,
      48              :     META,
      49              :     PAT,
      50              :     PATH,
      51              :     STMT,
      52              :     TT,
      53              :     TY,
      54              :     VIS,
      55              :     INVALID // not really a specifier, but used to mark invalid one passed in
      56              :   };
      57              : 
      58          968 :   MacroFragSpec (Kind kind) : kind (kind) {}
      59              : 
      60          968 :   static MacroFragSpec get_frag_spec_from_str (const std::string &str)
      61              :   {
      62          968 :     if (str == "block")
      63            4 :       return MacroFragSpec (BLOCK);
      64          964 :     else if (str == "expr")
      65          322 :       return MacroFragSpec (EXPR);
      66          642 :     else if (str == "ident")
      67          108 :       return MacroFragSpec (IDENT);
      68          534 :     else if (str == "item")
      69            3 :       return MacroFragSpec (ITEM);
      70          531 :     else if (str == "lifetime")
      71            2 :       return MacroFragSpec (LIFETIME);
      72          529 :     else if (str == "literal")
      73          111 :       return MacroFragSpec (LITERAL);
      74          418 :     else if (str == "meta")
      75           14 :       return MacroFragSpec (META);
      76          404 :     else if (str == "pat" || str == "pat_param")
      77           10 :       return MacroFragSpec (PAT);
      78          394 :     else if (str == "path")
      79            1 :       return MacroFragSpec (PATH);
      80          393 :     else if (str == "stmt")
      81           52 :       return MacroFragSpec (STMT);
      82          341 :     else if (str == "tt")
      83           35 :       return MacroFragSpec (TT);
      84          306 :     else if (str == "ty")
      85          303 :       return MacroFragSpec (TY);
      86            3 :     else if (str == "vis")
      87            3 :       return MacroFragSpec (VIS);
      88              :     else
      89              :       {
      90              :         // error_at("invalid string '%s' used as fragment specifier",
      91              :         // str->c_str()));
      92            0 :         return MacroFragSpec (INVALID);
      93              :       }
      94              :   }
      95              : 
      96         8382 :   Kind get_kind () const { return kind; }
      97          968 :   bool is_error () const { return kind == Kind::INVALID; }
      98              : 
      99              :   // Converts a frag spec enum item to a string form.
     100           13 :   std::string as_string () const
     101              :   {
     102           13 :     switch (kind)
     103              :       {
     104            0 :       case BLOCK:
     105            0 :         return "block";
     106           10 :       case EXPR:
     107           10 :         return "expr";
     108            1 :       case IDENT:
     109            1 :         return "ident";
     110            0 :       case ITEM:
     111            0 :         return "item";
     112            0 :       case LIFETIME:
     113            0 :         return "lifetime";
     114            0 :       case LITERAL:
     115            0 :         return "literal";
     116            0 :       case META:
     117            0 :         return "meta";
     118            0 :       case PAT:
     119            0 :         return "pat";
     120            0 :       case PATH:
     121            0 :         return "path";
     122            0 :       case STMT:
     123            0 :         return "stmt";
     124            0 :       case TT:
     125            0 :         return "tt";
     126            1 :       case TY:
     127            1 :         return "ty";
     128            1 :       case VIS:
     129            1 :         return "vis";
     130            0 :       case INVALID:
     131            0 :         return "INVALID_FRAG_SPEC";
     132            0 :       default:
     133            0 :         return "ERROR_MARK_STRING - unknown frag spec";
     134              :       }
     135              :   }
     136              : 
     137          250 :   bool has_follow_set_restrictions () const
     138              :   {
     139          250 :     switch (kind)
     140              :       {
     141              :       case EXPR:
     142              :       case STMT:
     143              :       case PAT:
     144              :       case PATH:
     145              :       case TY:
     146              :       case VIS:
     147              :         return true;
     148              :       default:
     149              :         return false;
     150              :       }
     151              :   }
     152              : 
     153            6 :   bool has_follow_set_fragment_restrictions () const
     154              :   {
     155            6 :     switch (kind)
     156              :       {
     157              :       case PATH:
     158              :       case PAT:
     159              :       case TY:
     160              :       case VIS:
     161              :         return true;
     162            2 :       default:
     163            2 :         return false;
     164              :       }
     165              :   }
     166              : 
     167              : private:
     168              :   Kind kind;
     169              : };
     170              : 
     171              : // A macro match that has an identifier and fragment spec
     172         3968 : class MacroMatchFragment : public MacroMatch
     173              : {
     174              :   Identifier ident;
     175              :   MacroFragSpec frag_spec;
     176              :   location_t locus;
     177              : 
     178              : public:
     179          968 :   MacroMatchFragment (Identifier ident, MacroFragSpec frag_spec,
     180              :                       location_t locus)
     181          968 :     : ident (std::move (ident)), frag_spec (frag_spec), locus (locus)
     182              :   {}
     183              : 
     184              :   // Returns whether macro match fragment is in an error state.
     185              :   bool is_error () const
     186              :   {
     187              :     return frag_spec.get_kind () == MacroFragSpec::INVALID;
     188              :   }
     189              : 
     190              :   // Creates an error state macro match fragment.
     191              :   static MacroMatchFragment create_error (location_t locus)
     192              :   {
     193              :     return MacroMatchFragment (std::string (""),
     194              :                                MacroFragSpec (MacroFragSpec::Kind::INVALID),
     195              :                                locus);
     196              :   }
     197              : 
     198              :   std::string as_string () const override;
     199           12 :   location_t get_match_locus () const override { return locus; };
     200              : 
     201              :   void accept_vis (ASTVisitor &vis) override;
     202              : 
     203        10412 :   MacroMatchType get_macro_match_type () const override
     204              :   {
     205        10412 :     return MacroMatchType::Fragment;
     206              :   }
     207              : 
     208        13714 :   Identifier get_ident () const { return ident; }
     209           15 :   const MacroFragSpec &get_frag_spec () const { return frag_spec; }
     210              : 
     211              : protected:
     212              :   /* Use covariance to implement clone function as returning this object rather
     213              :    * than base */
     214         1984 :   MacroMatchFragment *clone_macro_match_impl () const override
     215              :   {
     216         1984 :     return new MacroMatchFragment (*this);
     217              :   }
     218              : };
     219              : 
     220              : // A repetition macro match
     221              : class MacroMatchRepetition : public MacroMatch
     222              : {
     223              : public:
     224              :   enum MacroRepOp
     225              :   {
     226              :     NONE,
     227              :     ANY,
     228              :     ONE_OR_MORE,
     229              :     ZERO_OR_ONE,
     230              :   };
     231              : 
     232              : private:
     233              :   std::vector<std::unique_ptr<MacroMatch>> matches;
     234              :   MacroRepOp op;
     235              : 
     236              :   // bool has_sep;
     237              :   typedef Token MacroRepSep;
     238              :   // any token except delimiters and repetition operators
     239              :   std::unique_ptr<MacroRepSep> sep;
     240              :   location_t locus;
     241              : 
     242              : public:
     243              :   // Returns whether macro match repetition has separator token.
     244         4238 :   bool has_sep () const { return sep != nullptr; }
     245              : 
     246          516 :   MacroMatchRepetition (std::vector<std::unique_ptr<MacroMatch>> matches,
     247              :                         MacroRepOp op, std::unique_ptr<MacroRepSep> sep,
     248              :                         location_t locus)
     249          516 :     : matches (std::move (matches)), op (op), sep (std::move (sep)),
     250          516 :       locus (locus)
     251              :   {}
     252              : 
     253              :   // Copy constructor with clone
     254         1026 :   MacroMatchRepetition (MacroMatchRepetition const &other)
     255         1026 :     : op (other.op), locus (other.locus)
     256              :   {
     257              :     // guard to protect from null pointer dereference
     258         1026 :     if (other.sep != nullptr)
     259          275 :       sep = other.sep->clone_token ();
     260              : 
     261         1026 :     matches.reserve (other.matches.size ());
     262         2344 :     for (const auto &e : other.matches)
     263         1318 :       matches.push_back (e->clone_macro_match ());
     264         1026 :   }
     265              : 
     266              :   // Overloaded assignment operator to clone
     267              :   MacroMatchRepetition &operator= (MacroMatchRepetition const &other)
     268              :   {
     269              :     op = other.op;
     270              :     locus = other.locus;
     271              : 
     272              :     // guard to protect from null pointer dereference
     273              :     if (other.sep != nullptr)
     274              :       sep = other.sep->clone_token ();
     275              :     else
     276              :       sep = nullptr;
     277              : 
     278              :     matches.reserve (other.matches.size ());
     279              :     for (const auto &e : other.matches)
     280              :       matches.push_back (e->clone_macro_match ());
     281              : 
     282              :     return *this;
     283              :   }
     284              : 
     285              :   // move constructors
     286              :   MacroMatchRepetition (MacroMatchRepetition &&other) = default;
     287              :   MacroMatchRepetition &operator= (MacroMatchRepetition &&other) = default;
     288              : 
     289              :   std::string as_string () const override;
     290         1746 :   location_t get_match_locus () const override { return locus; };
     291              : 
     292              :   void accept_vis (ASTVisitor &vis) override;
     293              : 
     294         1800 :   MacroMatchType get_macro_match_type () const override
     295              :   {
     296         1800 :     return MacroMatchType::Repetition;
     297              :   }
     298              : 
     299         1744 :   MacroRepOp get_op () const { return op; }
     300          357 :   const std::unique_ptr<MacroRepSep> &get_sep () const { return sep; }
     301         8698 :   std::vector<std::unique_ptr<MacroMatch>> &get_matches () { return matches; }
     302              :   const std::vector<std::unique_ptr<MacroMatch>> &get_matches () const
     303              :   {
     304           44 :     return matches;
     305              :   }
     306              : 
     307              : protected:
     308              :   /* Use covariance to implement clone function as returning this object rather
     309              :    * than base */
     310         1026 :   MacroMatchRepetition *clone_macro_match_impl () const override
     311              :   {
     312         1026 :     return new MacroMatchRepetition (*this);
     313              :   }
     314              : };
     315              : 
     316              : // can't inline due to polymorphism
     317         2316 : class MacroMatcher : public MacroMatch
     318              : {
     319              :   DelimType delim_type;
     320              :   std::vector<std::unique_ptr<MacroMatch>> matches;
     321              :   location_t locus;
     322              : 
     323              :   // TODO: think of way to mark invalid that doesn't take up more space
     324              :   bool is_invalid;
     325              : 
     326              : public:
     327         1178 :   MacroMatcher (DelimType delim_type,
     328              :                 std::vector<std::unique_ptr<MacroMatch>> matches,
     329              :                 location_t locus)
     330         1178 :     : delim_type (delim_type), matches (std::move (matches)), locus (locus),
     331         1178 :       is_invalid (false)
     332              :   {}
     333              : 
     334              :   // copy constructor with vector clone
     335         2413 :   MacroMatcher (MacroMatcher const &other)
     336         2413 :     : delim_type (other.delim_type), locus (other.locus)
     337              :   {
     338         2413 :     matches.reserve (other.matches.size ());
     339         5290 :     for (const auto &e : other.matches)
     340         2877 :       matches.push_back (e->clone_macro_match ());
     341         2413 :   }
     342              : 
     343              :   // overloaded assignment operator with vector clone
     344            0 :   MacroMatcher &operator= (MacroMatcher const &other)
     345              :   {
     346            0 :     delim_type = other.delim_type;
     347            0 :     locus = other.locus;
     348              : 
     349            0 :     matches.reserve (other.matches.size ());
     350            0 :     for (const auto &e : other.matches)
     351            0 :       matches.push_back (e->clone_macro_match ());
     352              : 
     353            0 :     return *this;
     354              :   }
     355              : 
     356              :   // move constructors
     357         1177 :   MacroMatcher (MacroMatcher &&other) = default;
     358              :   MacroMatcher &operator= (MacroMatcher &&other) = default;
     359              : 
     360              :   // Creates an error state macro matcher.
     361           27 :   static MacroMatcher create_error (location_t locus)
     362              :   {
     363           27 :     return MacroMatcher (true, locus);
     364              :   }
     365              : 
     366              :   // Returns whether MacroMatcher is in an error state.
     367         1192 :   bool is_error () const { return is_invalid; }
     368            3 :   location_t get_match_locus () const override { return locus; }
     369              : 
     370              :   std::string as_string () const override;
     371              : 
     372              :   void accept_vis (ASTVisitor &vis) override;
     373              : 
     374          145 :   MacroMatchType get_macro_match_type () const override
     375              :   {
     376          145 :     return MacroMatchType::Matcher;
     377              :   }
     378              : 
     379          116 :   DelimType get_delim_type () const { return delim_type; }
     380        15164 :   std::vector<std::unique_ptr<MacroMatch>> &get_matches () { return matches; }
     381              :   const std::vector<std::unique_ptr<MacroMatch>> &get_matches () const
     382              :   {
     383              :     return matches;
     384              :   }
     385              : 
     386              : protected:
     387              :   /* Use covariance to implement clone function as returning this object rather
     388              :    * than base */
     389          130 :   MacroMatcher *clone_macro_match_impl () const override
     390              :   {
     391          130 :     return new MacroMatcher (*this);
     392              :   }
     393              : 
     394              :   // constructor only used to create error matcher
     395           27 :   MacroMatcher (bool is_invalid, location_t locus)
     396           14 :     : delim_type (PARENS), locus (locus), is_invalid (is_invalid)
     397              :   {}
     398              : };
     399              : 
     400              : // TODO: inline?
     401         2242 : struct MacroTranscriber
     402              : {
     403              : private:
     404              :   DelimTokenTree token_tree;
     405              :   location_t locus;
     406              : 
     407              : public:
     408         1125 :   MacroTranscriber (DelimTokenTree token_tree, location_t locus)
     409         1112 :     : token_tree (std::move (token_tree)), locus (locus)
     410              :   {}
     411              : 
     412            0 :   std::string as_string () const { return token_tree.as_string (); }
     413              : 
     414              :   location_t get_locus () const { return locus; }
     415              : 
     416        13153 :   DelimTokenTree &get_token_tree () { return token_tree; }
     417              :   const DelimTokenTree &get_token_tree () const { return token_tree; }
     418              : };
     419              : 
     420              : // A macro rule? Matcher and transcriber pair?
     421              : struct MacroRule
     422              : {
     423              : private:
     424              :   MacroMatcher matcher;
     425              :   MacroTranscriber transcriber;
     426              :   location_t locus;
     427              : 
     428              : public:
     429         1124 :   MacroRule (MacroMatcher matcher, MacroTranscriber transcriber,
     430              :              location_t locus)
     431         1124 :     : matcher (std::move (matcher)), transcriber (std::move (transcriber)),
     432         1124 :       locus (locus)
     433         1124 :   {}
     434              : 
     435              :   // Returns whether macro rule is in error state.
     436         1105 :   bool is_error () const { return matcher.is_error (); }
     437              : 
     438              :   // Creates an error state macro rule.
     439           13 :   static MacroRule create_error (location_t locus)
     440              :   {
     441           13 :     return MacroRule (MacroMatcher::create_error (locus),
     442           26 :                       MacroTranscriber (DelimTokenTree::create_empty (),
     443           13 :                                         UNDEF_LOCATION),
     444           13 :                       locus);
     445              :   }
     446              : 
     447            4 :   location_t get_locus () const { return locus; }
     448              : 
     449              :   std::string as_string () const;
     450              : 
     451        14549 :   MacroMatcher &get_matcher () { return matcher; }
     452        13149 :   MacroTranscriber &get_transcriber () { return transcriber; }
     453              : };
     454              : 
     455              : // A macro rules definition item AST node
     456              : class MacroRulesDefinition : public VisItem
     457              : {
     458              : public:
     459              :   enum MacroKind
     460              :   {
     461              :     // Macro by Example (legacy macro rules)
     462              :     MBE,
     463              :     // Declarative macros 2.0
     464              :     DeclMacro,
     465              :   };
     466              : 
     467              : private:
     468              :   std::vector<Attribute> outer_attrs;
     469              :   Identifier rule_name;
     470              :   // MacroRulesDef rules_def;
     471              :   // only curly without required semicolon at end
     472              :   DelimType delim_type;
     473              :   // MacroRules rules;
     474              :   std::vector<MacroRule> rules; // inlined form
     475              :   location_t locus;
     476              : 
     477              :   MacroTranscriberFunc associated_transcriber;
     478              : 
     479              :   // Since we can't compare std::functions, we need to use an extra boolean
     480              :   bool is_builtin_rule;
     481              :   MacroKind kind;
     482              : 
     483              :   /**
     484              :    * Default function to use as an associated transcriber. This function should
     485              :    * never be called, hence the rust_unreachable().
     486              :    * If this function is used, then the macro is not builtin and the compiler
     487              :    * should make use of the actual rules. If the macro is builtin, then another
     488              :    * associated transcriber should be used
     489              :    */
     490            0 :   static Fragment dummy_builtin (location_t, MacroInvocData &, AST::InvocKind)
     491              :   {
     492            0 :     rust_unreachable ();
     493              :     return Fragment::create_error ();
     494              :   }
     495              : 
     496              :   /* NOTE: in rustc, macro definitions are considered (and parsed as) a type
     497              :    * of macro, whereas here they are considered part of the language itself.
     498              :    * I am not aware of the implications of this decision. The rustc spec does
     499              :    * mention that using the same parser for macro definitions and invocations
     500              :    * is "extremely self-referential and non-intuitive". */
     501          970 :   MacroRulesDefinition (Identifier rule_name, DelimType delim_type,
     502              :                         std::vector<MacroRule> rules,
     503              :                         std::vector<Attribute> outer_attrs, location_t locus,
     504              :                         MacroKind kind, Visibility vis)
     505          970 :     : VisItem (std::move (vis), outer_attrs),
     506         1940 :       outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)),
     507          970 :       delim_type (delim_type), rules (std::move (rules)), locus (locus),
     508          970 :       associated_transcriber (dummy_builtin), is_builtin_rule (false),
     509          970 :       kind (kind)
     510          970 :   {}
     511              : 
     512              :   MacroRulesDefinition (Identifier builtin_name, DelimType delim_type,
     513              :                         MacroTranscriberFunc associated_transcriber,
     514              :                         MacroKind kind, Visibility vis)
     515              :     : VisItem (std::move (vis), std::vector<Attribute> ()),
     516              :       outer_attrs (std::vector<Attribute> ()), rule_name (builtin_name),
     517              :       delim_type (delim_type), rules (std::vector<MacroRule> ()),
     518              :       locus (UNDEF_LOCATION), associated_transcriber (associated_transcriber),
     519              :       is_builtin_rule (true), kind (kind)
     520              :   {}
     521              : 
     522              : public:
     523              :   std::string as_string () const override;
     524              : 
     525              :   static std::unique_ptr<MacroRulesDefinition>
     526          927 :   mbe (Identifier rule_name, DelimType delim_type, std::vector<MacroRule> rules,
     527              :        std::vector<Attribute> outer_attrs, location_t locus)
     528              :   {
     529          927 :     return std::make_unique<MacroRulesDefinition> (
     530          927 :       MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus,
     531              :                             AST::MacroRulesDefinition::MacroKind::MBE,
     532         1854 :                             AST::Visibility::create_private ()));
     533              :   }
     534              : 
     535              :   static std::unique_ptr<MacroRulesDefinition>
     536           43 :   decl_macro (Identifier rule_name, std::vector<MacroRule> rules,
     537              :               std::vector<Attribute> outer_attrs, location_t locus,
     538              :               Visibility vis)
     539              :   {
     540           43 :     return std::make_unique<MacroRulesDefinition> (MacroRulesDefinition (
     541              :       rule_name, AST::DelimType::CURLY, rules, outer_attrs, locus,
     542           86 :       AST::MacroRulesDefinition::MacroKind::DeclMacro, vis));
     543              :   }
     544              : 
     545              :   void accept_vis (ASTVisitor &vis) override;
     546              : 
     547              :   // Invalid if rule name is empty, so base stripping on that.
     548            0 :   void mark_for_strip () override { rule_name = {""}; }
     549         6229 :   bool is_marked_for_strip () const override { return rule_name.empty (); }
     550              : 
     551              :   // TODO: this mutable getter seems really dodgy. Think up better way.
     552        25106 :   std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
     553         3774 :   const std::vector<Attribute> &get_outer_attrs () const override
     554              :   {
     555         3774 :     return outer_attrs;
     556              :   }
     557              : 
     558         8492 :   std::vector<MacroRule> &get_macro_rules () { return rules; }
     559              :   const std::vector<MacroRule> &get_macro_rules () const { return rules; }
     560              : 
     561          505 :   location_t get_locus () const override final { return locus; }
     562              : 
     563         4237 :   Identifier get_rule_name () const { return rule_name; }
     564              : 
     565         2448 :   std::vector<MacroRule> &get_rules () { return rules; }
     566              :   const std::vector<MacroRule> &get_rules () const { return rules; }
     567              : 
     568         2800 :   bool is_builtin () const { return is_builtin_rule; }
     569          356 :   const MacroTranscriberFunc &get_builtin_transcriber () const
     570              :   {
     571          356 :     rust_assert (is_builtin ());
     572          356 :     return associated_transcriber;
     573              :   }
     574          145 :   void set_builtin_transcriber (MacroTranscriberFunc transcriber)
     575              :   {
     576          145 :     associated_transcriber = transcriber;
     577          145 :     is_builtin_rule = true;
     578              :   }
     579              : 
     580         4688 :   MacroKind get_kind () const { return kind; }
     581              : 
     582            0 :   Item::Kind get_item_kind () const override
     583              :   {
     584            0 :     return Item::Kind::MacroRulesDefinition;
     585              :   }
     586              : 
     587              : protected:
     588              :   /* Use covariance to implement clone function as returning this object rather
     589              :    * than base */
     590         1001 :   MacroRulesDefinition *clone_item_impl () const override
     591              :   {
     592         1001 :     return new MacroRulesDefinition (*this);
     593              :   }
     594              : };
     595              : 
     596              : /* AST node of a macro invocation, which is replaced by the macro result at
     597              :  * compile time. This is technically a sum-type/tagged-union, which represents
     598              :  * both classic macro invocations and builtin macro invocations. Regular macro
     599              :  * invocations are expanded lazily, but builtin macro invocations need to be
     600              :  * expanded eagerly, hence the differentiation.
     601              :  */
     602              : class MacroInvocation : public TypeNoBounds,
     603              :                         public Pattern,
     604              :                         public Item,
     605              :                         public TraitItem,
     606              :                         public ExternalItem,
     607              :                         public ExprWithoutBlock
     608              : {
     609              : public:
     610              :   enum class InvocKind
     611              :   {
     612              :     Regular,
     613              :     Builtin,
     614              :   };
     615              : 
     616              :   std::string as_string () const override;
     617              : 
     618              :   /**
     619              :    * The default constructor you should use. Whenever we parse a macro call, we
     620              :    * cannot possibly know whether or not this call refers to a builtin macro or
     621              :    * a regular macro. With name resolution and scopes and nested macro calls,
     622              :    * this is literally impossible. Hence, always start by creating a `Regular`
     623              :    * MacroInvocation which will then (maybe!) become a `Builtin` macro
     624              :    * invocation in the expander.
     625              :    */
     626              :   static std::unique_ptr<MacroInvocation>
     627         2953 :   Regular (MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
     628              :            location_t locus, bool is_semi_coloned = false)
     629              :   {
     630         2953 :     return std::unique_ptr<MacroInvocation> (
     631              :       new MacroInvocation (InvocKind::Regular, tl::nullopt, invoc_data,
     632         2953 :                            outer_attrs, locus, is_semi_coloned, {}));
     633              :   }
     634              : 
     635              :   /**
     636              :    * Create a builtin macro invocation. This can only be done after macro
     637              :    * name-resolution and within the macro expander, so unless you're modifying
     638              :    * these visitors, you probably do not want to use this function.
     639              :    */
     640           51 :   static std::unique_ptr<MacroInvocation> Builtin (
     641              :     BuiltinMacro kind, MacroInvocData invoc_data,
     642              :     std::vector<Attribute> outer_attrs, location_t locus,
     643              :     std::vector<std::unique_ptr<MacroInvocation>> &&pending_eager_invocations
     644              :     = {},
     645              :     bool is_semi_coloned = false)
     646              :   {
     647           51 :     return std::unique_ptr<MacroInvocation> (
     648           51 :       new MacroInvocation (InvocKind::Builtin, kind, invoc_data, outer_attrs,
     649              :                            locus, is_semi_coloned,
     650           51 :                            std::move (pending_eager_invocations)));
     651              :   }
     652              : 
     653         2947 :   location_t get_locus () const override final { return locus; }
     654              : 
     655              :   void accept_vis (ASTVisitor &vis) override;
     656              : 
     657              :   // Invalid if path is empty, so base stripping on that.
     658            0 :   void mark_for_strip () override { invoc_data.mark_for_strip (); }
     659         3917 :   bool is_marked_for_strip () const override
     660              :   {
     661         3917 :     return invoc_data.is_marked_for_strip ();
     662              :   }
     663              : 
     664          817 :   const std::vector<Attribute> &get_outer_attrs () const override
     665              :   {
     666          817 :     return outer_attrs;
     667              :   }
     668        12762 :   std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
     669              : 
     670            0 :   void set_outer_attrs (std::vector<Attribute> new_attrs) override
     671              :   {
     672            0 :     outer_attrs = std::move (new_attrs);
     673            0 :   }
     674              : 
     675         5586 :   NodeId get_node_id () const override final
     676              :   {
     677         5586 :     return ExprWithoutBlock::get_node_id ();
     678              :   }
     679              : 
     680        11239 :   NodeId get_macro_node_id () const { return node_id; }
     681              : 
     682         5775 :   MacroInvocData &get_invoc_data () { return invoc_data; }
     683              : 
     684         2793 :   bool has_semicolon () const { return is_semi_coloned; }
     685              : 
     686         5681 :   InvocKind get_kind () const { return kind; }
     687              :   tl::optional<BuiltinMacro> get_builtin_kind () const { return builtin_kind; }
     688              : 
     689              :   /**
     690              :    * Turn the current MacroInvocation into a builtin macro invocation
     691              :    */
     692              :   void map_to_builtin (BuiltinMacro macro)
     693              :   {
     694              :     kind = InvocKind::Builtin;
     695              :     builtin_kind = macro;
     696              :   }
     697              : 
     698              :   /**
     699              :    * Get the list of pending macro invcations within the builtin macro
     700              :    * invocation that should get expanded eagerly.
     701              :    */
     702              :   std::vector<std::unique_ptr<MacroInvocation>> &
     703          175 :   get_pending_eager_invocations ()
     704              :   {
     705          175 :     rust_assert (kind == InvocKind::Builtin);
     706              : 
     707          175 :     return pending_eager_invocs;
     708              :   }
     709              : 
     710              : private:
     711              :   /* Full constructor */
     712         3004 :   MacroInvocation (
     713              :     InvocKind kind, tl::optional<BuiltinMacro> builtin_kind,
     714              :     MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
     715              :     location_t locus, bool is_semi_coloned,
     716              :     std::vector<std::unique_ptr<MacroInvocation>> &&pending_eager_invocs)
     717         6008 :     : TraitItem (locus), outer_attrs (std::move (outer_attrs)), locus (locus),
     718         3004 :       node_id (Analysis::Mappings::get ().get_next_node_id ()),
     719         3004 :       invoc_data (std::move (invoc_data)), is_semi_coloned (is_semi_coloned),
     720         3004 :       kind (kind), builtin_kind (builtin_kind),
     721         3004 :       pending_eager_invocs (std::move (pending_eager_invocs))
     722         3004 :   {}
     723              : 
     724        11903 :   MacroInvocation (const MacroInvocation &other)
     725        35709 :     : TraitItem (other.locus), ExternalItem (other.node_id),
     726        23806 :       outer_attrs (other.outer_attrs), locus (other.locus),
     727        11903 :       node_id (other.node_id), invoc_data (other.invoc_data),
     728        11903 :       is_semi_coloned (other.is_semi_coloned), kind (other.kind),
     729        23806 :       builtin_kind (other.builtin_kind)
     730              :   {
     731        11903 :     if (other.kind == InvocKind::Builtin)
     732          683 :       for (auto &pending : other.pending_eager_invocs)
     733          332 :         pending_eager_invocs.emplace_back (
     734          332 :           pending->clone_macro_invocation_impl ());
     735        11903 :   }
     736              : 
     737              :   std::vector<Attribute> outer_attrs;
     738              :   location_t locus;
     739              :   NodeId node_id;
     740              : 
     741              :   /* The data given to the macro invocation */
     742              :   MacroInvocData invoc_data;
     743              : 
     744              :   /* Important for when we actually expand the macro */
     745              :   bool is_semi_coloned;
     746              : 
     747              :   /* Is this a builtin macro or a regular macro */
     748              :   InvocKind kind;
     749              : 
     750              :   /* If it is a builtin macro, which one */
     751              :   tl::optional<BuiltinMacro> builtin_kind = tl::nullopt;
     752              : 
     753              :   /**
     754              :    * Pending invocations within a builtin macro invocation. This vector is empty
     755              :    * and should not be accessed for a regular macro invocation. The macro
     756              :    * invocations within should be name resolved and expanded before the builtin
     757              :    * macro invocation get expanded again. It is then the role of the expander to
     758              :    * insert these new tokens properly in the delimited token tree and try the
     759              :    * builtin transcriber once again.
     760              :    */
     761              :   std::vector<std::unique_ptr<MacroInvocation>> pending_eager_invocs;
     762              : 
     763              : protected:
     764            0 :   MacroInvocation *clone_pattern_impl () const final override
     765              :   {
     766            0 :     return clone_macro_invocation_impl ();
     767              :   }
     768              : 
     769            0 :   MacroInvocation *clone_expr_without_block_impl () const final override
     770              :   {
     771            0 :     return clone_macro_invocation_impl ();
     772              :   }
     773              : 
     774           29 :   MacroInvocation *clone_type_no_bounds_impl () const final override
     775              :   {
     776           29 :     return clone_macro_invocation_impl ();
     777              :   }
     778              : 
     779            0 :   MacroInvocation *clone_external_item_impl () const final override
     780              :   {
     781            0 :     return clone_macro_invocation_impl ();
     782              :   }
     783              : 
     784              : public:
     785        11903 :   /*virtual*/ MacroInvocation *clone_macro_invocation_impl () const
     786              :   {
     787        11903 :     return new MacroInvocation (*this);
     788              :   }
     789              : 
     790              :   std::unique_ptr<MacroInvocation> reconstruct_macro_invocation () const
     791              :   {
     792              :     return nullptr;
     793              :     //  return reconstruct (this,
     794              :     // &MacroInvocation::reconstruct_macro_invocation_impl);
     795              :   }
     796              : 
     797            0 :   MacroInvocation *reconstruct_impl () const override
     798              :   {
     799            0 :     return new MacroInvocation (kind, builtin_kind, invoc_data, outer_attrs,
     800            0 :                                 locus, is_semi_coloned,
     801            0 :                                 reconstruct_vec (pending_eager_invocs));
     802              :   }
     803              : 
     804          516 :   void add_semicolon () override { is_semi_coloned = true; }
     805              : 
     806            0 :   Pattern::Kind get_pattern_kind () override
     807              :   {
     808            0 :     return Pattern::Kind::MacroInvocation;
     809              :   }
     810              : 
     811           18 :   Expr::Kind get_expr_kind () const override
     812              :   {
     813           18 :     return Expr::Kind::MacroInvocation;
     814              :   }
     815              : 
     816            0 :   Item::Kind get_item_kind () const override
     817              :   {
     818            0 :     return Item::Kind::MacroInvocation;
     819              :   }
     820              : 
     821            0 :   Type::Kind get_type_kind () const override
     822              :   {
     823            0 :     return Type::Kind::MacroInvocation;
     824              :   }
     825              : 
     826              : protected:
     827         1177 :   Item *clone_item_impl () const override
     828              :   {
     829         1177 :     return clone_macro_invocation_impl ();
     830              :   }
     831              : 
     832            0 :   bool is_item () const override { return !has_semicolon (); }
     833              : 
     834            0 :   MacroInvocation *clone_associated_item_impl () const override
     835              :   {
     836            0 :     return clone_macro_invocation_impl ();
     837              :   };
     838              : };
     839              : 
     840              : // more generic meta item path-only form
     841          291 : class MetaItemPath : public MetaItem
     842              : {
     843              :   SimplePath path;
     844              : 
     845              : public:
     846          291 :   MetaItemPath (SimplePath path) : path (std::move (path)) {}
     847              : 
     848            0 :   std::string as_string () const override { return path.as_string (); }
     849              : 
     850              :   void accept_vis (ASTVisitor &vis) override;
     851              : 
     852              :   // HACK: used to simplify parsing - returns non-empty only in this case
     853            0 :   SimplePath to_path_item () const override
     854              :   {
     855              :     // this should copy construct - TODO ensure it does
     856            0 :     return path;
     857              :   }
     858              : 
     859          491 :   SimplePath &get_path () { return path; }
     860              : 
     861            0 :   location_t get_locus () const override { return path.get_locus (); }
     862              : 
     863              :   bool check_cfg_predicate (const Session &session) const override;
     864              : 
     865              :   Attribute to_attribute () const override;
     866              : 
     867          200 :   MetaItem::ItemKind get_item_kind () const override
     868              :   {
     869          200 :     return MetaItem::ItemKind::Path;
     870              :   }
     871              : 
     872              : protected:
     873              :   // Use covariance to implement clone function as returning this type
     874          200 :   MetaItemPath *clone_meta_item_inner_impl () const override
     875              :   {
     876          200 :     return new MetaItemPath (*this);
     877              :   }
     878              : };
     879              : 
     880              : // more generic meta item sequence form
     881              : class MetaItemSeq : public MetaItem
     882              : {
     883              :   SimplePath path;
     884              :   std::vector<std::unique_ptr<MetaItemInner>> seq;
     885              : 
     886              : public:
     887          140 :   MetaItemSeq (SimplePath path, std::vector<std::unique_ptr<MetaItemInner>> seq)
     888          140 :     : path (std::move (path)), seq (std::move (seq))
     889          140 :   {}
     890              : 
     891              :   // copy constructor with vector clone
     892           19 :   MetaItemSeq (const MetaItemSeq &other) : path (other.path)
     893              :   {
     894           19 :     seq.reserve (other.seq.size ());
     895           45 :     for (const auto &e : other.seq)
     896           26 :       seq.push_back (e->clone_meta_item_inner ());
     897           19 :   }
     898              : 
     899              :   // overloaded assignment operator with vector clone
     900              :   MetaItemSeq &operator= (const MetaItemSeq &other)
     901              :   {
     902              :     MetaItem::operator= (other);
     903              :     path = other.path;
     904              : 
     905              :     seq.reserve (other.seq.size ());
     906              :     for (const auto &e : other.seq)
     907              :       seq.push_back (e->clone_meta_item_inner ());
     908              : 
     909              :     return *this;
     910              :   }
     911              : 
     912              :   // default move constructors
     913              :   MetaItemSeq (MetaItemSeq &&other) = default;
     914              :   MetaItemSeq &operator= (MetaItemSeq &&other) = default;
     915              : 
     916              :   std::string as_string () const override;
     917              : 
     918           31 :   SimplePath &get_path () { return path; }
     919              : 
     920           31 :   std::vector<std::unique_ptr<MetaItemInner>> &get_seq () { return seq; }
     921              : 
     922              :   void accept_vis (ASTVisitor &vis) override;
     923              : 
     924            0 :   location_t get_locus () const override { return path.get_locus (); }
     925              : 
     926              :   bool check_cfg_predicate (const Session &session) const override;
     927              : 
     928              :   Attribute to_attribute () const override;
     929              : 
     930            7 :   MetaItem::ItemKind get_item_kind () const override
     931              :   {
     932            7 :     return MetaItem::ItemKind::Seq;
     933              :   }
     934              : 
     935              : protected:
     936              :   // Use covariance to implement clone function as returning this type
     937           19 :   MetaItemSeq *clone_meta_item_inner_impl () const override
     938              :   {
     939           19 :     return new MetaItemSeq (*this);
     940              :   }
     941              : };
     942              : 
     943              : // Preferred specialisation for single-identifier meta items.
     944          244 : class MetaWord : public MetaItem
     945              : {
     946              :   Identifier ident;
     947              :   location_t ident_locus;
     948              : 
     949              : public:
     950        14459 :   MetaWord (Identifier ident, location_t ident_locus)
     951        14459 :     : ident (std::move (ident)), ident_locus (ident_locus)
     952              :   {}
     953              : 
     954         7050 :   std::string as_string () const override { return ident.as_string (); }
     955              : 
     956              :   void accept_vis (ASTVisitor &vis) override;
     957              : 
     958          291 :   Identifier &get_ident () { return ident; }
     959              : 
     960            4 :   location_t get_locus () const override { return ident_locus; }
     961              : 
     962              :   bool check_cfg_predicate (const Session &session) const override;
     963              : 
     964              :   Attribute to_attribute () const override;
     965              : 
     966          291 :   MetaItem::ItemKind get_item_kind () const override
     967              :   {
     968          291 :     return MetaItem::ItemKind::Word;
     969              :   }
     970              : 
     971              : protected:
     972              :   // Use covariance to implement clone function as returning this type
     973          122 :   MetaWord *clone_meta_item_inner_impl () const override
     974              :   {
     975          122 :     return new MetaWord (*this);
     976              :   }
     977              : };
     978              : 
     979              : // Preferred specialisation for "identifier '=' string literal" meta items.
     980              : class MetaNameValueStr : public MetaItem
     981              : {
     982              :   Identifier ident;
     983              :   location_t ident_locus;
     984              : 
     985              :   // NOTE: str stored without quotes
     986              :   std::string str;
     987              :   location_t str_locus;
     988              : 
     989              : public:
     990         5297 :   MetaNameValueStr (Identifier ident, location_t ident_locus, std::string str,
     991              :                     location_t str_locus)
     992        10594 :     : ident (std::move (ident)), ident_locus (ident_locus),
     993         5297 :       str (std::move (str)), str_locus (str_locus)
     994         5297 :   {}
     995              : 
     996         1867 :   std::string as_string () const override
     997              :   {
     998         3734 :     return ident.as_string () + " = \"" + str + "\"";
     999              :   }
    1000              : 
    1001              :   const Identifier &get_name () const { return ident; }
    1002              : 
    1003          909 :   const std::string &get_value () const { return str; }
    1004              : 
    1005              :   void accept_vis (ASTVisitor &vis) override;
    1006              : 
    1007              :   // HACK: used to simplify parsing - creates a copy of this
    1008            4 :   std::unique_ptr<MetaNameValueStr> to_meta_name_value_str () const override
    1009              :   {
    1010            4 :     return std::unique_ptr<MetaNameValueStr> (clone_meta_item_inner_impl ());
    1011              :   }
    1012              : 
    1013           15 :   location_t get_locus () const override { return ident_locus; }
    1014              : 
    1015              :   bool check_cfg_predicate (const Session &session) const override;
    1016              : 
    1017              :   Attribute to_attribute () const override;
    1018              : 
    1019          716 :   inline std::pair<Identifier, std::string> get_name_value_pair () const
    1020              :   {
    1021          716 :     return std::pair<Identifier, std::string> (ident, str);
    1022              :   }
    1023              : 
    1024         2525 :   bool is_key_value_pair () const override { return true; }
    1025              : 
    1026            0 :   MetaItem::ItemKind get_item_kind () const override
    1027              :   {
    1028            0 :     return MetaItem::ItemKind::NameValueStr;
    1029              :   }
    1030              : 
    1031              : protected:
    1032              :   // Use covariance to implement clone function as returning this type
    1033         2124 :   MetaNameValueStr *clone_meta_item_inner_impl () const override
    1034              :   {
    1035         2124 :     return new MetaNameValueStr (*this);
    1036              :   }
    1037              : };
    1038              : 
    1039              : // doubles up as MetaListIdents - determine via iterating through each path?
    1040              : // Preferred specialisation for "identifier '(' SimplePath, SimplePath, ... ')'"
    1041              : class MetaListPaths : public MetaItem
    1042              : {
    1043              :   Identifier ident;
    1044              :   location_t ident_locus;
    1045              :   std::vector<SimplePath> paths;
    1046              : 
    1047              : public:
    1048            0 :   MetaListPaths (Identifier ident, location_t ident_locus,
    1049              :                  std::vector<SimplePath> paths)
    1050            0 :     : ident (std::move (ident)), ident_locus (ident_locus),
    1051            0 :       paths (std::move (paths))
    1052            0 :   {}
    1053              : 
    1054              :   std::string as_string () const override;
    1055              : 
    1056              :   void accept_vis (ASTVisitor &vis) override;
    1057              : 
    1058            0 :   Identifier get_ident () const { return ident; }
    1059              : 
    1060            0 :   std::vector<SimplePath> &get_paths () { return paths; };
    1061              : 
    1062            0 :   location_t get_locus () const override { return ident_locus; }
    1063              : 
    1064              :   bool check_cfg_predicate (const Session &session) const override;
    1065              : 
    1066              :   Attribute to_attribute () const override;
    1067              : 
    1068            0 :   MetaItem::ItemKind get_item_kind () const override
    1069              :   {
    1070            0 :     return MetaItem::ItemKind::ListPaths;
    1071              :   }
    1072              : 
    1073              : private:
    1074              :   bool check_path_exists_in_cfg (const Session &session,
    1075              :                                  const SimplePath &path) const;
    1076              : 
    1077              : protected:
    1078              :   // Use covariance to implement clone function as returning this type
    1079            0 :   MetaListPaths *clone_meta_item_inner_impl () const override
    1080              :   {
    1081            0 :     return new MetaListPaths (*this);
    1082              :   }
    1083              : };
    1084              : 
    1085              : // Preferred specialisation for "identifier '(' MetaNameValueStr, ... ')'"
    1086              : class MetaListNameValueStr : public MetaItem
    1087              : {
    1088              :   Identifier ident;
    1089              :   location_t ident_locus;
    1090              :   std::vector<MetaNameValueStr> strs;
    1091              : 
    1092              : public:
    1093            0 :   MetaListNameValueStr (Identifier ident, location_t ident_locus,
    1094              :                         std::vector<MetaNameValueStr> strs)
    1095            0 :     : ident (std::move (ident)), ident_locus (ident_locus),
    1096            0 :       strs (std::move (strs))
    1097            0 :   {}
    1098              : 
    1099              :   std::string as_string () const override;
    1100              : 
    1101              :   void accept_vis (ASTVisitor &vis) override;
    1102              : 
    1103            0 :   Identifier get_ident () { return ident; }
    1104              : 
    1105            0 :   std::vector<MetaNameValueStr> &get_values () { return strs; }
    1106              : 
    1107            0 :   location_t get_locus () const override { return ident_locus; }
    1108              : 
    1109              :   bool check_cfg_predicate (const Session &session) const override;
    1110              : 
    1111              :   Attribute to_attribute () const override;
    1112              : 
    1113            0 :   MetaItem::ItemKind get_item_kind () const override
    1114              :   {
    1115            0 :     return MetaItem::ItemKind::ListNameValueStr;
    1116              :   }
    1117              : 
    1118              : protected:
    1119              :   // Use covariance to implement clone function as returning this type
    1120            0 :   MetaListNameValueStr *clone_meta_item_inner_impl () const override
    1121              :   {
    1122            0 :     return new MetaListNameValueStr (*this);
    1123              :   }
    1124              : };
    1125              : 
    1126              : // Object that parses macros from a token stream.
    1127              : /* TODO: would "AttributeParser" be a better name? MetaItems are only for
    1128              :  * attributes, I believe */
    1129              : struct AttributeParser
    1130              : {
    1131              : private:
    1132              :   // TODO: might as well rewrite to use lexer tokens
    1133              :   std::unique_ptr<MacroInvocLexer> lexer;
    1134              :   std::unique_ptr<Parser<MacroInvocLexer>> parser;
    1135              : 
    1136              : public:
    1137              :   AttributeParser (std::vector<const_TokenPtr> token_stream,
    1138              :                    int stream_start_pos = 0);
    1139              : 
    1140              :   ~AttributeParser ();
    1141              : 
    1142              :   std::vector<std::unique_ptr<MetaItemInner>> parse_meta_item_seq ();
    1143              : 
    1144              : private:
    1145              :   // Parses a MetaItemInner.
    1146              :   std::unique_ptr<MetaItemInner> parse_meta_item_inner ();
    1147              :   // Returns whether token can end a meta item.
    1148              :   bool is_end_meta_item_tok (TokenId id) const;
    1149              :   // Parses a MetaItemLitExpr.
    1150              :   std::unique_ptr<MetaItemLitExpr> parse_meta_item_lit ();
    1151              :   // Parses a meta item that begins with a simple path.
    1152              :   std::unique_ptr<MetaItem> parse_path_meta_item ();
    1153              : };
    1154              : } // namespace AST
    1155              : } // namespace Rust
    1156              : 
    1157              : /* <https://stackoverflow.com/a/35304501> */
    1158              : namespace std {
    1159              : template <> struct hash<Rust::AST::MacroFragSpec::Kind>
    1160              : {
    1161         1760 :   size_t operator() (const Rust::AST::MacroFragSpec::Kind &t) const noexcept
    1162              :   {
    1163         1760 :     return size_t (t);
    1164              :   }
    1165              : };
    1166              : } // namespace std
    1167              : 
    1168              : #endif
        

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.