Coverage Report

Created: 2018-09-23 03:40

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/include/clang/Lex/VariadicMacroSupport.h
Line
Count
Source
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
23.2M
          Ident__VA_OPT__(PP.Ident__VA_OPT__) {
40
23.2M
      assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned "
41
23.2M
                                              "outside an ISO C/C++ variadic "
42
23.2M
                                              "macro definition!");
43
23.2M
      assert(
44
23.2M
          !Ident__VA_OPT__ ||
45
23.2M
          (Ident__VA_OPT__->isPoisoned() && "__VA_OPT__ should be poisoned!"));
46
23.2M
    }
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
66.3k
    void enterScope() {
51
66.3k
      Ident__VA_ARGS__->setIsPoisoned(false);
52
66.3k
      if (Ident__VA_OPT__)
53
32
        Ident__VA_OPT__->setIsPoisoned(false);
54
66.3k
    }
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
23.2M
    void exitScope() {
61
23.2M
      Ident__VA_ARGS__->setIsPoisoned(true);
62
23.2M
      if (Ident__VA_OPT__)
63
18.7k
        Ident__VA_OPT__->setIsPoisoned(true);
64
23.2M
    }
65
66
23.2M
    ~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
7.27M
        : Ident__VA_OPT__(PP.Ident__VA_OPT__) {}
81
82
100M
    bool isVAOptToken(const Token &T) const {
83
100M
      return Ident__VA_OPT__ && 
T.getIdentifierInfo() == Ident__VA_OPT__2.53k
;
84
100M
    }
85
86
    /// Returns true if we have seen the __VA_OPT__ and '(' but before having
87
    /// seen the matching ')'.
88
103M
    bool isInVAOpt() const { return UnmatchedOpeningParens.size(); }
89
90
    /// Call this function as soon as you see __VA_OPT__ and '('.
91
74
    void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc) {
92
74
      assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this");
93
74
      UnmatchedOpeningParens.push_back(LParenLoc);
94
74
95
74
    }
96
97
2
    SourceLocation getUnmatchedOpeningParenLoc() const {
98
2
      assert(isInVAOpt() && "Must be within VAOPT context to call this");
99
2
      return UnmatchedOpeningParens.back();
100
2
    }
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
70
    bool sawClosingParen() {
106
70
      assert(isInVAOpt() && "Must be within VAOPT context to call this");
107
70
      UnmatchedOpeningParens.pop_back();
108
70
      return !UnmatchedOpeningParens.size();
109
70
    }
110
111
    /// Call this function each time an lparen is seen.
112
5
    void sawOpeningParen(SourceLocation LParenLoc) {
113
5
      assert(isInVAOpt() && "Must be within VAOPT context to call this");
114
5
      UnmatchedOpeningParens.push_back(LParenLoc);
115
5
    }
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
40
    bool hasStringifyBefore() const {
142
40
      assert(!isReset() &&
143
40
             "Must only be called if the state has not been reset");
144
40
      return StringifyBefore;
145
40
    }
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
4.02M
          StringifyBefore(false), CharifyBefore(false) {
156
4.02M
      SyntheticEOFToken.startToken();
157
4.02M
      SyntheticEOFToken.setKind(tok::eof);
158
4.02M
    }
159
160
40
    void reset() {
161
40
      VAOptLoc = SourceLocation();
162
40
      NumOfTokensPriorToVAOpt = -1;
163
40
      LeadingSpaceForStringifiedToken = false;
164
40
      StringifyBefore = false;
165
40
      CharifyBefore = false;
166
40
    }
167
168
14
    const Token &getEOFTok() const { return SyntheticEOFToken; }
169
170
    void sawHashOrHashAtBefore(const bool HasLeadingSpace,
171
14
                               const bool IsHashAt) {
172
14
173
14
      StringifyBefore = !IsHashAt;
174
14
      CharifyBefore = IsHashAt;
175
14
      LeadingSpaceForStringifiedToken = HasLeadingSpace;
176
14
    }
177
178
179
180
40
    bool hasCharifyBefore() const {
181
40
      assert(!isReset() &&
182
40
             "Must only be called if the state has not been reset");
183
40
      return CharifyBefore;
184
40
    }
185
40
    bool hasStringifyOrCharifyBefore() const {
186
40
      return hasStringifyBefore() || 
hasCharifyBefore()26
;
187
40
    }
188
189
41
    unsigned int getNumberOfTokensPriorToVAOpt() const {
190
41
      assert(!isReset() &&
191
41
             "Must only be called if the state has not been reset");
192
41
      return NumOfTokensPriorToVAOpt;
193
41
    }
194
195
14
    bool getLeadingSpaceForStringifiedToken() const {
196
14
      assert(hasStringifyBefore() &&
197
14
             "Must only be called if this has been marked for stringification");
198
14
      return LeadingSpaceForStringifiedToken;
199
14
    }
200
201
    void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc,
202
40
                                         const unsigned int NumPriorTokens) {
203
40
      assert(VAOptLoc.isFileID() && "Must not come from a macro expansion");
204
40
      assert(isReset() && "Must only be called if the state has been reset");
205
40
      VAOptDefinitionContext::sawVAOptFollowedByOpeningParens(SourceLocation());
206
40
      this->VAOptLoc = VAOptLoc;
207
40
      NumOfTokensPriorToVAOpt = NumPriorTokens;
208
40
      assert(NumOfTokensPriorToVAOpt > -1 &&
209
40
             "Too many prior tokens");
210
40
    }
211
212
14
    SourceLocation getVAOptLoc() const {
213
14
      assert(!isReset() &&
214
14
             "Must only be called if the state has not been reset");
215
14
      assert(VAOptLoc.isValid() && "__VA_OPT__ location must be valid");
216
14
      return VAOptLoc;
217
14
    }
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