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