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_LIB_PARSE_RAIIOBJECTSFORPARSER_H
16 #define LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_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(nullptr) {
54       if (activate) {
55         State = S.PushParsingDeclaration(DiagnosticPool);
56         Active = true;
57       } else {
58         Active = false;
59       }
60     }
61 
done()62     void done() {
63       assert(Active && "trying to end an inactive suppression");
64       S.PopParsingDeclaration(State, nullptr);
65       Active = false;
66     }
67 
redelay()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 
~SuppressAccessChecks()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 &) = delete;
91     void operator=(const ParsingDeclRAIIObject &) = delete;
92 
93   public:
94     enum NoParent_t { NoParent };
ParsingDeclRAIIObject(Parser & P,NoParent_t _)95     ParsingDeclRAIIObject(Parser &P, NoParent_t _)
96         : Actions(P.getActions()), DiagnosticPool(nullptr) {
97       push();
98     }
99 
100     /// Creates a RAII object whose pool is optionally parented by another.
ParsingDeclRAIIObject(Parser & P,const sema::DelayedDiagnosticPool * parentPool)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).
ParsingDeclRAIIObject(Parser & P,ParsingDeclRAIIObject * other)110     ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other)
111         : Actions(P.getActions()),
112           DiagnosticPool(other ? other->DiagnosticPool.getParent() : nullptr) {
113       if (other) {
114         DiagnosticPool.steal(other->DiagnosticPool);
115         other->abort();
116       }
117       push();
118     }
119 
~ParsingDeclRAIIObject()120     ~ParsingDeclRAIIObject() {
121       abort();
122     }
123 
getDelayedDiagnosticPool()124     sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() {
125       return DiagnosticPool;
126     }
getDelayedDiagnosticPool()127     const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const {
128       return DiagnosticPool;
129     }
130 
131     /// Resets the RAII object for a new declaration.
reset()132     void reset() {
133       abort();
134       push();
135     }
136 
137     /// Signals that the context was completed without an appropriate
138     /// declaration being parsed.
abort()139     void abort() {
140       pop(nullptr);
141     }
142 
complete(Decl * D)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.
abortAndRemember()150     void abortAndRemember() {
151       pop(nullptr);
152     }
153 
154   private:
push()155     void push() {
156       State = Actions.PushParsingDeclaration(DiagnosticPool);
157       Popped = false;
158     }
159 
pop(Decl * D)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:
ParsingDeclSpec(Parser & P)173     ParsingDeclSpec(Parser &P)
174       : DeclSpec(P.getAttrFactory()),
175         ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {}
ParsingDeclSpec(Parser & P,ParsingDeclRAIIObject * RAII)176     ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII)
177       : DeclSpec(P.getAttrFactory()),
178         ParsingRAII(P, RAII) {}
179 
getDelayedDiagnosticPool()180     const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const {
181       return ParsingRAII.getDelayedDiagnosticPool();
182     }
183 
complete(Decl * D)184     void complete(Decl *D) {
185       ParsingRAII.complete(D);
186     }
187 
abort()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:
ParsingDeclarator(Parser & P,const ParsingDeclSpec & DS,TheContext C)198     ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C)
199       : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {
200     }
201 
getDeclSpec()202     const ParsingDeclSpec &getDeclSpec() const {
203       return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec());
204     }
205 
getMutableDeclSpec()206     ParsingDeclSpec &getMutableDeclSpec() const {
207       return const_cast<ParsingDeclSpec&>(getDeclSpec());
208     }
209 
clear()210     void clear() {
211       Declarator::clear();
212       ParsingRAII.reset();
213     }
214 
complete(Decl * D)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:
ParsingFieldDeclarator(Parser & P,const ParsingDeclSpec & DS)225     ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS)
226       : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {
227     }
228 
getDeclSpec()229     const ParsingDeclSpec &getDeclSpec() const {
230       return static_cast<const ParsingDeclSpec&>(D.getDeclSpec());
231     }
232 
getMutableDeclSpec()233     ParsingDeclSpec &getMutableDeclSpec() const {
234       return const_cast<ParsingDeclSpec&>(getDeclSpec());
235     }
236 
complete(Decl * D)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 &) = delete;
248     void operator=(const ExtensionRAIIObject &) = delete;
249 
250     DiagnosticsEngine &Diags;
251   public:
ExtensionRAIIObject(DiagnosticsEngine & diags)252     ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) {
253       Diags.IncrementAllExtensionsSilenced();
254     }
255 
~ExtensionRAIIObject()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)
P(p)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.
restore()275     void restore() {
276       P.ColonIsSacred = OldVal;
277     }
278 
~ColonProtectionRAIIObject()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:
GreaterThanIsOperatorScope(bool & GTIO,bool Val)290     GreaterThanIsOperatorScope(bool &GTIO, bool Val)
291     : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) {
292       GreaterThanIsOperator = Val;
293     }
294 
~GreaterThanIsOperatorScope()295     ~GreaterThanIsOperatorScope() {
296       GreaterThanIsOperator = OldGreaterThanIsOperator;
297     }
298   };
299 
300   class InMessageExpressionRAIIObject {
301     bool &InMessageExpression;
302     bool OldValue;
303 
304   public:
InMessageExpressionRAIIObject(Parser & P,bool Value)305     InMessageExpressionRAIIObject(Parser &P, bool Value)
306       : InMessageExpression(P.InMessageExpression),
307         OldValue(P.InMessageExpression) {
308       InMessageExpression = Value;
309     }
310 
~InMessageExpressionRAIIObject()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:
ParenBraceBracketBalancer(Parser & p)322     ParenBraceBracketBalancer(Parser &p)
323       : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount),
324         BraceCount(p.BraceCount) { }
325 
~ParenBraceBracketBalancer()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:
PoisonSEHIdentifiersRAIIObject(Parser & Self,bool NewValue)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, FinalToken;
362     SourceLocation (Parser::*Consumer)();
363     SourceLocation LOpen, LClose;
364 
getDepth()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                              tok::TokenKind FinalToken = tok::semi)
382       : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true),
383         P(p), Kind(k), FinalToken(FinalToken)
384     {
385       switch (Kind) {
386         default: llvm_unreachable("Unexpected balanced token");
387         case tok::l_brace:
388           Close = tok::r_brace;
389           Consumer = &Parser::ConsumeBrace;
390           break;
391         case tok::l_paren:
392           Close = tok::r_paren;
393           Consumer = &Parser::ConsumeParen;
394           break;
395 
396         case tok::l_square:
397           Close = tok::r_square;
398           Consumer = &Parser::ConsumeBracket;
399           break;
400       }
401     }
402 
getOpenLocation()403     SourceLocation getOpenLocation() const { return LOpen; }
getCloseLocation()404     SourceLocation getCloseLocation() const { return LClose; }
getRange()405     SourceRange getRange() const { return SourceRange(LOpen, LClose); }
406 
consumeOpen()407     bool consumeOpen() {
408       if (!P.Tok.is(Kind))
409         return true;
410 
411       if (getDepth() < P.getLangOpts().BracketDepth) {
412         LOpen = (P.*Consumer)();
413         return false;
414       }
415 
416       return diagnoseOverflow();
417     }
418 
419     bool expectAndConsume(unsigned DiagID = diag::err_expected,
420                           const char *Msg = "",
421                           tok::TokenKind SkipToTok = tok::unknown);
consumeClose()422     bool consumeClose() {
423       if (P.Tok.is(Close)) {
424         LClose = (P.*Consumer)();
425         return false;
426       }
427 
428       return diagnoseMissingClose();
429     }
430     void skipToEnd();
431   };
432 
433 } // end namespace clang
434 
435 #endif
436