Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 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(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, 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(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(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(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(nullptr); |
||
158 | } |
||
159 | |||
160 | private: |
||
161 | void push() { |
||
162 | State = Actions.PushParsingDeclaration(DiagnosticPool); |
||
163 | Popped = false; |
||
164 | } |
||
165 | |||
166 | void pop(Decl *D) { |
||
167 | if (!Popped) { |
||
168 | Actions.PopParsingDeclaration(State, 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 | /// RAII object that makes '>' behave either as an operator |
||
313 | /// or as the closing angle bracket for a template argument list. |
||
314 | class GreaterThanIsOperatorScope { |
||
315 | bool &GreaterThanIsOperator; |
||
316 | bool OldGreaterThanIsOperator; |
||
317 | public: |
||
318 | GreaterThanIsOperatorScope(bool >IO, bool Val) |
||
319 | : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { |
||
320 | GreaterThanIsOperator = Val; |
||
321 | } |
||
322 | |||
323 | ~GreaterThanIsOperatorScope() { |
||
324 | GreaterThanIsOperator = OldGreaterThanIsOperator; |
||
325 | } |
||
326 | }; |
||
327 | |||
328 | class InMessageExpressionRAIIObject { |
||
329 | bool &InMessageExpression; |
||
330 | bool OldValue; |
||
331 | |||
332 | public: |
||
333 | InMessageExpressionRAIIObject(Parser &P, bool Value) |
||
334 | : InMessageExpression(P.InMessageExpression), |
||
335 | OldValue(P.InMessageExpression) { |
||
336 | InMessageExpression = Value; |
||
337 | } |
||
338 | |||
339 | ~InMessageExpressionRAIIObject() { |
||
340 | InMessageExpression = OldValue; |
||
341 | } |
||
342 | }; |
||
343 | |||
344 | class OffsetOfStateRAIIObject { |
||
345 | Sema::OffsetOfKind &OffsetOfState; |
||
346 | Sema::OffsetOfKind OldValue; |
||
347 | |||
348 | public: |
||
349 | OffsetOfStateRAIIObject(Parser &P, Sema::OffsetOfKind Value) |
||
350 | : OffsetOfState(P.OffsetOfState), OldValue(P.OffsetOfState) { |
||
351 | OffsetOfState = Value; |
||
352 | } |
||
353 | |||
354 | ~OffsetOfStateRAIIObject() { OffsetOfState = OldValue; } |
||
355 | }; |
||
356 | |||
357 | /// RAII object that makes sure paren/bracket/brace count is correct |
||
358 | /// after declaration/statement parsing, even when there's a parsing error. |
||
359 | class ParenBraceBracketBalancer { |
||
360 | Parser &P; |
||
361 | unsigned short ParenCount, BracketCount, BraceCount; |
||
362 | public: |
||
363 | ParenBraceBracketBalancer(Parser &p) |
||
364 | : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount), |
||
365 | BraceCount(p.BraceCount) { } |
||
366 | |||
367 | ~ParenBraceBracketBalancer() { |
||
368 | P.AngleBrackets.clear(P); |
||
369 | P.ParenCount = ParenCount; |
||
370 | P.BracketCount = BracketCount; |
||
371 | P.BraceCount = BraceCount; |
||
372 | } |
||
373 | }; |
||
374 | |||
375 | class PoisonSEHIdentifiersRAIIObject { |
||
376 | PoisonIdentifierRAIIObject Ident_AbnormalTermination; |
||
377 | PoisonIdentifierRAIIObject Ident_GetExceptionCode; |
||
378 | PoisonIdentifierRAIIObject Ident_GetExceptionInfo; |
||
379 | PoisonIdentifierRAIIObject Ident__abnormal_termination; |
||
380 | PoisonIdentifierRAIIObject Ident__exception_code; |
||
381 | PoisonIdentifierRAIIObject Ident__exception_info; |
||
382 | PoisonIdentifierRAIIObject Ident___abnormal_termination; |
||
383 | PoisonIdentifierRAIIObject Ident___exception_code; |
||
384 | PoisonIdentifierRAIIObject Ident___exception_info; |
||
385 | public: |
||
386 | PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue) |
||
387 | : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue), |
||
388 | Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue), |
||
389 | Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue), |
||
390 | Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue), |
||
391 | Ident__exception_code(Self.Ident__exception_code, NewValue), |
||
392 | Ident__exception_info(Self.Ident__exception_info, NewValue), |
||
393 | Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue), |
||
394 | Ident___exception_code(Self.Ident___exception_code, NewValue), |
||
395 | Ident___exception_info(Self.Ident___exception_info, NewValue) { |
||
396 | } |
||
397 | }; |
||
398 | |||
399 | /// RAII class that helps handle the parsing of an open/close delimiter |
||
400 | /// pair, such as braces { ... } or parentheses ( ... ). |
||
401 | class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { |
||
402 | Parser& P; |
||
403 | tok::TokenKind Kind, Close, FinalToken; |
||
404 | SourceLocation (Parser::*Consumer)(); |
||
405 | SourceLocation LOpen, LClose; |
||
406 | |||
407 | unsigned short &getDepth() { |
||
408 | switch (Kind) { |
||
409 | case tok::l_brace: return P.BraceCount; |
||
410 | case tok::l_square: return P.BracketCount; |
||
411 | case tok::l_paren: return P.ParenCount; |
||
412 | default: llvm_unreachable("Wrong token kind"); |
||
413 | } |
||
414 | } |
||
415 | |||
416 | bool diagnoseOverflow(); |
||
417 | bool diagnoseMissingClose(); |
||
418 | |||
419 | public: |
||
420 | BalancedDelimiterTracker(Parser& p, tok::TokenKind k, |
||
421 | tok::TokenKind FinalToken = tok::semi) |
||
422 | : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), |
||
423 | P(p), Kind(k), FinalToken(FinalToken) |
||
424 | { |
||
425 | switch (Kind) { |
||
426 | default: llvm_unreachable("Unexpected balanced token"); |
||
427 | case tok::l_brace: |
||
428 | Close = tok::r_brace; |
||
429 | Consumer = &Parser::ConsumeBrace; |
||
430 | break; |
||
431 | case tok::l_paren: |
||
432 | Close = tok::r_paren; |
||
433 | Consumer = &Parser::ConsumeParen; |
||
434 | break; |
||
435 | |||
436 | case tok::l_square: |
||
437 | Close = tok::r_square; |
||
438 | Consumer = &Parser::ConsumeBracket; |
||
439 | break; |
||
440 | } |
||
441 | } |
||
442 | |||
443 | SourceLocation getOpenLocation() const { return LOpen; } |
||
444 | SourceLocation getCloseLocation() const { return LClose; } |
||
445 | SourceRange getRange() const { return SourceRange(LOpen, LClose); } |
||
446 | |||
447 | bool consumeOpen() { |
||
448 | if (!P.Tok.is(Kind)) |
||
449 | return true; |
||
450 | |||
451 | if (getDepth() < P.getLangOpts().BracketDepth) { |
||
452 | LOpen = (P.*Consumer)(); |
||
453 | return false; |
||
454 | } |
||
455 | |||
456 | return diagnoseOverflow(); |
||
457 | } |
||
458 | |||
459 | bool expectAndConsume(unsigned DiagID = diag::err_expected, |
||
460 | const char *Msg = "", |
||
461 | tok::TokenKind SkipToTok = tok::unknown); |
||
462 | bool consumeClose() { |
||
463 | if (P.Tok.is(Close)) { |
||
464 | LClose = (P.*Consumer)(); |
||
465 | return false; |
||
466 | } else if (P.Tok.is(tok::semi) && P.NextToken().is(Close)) { |
||
467 | SourceLocation SemiLoc = P.ConsumeToken(); |
||
468 | P.Diag(SemiLoc, diag::err_unexpected_semi) |
||
469 | << Close << FixItHint::CreateRemoval(SourceRange(SemiLoc, SemiLoc)); |
||
470 | LClose = (P.*Consumer)(); |
||
471 | return false; |
||
472 | } |
||
473 | |||
474 | return diagnoseMissingClose(); |
||
475 | } |
||
476 | void skipToEnd(); |
||
477 | }; |
||
478 | } // end namespace clang |
||
479 | |||
480 | #endif |