Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/include/clang/Parse/RAIIObjectsForParser.h
Line
Count
Source (jump to first uncovered line)
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
5.40k
        : S(P.getActions()), DiagnosticPool(nullptr) {
54
5.40k
      if (activate) {
55
0
        State = S.PushParsingDeclaration(DiagnosticPool);
56
0
        Active = true;
57
5.40k
      } else {
58
5.40k
        Active = false;
59
5.40k
      }
60
5.40k
    }
61
    SuppressAccessChecks(SuppressAccessChecks &&Other)
62
      : S(Other.S), DiagnosticPool(std::move(Other.DiagnosticPool)),
63
0
        State(Other.State), Active(Other.Active) {
64
0
      Other.Active = false;
65
0
    }
66
    void operator=(SuppressAccessChecks &&Other) = delete;
67
68
0
    void done() {
69
0
      assert(Active && "trying to end an inactive suppression");
70
0
      S.PopParsingDeclaration(State, nullptr);
71
0
      Active = false;
72
0
    }
73
74
0
    void redelay() {
75
0
      assert(!Active && "redelaying without having ended first");
76
0
      if (!DiagnosticPool.pool_empty())
77
0
        S.redelayDiagnostics(DiagnosticPool);
78
0
      assert(DiagnosticPool.pool_empty());
79
0
    }
80
81
5.40k
    ~SuppressAccessChecks() {
82
5.40k
      if (Active) done();
83
5.40k
    }
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
24.0k
        : Actions(P.getActions()), DiagnosticPool(nullptr) {
103
24.0k
      push();
104
24.0k
    }
105
106
    /// Creates a RAII object whose pool is optionally parented by another.
107
    ParsingDeclRAIIObject(Parser &P,
108
                          const sema::DelayedDiagnosticPool *parentPool)
109
23.7k
        : Actions(P.getActions()), DiagnosticPool(parentPool) {
110
23.7k
      push();
111
23.7k
    }
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
0
          DiagnosticPool(other ? other->DiagnosticPool.getParent() : nullptr) {
119
0
      if (other) {
120
0
        DiagnosticPool.steal(other->DiagnosticPool);
121
0
        other->abort();
122
0
      }
123
0
      push();
124
0
    }
125
126
47.7k
    ~ParsingDeclRAIIObject() {
127
47.7k
      abort();
128
47.7k
    }
129
130
0
    sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() {
131
0
      return DiagnosticPool;
132
0
    }
133
23.7k
    const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const {
134
23.7k
      return DiagnosticPool;
135
23.7k
    }
136
137
    /// Resets the RAII object for a new declaration.
138
172
    void reset() {
139
172
      abort();
140
172
      push();
141
172
    }
142
143
    /// Signals that the context was completed without an appropriate
144
    /// declaration being parsed.
145
47.9k
    void abort() {
146
47.9k
      pop(nullptr);
147
47.9k
    }
148
149
5.21k
    void complete(Decl *D) {
150
5.21k
      assert(!Popped && "ParsingDeclaration has already been popped!");
151
0
      pop(D);
152
5.21k
    }
153
154
    /// Unregister this object from Sema, but remember all the
155
    /// diagnostics that were emitted into it.
156
0
    void abortAndRemember() {
157
0
      pop(nullptr);
158
0
    }
159
160
  private:
161
47.9k
    void push() {
162
47.9k
      State = Actions.PushParsingDeclaration(DiagnosticPool);
163
47.9k
      Popped = false;
164
47.9k
    }
165
166
53.1k
    void pop(Decl *D) {
167
53.1k
      if (!Popped) {
168
47.9k
        Actions.PopParsingDeclaration(State, D);
169
47.9k
        Popped = true;
170
47.9k
      }
171
53.1k
    }
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
23.8k
        ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {}
182
    ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII)
183
      : DeclSpec(P.getAttrFactory()),
184
0
        ParsingRAII(P, RAII) {}
185
186
23.7k
    const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const {
187
23.7k
      return ParsingRAII.getDelayedDiagnosticPool();
188
23.7k
    }
189
190
39
    void complete(Decl *D) {
191
39
      ParsingRAII.complete(D);
192
39
    }
193
194
0
    void abort() {
195
0
      ParsingRAII.abort();
196
0
    }
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
23.7k
          ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {}
209
210
0
    const ParsingDeclSpec &getDeclSpec() const {
211
0
      return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec());
212
0
    }
213
214
0
    ParsingDeclSpec &getMutableDeclSpec() const {
215
0
      return const_cast<ParsingDeclSpec&>(getDeclSpec());
216
0
    }
217
218
172
    void clear() {
219
172
      Declarator::clear();
220
172
      ParsingRAII.reset();
221
172
    }
222
223
5.08k
    void complete(Decl *D) {
224
5.08k
      ParsingRAII.complete(D);
225
5.08k
    }
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
0
          ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {}
237
238
0
    const ParsingDeclSpec &getDeclSpec() const {
239
0
      return static_cast<const ParsingDeclSpec&>(D.getDeclSpec());
240
0
    }
241
242
0
    ParsingDeclSpec &getMutableDeclSpec() const {
243
0
      return const_cast<ParsingDeclSpec&>(getDeclSpec());
244
0
    }
245
246
0
    void complete(Decl *D) {
247
0
      ParsingRAII.complete(D);
248
0
    }
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
0
    ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) {
262
0
      Diags.IncrementAllExtensionsSilenced();
263
0
    }
264
265
0
    ~ExtensionRAIIObject() {
266
0
      Diags.DecrementAllExtensionsSilenced();
267
0
    }
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
12.1k
      : P(p), OldVal(P.ColonIsSacred) {
279
12.1k
      P.ColonIsSacred = Value;
280
12.1k
    }
281
282
    /// restore - This can be used to restore the state early, before the dtor
283
    /// is run.
284
12.1k
    void restore() {
285
12.1k
      P.ColonIsSacred = OldVal;
286
12.1k
    }
287
288
12.1k
    ~ColonProtectionRAIIObject() {
289
12.1k
      restore();
290
12.1k
    }
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
0
        : P(P), OldVal(P.OpenMPDirectiveParsing) {
302
0
      P.OpenMPDirectiveParsing = Value;
303
0
    }
304
305
    /// This can be used to restore the state early, before the dtor
306
    /// is run.
307
0
    void restore() { P.OpenMPDirectiveParsing = OldVal; }
308
309
0
    ~ParsingOpenMPDirectiveRAII() { restore(); }
310
  };
311
312
  /// Activates OpenACC parsing mode to preseve OpenACC specific annotation
313
  /// tokens.
314
  class ParsingOpenACCDirectiveRAII {
315
    Parser &P;
316
    bool OldVal;
317
318
  public:
319
    ParsingOpenACCDirectiveRAII(Parser &P, bool Value = true)
320
0
        : P(P), OldVal(P.OpenACCDirectiveParsing) {
321
0
      P.OpenACCDirectiveParsing = Value;
322
0
    }
323
324
    /// This can be used to restore the state early, before the dtor
325
    /// is run.
326
0
    void restore() { P.OpenMPDirectiveParsing = OldVal; }
327
328
0
    ~ParsingOpenACCDirectiveRAII() { restore(); }
329
  };
330
331
  /// RAII object that makes '>' behave either as an operator
332
  /// or as the closing angle bracket for a template argument list.
333
  class GreaterThanIsOperatorScope {
334
    bool &GreaterThanIsOperator;
335
    bool OldGreaterThanIsOperator;
336
  public:
337
    GreaterThanIsOperatorScope(bool &GTIO, bool Val)
338
911
    : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) {
339
911
      GreaterThanIsOperator = Val;
340
911
    }
341
342
911
    ~GreaterThanIsOperatorScope() {
343
911
      GreaterThanIsOperator = OldGreaterThanIsOperator;
344
911
    }
345
  };
346
347
  class InMessageExpressionRAIIObject {
348
    bool &InMessageExpression;
349
    bool OldValue;
350
351
  public:
352
    InMessageExpressionRAIIObject(Parser &P, bool Value)
353
      : InMessageExpression(P.InMessageExpression),
354
141
        OldValue(P.InMessageExpression) {
355
141
      InMessageExpression = Value;
356
141
    }
357
358
141
    ~InMessageExpressionRAIIObject() {
359
141
      InMessageExpression = OldValue;
360
141
    }
361
  };
362
363
  class OffsetOfStateRAIIObject {
364
    Sema::OffsetOfKind &OffsetOfState;
365
    Sema::OffsetOfKind OldValue;
366
367
  public:
368
    OffsetOfStateRAIIObject(Parser &P, Sema::OffsetOfKind Value)
369
0
        : OffsetOfState(P.OffsetOfState), OldValue(P.OffsetOfState) {
370
0
      OffsetOfState = Value;
371
0
    }
372
373
0
    ~OffsetOfStateRAIIObject() { OffsetOfState = OldValue; }
374
  };
375
376
  /// RAII object that makes sure paren/bracket/brace count is correct
377
  /// after declaration/statement parsing, even when there's a parsing error.
378
  class ParenBraceBracketBalancer {
379
    Parser &P;
380
    unsigned short ParenCount, BracketCount, BraceCount;
381
  public:
382
    ParenBraceBracketBalancer(Parser &p)
383
      : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount),
384
34.6k
        BraceCount(p.BraceCount) { }
385
386
34.6k
    ~ParenBraceBracketBalancer() {
387
34.6k
      P.AngleBrackets.clear(P);
388
34.6k
      P.ParenCount = ParenCount;
389
34.6k
      P.BracketCount = BracketCount;
390
34.6k
      P.BraceCount = BraceCount;
391
34.6k
    }
392
  };
393
394
  class PoisonSEHIdentifiersRAIIObject {
395
    PoisonIdentifierRAIIObject Ident_AbnormalTermination;
396
    PoisonIdentifierRAIIObject Ident_GetExceptionCode;
397
    PoisonIdentifierRAIIObject Ident_GetExceptionInfo;
398
    PoisonIdentifierRAIIObject Ident__abnormal_termination;
399
    PoisonIdentifierRAIIObject Ident__exception_code;
400
    PoisonIdentifierRAIIObject Ident__exception_info;
401
    PoisonIdentifierRAIIObject Ident___abnormal_termination;
402
    PoisonIdentifierRAIIObject Ident___exception_code;
403
    PoisonIdentifierRAIIObject Ident___exception_info;
404
  public:
405
    PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue)
406
      : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue),
407
        Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue),
408
        Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue),
409
        Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue),
410
        Ident__exception_code(Self.Ident__exception_code, NewValue),
411
        Ident__exception_info(Self.Ident__exception_info, NewValue),
412
        Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue),
413
        Ident___exception_code(Self.Ident___exception_code, NewValue),
414
0
        Ident___exception_info(Self.Ident___exception_info, NewValue) {
415
0
    }
416
  };
417
418
  /// RAII class that helps handle the parsing of an open/close delimiter
419
  /// pair, such as braces { ... } or parentheses ( ... ).
420
  class BalancedDelimiterTracker : public GreaterThanIsOperatorScope {
421
    Parser& P;
422
    tok::TokenKind Kind, Close, FinalToken;
423
    SourceLocation (Parser::*Consumer)();
424
    SourceLocation LOpen, LClose;
425
426
794
    unsigned short &getDepth() {
427
794
      switch (Kind) {
428
126
        case tok::l_brace: return P.BraceCount;
429
355
        case tok::l_square: return P.BracketCount;
430
313
        case tok::l_paren: return P.ParenCount;
431
0
        default: llvm_unreachable("Wrong token kind");
432
794
      }
433
794
    }
434
435
    bool diagnoseOverflow();
436
    bool diagnoseMissingClose();
437
438
  public:
439
    BalancedDelimiterTracker(Parser& p, tok::TokenKind k,
440
                             tok::TokenKind FinalToken = tok::semi)
441
      : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true),
442
        P(p), Kind(k), FinalToken(FinalToken)
443
794
    {
444
794
      switch (Kind) {
445
0
        default: llvm_unreachable("Unexpected balanced token");
446
126
        case tok::l_brace:
447
126
          Close = tok::r_brace;
448
126
          Consumer = &Parser::ConsumeBrace;
449
126
          break;
450
313
        case tok::l_paren:
451
313
          Close = tok::r_paren;
452
313
          Consumer = &Parser::ConsumeParen;
453
313
          break;
454
455
355
        case tok::l_square:
456
355
          Close = tok::r_square;
457
355
          Consumer = &Parser::ConsumeBracket;
458
355
          break;
459
794
      }
460
794
    }
461
462
616
    SourceLocation getOpenLocation() const { return LOpen; }
463
586
    SourceLocation getCloseLocation() const { return LClose; }
464
0
    SourceRange getRange() const { return SourceRange(LOpen, LClose); }
465
466
794
    bool consumeOpen() {
467
794
      if (!P.Tok.is(Kind))
468
0
        return true;
469
470
794
      if (getDepth() < P.getLangOpts().BracketDepth) {
471
794
        LOpen = (P.*Consumer)();
472
794
        return false;
473
794
      }
474
475
0
      return diagnoseOverflow();
476
794
    }
477
478
    bool expectAndConsume(unsigned DiagID = diag::err_expected,
479
                          const char *Msg = "",
480
                          tok::TokenKind SkipToTok = tok::unknown);
481
470
    bool consumeClose() {
482
470
      if (P.Tok.is(Close)) {
483
87
        LClose = (P.*Consumer)();
484
87
        return false;
485
383
      } else if (P.Tok.is(tok::semi) && P.NextToken().is(Close)) {
486
0
        SourceLocation SemiLoc = P.ConsumeToken();
487
0
        P.Diag(SemiLoc, diag::err_unexpected_semi)
488
0
            << Close << FixItHint::CreateRemoval(SourceRange(SemiLoc, SemiLoc));
489
0
        LClose = (P.*Consumer)();
490
0
        return false;
491
0
      }
492
493
383
      return diagnoseMissingClose();
494
470
    }
495
    void skipToEnd();
496
  };
497
} // end namespace clang
498
499
#endif