]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/clang/include/clang/Lex/VariadicMacroSupport.h
Move all sources from the llvm project into contrib/llvm-project.
[FreeBSD/FreeBSD.git] / contrib / llvm-project / clang / 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
21 namespace 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       assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned "
40                                               "outside an ISO C/C++ variadic "
41                                               "macro definition!");
42       assert(
43           !Ident__VA_OPT__ ||
44           (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<SourceLocation, 8> UnmatchedOpeningParens;
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 &T) const {
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       assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this");
92       UnmatchedOpeningParens.push_back(LParenLoc);
93
94     }
95
96     SourceLocation getUnmatchedOpeningParenLoc() const {
97       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       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       assert(isInVAOpt() && "Must be within VAOPT context to call this");
113       UnmatchedOpeningParens.push_back(LParenLoc);
114     }
115
116     /// Are we at the top level within the __VA_OPT__?
117     bool isAtTopLevel() const { return UnmatchedOpeningParens.size() == 1; }
118   };
119
120   /// A class for tracking whether we're inside a VA_OPT during a
121   /// traversal of the tokens of a macro during macro expansion.
122   class VAOptExpansionContext : VAOptDefinitionContext {
123
124     Token SyntheticEOFToken;
125
126     // The (spelling) location of the current __VA_OPT__ in the replacement list
127     // of the function-like macro being expanded.
128     SourceLocation VAOptLoc;
129
130     // NumOfTokensPriorToVAOpt : when != -1, contains the index *of* the first
131     // token of the current VAOPT contents (so we know where to start eager
132     // token-pasting and stringification) *within*  the substituted tokens of
133     // the function-like macro's new replacement list.
134     int NumOfTokensPriorToVAOpt = -1;
135
136     unsigned LeadingSpaceForStringifiedToken : 1;
137
138     unsigned StringifyBefore : 1;
139     unsigned CharifyBefore : 1;
140     unsigned BeginsWithPlaceholder : 1;
141     unsigned EndsWithPlaceholder : 1;
142
143     bool hasStringifyBefore() const {
144       assert(!isReset() &&
145              "Must only be called if the state has not been reset");
146       return StringifyBefore;
147     }
148
149     bool isReset() const {
150       return NumOfTokensPriorToVAOpt == -1 ||
151              VAOptLoc.isInvalid();
152     }
153
154   public:
155     VAOptExpansionContext(Preprocessor &PP)
156         : VAOptDefinitionContext(PP), LeadingSpaceForStringifiedToken(false),
157           StringifyBefore(false), CharifyBefore(false),
158           BeginsWithPlaceholder(false), EndsWithPlaceholder(false) {
159       SyntheticEOFToken.startToken();
160       SyntheticEOFToken.setKind(tok::eof);
161     }
162
163     void reset() {
164       VAOptLoc = SourceLocation();
165       NumOfTokensPriorToVAOpt = -1;
166       LeadingSpaceForStringifiedToken = false;
167       StringifyBefore = false;
168       CharifyBefore = false;
169       BeginsWithPlaceholder = false;
170       EndsWithPlaceholder = false;
171     }
172
173     const Token &getEOFTok() const { return SyntheticEOFToken; }
174
175     void sawHashOrHashAtBefore(const bool HasLeadingSpace,
176                                const bool IsHashAt) {
177
178       StringifyBefore = !IsHashAt;
179       CharifyBefore = IsHashAt;
180       LeadingSpaceForStringifiedToken = HasLeadingSpace;
181     }
182
183     void hasPlaceholderAfterHashhashAtStart() { BeginsWithPlaceholder = true; }
184     void hasPlaceholderBeforeRParen() {
185       if (isAtTopLevel())
186         EndsWithPlaceholder = true;
187     }
188
189
190     bool beginsWithPlaceholder() const {
191       assert(!isReset() &&
192              "Must only be called if the state has not been reset");
193       return BeginsWithPlaceholder;
194     }
195     bool endsWithPlaceholder() const {
196       assert(!isReset() &&
197              "Must only be called if the state has not been reset");
198       return EndsWithPlaceholder;
199     }
200
201     bool hasCharifyBefore() const {
202       assert(!isReset() &&
203              "Must only be called if the state has not been reset");
204       return CharifyBefore;
205     }
206     bool hasStringifyOrCharifyBefore() const {
207       return hasStringifyBefore() || hasCharifyBefore();
208     }
209
210     unsigned int getNumberOfTokensPriorToVAOpt() const {
211       assert(!isReset() &&
212              "Must only be called if the state has not been reset");
213       return NumOfTokensPriorToVAOpt;
214     }
215
216     bool getLeadingSpaceForStringifiedToken() const {
217       assert(hasStringifyBefore() &&
218              "Must only be called if this has been marked for stringification");
219       return LeadingSpaceForStringifiedToken;
220     }
221
222     void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc,
223                                          const unsigned int NumPriorTokens) {
224       assert(VAOptLoc.isFileID() && "Must not come from a macro expansion");
225       assert(isReset() && "Must only be called if the state has been reset");
226       VAOptDefinitionContext::sawVAOptFollowedByOpeningParens(SourceLocation());
227       this->VAOptLoc = VAOptLoc;
228       NumOfTokensPriorToVAOpt = NumPriorTokens;
229       assert(NumOfTokensPriorToVAOpt > -1 &&
230              "Too many prior tokens");
231     }
232
233     SourceLocation getVAOptLoc() const {
234       assert(!isReset() &&
235              "Must only be called if the state has not been reset");
236       assert(VAOptLoc.isValid() && "__VA_OPT__ location must be valid");
237       return VAOptLoc;
238     }
239     using VAOptDefinitionContext::isVAOptToken;
240     using VAOptDefinitionContext::isInVAOpt;
241     using VAOptDefinitionContext::sawClosingParen;
242     using VAOptDefinitionContext::sawOpeningParen;
243
244   };
245 }  // end namespace clang
246
247 #endif