/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- 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 and implements the some simple RAII objects that are used |
11 | | // by the parser to manage bits in recursion. |
12 | | // |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #ifndef LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H |
16 | | #define LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H |
17 | | |
18 | | #include "clang/Parse/ParseDiagnostic.h" |
19 | | #include "clang/Parse/Parser.h" |
20 | | #include "clang/Sema/DelayedDiagnostic.h" |
21 | | #include "clang/Sema/Sema.h" |
22 | | |
23 | | namespace clang { |
24 | | // TODO: move ParsingClassDefinition here. |
25 | | // TODO: move TentativeParsingAction here. |
26 | | |
27 | | /// \brief A RAII object used to temporarily suppress access-like |
28 | | /// checking. Access-like checks are those associated with |
29 | | /// controlling the use of a declaration, like C++ access control |
30 | | /// errors and deprecation warnings. They are contextually |
31 | | /// dependent, in that they can only be resolved with full |
32 | | /// information about what's being declared. They are also |
33 | | /// suppressed in certain contexts, like the template arguments of |
34 | | /// an explicit instantiation. However, those suppression contexts |
35 | | /// cannot necessarily be fully determined in advance; for |
36 | | /// example, something starting like this: |
37 | | /// template <> class std::vector<A::PrivateType> |
38 | | /// might be the entirety of an explicit instantiation: |
39 | | /// template <> class std::vector<A::PrivateType>; |
40 | | /// or just an elaborated type specifier: |
41 | | /// template <> class std::vector<A::PrivateType> make_vector<>(); |
42 | | /// Therefore this class collects all the diagnostics and permits |
43 | | /// them to be re-delayed in a new context. |
44 | | class SuppressAccessChecks { |
45 | | Sema &S; |
46 | | sema::DelayedDiagnosticPool DiagnosticPool; |
47 | | Sema::ParsingDeclState State; |
48 | | bool Active; |
49 | | |
50 | | public: |
51 | | /// Begin suppressing access-like checks |
52 | | SuppressAccessChecks(Parser &P, bool activate = true) |
53 | 1.03M | : S(P.getActions()), DiagnosticPool(nullptr) { |
54 | 1.03M | if (activate1.03M ) {336k |
55 | 336k | State = S.PushParsingDeclaration(DiagnosticPool); |
56 | 336k | Active = true; |
57 | 693k | } else { |
58 | 693k | Active = false; |
59 | 693k | } |
60 | 1.03M | } |
61 | | SuppressAccessChecks(SuppressAccessChecks &&Other) |
62 | | : S(Other.S), DiagnosticPool(std::move(Other.DiagnosticPool)), |
63 | 133k | State(Other.State), Active(Other.Active) { |
64 | 133k | Other.Active = false; |
65 | 133k | } |
66 | | void operator=(SuppressAccessChecks &&Other) = delete; |
67 | | |
68 | 336k | void done() { |
69 | 336k | assert(Active && "trying to end an inactive suppression"); |
70 | 336k | S.PopParsingDeclaration(State, nullptr); |
71 | 336k | Active = false; |
72 | 336k | } |
73 | | |
74 | 333k | void redelay() { |
75 | 333k | assert(!Active && "redelaying without having ended first"); |
76 | 333k | if (!DiagnosticPool.pool_empty()) |
77 | 295 | S.redelayDiagnostics(DiagnosticPool); |
78 | 333k | assert(DiagnosticPool.pool_empty()); |
79 | 333k | } |
80 | | |
81 | 1.16M | ~SuppressAccessChecks() { |
82 | 1.16M | if (Active1.16M ) done()0 ; |
83 | 1.16M | } |
84 | | }; |
85 | | |
86 | | /// \brief RAII object used to inform the actions that we're |
87 | | /// currently parsing a declaration. This is active when parsing a |
88 | | /// variable's initializer, but not when parsing the body of a |
89 | | /// class or function definition. |
90 | | class ParsingDeclRAIIObject { |
91 | | Sema &Actions; |
92 | | sema::DelayedDiagnosticPool DiagnosticPool; |
93 | | Sema::ParsingDeclState State; |
94 | | bool Popped; |
95 | | |
96 | | ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) = delete; |
97 | | void operator=(const ParsingDeclRAIIObject &) = delete; |
98 | | |
99 | | public: |
100 | | enum NoParent_t { NoParent }; |
101 | | ParsingDeclRAIIObject(Parser &P, NoParent_t _) |
102 | 6.29M | : Actions(P.getActions()), DiagnosticPool(nullptr) { |
103 | 6.29M | push(); |
104 | 6.29M | } |
105 | | |
106 | | /// Creates a RAII object whose pool is optionally parented by another. |
107 | | ParsingDeclRAIIObject(Parser &P, |
108 | | const sema::DelayedDiagnosticPool *parentPool) |
109 | 6.20M | : Actions(P.getActions()), DiagnosticPool(parentPool) { |
110 | 6.20M | push(); |
111 | 6.20M | } |
112 | | |
113 | | /// Creates a RAII object and, optionally, initialize its |
114 | | /// diagnostics pool by stealing the diagnostics from another |
115 | | /// RAII object (which is assumed to be the current top pool). |
116 | | ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other) |
117 | | : Actions(P.getActions()), |
118 | 726k | DiagnosticPool(other ? other->DiagnosticPool.getParent() : nullptr) { |
119 | 726k | if (other726k ) {57.5k |
120 | 57.5k | DiagnosticPool.steal(other->DiagnosticPool); |
121 | 57.5k | other->abort(); |
122 | 57.5k | } |
123 | 726k | push(); |
124 | 726k | } |
125 | | |
126 | 13.2M | ~ParsingDeclRAIIObject() { |
127 | 13.2M | abort(); |
128 | 13.2M | } |
129 | | |
130 | 0 | sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() { |
131 | 0 | return DiagnosticPool; |
132 | 0 | } |
133 | 6.20M | const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { |
134 | 6.20M | return DiagnosticPool; |
135 | 6.20M | } |
136 | | |
137 | | /// Resets the RAII object for a new declaration. |
138 | 73.4k | void reset() { |
139 | 73.4k | abort(); |
140 | 73.4k | push(); |
141 | 73.4k | } |
142 | | |
143 | | /// Signals that the context was completed without an appropriate |
144 | | /// declaration being parsed. |
145 | 14.2M | void abort() { |
146 | 14.2M | pop(nullptr); |
147 | 14.2M | } |
148 | | |
149 | 7.02M | void complete(Decl *D) { |
150 | 7.02M | assert(!Popped && "ParsingDeclaration has already been popped!"); |
151 | 7.02M | pop(D); |
152 | 7.02M | } |
153 | | |
154 | | /// Unregister this object from Sema, but remember all the |
155 | | /// diagnostics that were emitted into it. |
156 | 0 | void abortAndRemember() { |
157 | 0 | pop(nullptr); |
158 | 0 | } |
159 | | |
160 | | private: |
161 | 13.2M | void push() { |
162 | 13.2M | State = Actions.PushParsingDeclaration(DiagnosticPool); |
163 | 13.2M | Popped = false; |
164 | 13.2M | } |
165 | | |
166 | 21.2M | void pop(Decl *D) { |
167 | 21.2M | if (!Popped21.2M ) {13.2M |
168 | 13.2M | Actions.PopParsingDeclaration(State, D); |
169 | 13.2M | Popped = true; |
170 | 13.2M | } |
171 | 21.2M | } |
172 | | }; |
173 | | |
174 | | /// A class for parsing a DeclSpec. |
175 | | class ParsingDeclSpec : public DeclSpec { |
176 | | ParsingDeclRAIIObject ParsingRAII; |
177 | | |
178 | | public: |
179 | | ParsingDeclSpec(Parser &P) |
180 | | : DeclSpec(P.getAttrFactory()), |
181 | 5.79M | ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {} |
182 | | ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) |
183 | | : DeclSpec(P.getAttrFactory()), |
184 | 726k | ParsingRAII(P, RAII) {} |
185 | | |
186 | 6.20M | const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { |
187 | 6.20M | return ParsingRAII.getDelayedDiagnosticPool(); |
188 | 6.20M | } |
189 | | |
190 | 305k | void complete(Decl *D) { |
191 | 305k | ParsingRAII.complete(D); |
192 | 305k | } |
193 | | |
194 | 897k | void abort() { |
195 | 897k | ParsingRAII.abort(); |
196 | 897k | } |
197 | | }; |
198 | | |
199 | | /// A class for parsing a declarator. |
200 | | class ParsingDeclarator : public Declarator { |
201 | | ParsingDeclRAIIObject ParsingRAII; |
202 | | |
203 | | public: |
204 | | ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) |
205 | 5.06M | : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { |
206 | 5.06M | } |
207 | | |
208 | 1.36M | const ParsingDeclSpec &getDeclSpec() const { |
209 | 1.36M | return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec()); |
210 | 1.36M | } |
211 | | |
212 | 867k | ParsingDeclSpec &getMutableDeclSpec() const { |
213 | 867k | return const_cast<ParsingDeclSpec&>(getDeclSpec()); |
214 | 867k | } |
215 | | |
216 | 73.4k | void clear() { |
217 | 73.4k | Declarator::clear(); |
218 | 73.4k | ParsingRAII.reset(); |
219 | 73.4k | } |
220 | | |
221 | 5.13M | void complete(Decl *D) { |
222 | 5.13M | ParsingRAII.complete(D); |
223 | 5.13M | } |
224 | | }; |
225 | | |
226 | | /// A class for parsing a field declarator. |
227 | | class ParsingFieldDeclarator : public FieldDeclarator { |
228 | | ParsingDeclRAIIObject ParsingRAII; |
229 | | |
230 | | public: |
231 | | ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS) |
232 | 1.13M | : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { |
233 | 1.13M | } |
234 | | |
235 | 0 | const ParsingDeclSpec &getDeclSpec() const { |
236 | 0 | return static_cast<const ParsingDeclSpec&>(D.getDeclSpec()); |
237 | 0 | } |
238 | | |
239 | 0 | ParsingDeclSpec &getMutableDeclSpec() const { |
240 | 0 | return const_cast<ParsingDeclSpec&>(getDeclSpec()); |
241 | 0 | } |
242 | | |
243 | 1.13M | void complete(Decl *D) { |
244 | 1.13M | ParsingRAII.complete(D); |
245 | 1.13M | } |
246 | | }; |
247 | | |
248 | | /// ExtensionRAIIObject - This saves the state of extension warnings when |
249 | | /// constructed and disables them. When destructed, it restores them back to |
250 | | /// the way they used to be. This is used to handle __extension__ in the |
251 | | /// parser. |
252 | | class ExtensionRAIIObject { |
253 | | ExtensionRAIIObject(const ExtensionRAIIObject &) = delete; |
254 | | void operator=(const ExtensionRAIIObject &) = delete; |
255 | | |
256 | | DiagnosticsEngine &Diags; |
257 | | public: |
258 | 28.9k | ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) { |
259 | 28.9k | Diags.IncrementAllExtensionsSilenced(); |
260 | 28.9k | } |
261 | | |
262 | 28.9k | ~ExtensionRAIIObject() { |
263 | 28.9k | Diags.DecrementAllExtensionsSilenced(); |
264 | 28.9k | } |
265 | | }; |
266 | | |
267 | | /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and |
268 | | /// restores it when destroyed. This says that "foo:" should not be |
269 | | /// considered a possible typo for "foo::" for error recovery purposes. |
270 | | class ColonProtectionRAIIObject { |
271 | | Parser &P; |
272 | | bool OldVal; |
273 | | public: |
274 | | ColonProtectionRAIIObject(Parser &p, bool Value = true) |
275 | 8.74M | : P(p), OldVal(P.ColonIsSacred) { |
276 | 8.74M | P.ColonIsSacred = Value; |
277 | 8.74M | } |
278 | | |
279 | | /// restore - This can be used to restore the state early, before the dtor |
280 | | /// is run. |
281 | 11.2M | void restore() { |
282 | 11.2M | P.ColonIsSacred = OldVal; |
283 | 11.2M | } |
284 | | |
285 | 8.74M | ~ColonProtectionRAIIObject() { |
286 | 8.74M | restore(); |
287 | 8.74M | } |
288 | | }; |
289 | | |
290 | | /// \brief RAII object that makes '>' behave either as an operator |
291 | | /// or as the closing angle bracket for a template argument list. |
292 | | class GreaterThanIsOperatorScope { |
293 | | bool &GreaterThanIsOperator; |
294 | | bool OldGreaterThanIsOperator; |
295 | | public: |
296 | | GreaterThanIsOperatorScope(bool >IO, bool Val) |
297 | 12.4M | : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { |
298 | 12.4M | GreaterThanIsOperator = Val; |
299 | 12.4M | } |
300 | | |
301 | 12.4M | ~GreaterThanIsOperatorScope() { |
302 | 12.4M | GreaterThanIsOperator = OldGreaterThanIsOperator; |
303 | 12.4M | } |
304 | | }; |
305 | | |
306 | | class InMessageExpressionRAIIObject { |
307 | | bool &InMessageExpression; |
308 | | bool OldValue; |
309 | | |
310 | | public: |
311 | | InMessageExpressionRAIIObject(Parser &P, bool Value) |
312 | | : InMessageExpression(P.InMessageExpression), |
313 | 4.18M | OldValue(P.InMessageExpression) { |
314 | 4.18M | InMessageExpression = Value; |
315 | 4.18M | } |
316 | | |
317 | 4.18M | ~InMessageExpressionRAIIObject() { |
318 | 4.18M | InMessageExpression = OldValue; |
319 | 4.18M | } |
320 | | }; |
321 | | |
322 | | /// \brief RAII object that makes sure paren/bracket/brace count is correct |
323 | | /// after declaration/statement parsing, even when there's a parsing error. |
324 | | class ParenBraceBracketBalancer { |
325 | | Parser &P; |
326 | | unsigned short ParenCount, BracketCount, BraceCount; |
327 | | public: |
328 | | ParenBraceBracketBalancer(Parser &p) |
329 | | : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount), |
330 | 9.11M | BraceCount(p.BraceCount) { } |
331 | | |
332 | 9.11M | ~ParenBraceBracketBalancer() { |
333 | 9.11M | P.ParenCount = ParenCount; |
334 | 9.11M | P.BracketCount = BracketCount; |
335 | 9.11M | P.BraceCount = BraceCount; |
336 | 9.11M | } |
337 | | }; |
338 | | |
339 | | class PoisonSEHIdentifiersRAIIObject { |
340 | | PoisonIdentifierRAIIObject Ident_AbnormalTermination; |
341 | | PoisonIdentifierRAIIObject Ident_GetExceptionCode; |
342 | | PoisonIdentifierRAIIObject Ident_GetExceptionInfo; |
343 | | PoisonIdentifierRAIIObject Ident__abnormal_termination; |
344 | | PoisonIdentifierRAIIObject Ident__exception_code; |
345 | | PoisonIdentifierRAIIObject Ident__exception_info; |
346 | | PoisonIdentifierRAIIObject Ident___abnormal_termination; |
347 | | PoisonIdentifierRAIIObject Ident___exception_code; |
348 | | PoisonIdentifierRAIIObject Ident___exception_info; |
349 | | public: |
350 | | PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue) |
351 | | : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue), |
352 | | Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue), |
353 | | Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue), |
354 | | Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue), |
355 | | Ident__exception_code(Self.Ident__exception_code, NewValue), |
356 | | Ident__exception_info(Self.Ident__exception_info, NewValue), |
357 | | Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue), |
358 | | Ident___exception_code(Self.Ident___exception_code, NewValue), |
359 | 889k | Ident___exception_info(Self.Ident___exception_info, NewValue) { |
360 | 889k | } |
361 | | }; |
362 | | |
363 | | /// \brief RAII class that helps handle the parsing of an open/close delimiter |
364 | | /// pair, such as braces { ... } or parentheses ( ... ). |
365 | | class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { |
366 | | Parser& P; |
367 | | tok::TokenKind Kind, Close, FinalToken; |
368 | | SourceLocation (Parser::*Consumer)(); |
369 | | SourceLocation LOpen, LClose; |
370 | | |
371 | 12.3M | unsigned short &getDepth() { |
372 | 12.3M | switch (Kind) { |
373 | 1.89M | case tok::l_brace: return P.BraceCount; |
374 | 984k | case tok::l_square: return P.BracketCount; |
375 | 9.43M | case tok::l_paren: return P.ParenCount; |
376 | 0 | default: 0 llvm_unreachable0 ("Wrong token kind"); |
377 | 12.3M | } |
378 | 12.3M | } |
379 | | |
380 | | enum { MaxDepth = 256 }; |
381 | | |
382 | | bool diagnoseOverflow(); |
383 | | bool diagnoseMissingClose(); |
384 | | |
385 | | public: |
386 | | BalancedDelimiterTracker(Parser& p, tok::TokenKind k, |
387 | | tok::TokenKind FinalToken = tok::semi) |
388 | | : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), |
389 | | P(p), Kind(k), FinalToken(FinalToken) |
390 | 12.3M | { |
391 | 12.3M | switch (Kind) { |
392 | 0 | default: 0 llvm_unreachable0 ("Unexpected balanced token"); |
393 | 1.89M | case tok::l_brace: |
394 | 1.89M | Close = tok::r_brace; |
395 | 1.89M | Consumer = &Parser::ConsumeBrace; |
396 | 1.89M | break; |
397 | 9.45M | case tok::l_paren: |
398 | 9.45M | Close = tok::r_paren; |
399 | 9.45M | Consumer = &Parser::ConsumeParen; |
400 | 9.45M | break; |
401 | 0 | |
402 | 984k | case tok::l_square: |
403 | 984k | Close = tok::r_square; |
404 | 984k | Consumer = &Parser::ConsumeBracket; |
405 | 984k | break; |
406 | 12.3M | } |
407 | 12.3M | } |
408 | | |
409 | 11.3M | SourceLocation getOpenLocation() const { return LOpen; } |
410 | 10.1M | SourceLocation getCloseLocation() const { return LClose; } |
411 | 432k | SourceRange getRange() const { return SourceRange(LOpen, LClose); } |
412 | | |
413 | 12.2M | bool consumeOpen() { |
414 | 12.2M | if (!P.Tok.is(Kind)) |
415 | 190 | return true; |
416 | 12.2M | |
417 | 12.2M | if (12.2M getDepth() < P.getLangOpts().BracketDepth12.2M ) {12.2M |
418 | 12.2M | LOpen = (P.*Consumer)(); |
419 | 12.2M | return false; |
420 | 12.2M | } |
421 | 12.2M | |
422 | 5 | return diagnoseOverflow(); |
423 | 12.2M | } |
424 | | |
425 | | bool expectAndConsume(unsigned DiagID = diag::err_expected, |
426 | | const char *Msg = "", |
427 | | tok::TokenKind SkipToTok = tok::unknown); |
428 | 12.2M | bool consumeClose() { |
429 | 12.2M | if (P.Tok.is(Close)12.2M ) {12.2M |
430 | 12.2M | LClose = (P.*Consumer)(); |
431 | 12.2M | return false; |
432 | 6.59k | } else if (6.59k P.Tok.is(tok::semi) && 6.59k P.NextToken().is(Close)28 ) {17 |
433 | 17 | SourceLocation SemiLoc = P.ConsumeToken(); |
434 | 17 | P.Diag(SemiLoc, diag::err_unexpected_semi) |
435 | 17 | << Close << FixItHint::CreateRemoval(SourceRange(SemiLoc, SemiLoc)); |
436 | 17 | LClose = (P.*Consumer)(); |
437 | 17 | return false; |
438 | 17 | } |
439 | 12.2M | |
440 | 6.57k | return diagnoseMissingClose(); |
441 | 12.2M | } |
442 | | void skipToEnd(); |
443 | | }; |
444 | | |
445 | | } // end namespace clang |
446 | | |
447 | | #endif |