Coverage Report

Created: 2022-07-16 07:03

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/AST/ExprConcepts.h
Line
Count
Source (jump to first uncovered line)
1
//===- ExprConcepts.h - C++2a Concepts expressions --------------*- 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
/// \file
10
/// Defines Expressions and AST nodes for C++2a concepts.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#ifndef LLVM_CLANG_AST_EXPRCONCEPTS_H
15
#define LLVM_CLANG_AST_EXPRCONCEPTS_H
16
17
#include "clang/AST/ASTContext.h"
18
#include "clang/AST/ASTConcept.h"
19
#include "clang/AST/Decl.h"
20
#include "clang/AST/DeclarationName.h"
21
#include "clang/AST/DeclTemplate.h"
22
#include "clang/AST/Expr.h"
23
#include "clang/AST/NestedNameSpecifier.h"
24
#include "clang/AST/TemplateBase.h"
25
#include "clang/AST/Type.h"
26
#include "clang/Basic/SourceLocation.h"
27
#include "llvm/Support/TrailingObjects.h"
28
#include <utility>
29
#include <string>
30
31
namespace clang {
32
class ASTStmtReader;
33
class ASTStmtWriter;
34
35
/// \brief Represents the specialization of a concept - evaluates to a prvalue
36
/// of type bool.
37
///
38
/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
39
/// specialization of a concept results in a prvalue of type bool.
40
class ConceptSpecializationExpr final : public Expr, public ConceptReference,
41
      private llvm::TrailingObjects<ConceptSpecializationExpr,
42
                                    TemplateArgument> {
43
  friend class ASTStmtReader;
44
  friend TrailingObjects;
45
public:
46
  using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>;
47
48
protected:
49
  /// \brief The number of template arguments in the tail-allocated list of
50
  /// converted template arguments.
51
  unsigned NumTemplateArgs;
52
53
  /// \brief Information about the satisfaction of the named concept with the
54
  /// given arguments. If this expression is value dependent, this is to be
55
  /// ignored.
56
  ASTConstraintSatisfaction *Satisfaction;
57
58
  ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS,
59
                            SourceLocation TemplateKWLoc,
60
                            DeclarationNameInfo ConceptNameInfo,
61
                            NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
62
                            const ASTTemplateArgumentListInfo *ArgsAsWritten,
63
                            ArrayRef<TemplateArgument> ConvertedArgs,
64
                            const ConstraintSatisfaction *Satisfaction);
65
66
  ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept,
67
                            ArrayRef<TemplateArgument> ConvertedArgs,
68
                            const ConstraintSatisfaction *Satisfaction,
69
                            bool Dependent,
70
                            bool ContainsUnexpandedParameterPack);
71
72
  ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
73
74
public:
75
76
  static ConceptSpecializationExpr *
77
  Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
78
         SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
79
         NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
80
         const ASTTemplateArgumentListInfo *ArgsAsWritten,
81
         ArrayRef<TemplateArgument> ConvertedArgs,
82
         const ConstraintSatisfaction *Satisfaction);
83
84
  static ConceptSpecializationExpr *
85
  Create(const ASTContext &C, ConceptDecl *NamedConcept,
86
         ArrayRef<TemplateArgument> ConvertedArgs,
87
         const ConstraintSatisfaction *Satisfaction,
88
         bool Dependent,
89
         bool ContainsUnexpandedParameterPack);
90
91
  static ConceptSpecializationExpr *
92
  Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
93
94
6.96k
  ArrayRef<TemplateArgument> getTemplateArguments() const {
95
6.96k
    return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
96
6.96k
                                      NumTemplateArgs);
97
6.96k
  }
98
99
  /// \brief Set new template arguments for this concept specialization.
100
  void setTemplateArguments(ArrayRef<TemplateArgument> Converted);
101
102
  /// \brief Whether or not the concept with the given arguments was satisfied
103
  /// when the expression was created.
104
  /// The expression must not be dependent.
105
9.82k
  bool isSatisfied() const {
106
9.82k
    assert(!isValueDependent()
107
9.82k
           && "isSatisfied called on a dependent ConceptSpecializationExpr");
108
0
    return Satisfaction->IsSatisfied;
109
9.82k
  }
110
111
  /// \brief Get elaborated satisfaction info about the template arguments'
112
  /// satisfaction of the named concept.
113
  /// The expression must not be dependent.
114
455
  const ASTConstraintSatisfaction &getSatisfaction() const {
115
455
    assert(!isValueDependent()
116
455
           && "getSatisfaction called on dependent ConceptSpecializationExpr");
117
0
    return *Satisfaction;
118
455
  }
119
120
15.1k
  static bool classof(const Stmt *T) {
121
15.1k
    return T->getStmtClass() == ConceptSpecializationExprClass;
122
15.1k
  }
123
124
36.8k
  SourceLocation getBeginLoc() const LLVM_READONLY {
125
36.8k
    if (auto QualifierLoc = getNestedNameSpecifierLoc())
126
717
      return QualifierLoc.getBeginLoc();
127
36.1k
    return ConceptName.getBeginLoc();
128
36.8k
  }
129
130
8.40k
  SourceLocation getEndLoc() const LLVM_READONLY {
131
    // If the ConceptSpecializationExpr is the ImmediatelyDeclaredConstraint
132
    // of a TypeConstraint written syntactically as a constrained-parameter,
133
    // there may not be a template argument list.
134
8.40k
    return ArgsAsWritten->RAngleLoc.isValid() ? 
ArgsAsWritten->RAngleLoc7.44k
135
8.40k
                                              : 
ConceptName.getEndLoc()955
;
136
8.40k
  }
137
138
  // Iterators
139
6.52k
  child_range children() {
140
6.52k
    return child_range(child_iterator(), child_iterator());
141
6.52k
  }
142
0
  const_child_range children() const {
143
0
    return const_child_range(const_child_iterator(), const_child_iterator());
144
0
  }
145
};
146
147
namespace concepts {
148
149
/// \brief A static requirement that can be used in a requires-expression to
150
/// check properties of types and expression.
151
class Requirement {
152
public:
153
  // Note - simple and compound requirements are both represented by the same
154
  // class (ExprRequirement).
155
  enum RequirementKind { RK_Type, RK_Simple, RK_Compound, RK_Nested };
156
private:
157
  const RequirementKind Kind;
158
  // FIXME: use RequirementDependence to model dependence?
159
  bool Dependent : 1;
160
  bool ContainsUnexpandedParameterPack : 1;
161
  bool Satisfied : 1;
162
public:
163
  struct SubstitutionDiagnostic {
164
    StringRef SubstitutedEntity;
165
    // FIXME: Store diagnostics semantically and not as prerendered strings.
166
    //  Fixing this probably requires serialization of PartialDiagnostic
167
    //  objects.
168
    SourceLocation DiagLoc;
169
    StringRef DiagMessage;
170
  };
171
172
  Requirement(RequirementKind Kind, bool IsDependent,
173
              bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) :
174
      Kind(Kind), Dependent(IsDependent),
175
      ContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack),
176
5.19k
      Satisfied(IsSatisfied) {}
177
178
19.1k
  RequirementKind getKind() const { return Kind; }
179
180
7.87k
  bool isSatisfied() const {
181
7.87k
    assert(!Dependent &&
182
7.87k
           "isSatisfied can only be called on non-dependent requirements.");
183
0
    return Satisfied;
184
7.87k
  }
185
186
0
  void setSatisfied(bool IsSatisfied) {
187
0
    assert(!Dependent &&
188
0
           "setSatisfied can only be called on non-dependent requirements.");
189
0
    Satisfied = IsSatisfied;
190
0
  }
191
192
0
  void setDependent(bool IsDependent) { Dependent = IsDependent; }
193
12.7k
  bool isDependent() const { return Dependent; }
194
195
0
  void setContainsUnexpandedParameterPack(bool Contains) {
196
0
    ContainsUnexpandedParameterPack = Contains;
197
0
  }
198
5.00k
  bool containsUnexpandedParameterPack() const {
199
5.00k
    return ContainsUnexpandedParameterPack;
200
5.00k
  }
201
};
202
203
/// \brief A requires-expression requirement which queries the existence of a
204
/// type name or type template specialization ('type' requirements).
205
class TypeRequirement : public Requirement {
206
public:
207
  enum SatisfactionStatus {
208
      SS_Dependent,
209
      SS_SubstitutionFailure,
210
      SS_Satisfied
211
  };
212
private:
213
  llvm::PointerUnion<SubstitutionDiagnostic *, TypeSourceInfo *> Value;
214
  SatisfactionStatus Status;
215
public:
216
  friend ASTStmtReader;
217
  friend ASTStmtWriter;
218
219
  /// \brief Construct a type requirement from a type. If the given type is not
220
  /// dependent, this indicates that the type exists and the requirement will be
221
  /// satisfied. Otherwise, the SubstitutionDiagnostic constructor is to be
222
  /// used.
223
  TypeRequirement(TypeSourceInfo *T);
224
225
  /// \brief Construct a type requirement when the nested name specifier is
226
  /// invalid due to a bad substitution. The requirement is unsatisfied.
227
  TypeRequirement(SubstitutionDiagnostic *Diagnostic) :
228
      Requirement(RK_Type, false, false, false), Value(Diagnostic),
229
30
      Status(SS_SubstitutionFailure) {}
230
231
16
  SatisfactionStatus getSatisfactionStatus() const { return Status; }
232
0
  void setSatisfactionStatus(SatisfactionStatus Status) {
233
0
    this->Status = Status;
234
0
  }
235
236
4.99k
  bool isSubstitutionFailure() const {
237
4.99k
    return Status == SS_SubstitutionFailure;
238
4.99k
  }
239
240
16
  SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
241
16
    assert(Status == SS_SubstitutionFailure &&
242
16
           "Attempted to get substitution diagnostic when there has been no "
243
16
           "substitution failure.");
244
0
    return Value.get<SubstitutionDiagnostic *>();
245
16
  }
246
247
3.85k
  TypeSourceInfo *getType() const {
248
3.85k
    assert(!isSubstitutionFailure() &&
249
3.85k
           "Attempted to get type when there has been a substitution failure.");
250
0
    return Value.get<TypeSourceInfo *>();
251
3.85k
  }
252
253
4.41k
  static bool classof(const Requirement *R) {
254
4.41k
    return R->getKind() == RK_Type;
255
4.41k
  }
256
};
257
258
/// \brief A requires-expression requirement which queries the validity and
259
/// properties of an expression ('simple' and 'compound' requirements).
260
class ExprRequirement : public Requirement {
261
public:
262
  enum SatisfactionStatus {
263
      SS_Dependent,
264
      SS_ExprSubstitutionFailure,
265
      SS_NoexceptNotMet,
266
      SS_TypeRequirementSubstitutionFailure,
267
      SS_ConstraintsNotSatisfied,
268
      SS_Satisfied
269
  };
270
  class ReturnTypeRequirement {
271
      llvm::PointerIntPair<
272
          llvm::PointerUnion<TemplateParameterList *, SubstitutionDiagnostic *>,
273
          1, bool>
274
          TypeConstraintInfo;
275
  public:
276
      friend ASTStmtReader;
277
      friend ASTStmtWriter;
278
279
      /// \brief No return type requirement was specified.
280
1.31k
      ReturnTypeRequirement() : TypeConstraintInfo(nullptr, false) {}
281
282
      /// \brief A return type requirement was specified but it was a
283
      /// substitution failure.
284
      ReturnTypeRequirement(SubstitutionDiagnostic *SubstDiag) :
285
4
          TypeConstraintInfo(SubstDiag, false) {}
286
287
      /// \brief A 'type constraint' style return type requirement.
288
      /// \param TPL an invented template parameter list containing a single
289
      /// type parameter with a type-constraint.
290
      // TODO: Can we maybe not save the whole template parameter list and just
291
      //  the type constraint? Saving the whole TPL makes it easier to handle in
292
      //  serialization but is less elegant.
293
      ReturnTypeRequirement(TemplateParameterList *TPL);
294
295
2.71k
      bool isDependent() const {
296
2.71k
        return TypeConstraintInfo.getInt();
297
2.71k
      }
298
299
1.03k
      bool containsUnexpandedParameterPack() const {
300
1.03k
        if (!isTypeConstraint())
301
422
          return false;
302
617
        return getTypeConstraintTemplateParameterList()
303
617
                ->containsUnexpandedParameterPack();
304
1.03k
      }
305
306
25.8k
      bool isEmpty() const {
307
25.8k
        return TypeConstraintInfo.getPointer().isNull();
308
25.8k
      }
309
310
4.46k
      bool isSubstitutionFailure() const {
311
4.46k
        return !isEmpty() &&
312
4.46k
            
TypeConstraintInfo.getPointer().is<SubstitutionDiagnostic *>()3.57k
;
313
4.46k
      }
314
315
17.3k
      bool isTypeConstraint() const {
316
17.3k
        return !isEmpty() &&
317
17.3k
            
TypeConstraintInfo.getPointer().is<TemplateParameterList *>()14.0k
;
318
17.3k
      }
319
320
1
      SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
321
1
        assert(isSubstitutionFailure());
322
0
        return TypeConstraintInfo.getPointer().get<SubstitutionDiagnostic *>();
323
1
      }
324
325
      const TypeConstraint *getTypeConstraint() const;
326
327
6.03k
      TemplateParameterList *getTypeConstraintTemplateParameterList() const {
328
6.03k
        assert(isTypeConstraint());
329
0
        return TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
330
6.03k
      }
331
  };
332
private:
333
  llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
334
  SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified.
335
  ReturnTypeRequirement TypeReq;
336
  ConceptSpecializationExpr *SubstitutedConstraintExpr;
337
  SatisfactionStatus Status;
338
public:
339
  friend ASTStmtReader;
340
  friend ASTStmtWriter;
341
342
  /// \brief Construct a compound requirement.
343
  /// \param E the expression which is checked by this requirement.
344
  /// \param IsSimple whether this was a simple requirement in source.
345
  /// \param NoexceptLoc the location of the noexcept keyword, if it was
346
  /// specified, otherwise an empty location.
347
  /// \param Req the requirement for the type of the checked expression.
348
  /// \param Status the satisfaction status of this requirement.
349
  ExprRequirement(
350
      Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
351
      ReturnTypeRequirement Req, SatisfactionStatus Status,
352
      ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr);
353
354
  /// \brief Construct a compound requirement whose expression was a
355
  /// substitution failure. The requirement is not satisfied.
356
  /// \param E the diagnostic emitted while instantiating the original
357
  /// expression.
358
  /// \param IsSimple whether this was a simple requirement in source.
359
  /// \param NoexceptLoc the location of the noexcept keyword, if it was
360
  /// specified, otherwise an empty location.
361
  /// \param Req the requirement for the type of the checked expression (omit
362
  /// if no requirement was specified).
363
  ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple,
364
                  SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {});
365
366
2.66k
  bool isSimple() const { return getKind() == RK_Simple; }
367
50
  bool isCompound() const { return getKind() == RK_Compound; }
368
369
6
  bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); }
370
2.74k
  SourceLocation getNoexceptLoc() const { return NoexceptLoc; }
371
372
41
  SatisfactionStatus getSatisfactionStatus() const { return Status; }
373
374
6.25k
  bool isExprSubstitutionFailure() const {
375
6.25k
    return Status == SS_ExprSubstitutionFailure;
376
6.25k
  }
377
378
7.75k
  const ReturnTypeRequirement &getReturnTypeRequirement() const {
379
7.75k
    return TypeReq;
380
7.75k
  }
381
382
  ConceptSpecializationExpr *
383
4
  getReturnTypeRequirementSubstitutedConstraintExpr() const {
384
4
    assert(Status >= SS_TypeRequirementSubstitutionFailure);
385
0
    return SubstitutedConstraintExpr;
386
4
  }
387
388
38
  SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const {
389
38
    assert(isExprSubstitutionFailure() &&
390
38
           "Attempted to get expression substitution diagnostic when there has "
391
38
           "been no expression substitution failure");
392
0
    return Value.get<SubstitutionDiagnostic *>();
393
38
  }
394
395
3.01k
  Expr *getExpr() const {
396
3.01k
    assert(!isExprSubstitutionFailure() &&
397
3.01k
           "ExprRequirement has no expression because there has been a "
398
3.01k
           "substitution failure.");
399
0
    return Value.get<Expr *>();
400
3.01k
  }
401
402
7.51k
  static bool classof(const Requirement *R) {
403
7.51k
    return R->getKind() == RK_Compound || 
R->getKind() == RK_Simple3.54k
;
404
7.51k
  }
405
};
406
407
/// \brief A requires-expression requirement which is satisfied when a general
408
/// constraint expression is satisfied ('nested' requirements).
409
class NestedRequirement : public Requirement {
410
  llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
411
  const ASTConstraintSatisfaction *Satisfaction = nullptr;
412
413
public:
414
  friend ASTStmtReader;
415
  friend ASTStmtWriter;
416
417
  NestedRequirement(SubstitutionDiagnostic *SubstDiag) :
418
      Requirement(RK_Nested, /*IsDependent=*/false,
419
                  /*ContainsUnexpandedParameterPack*/false,
420
3
                  /*IsSatisfied=*/false), Value(SubstDiag) {}
421
422
  NestedRequirement(Expr *Constraint) :
423
      Requirement(RK_Nested, /*IsDependent=*/true,
424
                  Constraint->containsUnexpandedParameterPack()),
425
14
      Value(Constraint) {
426
14
    assert(Constraint->isInstantiationDependent() &&
427
14
           "Nested requirement with non-dependent constraint must be "
428
14
           "constructed with a ConstraintSatisfaction object");
429
14
  }
430
431
  NestedRequirement(ASTContext &C, Expr *Constraint,
432
                    const ConstraintSatisfaction &Satisfaction) :
433
      Requirement(RK_Nested, Constraint->isInstantiationDependent(),
434
                  Constraint->containsUnexpandedParameterPack(),
435
                  Satisfaction.IsSatisfied),
436
      Value(Constraint),
437
327
      Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
438
439
1.72k
  bool isSubstitutionFailure() const {
440
1.72k
    return Value.is<SubstitutionDiagnostic *>();
441
1.72k
  }
442
443
2
  SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
444
2
    assert(isSubstitutionFailure() &&
445
2
           "getSubstitutionDiagnostic() may not be called when there was no "
446
2
           "substitution failure.");
447
0
    return Value.get<SubstitutionDiagnostic *>();
448
2
  }
449
450
1.35k
  Expr *getConstraintExpr() const {
451
1.35k
    assert(!isSubstitutionFailure() && "getConstraintExpr() may not be called "
452
1.35k
                                       "on nested requirements with "
453
1.35k
                                       "substitution failures.");
454
0
    return Value.get<Expr *>();
455
1.35k
  }
456
457
14
  const ASTConstraintSatisfaction &getConstraintSatisfaction() const {
458
14
    assert(!isSubstitutionFailure() && "getConstraintSatisfaction() may not be "
459
14
                                       "called on nested requirements with "
460
14
                                       "substitution failures.");
461
0
    return *Satisfaction;
462
14
  }
463
464
332
  static bool classof(const Requirement *R) {
465
332
    return R->getKind() == RK_Nested;
466
332
  }
467
};
468
469
} // namespace concepts
470
471
/// C++2a [expr.prim.req]:
472
///     A requires-expression provides a concise way to express requirements on
473
///     template arguments. A requirement is one that can be checked by name
474
///     lookup (6.4) or by checking properties of types and expressions.
475
///     [...]
476
///     A requires-expression is a prvalue of type bool [...]
477
class RequiresExpr final : public Expr,
478
    llvm::TrailingObjects<RequiresExpr, ParmVarDecl *,
479
                          concepts::Requirement *> {
480
  friend TrailingObjects;
481
  friend class ASTStmtReader;
482
483
  unsigned NumLocalParameters;
484
  unsigned NumRequirements;
485
  RequiresExprBodyDecl *Body;
486
  SourceLocation RBraceLoc;
487
488
6.85k
  unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
489
6.85k
    return NumLocalParameters;
490
6.85k
  }
491
492
0
  unsigned numTrailingObjects(OverloadToken<concepts::Requirement *>) const {
493
0
    return NumRequirements;
494
0
  }
495
496
  RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
497
               RequiresExprBodyDecl *Body,
498
               ArrayRef<ParmVarDecl *> LocalParameters,
499
               ArrayRef<concepts::Requirement *> Requirements,
500
               SourceLocation RBraceLoc);
501
  RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
502
               unsigned NumRequirements);
503
504
public:
505
  static RequiresExpr *
506
  Create(ASTContext &C, SourceLocation RequiresKWLoc,
507
         RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> LocalParameters,
508
         ArrayRef<concepts::Requirement *> Requirements,
509
         SourceLocation RBraceLoc);
510
  static RequiresExpr *
511
  Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
512
         unsigned NumRequirements);
513
514
3.35k
  ArrayRef<ParmVarDecl *> getLocalParameters() const {
515
3.35k
    return {getTrailingObjects<ParmVarDecl *>(), NumLocalParameters};
516
3.35k
  }
517
518
2.81k
  RequiresExprBodyDecl *getBody() const { return Body; }
519
520
3.44k
  ArrayRef<concepts::Requirement *> getRequirements() const {
521
3.44k
    return {getTrailingObjects<concepts::Requirement *>(), NumRequirements};
522
3.44k
  }
523
524
  /// \brief Whether or not the requires clause is satisfied.
525
  /// The expression must not be dependent.
526
2.55k
  bool isSatisfied() const {
527
2.55k
    assert(!isValueDependent()
528
2.55k
           && "isSatisfied called on a dependent RequiresExpr");
529
0
    return RequiresExprBits.IsSatisfied;
530
2.55k
  }
531
532
5.04k
  SourceLocation getRequiresKWLoc() const {
533
5.04k
    return RequiresExprBits.RequiresKWLoc;
534
5.04k
  }
535
536
2.51k
  SourceLocation getRBraceLoc() const { return RBraceLoc; }
537
538
38.6k
  static bool classof(const Stmt *T) {
539
38.6k
    return T->getStmtClass() == RequiresExprClass;
540
38.6k
  }
541
542
10.5k
  SourceLocation getBeginLoc() const LLVM_READONLY {
543
10.5k
    return RequiresExprBits.RequiresKWLoc;
544
10.5k
  }
545
2.72k
  SourceLocation getEndLoc() const LLVM_READONLY {
546
2.72k
    return RBraceLoc;
547
2.72k
  }
548
549
  // Iterators
550
540
  child_range children() {
551
540
    return child_range(child_iterator(), child_iterator());
552
540
  }
553
0
  const_child_range children() const {
554
0
    return const_child_range(const_child_iterator(), const_child_iterator());
555
0
  }
556
};
557
558
} // namespace clang
559
560
#endif // LLVM_CLANG_AST_EXPRCONCEPTS_H