/src/llvm-project/clang/include/clang/Parse/RAIIObjectsForParser.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- 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 and implements the some simple RAII objects that are used |
10 | | // by the parser to manage bits in recursion. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #ifndef LLVM_CLANG_PARSE_RAIIOBJECTSFORPARSER_H |
15 | | #define LLVM_CLANG_PARSE_RAIIOBJECTSFORPARSER_H |
16 | | |
17 | | #include "clang/Parse/ParseDiagnostic.h" |
18 | | #include "clang/Parse/Parser.h" |
19 | | #include "clang/Sema/DelayedDiagnostic.h" |
20 | | #include "clang/Sema/ParsedTemplate.h" |
21 | | #include "clang/Sema/Sema.h" |
22 | | |
23 | | namespace clang { |
24 | | // TODO: move ParsingClassDefinition here. |
25 | | // TODO: move TentativeParsingAction here. |
26 | | |
27 | | /// 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 | 5.40k | : S(P.getActions()), DiagnosticPool(nullptr) { |
54 | 5.40k | if (activate) { |
55 | 0 | State = S.PushParsingDeclaration(DiagnosticPool); |
56 | 0 | Active = true; |
57 | 5.40k | } else { |
58 | 5.40k | Active = false; |
59 | 5.40k | } |
60 | 5.40k | } |
61 | | SuppressAccessChecks(SuppressAccessChecks &&Other) |
62 | | : S(Other.S), DiagnosticPool(std::move(Other.DiagnosticPool)), |
63 | 0 | State(Other.State), Active(Other.Active) { |
64 | 0 | Other.Active = false; |
65 | 0 | } |
66 | | void operator=(SuppressAccessChecks &&Other) = delete; |
67 | | |
68 | 0 | void done() { |
69 | 0 | assert(Active && "trying to end an inactive suppression"); |
70 | 0 | S.PopParsingDeclaration(State, nullptr); |
71 | 0 | Active = false; |
72 | 0 | } |
73 | | |
74 | 0 | void redelay() { |
75 | 0 | assert(!Active && "redelaying without having ended first"); |
76 | 0 | if (!DiagnosticPool.pool_empty()) |
77 | 0 | S.redelayDiagnostics(DiagnosticPool); |
78 | 0 | assert(DiagnosticPool.pool_empty()); |
79 | 0 | } |
80 | | |
81 | 5.40k | ~SuppressAccessChecks() { |
82 | 5.40k | if (Active) done(); |
83 | 5.40k | } |
84 | | }; |
85 | | |
86 | | /// 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 | 24.0k | : Actions(P.getActions()), DiagnosticPool(nullptr) { |
103 | 24.0k | push(); |
104 | 24.0k | } |
105 | | |
106 | | /// Creates a RAII object whose pool is optionally parented by another. |
107 | | ParsingDeclRAIIObject(Parser &P, |
108 | | const sema::DelayedDiagnosticPool *parentPool) |
109 | 23.7k | : Actions(P.getActions()), DiagnosticPool(parentPool) { |
110 | 23.7k | push(); |
111 | 23.7k | } |
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 | 0 | DiagnosticPool(other ? other->DiagnosticPool.getParent() : nullptr) { |
119 | 0 | if (other) { |
120 | 0 | DiagnosticPool.steal(other->DiagnosticPool); |
121 | 0 | other->abort(); |
122 | 0 | } |
123 | 0 | push(); |
124 | 0 | } |
125 | | |
126 | 47.7k | ~ParsingDeclRAIIObject() { |
127 | 47.7k | abort(); |
128 | 47.7k | } |
129 | | |
130 | 0 | sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() { |
131 | 0 | return DiagnosticPool; |
132 | 0 | } |
133 | 23.7k | const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { |
134 | 23.7k | return DiagnosticPool; |
135 | 23.7k | } |
136 | | |
137 | | /// Resets the RAII object for a new declaration. |
138 | 172 | void reset() { |
139 | 172 | abort(); |
140 | 172 | push(); |
141 | 172 | } |
142 | | |
143 | | /// Signals that the context was completed without an appropriate |
144 | | /// declaration being parsed. |
145 | 47.9k | void abort() { |
146 | 47.9k | pop(nullptr); |
147 | 47.9k | } |
148 | | |
149 | 5.21k | void complete(Decl *D) { |
150 | 5.21k | assert(!Popped && "ParsingDeclaration has already been popped!"); |
151 | 0 | pop(D); |
152 | 5.21k | } |
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 | 47.9k | void push() { |
162 | 47.9k | State = Actions.PushParsingDeclaration(DiagnosticPool); |
163 | 47.9k | Popped = false; |
164 | 47.9k | } |
165 | | |
166 | 53.1k | void pop(Decl *D) { |
167 | 53.1k | if (!Popped) { |
168 | 47.9k | Actions.PopParsingDeclaration(State, D); |
169 | 47.9k | Popped = true; |
170 | 47.9k | } |
171 | 53.1k | } |
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 | 23.8k | ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {} |
182 | | ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) |
183 | | : DeclSpec(P.getAttrFactory()), |
184 | 0 | ParsingRAII(P, RAII) {} |
185 | | |
186 | 23.7k | const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { |
187 | 23.7k | return ParsingRAII.getDelayedDiagnosticPool(); |
188 | 23.7k | } |
189 | | |
190 | 39 | void complete(Decl *D) { |
191 | 39 | ParsingRAII.complete(D); |
192 | 39 | } |
193 | | |
194 | 0 | void abort() { |
195 | 0 | ParsingRAII.abort(); |
196 | 0 | } |
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, |
205 | | const ParsedAttributes &DeclarationAttrs, |
206 | | DeclaratorContext C) |
207 | | : Declarator(DS, DeclarationAttrs, C), |
208 | 23.7k | ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {} |
209 | | |
210 | 0 | const ParsingDeclSpec &getDeclSpec() const { |
211 | 0 | return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec()); |
212 | 0 | } |
213 | | |
214 | 0 | ParsingDeclSpec &getMutableDeclSpec() const { |
215 | 0 | return const_cast<ParsingDeclSpec&>(getDeclSpec()); |
216 | 0 | } |
217 | | |
218 | 172 | void clear() { |
219 | 172 | Declarator::clear(); |
220 | 172 | ParsingRAII.reset(); |
221 | 172 | } |
222 | | |
223 | 5.08k | void complete(Decl *D) { |
224 | 5.08k | ParsingRAII.complete(D); |
225 | 5.08k | } |
226 | | }; |
227 | | |
228 | | /// A class for parsing a field declarator. |
229 | | class ParsingFieldDeclarator : public FieldDeclarator { |
230 | | ParsingDeclRAIIObject ParsingRAII; |
231 | | |
232 | | public: |
233 | | ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS, |
234 | | const ParsedAttributes &DeclarationAttrs) |
235 | | : FieldDeclarator(DS, DeclarationAttrs), |
236 | 0 | ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {} |
237 | | |
238 | 0 | const ParsingDeclSpec &getDeclSpec() const { |
239 | 0 | return static_cast<const ParsingDeclSpec&>(D.getDeclSpec()); |
240 | 0 | } |
241 | | |
242 | 0 | ParsingDeclSpec &getMutableDeclSpec() const { |
243 | 0 | return const_cast<ParsingDeclSpec&>(getDeclSpec()); |
244 | 0 | } |
245 | | |
246 | 0 | void complete(Decl *D) { |
247 | 0 | ParsingRAII.complete(D); |
248 | 0 | } |
249 | | }; |
250 | | |
251 | | /// ExtensionRAIIObject - This saves the state of extension warnings when |
252 | | /// constructed and disables them. When destructed, it restores them back to |
253 | | /// the way they used to be. This is used to handle __extension__ in the |
254 | | /// parser. |
255 | | class ExtensionRAIIObject { |
256 | | ExtensionRAIIObject(const ExtensionRAIIObject &) = delete; |
257 | | void operator=(const ExtensionRAIIObject &) = delete; |
258 | | |
259 | | DiagnosticsEngine &Diags; |
260 | | public: |
261 | 0 | ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) { |
262 | 0 | Diags.IncrementAllExtensionsSilenced(); |
263 | 0 | } |
264 | | |
265 | 0 | ~ExtensionRAIIObject() { |
266 | 0 | Diags.DecrementAllExtensionsSilenced(); |
267 | 0 | } |
268 | | }; |
269 | | |
270 | | /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and |
271 | | /// restores it when destroyed. This says that "foo:" should not be |
272 | | /// considered a possible typo for "foo::" for error recovery purposes. |
273 | | class ColonProtectionRAIIObject { |
274 | | Parser &P; |
275 | | bool OldVal; |
276 | | public: |
277 | | ColonProtectionRAIIObject(Parser &p, bool Value = true) |
278 | 12.1k | : P(p), OldVal(P.ColonIsSacred) { |
279 | 12.1k | P.ColonIsSacred = Value; |
280 | 12.1k | } |
281 | | |
282 | | /// restore - This can be used to restore the state early, before the dtor |
283 | | /// is run. |
284 | 12.1k | void restore() { |
285 | 12.1k | P.ColonIsSacred = OldVal; |
286 | 12.1k | } |
287 | | |
288 | 12.1k | ~ColonProtectionRAIIObject() { |
289 | 12.1k | restore(); |
290 | 12.1k | } |
291 | | }; |
292 | | |
293 | | /// Activates OpenMP parsing mode to preseve OpenMP specific annotation |
294 | | /// tokens. |
295 | | class ParsingOpenMPDirectiveRAII { |
296 | | Parser &P; |
297 | | bool OldVal; |
298 | | |
299 | | public: |
300 | | ParsingOpenMPDirectiveRAII(Parser &P, bool Value = true) |
301 | 0 | : P(P), OldVal(P.OpenMPDirectiveParsing) { |
302 | 0 | P.OpenMPDirectiveParsing = Value; |
303 | 0 | } |
304 | | |
305 | | /// This can be used to restore the state early, before the dtor |
306 | | /// is run. |
307 | 0 | void restore() { P.OpenMPDirectiveParsing = OldVal; } |
308 | | |
309 | 0 | ~ParsingOpenMPDirectiveRAII() { restore(); } |
310 | | }; |
311 | | |
312 | | /// Activates OpenACC parsing mode to preseve OpenACC specific annotation |
313 | | /// tokens. |
314 | | class ParsingOpenACCDirectiveRAII { |
315 | | Parser &P; |
316 | | bool OldVal; |
317 | | |
318 | | public: |
319 | | ParsingOpenACCDirectiveRAII(Parser &P, bool Value = true) |
320 | 0 | : P(P), OldVal(P.OpenACCDirectiveParsing) { |
321 | 0 | P.OpenACCDirectiveParsing = Value; |
322 | 0 | } |
323 | | |
324 | | /// This can be used to restore the state early, before the dtor |
325 | | /// is run. |
326 | 0 | void restore() { P.OpenMPDirectiveParsing = OldVal; } |
327 | | |
328 | 0 | ~ParsingOpenACCDirectiveRAII() { restore(); } |
329 | | }; |
330 | | |
331 | | /// RAII object that makes '>' behave either as an operator |
332 | | /// or as the closing angle bracket for a template argument list. |
333 | | class GreaterThanIsOperatorScope { |
334 | | bool &GreaterThanIsOperator; |
335 | | bool OldGreaterThanIsOperator; |
336 | | public: |
337 | | GreaterThanIsOperatorScope(bool >IO, bool Val) |
338 | 911 | : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { |
339 | 911 | GreaterThanIsOperator = Val; |
340 | 911 | } |
341 | | |
342 | 911 | ~GreaterThanIsOperatorScope() { |
343 | 911 | GreaterThanIsOperator = OldGreaterThanIsOperator; |
344 | 911 | } |
345 | | }; |
346 | | |
347 | | class InMessageExpressionRAIIObject { |
348 | | bool &InMessageExpression; |
349 | | bool OldValue; |
350 | | |
351 | | public: |
352 | | InMessageExpressionRAIIObject(Parser &P, bool Value) |
353 | | : InMessageExpression(P.InMessageExpression), |
354 | 141 | OldValue(P.InMessageExpression) { |
355 | 141 | InMessageExpression = Value; |
356 | 141 | } |
357 | | |
358 | 141 | ~InMessageExpressionRAIIObject() { |
359 | 141 | InMessageExpression = OldValue; |
360 | 141 | } |
361 | | }; |
362 | | |
363 | | class OffsetOfStateRAIIObject { |
364 | | Sema::OffsetOfKind &OffsetOfState; |
365 | | Sema::OffsetOfKind OldValue; |
366 | | |
367 | | public: |
368 | | OffsetOfStateRAIIObject(Parser &P, Sema::OffsetOfKind Value) |
369 | 0 | : OffsetOfState(P.OffsetOfState), OldValue(P.OffsetOfState) { |
370 | 0 | OffsetOfState = Value; |
371 | 0 | } |
372 | | |
373 | 0 | ~OffsetOfStateRAIIObject() { OffsetOfState = OldValue; } |
374 | | }; |
375 | | |
376 | | /// RAII object that makes sure paren/bracket/brace count is correct |
377 | | /// after declaration/statement parsing, even when there's a parsing error. |
378 | | class ParenBraceBracketBalancer { |
379 | | Parser &P; |
380 | | unsigned short ParenCount, BracketCount, BraceCount; |
381 | | public: |
382 | | ParenBraceBracketBalancer(Parser &p) |
383 | | : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount), |
384 | 34.6k | BraceCount(p.BraceCount) { } |
385 | | |
386 | 34.6k | ~ParenBraceBracketBalancer() { |
387 | 34.6k | P.AngleBrackets.clear(P); |
388 | 34.6k | P.ParenCount = ParenCount; |
389 | 34.6k | P.BracketCount = BracketCount; |
390 | 34.6k | P.BraceCount = BraceCount; |
391 | 34.6k | } |
392 | | }; |
393 | | |
394 | | class PoisonSEHIdentifiersRAIIObject { |
395 | | PoisonIdentifierRAIIObject Ident_AbnormalTermination; |
396 | | PoisonIdentifierRAIIObject Ident_GetExceptionCode; |
397 | | PoisonIdentifierRAIIObject Ident_GetExceptionInfo; |
398 | | PoisonIdentifierRAIIObject Ident__abnormal_termination; |
399 | | PoisonIdentifierRAIIObject Ident__exception_code; |
400 | | PoisonIdentifierRAIIObject Ident__exception_info; |
401 | | PoisonIdentifierRAIIObject Ident___abnormal_termination; |
402 | | PoisonIdentifierRAIIObject Ident___exception_code; |
403 | | PoisonIdentifierRAIIObject Ident___exception_info; |
404 | | public: |
405 | | PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue) |
406 | | : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue), |
407 | | Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue), |
408 | | Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue), |
409 | | Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue), |
410 | | Ident__exception_code(Self.Ident__exception_code, NewValue), |
411 | | Ident__exception_info(Self.Ident__exception_info, NewValue), |
412 | | Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue), |
413 | | Ident___exception_code(Self.Ident___exception_code, NewValue), |
414 | 0 | Ident___exception_info(Self.Ident___exception_info, NewValue) { |
415 | 0 | } |
416 | | }; |
417 | | |
418 | | /// RAII class that helps handle the parsing of an open/close delimiter |
419 | | /// pair, such as braces { ... } or parentheses ( ... ). |
420 | | class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { |
421 | | Parser& P; |
422 | | tok::TokenKind Kind, Close, FinalToken; |
423 | | SourceLocation (Parser::*Consumer)(); |
424 | | SourceLocation LOpen, LClose; |
425 | | |
426 | 794 | unsigned short &getDepth() { |
427 | 794 | switch (Kind) { |
428 | 126 | case tok::l_brace: return P.BraceCount; |
429 | 355 | case tok::l_square: return P.BracketCount; |
430 | 313 | case tok::l_paren: return P.ParenCount; |
431 | 0 | default: llvm_unreachable("Wrong token kind"); |
432 | 794 | } |
433 | 794 | } |
434 | | |
435 | | bool diagnoseOverflow(); |
436 | | bool diagnoseMissingClose(); |
437 | | |
438 | | public: |
439 | | BalancedDelimiterTracker(Parser& p, tok::TokenKind k, |
440 | | tok::TokenKind FinalToken = tok::semi) |
441 | | : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), |
442 | | P(p), Kind(k), FinalToken(FinalToken) |
443 | 794 | { |
444 | 794 | switch (Kind) { |
445 | 0 | default: llvm_unreachable("Unexpected balanced token"); |
446 | 126 | case tok::l_brace: |
447 | 126 | Close = tok::r_brace; |
448 | 126 | Consumer = &Parser::ConsumeBrace; |
449 | 126 | break; |
450 | 313 | case tok::l_paren: |
451 | 313 | Close = tok::r_paren; |
452 | 313 | Consumer = &Parser::ConsumeParen; |
453 | 313 | break; |
454 | | |
455 | 355 | case tok::l_square: |
456 | 355 | Close = tok::r_square; |
457 | 355 | Consumer = &Parser::ConsumeBracket; |
458 | 355 | break; |
459 | 794 | } |
460 | 794 | } |
461 | | |
462 | 616 | SourceLocation getOpenLocation() const { return LOpen; } |
463 | 586 | SourceLocation getCloseLocation() const { return LClose; } |
464 | 0 | SourceRange getRange() const { return SourceRange(LOpen, LClose); } |
465 | | |
466 | 794 | bool consumeOpen() { |
467 | 794 | if (!P.Tok.is(Kind)) |
468 | 0 | return true; |
469 | | |
470 | 794 | if (getDepth() < P.getLangOpts().BracketDepth) { |
471 | 794 | LOpen = (P.*Consumer)(); |
472 | 794 | return false; |
473 | 794 | } |
474 | | |
475 | 0 | return diagnoseOverflow(); |
476 | 794 | } |
477 | | |
478 | | bool expectAndConsume(unsigned DiagID = diag::err_expected, |
479 | | const char *Msg = "", |
480 | | tok::TokenKind SkipToTok = tok::unknown); |
481 | 470 | bool consumeClose() { |
482 | 470 | if (P.Tok.is(Close)) { |
483 | 87 | LClose = (P.*Consumer)(); |
484 | 87 | return false; |
485 | 383 | } else if (P.Tok.is(tok::semi) && P.NextToken().is(Close)) { |
486 | 0 | SourceLocation SemiLoc = P.ConsumeToken(); |
487 | 0 | P.Diag(SemiLoc, diag::err_unexpected_semi) |
488 | 0 | << Close << FixItHint::CreateRemoval(SourceRange(SemiLoc, SemiLoc)); |
489 | 0 | LClose = (P.*Consumer)(); |
490 | 0 | return false; |
491 | 0 | } |
492 | | |
493 | 383 | return diagnoseMissingClose(); |
494 | 470 | } |
495 | | void skipToEnd(); |
496 | | }; |
497 | | } // end namespace clang |
498 | | |
499 | | #endif |