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