]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / tools / clang / lib / Parse / RAIIObjectsForParser.h
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 &GTIO, 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() < P.getLangOpts().BracketDepth) {
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