Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:35

0001 //===- ExprConcepts.h - C++2a Concepts expressions --------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 /// \file
0010 /// Defines Expressions and AST nodes for C++2a concepts.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_AST_EXPRCONCEPTS_H
0015 #define LLVM_CLANG_AST_EXPRCONCEPTS_H
0016 
0017 #include "clang/AST/ASTConcept.h"
0018 #include "clang/AST/ASTContext.h"
0019 #include "clang/AST/Decl.h"
0020 #include "clang/AST/DeclTemplate.h"
0021 #include "clang/AST/DeclarationName.h"
0022 #include "clang/AST/Expr.h"
0023 #include "clang/AST/NestedNameSpecifier.h"
0024 #include "clang/AST/TemplateBase.h"
0025 #include "clang/AST/Type.h"
0026 #include "clang/Basic/SourceLocation.h"
0027 #include "llvm/ADT/STLFunctionalExtras.h"
0028 #include "llvm/Support/ErrorHandling.h"
0029 #include "llvm/Support/TrailingObjects.h"
0030 #include <string>
0031 #include <utility>
0032 
0033 namespace clang {
0034 class ASTStmtReader;
0035 class ASTStmtWriter;
0036 
0037 /// \brief Represents the specialization of a concept - evaluates to a prvalue
0038 /// of type bool.
0039 ///
0040 /// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
0041 /// specialization of a concept results in a prvalue of type bool.
0042 class ConceptSpecializationExpr final : public Expr {
0043   friend class ASTReader;
0044   friend class ASTStmtReader;
0045 
0046 private:
0047   ConceptReference *ConceptRef;
0048 
0049   /// \brief The Implicit Concept Specialization Decl, which holds the template
0050   /// arguments for this specialization.
0051   ImplicitConceptSpecializationDecl *SpecDecl;
0052 
0053   /// \brief Information about the satisfaction of the named concept with the
0054   /// given arguments. If this expression is value dependent, this is to be
0055   /// ignored.
0056   ASTConstraintSatisfaction *Satisfaction;
0057 
0058   ConceptSpecializationExpr(const ASTContext &C, ConceptReference *ConceptRef,
0059                             ImplicitConceptSpecializationDecl *SpecDecl,
0060                             const ConstraintSatisfaction *Satisfaction);
0061 
0062   ConceptSpecializationExpr(const ASTContext &C, ConceptReference *ConceptRef,
0063                             ImplicitConceptSpecializationDecl *SpecDecl,
0064                             const ConstraintSatisfaction *Satisfaction,
0065                             bool Dependent,
0066                             bool ContainsUnexpandedParameterPack);
0067   ConceptSpecializationExpr(EmptyShell Empty);
0068 
0069 public:
0070   static ConceptSpecializationExpr *
0071   Create(const ASTContext &C, ConceptReference *ConceptRef,
0072          ImplicitConceptSpecializationDecl *SpecDecl,
0073          const ConstraintSatisfaction *Satisfaction);
0074 
0075   static ConceptSpecializationExpr *
0076   Create(const ASTContext &C, ConceptReference *ConceptRef,
0077          ImplicitConceptSpecializationDecl *SpecDecl,
0078          const ConstraintSatisfaction *Satisfaction, bool Dependent,
0079          bool ContainsUnexpandedParameterPack);
0080 
0081   ArrayRef<TemplateArgument> getTemplateArguments() const {
0082     return SpecDecl->getTemplateArguments();
0083   }
0084 
0085   ConceptReference *getConceptReference() const { return ConceptRef; }
0086 
0087   ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); }
0088 
0089   // FIXME: Several of the following functions can be removed. Instead the
0090   // caller can directly work with the ConceptReference.
0091   bool hasExplicitTemplateArgs() const {
0092     return ConceptRef->hasExplicitTemplateArgs();
0093   }
0094 
0095   SourceLocation getConceptNameLoc() const {
0096     return ConceptRef->getConceptNameLoc();
0097   }
0098   const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
0099     return ConceptRef->getTemplateArgsAsWritten();
0100   }
0101 
0102   const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
0103     return ConceptRef->getNestedNameSpecifierLoc();
0104   }
0105 
0106   SourceLocation getTemplateKWLoc() const {
0107     return ConceptRef->getTemplateKWLoc();
0108   }
0109 
0110   NamedDecl *getFoundDecl() const { return ConceptRef->getFoundDecl(); }
0111 
0112   const DeclarationNameInfo &getConceptNameInfo() const {
0113     return ConceptRef->getConceptNameInfo();
0114   }
0115 
0116   const ImplicitConceptSpecializationDecl *getSpecializationDecl() const {
0117     assert(SpecDecl && "Template Argument Decl not initialized");
0118     return SpecDecl;
0119   }
0120 
0121   /// \brief Whether or not the concept with the given arguments was satisfied
0122   /// when the expression was created.
0123   /// The expression must not be dependent.
0124   bool isSatisfied() const {
0125     assert(!isValueDependent() &&
0126            "isSatisfied called on a dependent ConceptSpecializationExpr");
0127     return Satisfaction->IsSatisfied;
0128   }
0129 
0130   /// \brief Get elaborated satisfaction info about the template arguments'
0131   /// satisfaction of the named concept.
0132   /// The expression must not be dependent.
0133   const ASTConstraintSatisfaction &getSatisfaction() const {
0134     assert(!isValueDependent() &&
0135            "getSatisfaction called on dependent ConceptSpecializationExpr");
0136     return *Satisfaction;
0137   }
0138 
0139   static bool classof(const Stmt *T) {
0140     return T->getStmtClass() == ConceptSpecializationExprClass;
0141   }
0142 
0143   SourceLocation getBeginLoc() const LLVM_READONLY {
0144     return ConceptRef->getBeginLoc();
0145   }
0146 
0147   SourceLocation getEndLoc() const LLVM_READONLY {
0148     return ConceptRef->getEndLoc();
0149   }
0150 
0151   SourceLocation getExprLoc() const LLVM_READONLY {
0152     return ConceptRef->getLocation();
0153   }
0154 
0155   // Iterators
0156   child_range children() {
0157     return child_range(child_iterator(), child_iterator());
0158   }
0159   const_child_range children() const {
0160     return const_child_range(const_child_iterator(), const_child_iterator());
0161   }
0162 };
0163 
0164 namespace concepts {
0165 
0166 /// \brief A static requirement that can be used in a requires-expression to
0167 /// check properties of types and expression.
0168 class Requirement {
0169 public:
0170   // Note - simple and compound requirements are both represented by the same
0171   // class (ExprRequirement).
0172   enum RequirementKind { RK_Type, RK_Simple, RK_Compound, RK_Nested };
0173 private:
0174   const RequirementKind Kind;
0175   // FIXME: use RequirementDependence to model dependence?
0176   LLVM_PREFERRED_TYPE(bool)
0177   bool Dependent : 1;
0178   LLVM_PREFERRED_TYPE(bool)
0179   bool ContainsUnexpandedParameterPack : 1;
0180   LLVM_PREFERRED_TYPE(bool)
0181   bool Satisfied : 1;
0182 public:
0183   struct SubstitutionDiagnostic {
0184     StringRef SubstitutedEntity;
0185     // FIXME: Store diagnostics semantically and not as prerendered strings.
0186     //  Fixing this probably requires serialization of PartialDiagnostic
0187     //  objects.
0188     SourceLocation DiagLoc;
0189     StringRef DiagMessage;
0190   };
0191 
0192   Requirement(RequirementKind Kind, bool IsDependent,
0193               bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) :
0194       Kind(Kind), Dependent(IsDependent),
0195       ContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack),
0196       Satisfied(IsSatisfied) {}
0197 
0198   RequirementKind getKind() const { return Kind; }
0199 
0200   bool isSatisfied() const {
0201     assert(!Dependent &&
0202            "isSatisfied can only be called on non-dependent requirements.");
0203     return Satisfied;
0204   }
0205 
0206   void setSatisfied(bool IsSatisfied) {
0207     assert(!Dependent &&
0208            "setSatisfied can only be called on non-dependent requirements.");
0209     Satisfied = IsSatisfied;
0210   }
0211 
0212   void setDependent(bool IsDependent) { Dependent = IsDependent; }
0213   bool isDependent() const { return Dependent; }
0214 
0215   void setContainsUnexpandedParameterPack(bool Contains) {
0216     ContainsUnexpandedParameterPack = Contains;
0217   }
0218   bool containsUnexpandedParameterPack() const {
0219     return ContainsUnexpandedParameterPack;
0220   }
0221 };
0222 
0223 /// \brief A requires-expression requirement which queries the existence of a
0224 /// type name or type template specialization ('type' requirements).
0225 class TypeRequirement : public Requirement {
0226 public:
0227   enum SatisfactionStatus {
0228       SS_Dependent,
0229       SS_SubstitutionFailure,
0230       SS_Satisfied
0231   };
0232 private:
0233   llvm::PointerUnion<SubstitutionDiagnostic *, TypeSourceInfo *> Value;
0234   SatisfactionStatus Status;
0235 public:
0236   friend ASTStmtReader;
0237   friend ASTStmtWriter;
0238 
0239   /// \brief Construct a type requirement from a type. If the given type is not
0240   /// dependent, this indicates that the type exists and the requirement will be
0241   /// satisfied. Otherwise, the SubstitutionDiagnostic constructor is to be
0242   /// used.
0243   TypeRequirement(TypeSourceInfo *T);
0244 
0245   /// \brief Construct a type requirement when the nested name specifier is
0246   /// invalid due to a bad substitution. The requirement is unsatisfied.
0247   TypeRequirement(SubstitutionDiagnostic *Diagnostic) :
0248       Requirement(RK_Type, false, false, false), Value(Diagnostic),
0249       Status(SS_SubstitutionFailure) {}
0250 
0251   SatisfactionStatus getSatisfactionStatus() const { return Status; }
0252   void setSatisfactionStatus(SatisfactionStatus Status) {
0253     this->Status = Status;
0254   }
0255 
0256   bool isSubstitutionFailure() const {
0257     return Status == SS_SubstitutionFailure;
0258   }
0259 
0260   SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
0261     assert(Status == SS_SubstitutionFailure &&
0262            "Attempted to get substitution diagnostic when there has been no "
0263            "substitution failure.");
0264     return cast<SubstitutionDiagnostic *>(Value);
0265   }
0266 
0267   TypeSourceInfo *getType() const {
0268     assert(!isSubstitutionFailure() &&
0269            "Attempted to get type when there has been a substitution failure.");
0270     return cast<TypeSourceInfo *>(Value);
0271   }
0272 
0273   static bool classof(const Requirement *R) {
0274     return R->getKind() == RK_Type;
0275   }
0276 };
0277 
0278 /// \brief A requires-expression requirement which queries the validity and
0279 /// properties of an expression ('simple' and 'compound' requirements).
0280 class ExprRequirement : public Requirement {
0281 public:
0282   enum SatisfactionStatus {
0283       SS_Dependent,
0284       SS_ExprSubstitutionFailure,
0285       SS_NoexceptNotMet,
0286       SS_TypeRequirementSubstitutionFailure,
0287       SS_ConstraintsNotSatisfied,
0288       SS_Satisfied
0289   };
0290   class ReturnTypeRequirement {
0291       llvm::PointerIntPair<
0292           llvm::PointerUnion<TemplateParameterList *, SubstitutionDiagnostic *>,
0293           1, bool>
0294           TypeConstraintInfo;
0295   public:
0296       friend ASTStmtReader;
0297       friend ASTStmtWriter;
0298 
0299       /// \brief No return type requirement was specified.
0300       ReturnTypeRequirement() : TypeConstraintInfo(nullptr, false) {}
0301 
0302       /// \brief A return type requirement was specified but it was a
0303       /// substitution failure.
0304       ReturnTypeRequirement(SubstitutionDiagnostic *SubstDiag) :
0305           TypeConstraintInfo(SubstDiag, false) {}
0306 
0307       /// \brief A 'type constraint' style return type requirement.
0308       /// \param TPL an invented template parameter list containing a single
0309       /// type parameter with a type-constraint.
0310       // TODO: Can we maybe not save the whole template parameter list and just
0311       //  the type constraint? Saving the whole TPL makes it easier to handle in
0312       //  serialization but is less elegant.
0313       ReturnTypeRequirement(TemplateParameterList *TPL);
0314 
0315       bool isDependent() const {
0316         return TypeConstraintInfo.getInt();
0317       }
0318 
0319       bool containsUnexpandedParameterPack() const {
0320         if (!isTypeConstraint())
0321           return false;
0322         return getTypeConstraintTemplateParameterList()
0323                 ->containsUnexpandedParameterPack();
0324       }
0325 
0326       bool isEmpty() const {
0327         return TypeConstraintInfo.getPointer().isNull();
0328       }
0329 
0330       bool isSubstitutionFailure() const {
0331         return !isEmpty() &&
0332                isa<SubstitutionDiagnostic *>(TypeConstraintInfo.getPointer());
0333       }
0334 
0335       bool isTypeConstraint() const {
0336         return !isEmpty() &&
0337                isa<TemplateParameterList *>(TypeConstraintInfo.getPointer());
0338       }
0339 
0340       SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
0341         assert(isSubstitutionFailure());
0342         return cast<SubstitutionDiagnostic *>(TypeConstraintInfo.getPointer());
0343       }
0344 
0345       const TypeConstraint *getTypeConstraint() const;
0346 
0347       TemplateParameterList *getTypeConstraintTemplateParameterList() const {
0348         assert(isTypeConstraint());
0349         return cast<TemplateParameterList *>(TypeConstraintInfo.getPointer());
0350       }
0351   };
0352 private:
0353   llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
0354   SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified.
0355   ReturnTypeRequirement TypeReq;
0356   ConceptSpecializationExpr *SubstitutedConstraintExpr;
0357   SatisfactionStatus Status;
0358 public:
0359   friend ASTStmtReader;
0360   friend ASTStmtWriter;
0361 
0362   /// \brief Construct a compound requirement.
0363   /// \param E the expression which is checked by this requirement.
0364   /// \param IsSimple whether this was a simple requirement in source.
0365   /// \param NoexceptLoc the location of the noexcept keyword, if it was
0366   /// specified, otherwise an empty location.
0367   /// \param Req the requirement for the type of the checked expression.
0368   /// \param Status the satisfaction status of this requirement.
0369   ExprRequirement(
0370       Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
0371       ReturnTypeRequirement Req, SatisfactionStatus Status,
0372       ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr);
0373 
0374   /// \brief Construct a compound requirement whose expression was a
0375   /// substitution failure. The requirement is not satisfied.
0376   /// \param E the diagnostic emitted while instantiating the original
0377   /// expression.
0378   /// \param IsSimple whether this was a simple requirement in source.
0379   /// \param NoexceptLoc the location of the noexcept keyword, if it was
0380   /// specified, otherwise an empty location.
0381   /// \param Req the requirement for the type of the checked expression (omit
0382   /// if no requirement was specified).
0383   ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple,
0384                   SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {});
0385 
0386   bool isSimple() const { return getKind() == RK_Simple; }
0387   bool isCompound() const { return getKind() == RK_Compound; }
0388 
0389   bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); }
0390   SourceLocation getNoexceptLoc() const { return NoexceptLoc; }
0391 
0392   SatisfactionStatus getSatisfactionStatus() const { return Status; }
0393 
0394   bool isExprSubstitutionFailure() const {
0395     return Status == SS_ExprSubstitutionFailure;
0396   }
0397 
0398   const ReturnTypeRequirement &getReturnTypeRequirement() const {
0399     return TypeReq;
0400   }
0401 
0402   ConceptSpecializationExpr *
0403   getReturnTypeRequirementSubstitutedConstraintExpr() const {
0404     assert(Status >= SS_TypeRequirementSubstitutionFailure);
0405     return SubstitutedConstraintExpr;
0406   }
0407 
0408   SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const {
0409     assert(isExprSubstitutionFailure() &&
0410            "Attempted to get expression substitution diagnostic when there has "
0411            "been no expression substitution failure");
0412     return cast<SubstitutionDiagnostic *>(Value);
0413   }
0414 
0415   Expr *getExpr() const {
0416     assert(!isExprSubstitutionFailure() &&
0417            "ExprRequirement has no expression because there has been a "
0418            "substitution failure.");
0419     return cast<Expr *>(Value);
0420   }
0421 
0422   static bool classof(const Requirement *R) {
0423     return R->getKind() == RK_Compound || R->getKind() == RK_Simple;
0424   }
0425 };
0426 
0427 /// \brief A requires-expression requirement which is satisfied when a general
0428 /// constraint expression is satisfied ('nested' requirements).
0429 class NestedRequirement : public Requirement {
0430   Expr *Constraint = nullptr;
0431   const ASTConstraintSatisfaction *Satisfaction = nullptr;
0432   bool HasInvalidConstraint = false;
0433   StringRef InvalidConstraintEntity;
0434 
0435 public:
0436   friend ASTStmtReader;
0437   friend ASTStmtWriter;
0438 
0439   NestedRequirement(Expr *Constraint)
0440       : Requirement(RK_Nested, /*IsDependent=*/true,
0441                     Constraint->containsUnexpandedParameterPack()),
0442         Constraint(Constraint) {
0443     assert(Constraint->isInstantiationDependent() &&
0444            "Nested requirement with non-dependent constraint must be "
0445            "constructed with a ConstraintSatisfaction object");
0446   }
0447 
0448   NestedRequirement(ASTContext &C, Expr *Constraint,
0449                     const ConstraintSatisfaction &Satisfaction)
0450       : Requirement(RK_Nested, Constraint->isInstantiationDependent(),
0451                     Constraint->containsUnexpandedParameterPack(),
0452                     Satisfaction.IsSatisfied),
0453         Constraint(Constraint),
0454         Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
0455 
0456   NestedRequirement(StringRef InvalidConstraintEntity,
0457                     const ASTConstraintSatisfaction *Satisfaction)
0458       : Requirement(RK_Nested,
0459                     /*IsDependent=*/false,
0460                     /*ContainsUnexpandedParameterPack*/ false,
0461                     Satisfaction->IsSatisfied),
0462         Satisfaction(Satisfaction), HasInvalidConstraint(true),
0463         InvalidConstraintEntity(InvalidConstraintEntity) {}
0464 
0465   NestedRequirement(ASTContext &C, StringRef InvalidConstraintEntity,
0466                     const ConstraintSatisfaction &Satisfaction)
0467       : NestedRequirement(InvalidConstraintEntity,
0468                           ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
0469 
0470   bool hasInvalidConstraint() const { return HasInvalidConstraint; }
0471 
0472   StringRef getInvalidConstraintEntity() {
0473     assert(hasInvalidConstraint());
0474     return InvalidConstraintEntity;
0475   }
0476 
0477   Expr *getConstraintExpr() const {
0478     assert(!hasInvalidConstraint() &&
0479            "getConstraintExpr() may not be called "
0480            "on nested requirements with invalid constraint.");
0481     return Constraint;
0482   }
0483 
0484   const ASTConstraintSatisfaction &getConstraintSatisfaction() const {
0485     return *Satisfaction;
0486   }
0487 
0488   static bool classof(const Requirement *R) {
0489     return R->getKind() == RK_Nested;
0490   }
0491 };
0492 } // namespace concepts
0493 
0494 /// C++2a [expr.prim.req]:
0495 ///     A requires-expression provides a concise way to express requirements on
0496 ///     template arguments. A requirement is one that can be checked by name
0497 ///     lookup (6.4) or by checking properties of types and expressions.
0498 ///     [...]
0499 ///     A requires-expression is a prvalue of type bool [...]
0500 class RequiresExpr final : public Expr,
0501     llvm::TrailingObjects<RequiresExpr, ParmVarDecl *,
0502                           concepts::Requirement *> {
0503   friend TrailingObjects;
0504   friend class ASTStmtReader;
0505 
0506   unsigned NumLocalParameters;
0507   unsigned NumRequirements;
0508   RequiresExprBodyDecl *Body;
0509   SourceLocation LParenLoc;
0510   SourceLocation RParenLoc;
0511   SourceLocation RBraceLoc;
0512 
0513   unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
0514     return NumLocalParameters;
0515   }
0516 
0517   unsigned numTrailingObjects(OverloadToken<concepts::Requirement *>) const {
0518     return NumRequirements;
0519   }
0520 
0521   RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
0522                RequiresExprBodyDecl *Body, SourceLocation LParenLoc,
0523                ArrayRef<ParmVarDecl *> LocalParameters,
0524                SourceLocation RParenLoc,
0525                ArrayRef<concepts::Requirement *> Requirements,
0526                SourceLocation RBraceLoc);
0527   RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
0528                unsigned NumRequirements);
0529 
0530 public:
0531   static RequiresExpr *Create(ASTContext &C, SourceLocation RequiresKWLoc,
0532                               RequiresExprBodyDecl *Body,
0533                               SourceLocation LParenLoc,
0534                               ArrayRef<ParmVarDecl *> LocalParameters,
0535                               SourceLocation RParenLoc,
0536                               ArrayRef<concepts::Requirement *> Requirements,
0537                               SourceLocation RBraceLoc);
0538   static RequiresExpr *
0539   Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
0540          unsigned NumRequirements);
0541 
0542   ArrayRef<ParmVarDecl *> getLocalParameters() const {
0543     return {getTrailingObjects<ParmVarDecl *>(), NumLocalParameters};
0544   }
0545 
0546   RequiresExprBodyDecl *getBody() const { return Body; }
0547 
0548   ArrayRef<concepts::Requirement *> getRequirements() const {
0549     return {getTrailingObjects<concepts::Requirement *>(), NumRequirements};
0550   }
0551 
0552   /// \brief Whether or not the requires clause is satisfied.
0553   /// The expression must not be dependent.
0554   bool isSatisfied() const {
0555     assert(!isValueDependent()
0556            && "isSatisfied called on a dependent RequiresExpr");
0557     return RequiresExprBits.IsSatisfied;
0558   }
0559 
0560   void setSatisfied(bool IsSatisfied) {
0561     assert(!isValueDependent() &&
0562            "setSatisfied called on a dependent RequiresExpr");
0563     RequiresExprBits.IsSatisfied = IsSatisfied;
0564   }
0565 
0566   SourceLocation getRequiresKWLoc() const {
0567     return RequiresExprBits.RequiresKWLoc;
0568   }
0569 
0570   SourceLocation getLParenLoc() const { return LParenLoc; }
0571   SourceLocation getRParenLoc() const { return RParenLoc; }
0572   SourceLocation getRBraceLoc() const { return RBraceLoc; }
0573 
0574   static bool classof(const Stmt *T) {
0575     return T->getStmtClass() == RequiresExprClass;
0576   }
0577 
0578   SourceLocation getBeginLoc() const LLVM_READONLY {
0579     return RequiresExprBits.RequiresKWLoc;
0580   }
0581   SourceLocation getEndLoc() const LLVM_READONLY {
0582     return RBraceLoc;
0583   }
0584 
0585   // Iterators
0586   child_range children() {
0587     return child_range(child_iterator(), child_iterator());
0588   }
0589   const_child_range children() const {
0590     return const_child_range(const_child_iterator(), const_child_iterator());
0591   }
0592 };
0593 
0594 } // namespace clang
0595 
0596 #endif // LLVM_CLANG_AST_EXPRCONCEPTS_H