]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
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_PARSE_RAII_OBJECTS_FOR_PARSER_H | |
16 | #define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_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 | : S(P.getActions()), DiagnosticPool(NULL) { | |
54 | if (activate) { | |
55 | State = S.PushParsingDeclaration(DiagnosticPool); | |
56 | Active = true; | |
57 | } else { | |
58 | Active = false; | |
59 | } | |
60 | } | |
61 | ||
62 | void done() { | |
63 | assert(Active && "trying to end an inactive suppression"); | |
64 | S.PopParsingDeclaration(State, NULL); | |
65 | Active = false; | |
66 | } | |
67 | ||
68 | void redelay() { | |
69 | assert(!Active && "redelaying without having ended first"); | |
70 | if (!DiagnosticPool.pool_empty()) | |
71 | S.redelayDiagnostics(DiagnosticPool); | |
72 | assert(DiagnosticPool.pool_empty()); | |
73 | } | |
74 | ||
75 | ~SuppressAccessChecks() { | |
76 | if (Active) done(); | |
77 | } | |
78 | }; | |
79 | ||
80 | /// \brief RAII object used to inform the actions that we're | |
81 | /// currently parsing a declaration. This is active when parsing a | |
82 | /// variable's initializer, but not when parsing the body of a | |
83 | /// class or function definition. | |
84 | class ParsingDeclRAIIObject { | |
85 | Sema &Actions; | |
86 | sema::DelayedDiagnosticPool DiagnosticPool; | |
87 | Sema::ParsingDeclState State; | |
88 | bool Popped; | |
89 | ||
90 | ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION; | |
91 | void operator=(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION; | |
92 | ||
93 | public: | |
94 | enum NoParent_t { NoParent }; | |
95 | ParsingDeclRAIIObject(Parser &P, NoParent_t _) | |
96 | : Actions(P.getActions()), DiagnosticPool(NULL) { | |
97 | push(); | |
98 | } | |
99 | ||
100 | /// Creates a RAII object whose pool is optionally parented by another. | |
101 | ParsingDeclRAIIObject(Parser &P, | |
102 | const sema::DelayedDiagnosticPool *parentPool) | |
103 | : Actions(P.getActions()), DiagnosticPool(parentPool) { | |
104 | push(); | |
105 | } | |
106 | ||
107 | /// Creates a RAII object and, optionally, initialize its | |
108 | /// diagnostics pool by stealing the diagnostics from another | |
109 | /// RAII object (which is assumed to be the current top pool). | |
110 | ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other) | |
111 | : Actions(P.getActions()), | |
112 | DiagnosticPool(other ? other->DiagnosticPool.getParent() : NULL) { | |
113 | if (other) { | |
114 | DiagnosticPool.steal(other->DiagnosticPool); | |
115 | other->abort(); | |
116 | } | |
117 | push(); | |
118 | } | |
119 | ||
120 | ~ParsingDeclRAIIObject() { | |
121 | abort(); | |
122 | } | |
123 | ||
124 | sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() { | |
125 | return DiagnosticPool; | |
126 | } | |
127 | const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { | |
128 | return DiagnosticPool; | |
129 | } | |
130 | ||
131 | /// Resets the RAII object for a new declaration. | |
132 | void reset() { | |
133 | abort(); | |
134 | push(); | |
135 | } | |
136 | ||
137 | /// Signals that the context was completed without an appropriate | |
138 | /// declaration being parsed. | |
139 | void abort() { | |
140 | pop(0); | |
141 | } | |
142 | ||
143 | void complete(Decl *D) { | |
144 | assert(!Popped && "ParsingDeclaration has already been popped!"); | |
145 | pop(D); | |
146 | } | |
147 | ||
148 | /// Unregister this object from Sema, but remember all the | |
149 | /// diagnostics that were emitted into it. | |
150 | void abortAndRemember() { | |
151 | pop(0); | |
152 | } | |
153 | ||
154 | private: | |
155 | void push() { | |
156 | State = Actions.PushParsingDeclaration(DiagnosticPool); | |
157 | Popped = false; | |
158 | } | |
159 | ||
160 | void pop(Decl *D) { | |
161 | if (!Popped) { | |
162 | Actions.PopParsingDeclaration(State, D); | |
163 | Popped = true; | |
164 | } | |
165 | } | |
166 | }; | |
167 | ||
168 | /// A class for parsing a DeclSpec. | |
169 | class ParsingDeclSpec : public DeclSpec { | |
170 | ParsingDeclRAIIObject ParsingRAII; | |
171 | ||
172 | public: | |
173 | ParsingDeclSpec(Parser &P) | |
174 | : DeclSpec(P.getAttrFactory()), | |
175 | ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {} | |
176 | ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) | |
177 | : DeclSpec(P.getAttrFactory()), | |
178 | ParsingRAII(P, RAII) {} | |
179 | ||
180 | const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { | |
181 | return ParsingRAII.getDelayedDiagnosticPool(); | |
182 | } | |
183 | ||
184 | void complete(Decl *D) { | |
185 | ParsingRAII.complete(D); | |
186 | } | |
187 | ||
188 | void abort() { | |
189 | ParsingRAII.abort(); | |
190 | } | |
191 | }; | |
192 | ||
193 | /// A class for parsing a declarator. | |
194 | class ParsingDeclarator : public Declarator { | |
195 | ParsingDeclRAIIObject ParsingRAII; | |
196 | ||
197 | public: | |
198 | ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) | |
199 | : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { | |
200 | } | |
201 | ||
202 | const ParsingDeclSpec &getDeclSpec() const { | |
203 | return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec()); | |
204 | } | |
205 | ||
206 | ParsingDeclSpec &getMutableDeclSpec() const { | |
207 | return const_cast<ParsingDeclSpec&>(getDeclSpec()); | |
208 | } | |
209 | ||
210 | void clear() { | |
211 | Declarator::clear(); | |
212 | ParsingRAII.reset(); | |
213 | } | |
214 | ||
215 | void complete(Decl *D) { | |
216 | ParsingRAII.complete(D); | |
217 | } | |
218 | }; | |
219 | ||
220 | /// A class for parsing a field declarator. | |
221 | class ParsingFieldDeclarator : public FieldDeclarator { | |
222 | ParsingDeclRAIIObject ParsingRAII; | |
223 | ||
224 | public: | |
225 | ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS) | |
226 | : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { | |
227 | } | |
228 | ||
229 | const ParsingDeclSpec &getDeclSpec() const { | |
230 | return static_cast<const ParsingDeclSpec&>(D.getDeclSpec()); | |
231 | } | |
232 | ||
233 | ParsingDeclSpec &getMutableDeclSpec() const { | |
234 | return const_cast<ParsingDeclSpec&>(getDeclSpec()); | |
235 | } | |
236 | ||
237 | void complete(Decl *D) { | |
238 | ParsingRAII.complete(D); | |
239 | } | |
240 | }; | |
241 | ||
242 | /// ExtensionRAIIObject - This saves the state of extension warnings when | |
243 | /// constructed and disables them. When destructed, it restores them back to | |
244 | /// the way they used to be. This is used to handle __extension__ in the | |
245 | /// parser. | |
246 | class ExtensionRAIIObject { | |
247 | ExtensionRAIIObject(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION; | |
248 | void operator=(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION; | |
249 | ||
250 | DiagnosticsEngine &Diags; | |
251 | public: | |
252 | ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) { | |
253 | Diags.IncrementAllExtensionsSilenced(); | |
254 | } | |
255 | ||
256 | ~ExtensionRAIIObject() { | |
257 | Diags.DecrementAllExtensionsSilenced(); | |
258 | } | |
259 | }; | |
260 | ||
261 | /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and | |
262 | /// restores it when destroyed. This says that "foo:" should not be | |
263 | /// considered a possible typo for "foo::" for error recovery purposes. | |
264 | class ColonProtectionRAIIObject { | |
265 | Parser &P; | |
266 | bool OldVal; | |
267 | public: | |
268 | ColonProtectionRAIIObject(Parser &p, bool Value = true) | |
269 | : P(p), OldVal(P.ColonIsSacred) { | |
270 | P.ColonIsSacred = Value; | |
271 | } | |
272 | ||
273 | /// restore - This can be used to restore the state early, before the dtor | |
274 | /// is run. | |
275 | void restore() { | |
276 | P.ColonIsSacred = OldVal; | |
277 | } | |
278 | ||
279 | ~ColonProtectionRAIIObject() { | |
280 | restore(); | |
281 | } | |
282 | }; | |
283 | ||
284 | /// \brief RAII object that makes '>' behave either as an operator | |
285 | /// or as the closing angle bracket for a template argument list. | |
286 | class GreaterThanIsOperatorScope { | |
287 | bool &GreaterThanIsOperator; | |
288 | bool OldGreaterThanIsOperator; | |
289 | public: | |
290 | GreaterThanIsOperatorScope(bool >IO, bool Val) | |
291 | : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { | |
292 | GreaterThanIsOperator = Val; | |
293 | } | |
294 | ||
295 | ~GreaterThanIsOperatorScope() { | |
296 | GreaterThanIsOperator = OldGreaterThanIsOperator; | |
297 | } | |
298 | }; | |
299 | ||
300 | class InMessageExpressionRAIIObject { | |
301 | bool &InMessageExpression; | |
302 | bool OldValue; | |
303 | ||
304 | public: | |
305 | InMessageExpressionRAIIObject(Parser &P, bool Value) | |
306 | : InMessageExpression(P.InMessageExpression), | |
307 | OldValue(P.InMessageExpression) { | |
308 | InMessageExpression = Value; | |
309 | } | |
310 | ||
311 | ~InMessageExpressionRAIIObject() { | |
312 | InMessageExpression = OldValue; | |
313 | } | |
314 | }; | |
315 | ||
316 | /// \brief RAII object that makes sure paren/bracket/brace count is correct | |
317 | /// after declaration/statement parsing, even when there's a parsing error. | |
318 | class ParenBraceBracketBalancer { | |
319 | Parser &P; | |
320 | unsigned short ParenCount, BracketCount, BraceCount; | |
321 | public: | |
322 | ParenBraceBracketBalancer(Parser &p) | |
323 | : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount), | |
324 | BraceCount(p.BraceCount) { } | |
325 | ||
326 | ~ParenBraceBracketBalancer() { | |
327 | P.ParenCount = ParenCount; | |
328 | P.BracketCount = BracketCount; | |
329 | P.BraceCount = BraceCount; | |
330 | } | |
331 | }; | |
332 | ||
333 | class PoisonSEHIdentifiersRAIIObject { | |
334 | PoisonIdentifierRAIIObject Ident_AbnormalTermination; | |
335 | PoisonIdentifierRAIIObject Ident_GetExceptionCode; | |
336 | PoisonIdentifierRAIIObject Ident_GetExceptionInfo; | |
337 | PoisonIdentifierRAIIObject Ident__abnormal_termination; | |
338 | PoisonIdentifierRAIIObject Ident__exception_code; | |
339 | PoisonIdentifierRAIIObject Ident__exception_info; | |
340 | PoisonIdentifierRAIIObject Ident___abnormal_termination; | |
341 | PoisonIdentifierRAIIObject Ident___exception_code; | |
342 | PoisonIdentifierRAIIObject Ident___exception_info; | |
343 | public: | |
344 | PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue) | |
345 | : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue), | |
346 | Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue), | |
347 | Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue), | |
348 | Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue), | |
349 | Ident__exception_code(Self.Ident__exception_code, NewValue), | |
350 | Ident__exception_info(Self.Ident__exception_info, NewValue), | |
351 | Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue), | |
352 | Ident___exception_code(Self.Ident___exception_code, NewValue), | |
353 | Ident___exception_info(Self.Ident___exception_info, NewValue) { | |
354 | } | |
355 | }; | |
356 | ||
357 | /// \brief RAII class that helps handle the parsing of an open/close delimiter | |
358 | /// pair, such as braces { ... } or parentheses ( ... ). | |
359 | class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { | |
360 | Parser& P; | |
361 | tok::TokenKind Kind, Close; | |
362 | SourceLocation (Parser::*Consumer)(); | |
363 | SourceLocation LOpen, LClose; | |
364 | ||
365 | unsigned short &getDepth() { | |
366 | switch (Kind) { | |
367 | case tok::l_brace: return P.BraceCount; | |
368 | case tok::l_square: return P.BracketCount; | |
369 | case tok::l_paren: return P.ParenCount; | |
370 | default: llvm_unreachable("Wrong token kind"); | |
371 | } | |
372 | } | |
373 | ||
374 | enum { MaxDepth = 256 }; | |
375 | ||
376 | bool diagnoseOverflow(); | |
377 | bool diagnoseMissingClose(); | |
378 | ||
379 | public: | |
380 | BalancedDelimiterTracker(Parser& p, tok::TokenKind k) | |
381 | : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), | |
382 | P(p), Kind(k) | |
383 | { | |
384 | switch (Kind) { | |
385 | default: llvm_unreachable("Unexpected balanced token"); | |
386 | case tok::l_brace: | |
387 | Close = tok::r_brace; | |
388 | Consumer = &Parser::ConsumeBrace; | |
389 | break; | |
390 | case tok::l_paren: | |
391 | Close = tok::r_paren; | |
392 | Consumer = &Parser::ConsumeParen; | |
393 | break; | |
394 | ||
395 | case tok::l_square: | |
396 | Close = tok::r_square; | |
397 | Consumer = &Parser::ConsumeBracket; | |
398 | break; | |
399 | } | |
400 | } | |
401 | ||
402 | SourceLocation getOpenLocation() const { return LOpen; } | |
403 | SourceLocation getCloseLocation() const { return LClose; } | |
404 | SourceRange getRange() const { return SourceRange(LOpen, LClose); } | |
405 | ||
406 | bool consumeOpen() { | |
407 | if (!P.Tok.is(Kind)) | |
408 | return true; | |
409 | ||
410 | if (getDepth() < MaxDepth) { | |
411 | LOpen = (P.*Consumer)(); | |
412 | return false; | |
413 | } | |
414 | ||
415 | return diagnoseOverflow(); | |
416 | } | |
417 | ||
418 | bool expectAndConsume(unsigned DiagID, | |
419 | const char *Msg = "", | |
420 | tok::TokenKind SkipToTok = tok::unknown); | |
421 | bool consumeClose() { | |
422 | if (P.Tok.is(Close)) { | |
423 | LClose = (P.*Consumer)(); | |
424 | return false; | |
425 | } | |
426 | ||
427 | return diagnoseMissingClose(); | |
428 | } | |
429 | void skipToEnd(); | |
430 | }; | |
431 | ||
432 | } // end namespace clang | |
433 | ||
434 | #endif |