]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h
IFC @ 243795
[FreeBSD/FreeBSD.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     // Do not implement.
91     ParsingDeclRAIIObject(const ParsingDeclRAIIObject &other);
92     ParsingDeclRAIIObject &operator=(const ParsingDeclRAIIObject &other);
93
94   public:
95     enum NoParent_t { NoParent };
96     ParsingDeclRAIIObject(Parser &P, NoParent_t _)
97         : Actions(P.getActions()), DiagnosticPool(NULL) {
98       push();
99     }
100
101     /// Creates a RAII object whose pool is optionally parented by another.
102     ParsingDeclRAIIObject(Parser &P,
103                           const sema::DelayedDiagnosticPool *parentPool)
104         : Actions(P.getActions()), DiagnosticPool(parentPool) {
105       push();
106     }
107
108     /// Creates a RAII object and, optionally, initialize its
109     /// diagnostics pool by stealing the diagnostics from another
110     /// RAII object (which is assumed to be the current top pool).
111     ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other)
112         : Actions(P.getActions()),
113           DiagnosticPool(other ? other->DiagnosticPool.getParent() : NULL) {
114       if (other) {
115         DiagnosticPool.steal(other->DiagnosticPool);
116         other->abort();
117       }
118       push();
119     }
120
121     ~ParsingDeclRAIIObject() {
122       abort();
123     }
124
125     sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() {
126       return DiagnosticPool;
127     }
128     const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const {
129       return DiagnosticPool;
130     }
131
132     /// Resets the RAII object for a new declaration.
133     void reset() {
134       abort();
135       push();
136     }
137
138     /// Signals that the context was completed without an appropriate
139     /// declaration being parsed.
140     void abort() {
141       pop(0);
142     }
143
144     void complete(Decl *D) {
145       assert(!Popped && "ParsingDeclaration has already been popped!");
146       pop(D);
147     }
148
149     /// Unregister this object from Sema, but remember all the
150     /// diagnostics that were emitted into it.
151     void abortAndRemember() {
152       pop(0);
153     }
154
155   private:
156     void push() {
157       State = Actions.PushParsingDeclaration(DiagnosticPool);
158       Popped = false;
159     }
160
161     void pop(Decl *D) {
162       if (!Popped) {
163         Actions.PopParsingDeclaration(State, D);
164         Popped = true;
165       }
166     }
167   };
168
169   /// A class for parsing a DeclSpec.
170   class ParsingDeclSpec : public DeclSpec {
171     ParsingDeclRAIIObject ParsingRAII;
172
173   public:
174     ParsingDeclSpec(Parser &P)
175       : DeclSpec(P.getAttrFactory()),
176         ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {}
177     ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII)
178       : DeclSpec(P.getAttrFactory()),
179         ParsingRAII(P, RAII) {}
180
181     const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const {
182       return ParsingRAII.getDelayedDiagnosticPool();
183     }
184
185     void complete(Decl *D) {
186       ParsingRAII.complete(D);
187     }
188
189     void abort() {
190       ParsingRAII.abort();
191     }
192   };
193
194   /// A class for parsing a declarator.
195   class ParsingDeclarator : public Declarator {
196     ParsingDeclRAIIObject ParsingRAII;
197
198   public:
199     ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C)
200       : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {
201     }
202
203     const ParsingDeclSpec &getDeclSpec() const {
204       return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec());
205     }
206
207     ParsingDeclSpec &getMutableDeclSpec() const {
208       return const_cast<ParsingDeclSpec&>(getDeclSpec());
209     }
210
211     void clear() {
212       Declarator::clear();
213       ParsingRAII.reset();
214     }
215
216     void complete(Decl *D) {
217       ParsingRAII.complete(D);
218     }
219   };
220
221   /// A class for parsing a field declarator.
222   class ParsingFieldDeclarator : public FieldDeclarator {
223     ParsingDeclRAIIObject ParsingRAII;
224
225   public:
226     ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS)
227       : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {
228     }
229
230     const ParsingDeclSpec &getDeclSpec() const {
231       return static_cast<const ParsingDeclSpec&>(D.getDeclSpec());
232     }
233
234     ParsingDeclSpec &getMutableDeclSpec() const {
235       return const_cast<ParsingDeclSpec&>(getDeclSpec());
236     }
237
238     void complete(Decl *D) {
239       ParsingRAII.complete(D);
240     }
241   };
242
243   /// ExtensionRAIIObject - This saves the state of extension warnings when
244   /// constructed and disables them.  When destructed, it restores them back to
245   /// the way they used to be.  This is used to handle __extension__ in the
246   /// parser.
247   class ExtensionRAIIObject {
248     void operator=(const ExtensionRAIIObject &);     // DO NOT IMPLEMENT
249     ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT
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() < 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