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