Clang Project

clang_source_code/include/clang/Lex/VariadicMacroSupport.h
1//===- VariadicMacroSupport.h - state machines and scope guards -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines support types to help with preprocessing variadic macro
10// (i.e. macros that use: ellipses __VA_ARGS__ ) definitions and
11// expansions.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H
16#define LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H
17
18#include "clang/Lex/Preprocessor.h"
19#include "llvm/ADT/SmallVector.h"
20
21namespace clang {
22  class Preprocessor;
23
24  /// An RAII class that tracks when the Preprocessor starts and stops lexing
25  /// the definition of a (ISO C/C++) variadic macro.  As an example, this is
26  /// useful for unpoisoning and repoisoning certain identifiers (such as
27  /// __VA_ARGS__) that are only allowed in this context.  Also, being a friend
28  /// of the Preprocessor class allows it to access PP's cached identifiers
29  /// directly (as opposed to performing a lookup each time).
30  class VariadicMacroScopeGuard {
31    const Preprocessor &PP;
32    IdentifierInfo *const Ident__VA_ARGS__;
33    IdentifierInfo *const Ident__VA_OPT__;
34
35  public:
36    VariadicMacroScopeGuard(const Preprocessor &P)
37        : PP(P), Ident__VA_ARGS__(PP.Ident__VA_ARGS__),
38          Ident__VA_OPT__(PP.Ident__VA_OPT__) {
39       (0) . __assert_fail ("Ident__VA_ARGS__->isPoisoned() && \"__VA_ARGS__ should be poisoned \" \"outside an ISO C/C++ variadic \" \"macro definition!\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 41, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned "
40 (0) . __assert_fail ("Ident__VA_ARGS__->isPoisoned() && \"__VA_ARGS__ should be poisoned \" \"outside an ISO C/C++ variadic \" \"macro definition!\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 41, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">                                              "outside an ISO C/C++ variadic "
41 (0) . __assert_fail ("Ident__VA_ARGS__->isPoisoned() && \"__VA_ARGS__ should be poisoned \" \"outside an ISO C/C++ variadic \" \"macro definition!\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 41, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">                                              "macro definition!");
42       (0) . __assert_fail ("!Ident__VA_OPT__ || (Ident__VA_OPT__->isPoisoned() && \"__VA_OPT__ should be poisoned!\")", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 44, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(
43 (0) . __assert_fail ("!Ident__VA_OPT__ || (Ident__VA_OPT__->isPoisoned() && \"__VA_OPT__ should be poisoned!\")", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 44, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">          !Ident__VA_OPT__ ||
44 (0) . __assert_fail ("!Ident__VA_OPT__ || (Ident__VA_OPT__->isPoisoned() && \"__VA_OPT__ should be poisoned!\")", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 44, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">          (Ident__VA_OPT__->isPoisoned() && "__VA_OPT__ should be poisoned!"));
45    }
46
47    /// Client code should call this function just before the Preprocessor is
48    /// about to Lex tokens from the definition of a variadic (ISO C/C++) macro.
49    void enterScope() {
50      Ident__VA_ARGS__->setIsPoisoned(false);
51      if (Ident__VA_OPT__)
52        Ident__VA_OPT__->setIsPoisoned(false);
53    }
54
55    /// Client code should call this function as soon as the Preprocessor has
56    /// either completed lexing the macro's definition tokens, or an error
57    /// occurred and the context is being exited.  This function is idempotent
58    /// (might be explicitly called, and then reinvoked via the destructor).
59    void exitScope() {
60      Ident__VA_ARGS__->setIsPoisoned(true);
61      if (Ident__VA_OPT__)
62        Ident__VA_OPT__->setIsPoisoned(true);
63    }
64
65    ~VariadicMacroScopeGuard() { exitScope(); }
66  };
67
68  /// A class for tracking whether we're inside a VA_OPT during a
69  /// traversal of the tokens of a variadic macro definition.
70  class VAOptDefinitionContext {
71    /// Contains all the locations of so far unmatched lparens.
72    SmallVector<SourceLocation8UnmatchedOpeningParens;
73
74    const IdentifierInfo *const Ident__VA_OPT__;
75
76
77  public:
78    VAOptDefinitionContext(Preprocessor &PP)
79        : Ident__VA_OPT__(PP.Ident__VA_OPT__) {}
80
81    bool isVAOptToken(const Token &Tconst {
82      return Ident__VA_OPT__ && T.getIdentifierInfo() == Ident__VA_OPT__;
83    }
84
85    /// Returns true if we have seen the __VA_OPT__ and '(' but before having
86    /// seen the matching ')'.
87    bool isInVAOpt() const { return UnmatchedOpeningParens.size(); }
88
89    /// Call this function as soon as you see __VA_OPT__ and '('.
90    void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc) {
91       (0) . __assert_fail ("!isInVAOpt() && \"Must NOT be within VAOPT context to call this\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 91, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this");
92      UnmatchedOpeningParens.push_back(LParenLoc);
93
94    }
95
96    SourceLocation getUnmatchedOpeningParenLoc() const {
97       (0) . __assert_fail ("isInVAOpt() && \"Must be within VAOPT context to call this\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 97, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(isInVAOpt() && "Must be within VAOPT context to call this");
98      return UnmatchedOpeningParens.back();
99    }
100
101    /// Call this function each time an rparen is seen.  It returns true only if
102    /// the rparen that was just seen was the eventual (non-nested) closing
103    /// paren for VAOPT, and ejects us out of the VAOPT context.
104    bool sawClosingParen() {
105       (0) . __assert_fail ("isInVAOpt() && \"Must be within VAOPT context to call this\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 105, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(isInVAOpt() && "Must be within VAOPT context to call this");
106      UnmatchedOpeningParens.pop_back();
107      return !UnmatchedOpeningParens.size();
108    }
109
110    /// Call this function each time an lparen is seen.
111    void sawOpeningParen(SourceLocation LParenLoc) {
112       (0) . __assert_fail ("isInVAOpt() && \"Must be within VAOPT context to call this\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 112, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(isInVAOpt() && "Must be within VAOPT context to call this");
113      UnmatchedOpeningParens.push_back(LParenLoc);
114    }
115
116  };
117
118  /// A class for tracking whether we're inside a VA_OPT during a
119  /// traversal of the tokens of a macro during macro expansion.
120  class VAOptExpansionContext : VAOptDefinitionContext {
121
122    Token SyntheticEOFToken;
123
124    // The (spelling) location of the current __VA_OPT__ in the replacement list
125    // of the function-like macro being expanded.
126    SourceLocation VAOptLoc;
127
128    // NumOfTokensPriorToVAOpt : when != -1, contains the index *of* the first
129    // token of the current VAOPT contents (so we know where to start eager
130    // token-pasting and stringification) *within*  the substituted tokens of
131    // the function-like macro's new replacement list.
132    int NumOfTokensPriorToVAOpt = -1;
133
134    unsigned LeadingSpaceForStringifiedToken : 1;
135
136    unsigned StringifyBefore : 1;
137    unsigned CharifyBefore : 1;
138
139
140    bool hasStringifyBefore() const {
141       (0) . __assert_fail ("!isReset() && \"Must only be called if the state has not been reset\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 142, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!isReset() &&
142 (0) . __assert_fail ("!isReset() && \"Must only be called if the state has not been reset\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 142, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">             "Must only be called if the state has not been reset");
143      return StringifyBefore;
144    }
145
146    bool isReset() const {
147      return NumOfTokensPriorToVAOpt == -1 ||
148             VAOptLoc.isInvalid();
149    }
150
151  public:
152    VAOptExpansionContext(Preprocessor &PP)
153        : VAOptDefinitionContext(PP), LeadingSpaceForStringifiedToken(false),
154          StringifyBefore(false), CharifyBefore(false) {
155      SyntheticEOFToken.startToken();
156      SyntheticEOFToken.setKind(tok::eof);
157    }
158
159    void reset() {
160      VAOptLoc = SourceLocation();
161      NumOfTokensPriorToVAOpt = -1;
162      LeadingSpaceForStringifiedToken = false;
163      StringifyBefore = false;
164      CharifyBefore = false;
165    }
166
167    const Token &getEOFTok() const { return SyntheticEOFToken; }
168
169    void sawHashOrHashAtBefore(const bool HasLeadingSpace,
170                               const bool IsHashAt) {
171
172      StringifyBefore = !IsHashAt;
173      CharifyBefore = IsHashAt;
174      LeadingSpaceForStringifiedToken = HasLeadingSpace;
175    }
176
177
178
179    bool hasCharifyBefore() const {
180       (0) . __assert_fail ("!isReset() && \"Must only be called if the state has not been reset\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 181, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!isReset() &&
181 (0) . __assert_fail ("!isReset() && \"Must only be called if the state has not been reset\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 181, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">             "Must only be called if the state has not been reset");
182      return CharifyBefore;
183    }
184    bool hasStringifyOrCharifyBefore() const {
185      return hasStringifyBefore() || hasCharifyBefore();
186    }
187
188    unsigned int getNumberOfTokensPriorToVAOpt() const {
189       (0) . __assert_fail ("!isReset() && \"Must only be called if the state has not been reset\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 190, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!isReset() &&
190 (0) . __assert_fail ("!isReset() && \"Must only be called if the state has not been reset\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 190, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">             "Must only be called if the state has not been reset");
191      return NumOfTokensPriorToVAOpt;
192    }
193
194    bool getLeadingSpaceForStringifiedToken() const {
195       (0) . __assert_fail ("hasStringifyBefore() && \"Must only be called if this has been marked for stringification\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 196, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(hasStringifyBefore() &&
196 (0) . __assert_fail ("hasStringifyBefore() && \"Must only be called if this has been marked for stringification\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 196, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">             "Must only be called if this has been marked for stringification");
197      return LeadingSpaceForStringifiedToken;
198    }
199
200    void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc,
201                                         const unsigned int NumPriorTokens) {
202       (0) . __assert_fail ("VAOptLoc.isFileID() && \"Must not come from a macro expansion\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 202, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(VAOptLoc.isFileID() && "Must not come from a macro expansion");
203       (0) . __assert_fail ("isReset() && \"Must only be called if the state has been reset\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 203, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(isReset() && "Must only be called if the state has been reset");
204      VAOptDefinitionContext::sawVAOptFollowedByOpeningParens(SourceLocation());
205      this->VAOptLoc = VAOptLoc;
206      NumOfTokensPriorToVAOpt = NumPriorTokens;
207       (0) . __assert_fail ("NumOfTokensPriorToVAOpt > -1 && \"Too many prior tokens\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 208, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(NumOfTokensPriorToVAOpt > -1 &&
208 (0) . __assert_fail ("NumOfTokensPriorToVAOpt > -1 && \"Too many prior tokens\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 208, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">             "Too many prior tokens");
209    }
210
211    SourceLocation getVAOptLoc() const {
212       (0) . __assert_fail ("!isReset() && \"Must only be called if the state has not been reset\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 213, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!isReset() &&
213 (0) . __assert_fail ("!isReset() && \"Must only be called if the state has not been reset\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 213, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">             "Must only be called if the state has not been reset");
214       (0) . __assert_fail ("VAOptLoc.isValid() && \"__VA_OPT__ location must be valid\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Lex/VariadicMacroSupport.h", 214, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(VAOptLoc.isValid() && "__VA_OPT__ location must be valid");
215      return VAOptLoc;
216    }
217    using VAOptDefinitionContext::isVAOptToken;
218    using VAOptDefinitionContext::isInVAOpt;
219    using VAOptDefinitionContext::sawClosingParen;
220    using VAOptDefinitionContext::sawOpeningParen;
221
222  };
223}  // end namespace clang
224
225#endif
226
clang::VariadicMacroScopeGuard::PP
clang::VariadicMacroScopeGuard::Ident__VA_ARGS__
clang::VariadicMacroScopeGuard::Ident__VA_OPT__
clang::VariadicMacroScopeGuard::enterScope
clang::VariadicMacroScopeGuard::exitScope
clang::VAOptDefinitionContext::UnmatchedOpeningParens
clang::VAOptDefinitionContext::Ident__VA_OPT__
clang::VAOptDefinitionContext::isVAOptToken
clang::VAOptDefinitionContext::isInVAOpt
clang::VAOptDefinitionContext::sawVAOptFollowedByOpeningParens
clang::VAOptDefinitionContext::getUnmatchedOpeningParenLoc
clang::VAOptDefinitionContext::sawClosingParen
clang::VAOptDefinitionContext::sawOpeningParen
clang::VAOptExpansionContext::SyntheticEOFToken
clang::VAOptExpansionContext::VAOptLoc
clang::VAOptExpansionContext::NumOfTokensPriorToVAOpt
clang::VAOptExpansionContext::LeadingSpaceForStringifiedToken
clang::VAOptExpansionContext::StringifyBefore
clang::VAOptExpansionContext::CharifyBefore
clang::VAOptExpansionContext::hasStringifyBefore
clang::VAOptExpansionContext::isReset
clang::VAOptExpansionContext::reset
clang::VAOptExpansionContext::getEOFTok
clang::VAOptExpansionContext::sawHashOrHashAtBefore
clang::VAOptExpansionContext::hasCharifyBefore
clang::VAOptExpansionContext::hasStringifyOrCharifyBefore
clang::VAOptExpansionContext::getNumberOfTokensPriorToVAOpt
clang::VAOptExpansionContext::getLeadingSpaceForStringifiedToken
clang::VAOptExpansionContext::sawVAOptFollowedByOpeningParens
clang::VAOptExpansionContext::getVAOptLoc