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