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 | : S(P.getActions()), DiagnosticPool(nullptr) { |
54 | if (activate) { |
55 | State = S.PushParsingDeclaration(pool&: DiagnosticPool); |
56 | Active = true; |
57 | } else { |
58 | Active = false; |
59 | } |
60 | } |
61 | SuppressAccessChecks(SuppressAccessChecks &&Other) |
62 | : S(Other.S), DiagnosticPool(std::move(Other.DiagnosticPool)), |
63 | State(Other.State), Active(Other.Active) { |
64 | Other.Active = false; |
65 | } |
66 | void operator=(SuppressAccessChecks &&Other) = delete; |
67 | |
68 | void done() { |
69 | assert(Active && "trying to end an inactive suppression" ); |
70 | S.PopParsingDeclaration(state: State, decl: nullptr); |
71 | Active = false; |
72 | } |
73 | |
74 | void redelay() { |
75 | assert(!Active && "redelaying without having ended first" ); |
76 | if (!DiagnosticPool.pool_empty()) |
77 | S.redelayDiagnostics(pool&: DiagnosticPool); |
78 | assert(DiagnosticPool.pool_empty()); |
79 | } |
80 | |
81 | ~SuppressAccessChecks() { |
82 | if (Active) done(); |
83 | } |
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 | : Actions(P.getActions()), DiagnosticPool(nullptr) { |
103 | push(); |
104 | } |
105 | |
106 | /// Creates a RAII object whose pool is optionally parented by another. |
107 | ParsingDeclRAIIObject(Parser &P, |
108 | const sema::DelayedDiagnosticPool *parentPool) |
109 | : Actions(P.getActions()), DiagnosticPool(parentPool) { |
110 | push(); |
111 | } |
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 | DiagnosticPool(other ? other->DiagnosticPool.getParent() : nullptr) { |
119 | if (other) { |
120 | DiagnosticPool.steal(pool&: other->DiagnosticPool); |
121 | other->abort(); |
122 | } |
123 | push(); |
124 | } |
125 | |
126 | ~ParsingDeclRAIIObject() { |
127 | abort(); |
128 | } |
129 | |
130 | sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() { |
131 | return DiagnosticPool; |
132 | } |
133 | const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { |
134 | return DiagnosticPool; |
135 | } |
136 | |
137 | /// Resets the RAII object for a new declaration. |
138 | void reset() { |
139 | abort(); |
140 | push(); |
141 | } |
142 | |
143 | /// Signals that the context was completed without an appropriate |
144 | /// declaration being parsed. |
145 | void abort() { |
146 | pop(D: nullptr); |
147 | } |
148 | |
149 | void complete(Decl *D) { |
150 | assert(!Popped && "ParsingDeclaration has already been popped!" ); |
151 | pop(D); |
152 | } |
153 | |
154 | /// Unregister this object from Sema, but remember all the |
155 | /// diagnostics that were emitted into it. |
156 | void abortAndRemember() { |
157 | pop(D: nullptr); |
158 | } |
159 | |
160 | private: |
161 | void push() { |
162 | State = Actions.PushParsingDeclaration(pool&: DiagnosticPool); |
163 | Popped = false; |
164 | } |
165 | |
166 | void pop(Decl *D) { |
167 | if (!Popped) { |
168 | Actions.PopParsingDeclaration(state: State, decl: D); |
169 | Popped = true; |
170 | } |
171 | } |
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 | ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {} |
182 | ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) |
183 | : DeclSpec(P.getAttrFactory()), |
184 | ParsingRAII(P, RAII) {} |
185 | |
186 | const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { |
187 | return ParsingRAII.getDelayedDiagnosticPool(); |
188 | } |
189 | |
190 | void complete(Decl *D) { |
191 | ParsingRAII.complete(D); |
192 | } |
193 | |
194 | void abort() { |
195 | ParsingRAII.abort(); |
196 | } |
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 | ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {} |
209 | |
210 | const ParsingDeclSpec &getDeclSpec() const { |
211 | return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec()); |
212 | } |
213 | |
214 | ParsingDeclSpec &getMutableDeclSpec() const { |
215 | return const_cast<ParsingDeclSpec&>(getDeclSpec()); |
216 | } |
217 | |
218 | void clear() { |
219 | Declarator::clear(); |
220 | ParsingRAII.reset(); |
221 | } |
222 | |
223 | void complete(Decl *D) { |
224 | ParsingRAII.complete(D); |
225 | } |
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 | ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {} |
237 | |
238 | const ParsingDeclSpec &getDeclSpec() const { |
239 | return static_cast<const ParsingDeclSpec&>(D.getDeclSpec()); |
240 | } |
241 | |
242 | ParsingDeclSpec &getMutableDeclSpec() const { |
243 | return const_cast<ParsingDeclSpec&>(getDeclSpec()); |
244 | } |
245 | |
246 | void complete(Decl *D) { |
247 | ParsingRAII.complete(D); |
248 | } |
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 | ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) { |
262 | Diags.IncrementAllExtensionsSilenced(); |
263 | } |
264 | |
265 | ~ExtensionRAIIObject() { |
266 | Diags.DecrementAllExtensionsSilenced(); |
267 | } |
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 | : P(p), OldVal(P.ColonIsSacred) { |
279 | P.ColonIsSacred = Value; |
280 | } |
281 | |
282 | /// restore - This can be used to restore the state early, before the dtor |
283 | /// is run. |
284 | void restore() { |
285 | P.ColonIsSacred = OldVal; |
286 | } |
287 | |
288 | ~ColonProtectionRAIIObject() { |
289 | restore(); |
290 | } |
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 | : P(P), OldVal(P.OpenMPDirectiveParsing) { |
302 | P.OpenMPDirectiveParsing = Value; |
303 | } |
304 | |
305 | /// This can be used to restore the state early, before the dtor |
306 | /// is run. |
307 | void restore() { P.OpenMPDirectiveParsing = OldVal; } |
308 | |
309 | ~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 | : P(P), OldVal(P.OpenACCDirectiveParsing) { |
321 | P.OpenACCDirectiveParsing = Value; |
322 | } |
323 | |
324 | /// This can be used to restore the state early, before the dtor |
325 | /// is run. |
326 | void restore() { P.OpenACCDirectiveParsing = OldVal; } |
327 | |
328 | ~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 | : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { |
339 | GreaterThanIsOperator = Val; |
340 | } |
341 | |
342 | ~GreaterThanIsOperatorScope() { |
343 | GreaterThanIsOperator = OldGreaterThanIsOperator; |
344 | } |
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 | OldValue(P.InMessageExpression) { |
355 | InMessageExpression = Value; |
356 | } |
357 | |
358 | ~InMessageExpressionRAIIObject() { |
359 | InMessageExpression = OldValue; |
360 | } |
361 | }; |
362 | |
363 | class OffsetOfStateRAIIObject { |
364 | Sema::OffsetOfKind &OffsetOfState; |
365 | Sema::OffsetOfKind OldValue; |
366 | |
367 | public: |
368 | OffsetOfStateRAIIObject(Parser &P, Sema::OffsetOfKind Value) |
369 | : OffsetOfState(P.OffsetOfState), OldValue(P.OffsetOfState) { |
370 | OffsetOfState = Value; |
371 | } |
372 | |
373 | ~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 | BraceCount(p.BraceCount) { } |
385 | |
386 | ~ParenBraceBracketBalancer() { |
387 | P.AngleBrackets.clear(P); |
388 | P.ParenCount = ParenCount; |
389 | P.BracketCount = BracketCount; |
390 | P.BraceCount = BraceCount; |
391 | } |
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 | Ident___exception_info(Self.Ident___exception_info, NewValue) { |
415 | } |
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 | unsigned short &getDepth() { |
427 | switch (Kind) { |
428 | case tok::l_brace: return P.BraceCount; |
429 | case tok::l_square: return P.BracketCount; |
430 | case tok::l_paren: return P.ParenCount; |
431 | default: llvm_unreachable("Wrong token kind" ); |
432 | } |
433 | } |
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 | { |
444 | switch (Kind) { |
445 | default: llvm_unreachable("Unexpected balanced token" ); |
446 | case tok::l_brace: |
447 | Close = tok::r_brace; |
448 | Consumer = &Parser::ConsumeBrace; |
449 | break; |
450 | case tok::l_paren: |
451 | Close = tok::r_paren; |
452 | Consumer = &Parser::ConsumeParen; |
453 | break; |
454 | |
455 | case tok::l_square: |
456 | Close = tok::r_square; |
457 | Consumer = &Parser::ConsumeBracket; |
458 | break; |
459 | } |
460 | } |
461 | |
462 | SourceLocation getOpenLocation() const { return LOpen; } |
463 | SourceLocation getCloseLocation() const { return LClose; } |
464 | SourceRange getRange() const { return SourceRange(LOpen, LClose); } |
465 | |
466 | bool consumeOpen() { |
467 | if (!P.Tok.is(K: Kind)) |
468 | return true; |
469 | |
470 | if (getDepth() < P.getLangOpts().BracketDepth) { |
471 | LOpen = (P.*Consumer)(); |
472 | return false; |
473 | } |
474 | |
475 | return diagnoseOverflow(); |
476 | } |
477 | |
478 | bool expectAndConsume(unsigned DiagID = diag::err_expected, |
479 | const char *Msg = "" , |
480 | tok::TokenKind SkipToTok = tok::unknown); |
481 | bool consumeClose() { |
482 | if (P.Tok.is(K: Close)) { |
483 | LClose = (P.*Consumer)(); |
484 | return false; |
485 | } else if (P.Tok.is(K: tok::semi) && P.NextToken().is(K: Close)) { |
486 | SourceLocation SemiLoc = P.ConsumeToken(); |
487 | P.Diag(SemiLoc, diag::err_unexpected_semi) |
488 | << Close << FixItHint::CreateRemoval(SourceRange(SemiLoc, SemiLoc)); |
489 | LClose = (P.*Consumer)(); |
490 | return false; |
491 | } |
492 | |
493 | return diagnoseMissingClose(); |
494 | } |
495 | void skipToEnd(); |
496 | }; |
497 | } // end namespace clang |
498 | |
499 | #endif |
500 | |