LCOV - code coverage report
Current view: top level - gcc/rust/ast - rust-macro.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 73.0 % 333 243
Test Date: 2026-03-28 14:25:54 Functions: 65.1 % 83 54
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          979 :   MacroFragSpec (Kind kind) : kind (kind) {}
      59              : 
      60          979 :   static MacroFragSpec get_frag_spec_from_str (const std::string &str)
      61              :   {
      62          979 :     if (str == "block")
      63            4 :       return MacroFragSpec (BLOCK);
      64          975 :     else if (str == "expr")
      65          328 :       return MacroFragSpec (EXPR);
      66          647 :     else if (str == "ident")
      67          109 :       return MacroFragSpec (IDENT);
      68          538 :     else if (str == "item")
      69            3 :       return MacroFragSpec (ITEM);
      70          535 :     else if (str == "lifetime")
      71            2 :       return MacroFragSpec (LIFETIME);
      72          533 :     else if (str == "literal")
      73          111 :       return MacroFragSpec (LITERAL);
      74          422 :     else if (str == "meta")
      75           14 :       return MacroFragSpec (META);
      76          408 :     else if (str == "pat" || str == "pat_param")
      77           10 :       return MacroFragSpec (PAT);
      78          398 :     else if (str == "path")
      79            1 :       return MacroFragSpec (PATH);
      80          397 :     else if (str == "stmt")
      81           52 :       return MacroFragSpec (STMT);
      82          345 :     else if (str == "tt")
      83           39 :       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         8397 :   Kind get_kind () const { return kind; }
      97          979 :   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          257 :   bool has_follow_set_restrictions () const
     138              :   {
     139          257 :     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         4006 : class MacroMatchFragment : public MacroMatch
     173              : {
     174              :   Identifier ident;
     175              :   MacroFragSpec frag_spec;
     176              :   location_t locus;
     177              : 
     178              : public:
     179          979 :   MacroMatchFragment (Identifier ident, MacroFragSpec frag_spec,
     180              :                       location_t locus)
     181          979 :     : 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        10433 :   MacroMatchType get_macro_match_type () const override
     204              :   {
     205        10433 :     return MacroMatchType::Fragment;
     206              :   }
     207              : 
     208        13726 :   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         2003 :   MacroMatchFragment *clone_macro_match_impl () const override
     215              :   {
     216         2003 :     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         4239 :   bool has_sep () const { return sep != nullptr; }
     245              : 
     246          523 :   MacroMatchRepetition (std::vector<std::unique_ptr<MacroMatch>> matches,
     247              :                         MacroRepOp op, std::unique_ptr<MacroRepSep> sep,
     248              :                         location_t locus)
     249          523 :     : matches (std::move (matches)), op (op), sep (std::move (sep)),
     250          523 :       locus (locus)
     251              :   {}
     252              : 
     253              :   // Copy constructor with clone
     254         1038 :   MacroMatchRepetition (MacroMatchRepetition const &other)
     255         1038 :     : op (other.op), locus (other.locus)
     256              :   {
     257              :     // guard to protect from null pointer dereference
     258         1038 :     if (other.sep != nullptr)
     259          275 :       sep = other.sep->clone_token ();
     260              : 
     261         1038 :     matches.reserve (other.matches.size ());
     262         2370 :     for (const auto &e : other.matches)
     263         1332 :       matches.push_back (e->clone_macro_match ());
     264         1038 :   }
     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         1754 :   location_t get_match_locus () const override { return locus; };
     291              : 
     292              :   void accept_vis (ASTVisitor &vis) override;
     293              : 
     294         1808 :   MacroMatchType get_macro_match_type () const override
     295              :   {
     296         1808 :     return MacroMatchType::Repetition;
     297              :   }
     298              : 
     299         1749 :   MacroRepOp get_op () const { return op; }
     300          357 :   const std::unique_ptr<MacroRepSep> &get_sep () const { return sep; }
     301         9254 :   std::vector<std::unique_ptr<MacroMatch>> &get_matches () { return matches; }
     302              :   const std::vector<std::unique_ptr<MacroMatch>> &get_matches () const
     303              :   {
     304           47 :     return matches;
     305              :   }
     306              : 
     307              : protected:
     308              :   /* Use covariance to implement clone function as returning this object rather
     309              :    * than base */
     310         1038 :   MacroMatchRepetition *clone_macro_match_impl () const override
     311              :   {
     312         1038 :     return new MacroMatchRepetition (*this);
     313              :   }
     314              : };
     315              : 
     316              : // can't inline due to polymorphism
     317         2333 : 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         1187 :   MacroMatcher (DelimType delim_type,
     328              :                 std::vector<std::unique_ptr<MacroMatch>> matches,
     329              :                 location_t locus)
     330         1187 :     : delim_type (delim_type), matches (std::move (matches)), locus (locus),
     331         1187 :       is_invalid (false)
     332              :   {}
     333              : 
     334              :   // copy constructor with vector clone
     335         2429 :   MacroMatcher (MacroMatcher const &other)
     336         2429 :     : delim_type (other.delim_type), locus (other.locus)
     337              :   {
     338         2429 :     matches.reserve (other.matches.size ());
     339         5339 :     for (const auto &e : other.matches)
     340         2910 :       matches.push_back (e->clone_macro_match ());
     341         2429 :   }
     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         1186 :   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         1201 :   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          146 :   MacroMatchType get_macro_match_type () const override
     375              :   {
     376          146 :     return MacroMatchType::Matcher;
     377              :   }
     378              : 
     379          117 :   DelimType get_delim_type () const { return delim_type; }
     380        16400 :   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          132 :   MacroMatcher *clone_macro_match_impl () const override
     390              :   {
     391          132 :     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         2258 : struct MacroTranscriber
     402              : {
     403              : private:
     404              :   DelimTokenTree token_tree;
     405              :   location_t locus;
     406              : 
     407              : public:
     408         1133 :   MacroTranscriber (DelimTokenTree token_tree, location_t locus)
     409         1120 :     : 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        14314 :   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         1132 :   MacroRule (MacroMatcher matcher, MacroTranscriber transcriber,
     430              :              location_t locus)
     431         1132 :     : matcher (std::move (matcher)), transcriber (std::move (transcriber)),
     432         1132 :       locus (locus)
     433         1132 :   {}
     434              : 
     435              :   // Returns whether macro rule is in error state.
     436         1113 :   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        15710 :   MacroMatcher &get_matcher () { return matcher; }
     452        14310 :   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          975 :   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          975 :     : VisItem (std::move (vis), outer_attrs),
     506         1950 :       outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)),
     507          975 :       delim_type (delim_type), rules (std::move (rules)), locus (locus),
     508          975 :       associated_transcriber (dummy_builtin), is_builtin_rule (false),
     509          975 :       kind (kind)
     510          975 :   {}
     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          932 :   mbe (Identifier rule_name, DelimType delim_type, std::vector<MacroRule> rules,
     527              :        std::vector<Attribute> outer_attrs, location_t locus)
     528              :   {
     529          932 :     return std::make_unique<MacroRulesDefinition> (
     530          932 :       MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus,
     531              :                             AST::MacroRulesDefinition::MacroKind::MBE,
     532         1864 :                             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         6244 :   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        26156 :   std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
     553         3784 :   const std::vector<Attribute> &get_outer_attrs () const override
     554              :   {
     555         3784 :     return outer_attrs;
     556              :   }
     557              : 
     558         9491 :   std::vector<MacroRule> &get_macro_rules () { return rules; }
     559              :   const std::vector<MacroRule> &get_macro_rules () const { return rules; }
     560              : 
     561          507 :   location_t get_locus () const override final { return locus; }
     562              : 
     563         4249 :   Identifier get_rule_name () const { return rule_name; }
     564              : 
     565         2453 :   std::vector<MacroRule> &get_rules () { return rules; }
     566              :   const std::vector<MacroRule> &get_rules () const { return rules; }
     567              : 
     568         2805 :   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          146 :   void set_builtin_transcriber (MacroTranscriberFunc transcriber)
     575              :   {
     576          146 :     associated_transcriber = transcriber;
     577          146 :     is_builtin_rule = true;
     578              :   }
     579              : 
     580         4702 :   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         1005 :   MacroRulesDefinition *clone_item_impl () const override
     591              :   {
     592         1005 :     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         2960 :   Regular (MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
     628              :            location_t locus, bool is_semi_coloned = false)
     629              :   {
     630         2960 :     return std::unique_ptr<MacroInvocation> (
     631              :       new MacroInvocation (InvocKind::Regular, tl::nullopt, invoc_data,
     632         2960 :                            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         2952 :   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         3924 :   bool is_marked_for_strip () const override
     660              :   {
     661         3924 :     return invoc_data.is_marked_for_strip ();
     662              :   }
     663              : 
     664          818 :   const std::vector<Attribute> &get_outer_attrs () const override
     665              :   {
     666          818 :     return outer_attrs;
     667              :   }
     668        14095 :   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        16855 :   NodeId get_node_id () const override final { return node_id; }
     676              : 
     677         7085 :   MacroInvocData &get_invoc_data () { return invoc_data; }
     678              : 
     679         2798 :   bool has_semicolon () const { return is_semi_coloned; }
     680              : 
     681         5691 :   InvocKind get_kind () const { return kind; }
     682              :   tl::optional<BuiltinMacro> get_builtin_kind () const { return builtin_kind; }
     683              : 
     684              :   /**
     685              :    * Turn the current MacroInvocation into a builtin macro invocation
     686              :    */
     687              :   void map_to_builtin (BuiltinMacro macro)
     688              :   {
     689              :     kind = InvocKind::Builtin;
     690              :     builtin_kind = macro;
     691              :   }
     692              : 
     693              :   /**
     694              :    * Get the list of pending macro invcations within the builtin macro
     695              :    * invocation that should get expanded eagerly.
     696              :    */
     697              :   std::vector<std::unique_ptr<MacroInvocation>> &
     698          175 :   get_pending_eager_invocations ()
     699              :   {
     700          175 :     rust_assert (kind == InvocKind::Builtin);
     701              : 
     702          175 :     return pending_eager_invocs;
     703              :   }
     704              : 
     705              : private:
     706              :   /* Full constructor */
     707         3011 :   MacroInvocation (
     708              :     InvocKind kind, tl::optional<BuiltinMacro> builtin_kind,
     709              :     MacroInvocData invoc_data, std::vector<Attribute> outer_attrs,
     710              :     location_t locus, bool is_semi_coloned,
     711              :     std::vector<std::unique_ptr<MacroInvocation>> &&pending_eager_invocs)
     712         3011 :     : TraitItem (locus),
     713         3011 :       ExternalItem (Analysis::Mappings::get ().get_next_node_id ()),
     714         3011 :       outer_attrs (std::move (outer_attrs)), locus (locus),
     715         3011 :       node_id (ExternalItem::get_node_id ()),
     716         3011 :       invoc_data (std::move (invoc_data)), is_semi_coloned (is_semi_coloned),
     717         3011 :       kind (kind), builtin_kind (builtin_kind),
     718         3011 :       pending_eager_invocs (std::move (pending_eager_invocs))
     719         3011 :   {}
     720              : 
     721        11922 :   MacroInvocation (const MacroInvocation &other)
     722        35766 :     : TraitItem (other.locus), ExternalItem (other.node_id),
     723        23844 :       outer_attrs (other.outer_attrs), locus (other.locus),
     724        11922 :       node_id (other.node_id), invoc_data (other.invoc_data),
     725        11922 :       is_semi_coloned (other.is_semi_coloned), kind (other.kind),
     726        23844 :       builtin_kind (other.builtin_kind)
     727              :   {
     728        11922 :     if (other.kind == InvocKind::Builtin)
     729          683 :       for (auto &pending : other.pending_eager_invocs)
     730          332 :         pending_eager_invocs.emplace_back (
     731          332 :           pending->clone_macro_invocation_impl ());
     732        11922 :   }
     733              : 
     734              :   std::vector<Attribute> outer_attrs;
     735              :   location_t locus;
     736              :   NodeId node_id;
     737              : 
     738              :   /* The data given to the macro invocation */
     739              :   MacroInvocData invoc_data;
     740              : 
     741              :   /* Important for when we actually expand the macro */
     742              :   bool is_semi_coloned;
     743              : 
     744              :   /* Is this a builtin macro or a regular macro */
     745              :   InvocKind kind;
     746              : 
     747              :   /* If it is a builtin macro, which one */
     748              :   tl::optional<BuiltinMacro> builtin_kind = tl::nullopt;
     749              : 
     750              :   /**
     751              :    * Pending invocations within a builtin macro invocation. This vector is empty
     752              :    * and should not be accessed for a regular macro invocation. The macro
     753              :    * invocations within should be name resolved and expanded before the builtin
     754              :    * macro invocation get expanded again. It is then the role of the expander to
     755              :    * insert these new tokens properly in the delimited token tree and try the
     756              :    * builtin transcriber once again.
     757              :    */
     758              :   std::vector<std::unique_ptr<MacroInvocation>> pending_eager_invocs;
     759              : 
     760              : protected:
     761            0 :   MacroInvocation *clone_pattern_impl () const final override
     762              :   {
     763            0 :     return clone_macro_invocation_impl ();
     764              :   }
     765              : 
     766            0 :   MacroInvocation *clone_expr_without_block_impl () const final override
     767              :   {
     768            0 :     return clone_macro_invocation_impl ();
     769              :   }
     770              : 
     771           29 :   MacroInvocation *clone_type_no_bounds_impl () const final override
     772              :   {
     773           29 :     return clone_macro_invocation_impl ();
     774              :   }
     775              : 
     776            0 :   MacroInvocation *clone_external_item_impl () const final override
     777              :   {
     778            0 :     return clone_macro_invocation_impl ();
     779              :   }
     780              : 
     781              : public:
     782        11922 :   /*virtual*/ MacroInvocation *clone_macro_invocation_impl () const
     783              :   {
     784        11922 :     return new MacroInvocation (*this);
     785              :   }
     786              : 
     787              :   std::unique_ptr<MacroInvocation> reconstruct_macro_invocation () const
     788              :   {
     789              :     return nullptr;
     790              :     //  return reconstruct (this,
     791              :     // &MacroInvocation::reconstruct_macro_invocation_impl);
     792              :   }
     793              : 
     794            0 :   MacroInvocation *reconstruct_impl () const override
     795              :   {
     796            0 :     return new MacroInvocation (kind, builtin_kind, invoc_data, outer_attrs,
     797            0 :                                 locus, is_semi_coloned,
     798            0 :                                 reconstruct_vec (pending_eager_invocs));
     799              :   }
     800              : 
     801          516 :   void add_semicolon () override { is_semi_coloned = true; }
     802              : 
     803            0 :   Pattern::Kind get_pattern_kind () override
     804              :   {
     805            0 :     return Pattern::Kind::MacroInvocation;
     806              :   }
     807              : 
     808           18 :   Expr::Kind get_expr_kind () const override
     809              :   {
     810           18 :     return Expr::Kind::MacroInvocation;
     811              :   }
     812              : 
     813            0 :   Item::Kind get_item_kind () const override
     814              :   {
     815            0 :     return Item::Kind::MacroInvocation;
     816              :   }
     817              : 
     818            0 :   Type::Kind get_type_kind () const override
     819              :   {
     820            0 :     return Type::Kind::MacroInvocation;
     821              :   }
     822              : 
     823              : protected:
     824         1178 :   Item *clone_item_impl () const override
     825              :   {
     826         1178 :     return clone_macro_invocation_impl ();
     827              :   }
     828              : 
     829            0 :   bool is_item () const override { return !has_semicolon (); }
     830              : 
     831            0 :   MacroInvocation *clone_associated_item_impl () const override
     832              :   {
     833            0 :     return clone_macro_invocation_impl ();
     834              :   };
     835              : };
     836              : 
     837              : // more generic meta item path-only form
     838          300 : class MetaItemPath : public MetaItem
     839              : {
     840              :   SimplePath path;
     841              : 
     842              : public:
     843          300 :   MetaItemPath (SimplePath path) : path (std::move (path)) {}
     844              : 
     845            0 :   std::string as_string () const override { return path.as_string (); }
     846              : 
     847              :   void accept_vis (ASTVisitor &vis) override;
     848              : 
     849              :   // HACK: used to simplify parsing - returns non-empty only in this case
     850            0 :   SimplePath to_path_item () const override
     851              :   {
     852              :     // this should copy construct - TODO ensure it does
     853            0 :     return path;
     854              :   }
     855              : 
     856          606 :   SimplePath &get_path () { return path; }
     857              : 
     858            0 :   location_t get_locus () const override { return path.get_locus (); }
     859              : 
     860              :   bool check_cfg_predicate (const Session &session) const override;
     861              : 
     862              :   Attribute to_attribute () const override;
     863              : 
     864          298 :   MetaItem::ItemKind get_item_kind () const override
     865              :   {
     866          298 :     return MetaItem::ItemKind::Path;
     867              :   }
     868              : 
     869              : protected:
     870              :   // Use covariance to implement clone function as returning this type
     871          298 :   MetaItemPath *clone_meta_item_inner_impl () const override
     872              :   {
     873          298 :     return new MetaItemPath (*this);
     874              :   }
     875              : };
     876              : 
     877              : // more generic meta item sequence form
     878              : class MetaItemSeq : public MetaItem
     879              : {
     880              :   SimplePath path;
     881              :   std::vector<std::unique_ptr<MetaItemInner>> seq;
     882              : 
     883              : public:
     884          111 :   MetaItemSeq (SimplePath path, std::vector<std::unique_ptr<MetaItemInner>> seq)
     885          111 :     : path (std::move (path)), seq (std::move (seq))
     886          111 :   {}
     887              : 
     888              :   // copy constructor with vector clone
     889           21 :   MetaItemSeq (const MetaItemSeq &other) : path (other.path)
     890              :   {
     891           21 :     seq.reserve (other.seq.size ());
     892           49 :     for (const auto &e : other.seq)
     893           28 :       seq.push_back (e->clone_meta_item_inner ());
     894           21 :   }
     895              : 
     896              :   // overloaded assignment operator with vector clone
     897              :   MetaItemSeq &operator= (const MetaItemSeq &other)
     898              :   {
     899              :     MetaItem::operator= (other);
     900              :     path = other.path;
     901              : 
     902              :     seq.reserve (other.seq.size ());
     903              :     for (const auto &e : other.seq)
     904              :       seq.push_back (e->clone_meta_item_inner ());
     905              : 
     906              :     return *this;
     907              :   }
     908              : 
     909              :   // default move constructors
     910              :   MetaItemSeq (MetaItemSeq &&other) = default;
     911              :   MetaItemSeq &operator= (MetaItemSeq &&other) = default;
     912              : 
     913              :   std::string as_string () const override;
     914              : 
     915          175 :   SimplePath &get_path () { return path; }
     916              : 
     917          175 :   std::vector<std::unique_ptr<MetaItemInner>> &get_seq () { return seq; }
     918              : 
     919              :   void accept_vis (ASTVisitor &vis) override;
     920              : 
     921            0 :   location_t get_locus () const override { return path.get_locus (); }
     922              : 
     923              :   bool check_cfg_predicate (const Session &session) const override;
     924              : 
     925              :   Attribute to_attribute () const override;
     926              : 
     927            0 :   MetaItem::ItemKind get_item_kind () const override
     928              :   {
     929            0 :     return MetaItem::ItemKind::Seq;
     930              :   }
     931              : 
     932              : protected:
     933              :   // Use covariance to implement clone function as returning this type
     934           21 :   MetaItemSeq *clone_meta_item_inner_impl () const override
     935              :   {
     936           21 :     return new MetaItemSeq (*this);
     937              :   }
     938              : };
     939              : 
     940              : // Preferred specialisation for single-identifier meta items.
     941          258 : class MetaWord : public MetaItem
     942              : {
     943              :   Identifier ident;
     944              :   location_t ident_locus;
     945              : 
     946              : public:
     947         7397 :   MetaWord (Identifier ident, location_t ident_locus)
     948         7397 :     : ident (std::move (ident)), ident_locus (ident_locus)
     949              :   {}
     950              : 
     951         7073 :   std::string as_string () const override { return ident.as_string (); }
     952              : 
     953              :   void accept_vis (ASTVisitor &vis) override;
     954              : 
     955              :   Identifier &get_ident () { return ident; }
     956              : 
     957          304 :   location_t get_locus () const override { return ident_locus; }
     958              : 
     959              :   bool check_cfg_predicate (const Session &session) const override;
     960              : 
     961              :   Attribute to_attribute () const override;
     962              : 
     963          300 :   MetaItem::ItemKind get_item_kind () const override
     964              :   {
     965          300 :     return MetaItem::ItemKind::Word;
     966              :   }
     967              : 
     968              : protected:
     969              :   // Use covariance to implement clone function as returning this type
     970          129 :   MetaWord *clone_meta_item_inner_impl () const override
     971              :   {
     972          129 :     return new MetaWord (*this);
     973              :   }
     974              : };
     975              : 
     976              : // Preferred specialisation for "identifier '=' string literal" meta items.
     977              : class MetaNameValueStr : public MetaItem
     978              : {
     979              :   Identifier ident;
     980              :   location_t ident_locus;
     981              : 
     982              :   // NOTE: str stored without quotes
     983              :   std::string str;
     984              :   location_t str_locus;
     985              : 
     986              : public:
     987         3598 :   MetaNameValueStr (Identifier ident, location_t ident_locus, std::string str,
     988              :                     location_t str_locus)
     989         7196 :     : ident (std::move (ident)), ident_locus (ident_locus),
     990         3598 :       str (std::move (str)), str_locus (str_locus)
     991         3598 :   {}
     992              : 
     993         1867 :   std::string as_string () const override
     994              :   {
     995         3734 :     return ident.as_string () + " = \"" + str + "\"";
     996              :   }
     997              : 
     998              :   const Identifier &get_name () const { return ident; }
     999              : 
    1000          909 :   const std::string &get_value () const { return str; }
    1001              : 
    1002              :   void accept_vis (ASTVisitor &vis) override;
    1003              : 
    1004              :   // HACK: used to simplify parsing - creates a copy of this
    1005            4 :   std::unique_ptr<MetaNameValueStr> to_meta_name_value_str () const override
    1006              :   {
    1007            4 :     return std::unique_ptr<MetaNameValueStr> (clone_meta_item_inner_impl ());
    1008              :   }
    1009              : 
    1010           15 :   location_t get_locus () const override { return ident_locus; }
    1011              : 
    1012              :   bool check_cfg_predicate (const Session &session) const override;
    1013              : 
    1014              :   Attribute to_attribute () const override;
    1015              : 
    1016          716 :   inline std::pair<Identifier, std::string> get_name_value_pair () const
    1017              :   {
    1018          716 :     return std::pair<Identifier, std::string> (ident, str);
    1019              :   }
    1020              : 
    1021         2525 :   bool is_key_value_pair () const override { return true; }
    1022              : 
    1023            0 :   MetaItem::ItemKind get_item_kind () const override
    1024              :   {
    1025            0 :     return MetaItem::ItemKind::NameValueStr;
    1026              :   }
    1027              : 
    1028              : protected:
    1029              :   // Use covariance to implement clone function as returning this type
    1030         2096 :   MetaNameValueStr *clone_meta_item_inner_impl () const override
    1031              :   {
    1032         2096 :     return new MetaNameValueStr (*this);
    1033              :   }
    1034              : };
    1035              : 
    1036              : // doubles up as MetaListIdents - determine via iterating through each path?
    1037              : // Preferred specialisation for "identifier '(' SimplePath, SimplePath, ... ')'"
    1038              : class MetaListPaths : public MetaItem
    1039              : {
    1040              :   Identifier ident;
    1041              :   location_t ident_locus;
    1042              :   std::vector<SimplePath> paths;
    1043              : 
    1044              : public:
    1045            0 :   MetaListPaths (Identifier ident, location_t ident_locus,
    1046              :                  std::vector<SimplePath> paths)
    1047            0 :     : ident (std::move (ident)), ident_locus (ident_locus),
    1048            0 :       paths (std::move (paths))
    1049            0 :   {}
    1050              : 
    1051              :   std::string as_string () const override;
    1052              : 
    1053              :   void accept_vis (ASTVisitor &vis) override;
    1054              : 
    1055            0 :   Identifier get_ident () const { return ident; }
    1056              : 
    1057            0 :   std::vector<SimplePath> &get_paths () { return paths; };
    1058              : 
    1059            0 :   location_t get_locus () const override { return ident_locus; }
    1060              : 
    1061              :   bool check_cfg_predicate (const Session &session) const override;
    1062              : 
    1063              :   Attribute to_attribute () const override;
    1064              : 
    1065            0 :   MetaItem::ItemKind get_item_kind () const override
    1066              :   {
    1067            0 :     return MetaItem::ItemKind::ListPaths;
    1068              :   }
    1069              : 
    1070              : private:
    1071              :   bool check_path_exists_in_cfg (const Session &session,
    1072              :                                  const SimplePath &path) const;
    1073              : 
    1074              : protected:
    1075              :   // Use covariance to implement clone function as returning this type
    1076            0 :   MetaListPaths *clone_meta_item_inner_impl () const override
    1077              :   {
    1078            0 :     return new MetaListPaths (*this);
    1079              :   }
    1080              : };
    1081              : 
    1082              : // Preferred specialisation for "identifier '(' MetaNameValueStr, ... ')'"
    1083              : class MetaListNameValueStr : public MetaItem
    1084              : {
    1085              :   Identifier ident;
    1086              :   location_t ident_locus;
    1087              :   std::vector<MetaNameValueStr> strs;
    1088              : 
    1089              : public:
    1090            0 :   MetaListNameValueStr (Identifier ident, location_t ident_locus,
    1091              :                         std::vector<MetaNameValueStr> strs)
    1092            0 :     : ident (std::move (ident)), ident_locus (ident_locus),
    1093            0 :       strs (std::move (strs))
    1094            0 :   {}
    1095              : 
    1096              :   std::string as_string () const override;
    1097              : 
    1098              :   void accept_vis (ASTVisitor &vis) override;
    1099              : 
    1100            0 :   Identifier get_ident () { return ident; }
    1101              : 
    1102            0 :   std::vector<MetaNameValueStr> &get_values () { return strs; }
    1103              : 
    1104            0 :   location_t get_locus () const override { return ident_locus; }
    1105              : 
    1106              :   bool check_cfg_predicate (const Session &session) const override;
    1107              : 
    1108              :   Attribute to_attribute () const override;
    1109              : 
    1110            0 :   MetaItem::ItemKind get_item_kind () const override
    1111              :   {
    1112            0 :     return MetaItem::ItemKind::ListNameValueStr;
    1113              :   }
    1114              : 
    1115              : protected:
    1116              :   // Use covariance to implement clone function as returning this type
    1117            0 :   MetaListNameValueStr *clone_meta_item_inner_impl () const override
    1118              :   {
    1119            0 :     return new MetaListNameValueStr (*this);
    1120              :   }
    1121              : };
    1122              : 
    1123              : // Object that parses macros from a token stream.
    1124              : /* TODO: would "AttributeParser" be a better name? MetaItems are only for
    1125              :  * attributes, I believe */
    1126              : struct AttributeParser
    1127              : {
    1128              : private:
    1129              :   // TODO: might as well rewrite to use lexer tokens
    1130              :   std::unique_ptr<MacroInvocLexer> lexer;
    1131              :   std::unique_ptr<Parser<MacroInvocLexer>> parser;
    1132              : 
    1133              : public:
    1134              :   AttributeParser (std::vector<const_TokenPtr> token_stream,
    1135              :                    int stream_start_pos = 0);
    1136              : 
    1137              :   ~AttributeParser ();
    1138              : 
    1139              :   std::vector<std::unique_ptr<MetaItemInner>> parse_meta_item_seq ();
    1140              : 
    1141              : private:
    1142              :   // Parses a MetaItemInner.
    1143              :   std::unique_ptr<MetaItemInner> parse_meta_item_inner ();
    1144              :   // Returns whether token can end a meta item.
    1145              :   bool is_end_meta_item_tok (TokenId id) const;
    1146              :   // Parses a MetaItemLitExpr.
    1147              :   std::unique_ptr<MetaItemLitExpr> parse_meta_item_lit ();
    1148              :   // Parses a meta item that begins with a simple path.
    1149              :   std::unique_ptr<MetaItem> parse_path_meta_item ();
    1150              : };
    1151              : } // namespace AST
    1152              : } // namespace Rust
    1153              : 
    1154              : /* <https://stackoverflow.com/a/35304501> */
    1155              : namespace std {
    1156              : template <> struct hash<Rust::AST::MacroFragSpec::Kind>
    1157              : {
    1158         1802 :   size_t operator() (const Rust::AST::MacroFragSpec::Kind &t) const noexcept
    1159              :   {
    1160         1802 :     return size_t (t);
    1161              :   }
    1162              : };
    1163              : } // namespace std
    1164              : 
    1165              : #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.