155e4f9d5SDimitry Andric //===- ExprConcepts.h - C++2a Concepts expressions --------------*- C++ -*-===//
255e4f9d5SDimitry Andric //
355e4f9d5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
455e4f9d5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
555e4f9d5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
655e4f9d5SDimitry Andric //
755e4f9d5SDimitry Andric //===----------------------------------------------------------------------===//
855e4f9d5SDimitry Andric //
955e4f9d5SDimitry Andric /// \file
1055e4f9d5SDimitry Andric /// Defines Expressions and AST nodes for C++2a concepts.
1155e4f9d5SDimitry Andric //
1255e4f9d5SDimitry Andric //===----------------------------------------------------------------------===//
1355e4f9d5SDimitry Andric 
1455e4f9d5SDimitry Andric #ifndef LLVM_CLANG_AST_EXPRCONCEPTS_H
1555e4f9d5SDimitry Andric #define LLVM_CLANG_AST_EXPRCONCEPTS_H
1655e4f9d5SDimitry Andric 
1755e4f9d5SDimitry Andric #include "clang/AST/ASTConcept.h"
188a4dda33SDimitry Andric #include "clang/AST/ASTContext.h"
1955e4f9d5SDimitry Andric #include "clang/AST/Decl.h"
2055e4f9d5SDimitry Andric #include "clang/AST/DeclTemplate.h"
218a4dda33SDimitry Andric #include "clang/AST/DeclarationName.h"
2255e4f9d5SDimitry Andric #include "clang/AST/Expr.h"
2355e4f9d5SDimitry Andric #include "clang/AST/NestedNameSpecifier.h"
2455e4f9d5SDimitry Andric #include "clang/AST/TemplateBase.h"
2555e4f9d5SDimitry Andric #include "clang/AST/Type.h"
2655e4f9d5SDimitry Andric #include "clang/Basic/SourceLocation.h"
278a4dda33SDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h"
28bdd1243dSDimitry Andric #include "llvm/Support/ErrorHandling.h"
2955e4f9d5SDimitry Andric #include "llvm/Support/TrailingObjects.h"
3055e4f9d5SDimitry Andric #include <string>
318a4dda33SDimitry Andric #include <utility>
3255e4f9d5SDimitry Andric 
3355e4f9d5SDimitry Andric namespace clang {
3455e4f9d5SDimitry Andric class ASTStmtReader;
3555e4f9d5SDimitry Andric class ASTStmtWriter;
3655e4f9d5SDimitry Andric 
3755e4f9d5SDimitry Andric /// \brief Represents the specialization of a concept - evaluates to a prvalue
3855e4f9d5SDimitry Andric /// of type bool.
3955e4f9d5SDimitry Andric ///
4055e4f9d5SDimitry Andric /// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
4155e4f9d5SDimitry Andric /// specialization of a concept results in a prvalue of type bool.
42*5f757f3fSDimitry Andric class ConceptSpecializationExpr final : public Expr {
43bdd1243dSDimitry Andric   friend class ASTReader;
4455e4f9d5SDimitry Andric   friend class ASTStmtReader;
45bdd1243dSDimitry Andric 
46*5f757f3fSDimitry Andric private:
47*5f757f3fSDimitry Andric   ConceptReference *ConceptRef;
4855e4f9d5SDimitry Andric 
49bdd1243dSDimitry Andric   /// \brief The Implicit Concept Specialization Decl, which holds the template
50bdd1243dSDimitry Andric   /// arguments for this specialization.
51bdd1243dSDimitry Andric   ImplicitConceptSpecializationDecl *SpecDecl;
5255e4f9d5SDimitry Andric 
5355e4f9d5SDimitry Andric   /// \brief Information about the satisfaction of the named concept with the
5455e4f9d5SDimitry Andric   /// given arguments. If this expression is value dependent, this is to be
5555e4f9d5SDimitry Andric   /// ignored.
5655e4f9d5SDimitry Andric   ASTConstraintSatisfaction *Satisfaction;
5755e4f9d5SDimitry Andric 
58*5f757f3fSDimitry Andric   ConceptSpecializationExpr(const ASTContext &C, ConceptReference *ConceptRef,
59bdd1243dSDimitry Andric                             ImplicitConceptSpecializationDecl *SpecDecl,
6055e4f9d5SDimitry Andric                             const ConstraintSatisfaction *Satisfaction);
6155e4f9d5SDimitry Andric 
62*5f757f3fSDimitry Andric   ConceptSpecializationExpr(const ASTContext &C, ConceptReference *ConceptRef,
63bdd1243dSDimitry Andric                             ImplicitConceptSpecializationDecl *SpecDecl,
6413138422SDimitry Andric                             const ConstraintSatisfaction *Satisfaction,
6513138422SDimitry Andric                             bool Dependent,
6613138422SDimitry Andric                             bool ContainsUnexpandedParameterPack);
67bdd1243dSDimitry Andric   ConceptSpecializationExpr(EmptyShell Empty);
6855e4f9d5SDimitry Andric 
6955e4f9d5SDimitry Andric public:
7055e4f9d5SDimitry Andric   static ConceptSpecializationExpr *
71*5f757f3fSDimitry Andric   Create(const ASTContext &C, ConceptReference *ConceptRef,
72bdd1243dSDimitry Andric          ImplicitConceptSpecializationDecl *SpecDecl,
7355e4f9d5SDimitry Andric          const ConstraintSatisfaction *Satisfaction);
7455e4f9d5SDimitry Andric 
7555e4f9d5SDimitry Andric   static ConceptSpecializationExpr *
76*5f757f3fSDimitry Andric   Create(const ASTContext &C, ConceptReference *ConceptRef,
772efbaac7SDimitry Andric          ImplicitConceptSpecializationDecl *SpecDecl,
782efbaac7SDimitry Andric          const ConstraintSatisfaction *Satisfaction, bool Dependent,
792efbaac7SDimitry Andric          bool ContainsUnexpandedParameterPack);
802efbaac7SDimitry Andric 
getTemplateArguments()8155e4f9d5SDimitry Andric   ArrayRef<TemplateArgument> getTemplateArguments() const {
82bdd1243dSDimitry Andric     return SpecDecl->getTemplateArguments();
8355e4f9d5SDimitry Andric   }
8455e4f9d5SDimitry Andric 
getConceptReference()85*5f757f3fSDimitry Andric   ConceptReference *getConceptReference() const { return ConceptRef; }
86*5f757f3fSDimitry Andric 
getNamedConcept()87*5f757f3fSDimitry Andric   ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); }
88*5f757f3fSDimitry Andric 
89*5f757f3fSDimitry Andric   // FIXME: Several of the following functions can be removed. Instead the
90*5f757f3fSDimitry Andric   // caller can directly work with the ConceptReference.
hasExplicitTemplateArgs()91*5f757f3fSDimitry Andric   bool hasExplicitTemplateArgs() const {
92*5f757f3fSDimitry Andric     return ConceptRef->hasExplicitTemplateArgs();
93*5f757f3fSDimitry Andric   }
94*5f757f3fSDimitry Andric 
getConceptNameLoc()95*5f757f3fSDimitry Andric   SourceLocation getConceptNameLoc() const {
96*5f757f3fSDimitry Andric     return ConceptRef->getConceptNameLoc();
97*5f757f3fSDimitry Andric   }
getTemplateArgsAsWritten()98*5f757f3fSDimitry Andric   const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
99*5f757f3fSDimitry Andric     return ConceptRef->getTemplateArgsAsWritten();
100*5f757f3fSDimitry Andric   }
101*5f757f3fSDimitry Andric 
getNestedNameSpecifierLoc()102*5f757f3fSDimitry Andric   const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
103*5f757f3fSDimitry Andric     return ConceptRef->getNestedNameSpecifierLoc();
104*5f757f3fSDimitry Andric   }
105*5f757f3fSDimitry Andric 
getTemplateKWLoc()106*5f757f3fSDimitry Andric   SourceLocation getTemplateKWLoc() const {
107*5f757f3fSDimitry Andric     return ConceptRef->getTemplateKWLoc();
108*5f757f3fSDimitry Andric   }
109*5f757f3fSDimitry Andric 
getFoundDecl()110*5f757f3fSDimitry Andric   NamedDecl *getFoundDecl() const { return ConceptRef->getFoundDecl(); }
111*5f757f3fSDimitry Andric 
getConceptNameInfo()112*5f757f3fSDimitry Andric   const DeclarationNameInfo &getConceptNameInfo() const {
113*5f757f3fSDimitry Andric     return ConceptRef->getConceptNameInfo();
114*5f757f3fSDimitry Andric   }
115*5f757f3fSDimitry Andric 
getSpecializationDecl()116bdd1243dSDimitry Andric   const ImplicitConceptSpecializationDecl *getSpecializationDecl() const {
117bdd1243dSDimitry Andric     assert(SpecDecl && "Template Argument Decl not initialized");
118bdd1243dSDimitry Andric     return SpecDecl;
119bdd1243dSDimitry Andric   }
12055e4f9d5SDimitry Andric 
12155e4f9d5SDimitry Andric   /// \brief Whether or not the concept with the given arguments was satisfied
12255e4f9d5SDimitry Andric   /// when the expression was created.
12355e4f9d5SDimitry Andric   /// The expression must not be dependent.
isSatisfied()12455e4f9d5SDimitry Andric   bool isSatisfied() const {
125bdd1243dSDimitry Andric     assert(!isValueDependent() &&
126bdd1243dSDimitry Andric            "isSatisfied called on a dependent ConceptSpecializationExpr");
12755e4f9d5SDimitry Andric     return Satisfaction->IsSatisfied;
12855e4f9d5SDimitry Andric   }
12955e4f9d5SDimitry Andric 
13055e4f9d5SDimitry Andric   /// \brief Get elaborated satisfaction info about the template arguments'
13155e4f9d5SDimitry Andric   /// satisfaction of the named concept.
13255e4f9d5SDimitry Andric   /// The expression must not be dependent.
getSatisfaction()13355e4f9d5SDimitry Andric   const ASTConstraintSatisfaction &getSatisfaction() const {
134bdd1243dSDimitry Andric     assert(!isValueDependent() &&
135bdd1243dSDimitry Andric            "getSatisfaction called on dependent ConceptSpecializationExpr");
13655e4f9d5SDimitry Andric     return *Satisfaction;
13755e4f9d5SDimitry Andric   }
13855e4f9d5SDimitry Andric 
classof(const Stmt * T)13955e4f9d5SDimitry Andric   static bool classof(const Stmt *T) {
14055e4f9d5SDimitry Andric     return T->getStmtClass() == ConceptSpecializationExprClass;
14155e4f9d5SDimitry Andric   }
14255e4f9d5SDimitry Andric 
getBeginLoc()14355e4f9d5SDimitry Andric   SourceLocation getBeginLoc() const LLVM_READONLY {
144*5f757f3fSDimitry Andric     return ConceptRef->getBeginLoc();
14555e4f9d5SDimitry Andric   }
14655e4f9d5SDimitry Andric 
getEndLoc()14755e4f9d5SDimitry Andric   SourceLocation getEndLoc() const LLVM_READONLY {
148*5f757f3fSDimitry Andric     return ConceptRef->getEndLoc();
149*5f757f3fSDimitry Andric   }
150*5f757f3fSDimitry Andric 
getExprLoc()151*5f757f3fSDimitry Andric   SourceLocation getExprLoc() const LLVM_READONLY {
152*5f757f3fSDimitry Andric     return ConceptRef->getLocation();
15355e4f9d5SDimitry Andric   }
15455e4f9d5SDimitry Andric 
15555e4f9d5SDimitry Andric   // Iterators
children()15655e4f9d5SDimitry Andric   child_range children() {
15755e4f9d5SDimitry Andric     return child_range(child_iterator(), child_iterator());
15855e4f9d5SDimitry Andric   }
children()15955e4f9d5SDimitry Andric   const_child_range children() const {
16055e4f9d5SDimitry Andric     return const_child_range(const_child_iterator(), const_child_iterator());
16155e4f9d5SDimitry Andric   }
16255e4f9d5SDimitry Andric };
16355e4f9d5SDimitry Andric 
16455e4f9d5SDimitry Andric namespace concepts {
16555e4f9d5SDimitry Andric 
16655e4f9d5SDimitry Andric /// \brief A static requirement that can be used in a requires-expression to
16755e4f9d5SDimitry Andric /// check properties of types and expression.
16855e4f9d5SDimitry Andric class Requirement {
16955e4f9d5SDimitry Andric public:
17055e4f9d5SDimitry Andric   // Note - simple and compound requirements are both represented by the same
17155e4f9d5SDimitry Andric   // class (ExprRequirement).
17255e4f9d5SDimitry Andric   enum RequirementKind { RK_Type, RK_Simple, RK_Compound, RK_Nested };
17355e4f9d5SDimitry Andric private:
17455e4f9d5SDimitry Andric   const RequirementKind Kind;
1755ffd83dbSDimitry Andric   // FIXME: use RequirementDependence to model dependence?
176*5f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
17755e4f9d5SDimitry Andric   bool Dependent : 1;
178*5f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
17955e4f9d5SDimitry Andric   bool ContainsUnexpandedParameterPack : 1;
180*5f757f3fSDimitry Andric   LLVM_PREFERRED_TYPE(bool)
18155e4f9d5SDimitry Andric   bool Satisfied : 1;
18255e4f9d5SDimitry Andric public:
18355e4f9d5SDimitry Andric   struct SubstitutionDiagnostic {
18455e4f9d5SDimitry Andric     StringRef SubstitutedEntity;
18555e4f9d5SDimitry Andric     // FIXME: Store diagnostics semantically and not as prerendered strings.
18655e4f9d5SDimitry Andric     //  Fixing this probably requires serialization of PartialDiagnostic
18755e4f9d5SDimitry Andric     //  objects.
18855e4f9d5SDimitry Andric     SourceLocation DiagLoc;
18955e4f9d5SDimitry Andric     StringRef DiagMessage;
19055e4f9d5SDimitry Andric   };
19155e4f9d5SDimitry Andric 
19255e4f9d5SDimitry Andric   Requirement(RequirementKind Kind, bool IsDependent,
19355e4f9d5SDimitry Andric               bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) :
Kind(Kind)19455e4f9d5SDimitry Andric       Kind(Kind), Dependent(IsDependent),
19555e4f9d5SDimitry Andric       ContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack),
19655e4f9d5SDimitry Andric       Satisfied(IsSatisfied) {}
19755e4f9d5SDimitry Andric 
getKind()19855e4f9d5SDimitry Andric   RequirementKind getKind() const { return Kind; }
19955e4f9d5SDimitry Andric 
isSatisfied()20055e4f9d5SDimitry Andric   bool isSatisfied() const {
20155e4f9d5SDimitry Andric     assert(!Dependent &&
20255e4f9d5SDimitry Andric            "isSatisfied can only be called on non-dependent requirements.");
20355e4f9d5SDimitry Andric     return Satisfied;
20455e4f9d5SDimitry Andric   }
20555e4f9d5SDimitry Andric 
setSatisfied(bool IsSatisfied)20655e4f9d5SDimitry Andric   void setSatisfied(bool IsSatisfied) {
20755e4f9d5SDimitry Andric     assert(!Dependent &&
20855e4f9d5SDimitry Andric            "setSatisfied can only be called on non-dependent requirements.");
20955e4f9d5SDimitry Andric     Satisfied = IsSatisfied;
21055e4f9d5SDimitry Andric   }
21155e4f9d5SDimitry Andric 
setDependent(bool IsDependent)21255e4f9d5SDimitry Andric   void setDependent(bool IsDependent) { Dependent = IsDependent; }
isDependent()21355e4f9d5SDimitry Andric   bool isDependent() const { return Dependent; }
21455e4f9d5SDimitry Andric 
setContainsUnexpandedParameterPack(bool Contains)21555e4f9d5SDimitry Andric   void setContainsUnexpandedParameterPack(bool Contains) {
21655e4f9d5SDimitry Andric     ContainsUnexpandedParameterPack = Contains;
21755e4f9d5SDimitry Andric   }
containsUnexpandedParameterPack()21855e4f9d5SDimitry Andric   bool containsUnexpandedParameterPack() const {
21955e4f9d5SDimitry Andric     return ContainsUnexpandedParameterPack;
22055e4f9d5SDimitry Andric   }
22155e4f9d5SDimitry Andric };
22255e4f9d5SDimitry Andric 
22355e4f9d5SDimitry Andric /// \brief A requires-expression requirement which queries the existence of a
22455e4f9d5SDimitry Andric /// type name or type template specialization ('type' requirements).
22555e4f9d5SDimitry Andric class TypeRequirement : public Requirement {
22655e4f9d5SDimitry Andric public:
22755e4f9d5SDimitry Andric   enum SatisfactionStatus {
22855e4f9d5SDimitry Andric       SS_Dependent,
22955e4f9d5SDimitry Andric       SS_SubstitutionFailure,
23055e4f9d5SDimitry Andric       SS_Satisfied
23155e4f9d5SDimitry Andric   };
23255e4f9d5SDimitry Andric private:
23355e4f9d5SDimitry Andric   llvm::PointerUnion<SubstitutionDiagnostic *, TypeSourceInfo *> Value;
23455e4f9d5SDimitry Andric   SatisfactionStatus Status;
23555e4f9d5SDimitry Andric public:
23655e4f9d5SDimitry Andric   friend ASTStmtReader;
23755e4f9d5SDimitry Andric   friend ASTStmtWriter;
23855e4f9d5SDimitry Andric 
23955e4f9d5SDimitry Andric   /// \brief Construct a type requirement from a type. If the given type is not
24055e4f9d5SDimitry Andric   /// dependent, this indicates that the type exists and the requirement will be
24155e4f9d5SDimitry Andric   /// satisfied. Otherwise, the SubstitutionDiagnostic constructor is to be
24255e4f9d5SDimitry Andric   /// used.
24355e4f9d5SDimitry Andric   TypeRequirement(TypeSourceInfo *T);
24455e4f9d5SDimitry Andric 
24555e4f9d5SDimitry Andric   /// \brief Construct a type requirement when the nested name specifier is
24655e4f9d5SDimitry Andric   /// invalid due to a bad substitution. The requirement is unsatisfied.
TypeRequirement(SubstitutionDiagnostic * Diagnostic)24755e4f9d5SDimitry Andric   TypeRequirement(SubstitutionDiagnostic *Diagnostic) :
24855e4f9d5SDimitry Andric       Requirement(RK_Type, false, false, false), Value(Diagnostic),
24955e4f9d5SDimitry Andric       Status(SS_SubstitutionFailure) {}
25055e4f9d5SDimitry Andric 
getSatisfactionStatus()25155e4f9d5SDimitry Andric   SatisfactionStatus getSatisfactionStatus() const { return Status; }
setSatisfactionStatus(SatisfactionStatus Status)25255e4f9d5SDimitry Andric   void setSatisfactionStatus(SatisfactionStatus Status) {
25355e4f9d5SDimitry Andric     this->Status = Status;
25455e4f9d5SDimitry Andric   }
25555e4f9d5SDimitry Andric 
isSubstitutionFailure()25655e4f9d5SDimitry Andric   bool isSubstitutionFailure() const {
25755e4f9d5SDimitry Andric     return Status == SS_SubstitutionFailure;
25855e4f9d5SDimitry Andric   }
25955e4f9d5SDimitry Andric 
getSubstitutionDiagnostic()26055e4f9d5SDimitry Andric   SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
26155e4f9d5SDimitry Andric     assert(Status == SS_SubstitutionFailure &&
26255e4f9d5SDimitry Andric            "Attempted to get substitution diagnostic when there has been no "
26355e4f9d5SDimitry Andric            "substitution failure.");
26455e4f9d5SDimitry Andric     return Value.get<SubstitutionDiagnostic *>();
26555e4f9d5SDimitry Andric   }
26655e4f9d5SDimitry Andric 
getType()26755e4f9d5SDimitry Andric   TypeSourceInfo *getType() const {
26855e4f9d5SDimitry Andric     assert(!isSubstitutionFailure() &&
26955e4f9d5SDimitry Andric            "Attempted to get type when there has been a substitution failure.");
27055e4f9d5SDimitry Andric     return Value.get<TypeSourceInfo *>();
27155e4f9d5SDimitry Andric   }
27255e4f9d5SDimitry Andric 
classof(const Requirement * R)27355e4f9d5SDimitry Andric   static bool classof(const Requirement *R) {
27455e4f9d5SDimitry Andric     return R->getKind() == RK_Type;
27555e4f9d5SDimitry Andric   }
27655e4f9d5SDimitry Andric };
27755e4f9d5SDimitry Andric 
27855e4f9d5SDimitry Andric /// \brief A requires-expression requirement which queries the validity and
27955e4f9d5SDimitry Andric /// properties of an expression ('simple' and 'compound' requirements).
28055e4f9d5SDimitry Andric class ExprRequirement : public Requirement {
28155e4f9d5SDimitry Andric public:
28255e4f9d5SDimitry Andric   enum SatisfactionStatus {
28355e4f9d5SDimitry Andric       SS_Dependent,
28455e4f9d5SDimitry Andric       SS_ExprSubstitutionFailure,
28555e4f9d5SDimitry Andric       SS_NoexceptNotMet,
28655e4f9d5SDimitry Andric       SS_TypeRequirementSubstitutionFailure,
28755e4f9d5SDimitry Andric       SS_ConstraintsNotSatisfied,
28855e4f9d5SDimitry Andric       SS_Satisfied
28955e4f9d5SDimitry Andric   };
29055e4f9d5SDimitry Andric   class ReturnTypeRequirement {
29155e4f9d5SDimitry Andric       llvm::PointerIntPair<
29255e4f9d5SDimitry Andric           llvm::PointerUnion<TemplateParameterList *, SubstitutionDiagnostic *>,
29355e4f9d5SDimitry Andric           1, bool>
29455e4f9d5SDimitry Andric           TypeConstraintInfo;
29555e4f9d5SDimitry Andric   public:
29655e4f9d5SDimitry Andric       friend ASTStmtReader;
29755e4f9d5SDimitry Andric       friend ASTStmtWriter;
29855e4f9d5SDimitry Andric 
29955e4f9d5SDimitry Andric       /// \brief No return type requirement was specified.
ReturnTypeRequirement()30004eeddc0SDimitry Andric       ReturnTypeRequirement() : TypeConstraintInfo(nullptr, false) {}
30155e4f9d5SDimitry Andric 
30255e4f9d5SDimitry Andric       /// \brief A return type requirement was specified but it was a
30355e4f9d5SDimitry Andric       /// substitution failure.
ReturnTypeRequirement(SubstitutionDiagnostic * SubstDiag)30455e4f9d5SDimitry Andric       ReturnTypeRequirement(SubstitutionDiagnostic *SubstDiag) :
30504eeddc0SDimitry Andric           TypeConstraintInfo(SubstDiag, false) {}
30655e4f9d5SDimitry Andric 
30755e4f9d5SDimitry Andric       /// \brief A 'type constraint' style return type requirement.
30855e4f9d5SDimitry Andric       /// \param TPL an invented template parameter list containing a single
30955e4f9d5SDimitry Andric       /// type parameter with a type-constraint.
31055e4f9d5SDimitry Andric       // TODO: Can we maybe not save the whole template parameter list and just
31155e4f9d5SDimitry Andric       //  the type constraint? Saving the whole TPL makes it easier to handle in
31255e4f9d5SDimitry Andric       //  serialization but is less elegant.
31355e4f9d5SDimitry Andric       ReturnTypeRequirement(TemplateParameterList *TPL);
31455e4f9d5SDimitry Andric 
isDependent()31555e4f9d5SDimitry Andric       bool isDependent() const {
31655e4f9d5SDimitry Andric         return TypeConstraintInfo.getInt();
31755e4f9d5SDimitry Andric       }
31855e4f9d5SDimitry Andric 
containsUnexpandedParameterPack()31955e4f9d5SDimitry Andric       bool containsUnexpandedParameterPack() const {
32055e4f9d5SDimitry Andric         if (!isTypeConstraint())
32155e4f9d5SDimitry Andric           return false;
32255e4f9d5SDimitry Andric         return getTypeConstraintTemplateParameterList()
32355e4f9d5SDimitry Andric                 ->containsUnexpandedParameterPack();
32455e4f9d5SDimitry Andric       }
32555e4f9d5SDimitry Andric 
isEmpty()32655e4f9d5SDimitry Andric       bool isEmpty() const {
32755e4f9d5SDimitry Andric         return TypeConstraintInfo.getPointer().isNull();
32855e4f9d5SDimitry Andric       }
32955e4f9d5SDimitry Andric 
isSubstitutionFailure()33055e4f9d5SDimitry Andric       bool isSubstitutionFailure() const {
33155e4f9d5SDimitry Andric         return !isEmpty() &&
33255e4f9d5SDimitry Andric             TypeConstraintInfo.getPointer().is<SubstitutionDiagnostic *>();
33355e4f9d5SDimitry Andric       }
33455e4f9d5SDimitry Andric 
isTypeConstraint()33555e4f9d5SDimitry Andric       bool isTypeConstraint() const {
33655e4f9d5SDimitry Andric         return !isEmpty() &&
33755e4f9d5SDimitry Andric             TypeConstraintInfo.getPointer().is<TemplateParameterList *>();
33855e4f9d5SDimitry Andric       }
33955e4f9d5SDimitry Andric 
getSubstitutionDiagnostic()34055e4f9d5SDimitry Andric       SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
34155e4f9d5SDimitry Andric         assert(isSubstitutionFailure());
34255e4f9d5SDimitry Andric         return TypeConstraintInfo.getPointer().get<SubstitutionDiagnostic *>();
34355e4f9d5SDimitry Andric       }
34455e4f9d5SDimitry Andric 
34555e4f9d5SDimitry Andric       const TypeConstraint *getTypeConstraint() const;
34655e4f9d5SDimitry Andric 
getTypeConstraintTemplateParameterList()34755e4f9d5SDimitry Andric       TemplateParameterList *getTypeConstraintTemplateParameterList() const {
34855e4f9d5SDimitry Andric         assert(isTypeConstraint());
34955e4f9d5SDimitry Andric         return TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
35055e4f9d5SDimitry Andric       }
35155e4f9d5SDimitry Andric   };
35255e4f9d5SDimitry Andric private:
35355e4f9d5SDimitry Andric   llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
35455e4f9d5SDimitry Andric   SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified.
35555e4f9d5SDimitry Andric   ReturnTypeRequirement TypeReq;
35655e4f9d5SDimitry Andric   ConceptSpecializationExpr *SubstitutedConstraintExpr;
35755e4f9d5SDimitry Andric   SatisfactionStatus Status;
35855e4f9d5SDimitry Andric public:
35955e4f9d5SDimitry Andric   friend ASTStmtReader;
36055e4f9d5SDimitry Andric   friend ASTStmtWriter;
36155e4f9d5SDimitry Andric 
36255e4f9d5SDimitry Andric   /// \brief Construct a compound requirement.
36355e4f9d5SDimitry Andric   /// \param E the expression which is checked by this requirement.
36455e4f9d5SDimitry Andric   /// \param IsSimple whether this was a simple requirement in source.
36555e4f9d5SDimitry Andric   /// \param NoexceptLoc the location of the noexcept keyword, if it was
36655e4f9d5SDimitry Andric   /// specified, otherwise an empty location.
36755e4f9d5SDimitry Andric   /// \param Req the requirement for the type of the checked expression.
36855e4f9d5SDimitry Andric   /// \param Status the satisfaction status of this requirement.
36955e4f9d5SDimitry Andric   ExprRequirement(
37055e4f9d5SDimitry Andric       Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
37155e4f9d5SDimitry Andric       ReturnTypeRequirement Req, SatisfactionStatus Status,
37255e4f9d5SDimitry Andric       ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr);
37355e4f9d5SDimitry Andric 
37455e4f9d5SDimitry Andric   /// \brief Construct a compound requirement whose expression was a
37555e4f9d5SDimitry Andric   /// substitution failure. The requirement is not satisfied.
37655e4f9d5SDimitry Andric   /// \param E the diagnostic emitted while instantiating the original
37755e4f9d5SDimitry Andric   /// expression.
37855e4f9d5SDimitry Andric   /// \param IsSimple whether this was a simple requirement in source.
37955e4f9d5SDimitry Andric   /// \param NoexceptLoc the location of the noexcept keyword, if it was
38055e4f9d5SDimitry Andric   /// specified, otherwise an empty location.
38155e4f9d5SDimitry Andric   /// \param Req the requirement for the type of the checked expression (omit
38255e4f9d5SDimitry Andric   /// if no requirement was specified).
38355e4f9d5SDimitry Andric   ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple,
38455e4f9d5SDimitry Andric                   SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {});
38555e4f9d5SDimitry Andric 
isSimple()38655e4f9d5SDimitry Andric   bool isSimple() const { return getKind() == RK_Simple; }
isCompound()38755e4f9d5SDimitry Andric   bool isCompound() const { return getKind() == RK_Compound; }
38855e4f9d5SDimitry Andric 
hasNoexceptRequirement()38955e4f9d5SDimitry Andric   bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); }
getNoexceptLoc()39055e4f9d5SDimitry Andric   SourceLocation getNoexceptLoc() const { return NoexceptLoc; }
39155e4f9d5SDimitry Andric 
getSatisfactionStatus()39255e4f9d5SDimitry Andric   SatisfactionStatus getSatisfactionStatus() const { return Status; }
39355e4f9d5SDimitry Andric 
isExprSubstitutionFailure()39455e4f9d5SDimitry Andric   bool isExprSubstitutionFailure() const {
39555e4f9d5SDimitry Andric     return Status == SS_ExprSubstitutionFailure;
39655e4f9d5SDimitry Andric   }
39755e4f9d5SDimitry Andric 
getReturnTypeRequirement()39855e4f9d5SDimitry Andric   const ReturnTypeRequirement &getReturnTypeRequirement() const {
39955e4f9d5SDimitry Andric     return TypeReq;
40055e4f9d5SDimitry Andric   }
40155e4f9d5SDimitry Andric 
40255e4f9d5SDimitry Andric   ConceptSpecializationExpr *
getReturnTypeRequirementSubstitutedConstraintExpr()40355e4f9d5SDimitry Andric   getReturnTypeRequirementSubstitutedConstraintExpr() const {
40455e4f9d5SDimitry Andric     assert(Status >= SS_TypeRequirementSubstitutionFailure);
40555e4f9d5SDimitry Andric     return SubstitutedConstraintExpr;
40655e4f9d5SDimitry Andric   }
40755e4f9d5SDimitry Andric 
getExprSubstitutionDiagnostic()40855e4f9d5SDimitry Andric   SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const {
40955e4f9d5SDimitry Andric     assert(isExprSubstitutionFailure() &&
41055e4f9d5SDimitry Andric            "Attempted to get expression substitution diagnostic when there has "
41155e4f9d5SDimitry Andric            "been no expression substitution failure");
41255e4f9d5SDimitry Andric     return Value.get<SubstitutionDiagnostic *>();
41355e4f9d5SDimitry Andric   }
41455e4f9d5SDimitry Andric 
getExpr()41555e4f9d5SDimitry Andric   Expr *getExpr() const {
41655e4f9d5SDimitry Andric     assert(!isExprSubstitutionFailure() &&
41755e4f9d5SDimitry Andric            "ExprRequirement has no expression because there has been a "
41855e4f9d5SDimitry Andric            "substitution failure.");
41955e4f9d5SDimitry Andric     return Value.get<Expr *>();
42055e4f9d5SDimitry Andric   }
42155e4f9d5SDimitry Andric 
classof(const Requirement * R)42255e4f9d5SDimitry Andric   static bool classof(const Requirement *R) {
42355e4f9d5SDimitry Andric     return R->getKind() == RK_Compound || R->getKind() == RK_Simple;
42455e4f9d5SDimitry Andric   }
42555e4f9d5SDimitry Andric };
42655e4f9d5SDimitry Andric 
42755e4f9d5SDimitry Andric /// \brief A requires-expression requirement which is satisfied when a general
42855e4f9d5SDimitry Andric /// constraint expression is satisfied ('nested' requirements).
42955e4f9d5SDimitry Andric class NestedRequirement : public Requirement {
430bdd1243dSDimitry Andric   Expr *Constraint = nullptr;
43155e4f9d5SDimitry Andric   const ASTConstraintSatisfaction *Satisfaction = nullptr;
432bdd1243dSDimitry Andric   bool HasInvalidConstraint = false;
433bdd1243dSDimitry Andric   StringRef InvalidConstraintEntity;
43455e4f9d5SDimitry Andric 
43555e4f9d5SDimitry Andric public:
43655e4f9d5SDimitry Andric   friend ASTStmtReader;
43755e4f9d5SDimitry Andric   friend ASTStmtWriter;
43855e4f9d5SDimitry Andric 
NestedRequirement(Expr * Constraint)439bdd1243dSDimitry Andric   NestedRequirement(Expr *Constraint)
440bdd1243dSDimitry Andric       : Requirement(RK_Nested, /*IsDependent=*/true,
44155e4f9d5SDimitry Andric                     Constraint->containsUnexpandedParameterPack()),
442bdd1243dSDimitry Andric         Constraint(Constraint) {
44355e4f9d5SDimitry Andric     assert(Constraint->isInstantiationDependent() &&
44455e4f9d5SDimitry Andric            "Nested requirement with non-dependent constraint must be "
44555e4f9d5SDimitry Andric            "constructed with a ConstraintSatisfaction object");
44655e4f9d5SDimitry Andric   }
44755e4f9d5SDimitry Andric 
NestedRequirement(ASTContext & C,Expr * Constraint,const ConstraintSatisfaction & Satisfaction)44855e4f9d5SDimitry Andric   NestedRequirement(ASTContext &C, Expr *Constraint,
449bdd1243dSDimitry Andric                     const ConstraintSatisfaction &Satisfaction)
450bdd1243dSDimitry Andric       : Requirement(RK_Nested, Constraint->isInstantiationDependent(),
45155e4f9d5SDimitry Andric                     Constraint->containsUnexpandedParameterPack(),
45255e4f9d5SDimitry Andric                     Satisfaction.IsSatisfied),
453bdd1243dSDimitry Andric         Constraint(Constraint),
45455e4f9d5SDimitry Andric         Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
45555e4f9d5SDimitry Andric 
NestedRequirement(StringRef InvalidConstraintEntity,const ASTConstraintSatisfaction * Satisfaction)456bdd1243dSDimitry Andric   NestedRequirement(StringRef InvalidConstraintEntity,
457bdd1243dSDimitry Andric                     const ASTConstraintSatisfaction *Satisfaction)
458bdd1243dSDimitry Andric       : Requirement(RK_Nested,
459bdd1243dSDimitry Andric                     /*IsDependent=*/false,
460bdd1243dSDimitry Andric                     /*ContainsUnexpandedParameterPack*/ false,
461bdd1243dSDimitry Andric                     Satisfaction->IsSatisfied),
462bdd1243dSDimitry Andric         Satisfaction(Satisfaction), HasInvalidConstraint(true),
463bdd1243dSDimitry Andric         InvalidConstraintEntity(InvalidConstraintEntity) {}
46455e4f9d5SDimitry Andric 
NestedRequirement(ASTContext & C,StringRef InvalidConstraintEntity,const ConstraintSatisfaction & Satisfaction)465bdd1243dSDimitry Andric   NestedRequirement(ASTContext &C, StringRef InvalidConstraintEntity,
466bdd1243dSDimitry Andric                     const ConstraintSatisfaction &Satisfaction)
467bdd1243dSDimitry Andric       : NestedRequirement(InvalidConstraintEntity,
468bdd1243dSDimitry Andric                           ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
469bdd1243dSDimitry Andric 
hasInvalidConstraint()470bdd1243dSDimitry Andric   bool hasInvalidConstraint() const { return HasInvalidConstraint; }
471bdd1243dSDimitry Andric 
getInvalidConstraintEntity()472bdd1243dSDimitry Andric   StringRef getInvalidConstraintEntity() {
473bdd1243dSDimitry Andric     assert(hasInvalidConstraint());
474bdd1243dSDimitry Andric     return InvalidConstraintEntity;
47555e4f9d5SDimitry Andric   }
47655e4f9d5SDimitry Andric 
getConstraintExpr()47755e4f9d5SDimitry Andric   Expr *getConstraintExpr() const {
478bdd1243dSDimitry Andric     assert(!hasInvalidConstraint() &&
479bdd1243dSDimitry Andric            "getConstraintExpr() may not be called "
480bdd1243dSDimitry Andric            "on nested requirements with invalid constraint.");
481bdd1243dSDimitry Andric     return Constraint;
48255e4f9d5SDimitry Andric   }
48355e4f9d5SDimitry Andric 
getConstraintSatisfaction()48455e4f9d5SDimitry Andric   const ASTConstraintSatisfaction &getConstraintSatisfaction() const {
48555e4f9d5SDimitry Andric     return *Satisfaction;
48655e4f9d5SDimitry Andric   }
48755e4f9d5SDimitry Andric 
classof(const Requirement * R)48855e4f9d5SDimitry Andric   static bool classof(const Requirement *R) {
48955e4f9d5SDimitry Andric     return R->getKind() == RK_Nested;
49055e4f9d5SDimitry Andric   }
49155e4f9d5SDimitry Andric };
49255e4f9d5SDimitry Andric 
4938a4dda33SDimitry Andric using EntityPrinter = llvm::function_ref<void(llvm::raw_ostream &)>;
4948a4dda33SDimitry Andric 
4958a4dda33SDimitry Andric /// \brief create a Requirement::SubstitutionDiagnostic with only a
4968a4dda33SDimitry Andric /// SubstitutedEntity and DiagLoc using Sema's allocator.
4978a4dda33SDimitry Andric Requirement::SubstitutionDiagnostic *
4988a4dda33SDimitry Andric createSubstDiagAt(Sema &S, SourceLocation Location, EntityPrinter Printer);
4998a4dda33SDimitry Andric 
50055e4f9d5SDimitry Andric } // namespace concepts
50155e4f9d5SDimitry Andric 
50255e4f9d5SDimitry Andric /// C++2a [expr.prim.req]:
50355e4f9d5SDimitry Andric ///     A requires-expression provides a concise way to express requirements on
50455e4f9d5SDimitry Andric ///     template arguments. A requirement is one that can be checked by name
50555e4f9d5SDimitry Andric ///     lookup (6.4) or by checking properties of types and expressions.
50655e4f9d5SDimitry Andric ///     [...]
50755e4f9d5SDimitry Andric ///     A requires-expression is a prvalue of type bool [...]
50855e4f9d5SDimitry Andric class RequiresExpr final : public Expr,
50955e4f9d5SDimitry Andric     llvm::TrailingObjects<RequiresExpr, ParmVarDecl *,
51055e4f9d5SDimitry Andric                           concepts::Requirement *> {
51155e4f9d5SDimitry Andric   friend TrailingObjects;
51255e4f9d5SDimitry Andric   friend class ASTStmtReader;
51355e4f9d5SDimitry Andric 
51455e4f9d5SDimitry Andric   unsigned NumLocalParameters;
51555e4f9d5SDimitry Andric   unsigned NumRequirements;
51655e4f9d5SDimitry Andric   RequiresExprBodyDecl *Body;
517*5f757f3fSDimitry Andric   SourceLocation LParenLoc;
518*5f757f3fSDimitry Andric   SourceLocation RParenLoc;
51955e4f9d5SDimitry Andric   SourceLocation RBraceLoc;
52055e4f9d5SDimitry Andric 
numTrailingObjects(OverloadToken<ParmVarDecl * >)52155e4f9d5SDimitry Andric   unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
52255e4f9d5SDimitry Andric     return NumLocalParameters;
52355e4f9d5SDimitry Andric   }
52455e4f9d5SDimitry Andric 
numTrailingObjects(OverloadToken<concepts::Requirement * >)52555e4f9d5SDimitry Andric   unsigned numTrailingObjects(OverloadToken<concepts::Requirement *>) const {
52655e4f9d5SDimitry Andric     return NumRequirements;
52755e4f9d5SDimitry Andric   }
52855e4f9d5SDimitry Andric 
52955e4f9d5SDimitry Andric   RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
530*5f757f3fSDimitry Andric                RequiresExprBodyDecl *Body, SourceLocation LParenLoc,
53155e4f9d5SDimitry Andric                ArrayRef<ParmVarDecl *> LocalParameters,
532*5f757f3fSDimitry Andric                SourceLocation RParenLoc,
53355e4f9d5SDimitry Andric                ArrayRef<concepts::Requirement *> Requirements,
53455e4f9d5SDimitry Andric                SourceLocation RBraceLoc);
53555e4f9d5SDimitry Andric   RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
53655e4f9d5SDimitry Andric                unsigned NumRequirements);
53755e4f9d5SDimitry Andric 
53855e4f9d5SDimitry Andric public:
539*5f757f3fSDimitry Andric   static RequiresExpr *Create(ASTContext &C, SourceLocation RequiresKWLoc,
540*5f757f3fSDimitry Andric                               RequiresExprBodyDecl *Body,
541*5f757f3fSDimitry Andric                               SourceLocation LParenLoc,
542*5f757f3fSDimitry Andric                               ArrayRef<ParmVarDecl *> LocalParameters,
543*5f757f3fSDimitry Andric                               SourceLocation RParenLoc,
54455e4f9d5SDimitry Andric                               ArrayRef<concepts::Requirement *> Requirements,
54555e4f9d5SDimitry Andric                               SourceLocation RBraceLoc);
54655e4f9d5SDimitry Andric   static RequiresExpr *
54755e4f9d5SDimitry Andric   Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
54855e4f9d5SDimitry Andric          unsigned NumRequirements);
54955e4f9d5SDimitry Andric 
getLocalParameters()55055e4f9d5SDimitry Andric   ArrayRef<ParmVarDecl *> getLocalParameters() const {
55155e4f9d5SDimitry Andric     return {getTrailingObjects<ParmVarDecl *>(), NumLocalParameters};
55255e4f9d5SDimitry Andric   }
55355e4f9d5SDimitry Andric 
getBody()55455e4f9d5SDimitry Andric   RequiresExprBodyDecl *getBody() const { return Body; }
55555e4f9d5SDimitry Andric 
getRequirements()55655e4f9d5SDimitry Andric   ArrayRef<concepts::Requirement *> getRequirements() const {
55755e4f9d5SDimitry Andric     return {getTrailingObjects<concepts::Requirement *>(), NumRequirements};
55855e4f9d5SDimitry Andric   }
55955e4f9d5SDimitry Andric 
56055e4f9d5SDimitry Andric   /// \brief Whether or not the requires clause is satisfied.
56155e4f9d5SDimitry Andric   /// The expression must not be dependent.
isSatisfied()56255e4f9d5SDimitry Andric   bool isSatisfied() const {
56355e4f9d5SDimitry Andric     assert(!isValueDependent()
56455e4f9d5SDimitry Andric            && "isSatisfied called on a dependent RequiresExpr");
56555e4f9d5SDimitry Andric     return RequiresExprBits.IsSatisfied;
56655e4f9d5SDimitry Andric   }
56755e4f9d5SDimitry Andric 
setSatisfied(bool IsSatisfied)568bdd1243dSDimitry Andric   void setSatisfied(bool IsSatisfied) {
569bdd1243dSDimitry Andric     assert(!isValueDependent() &&
570bdd1243dSDimitry Andric            "setSatisfied called on a dependent RequiresExpr");
571bdd1243dSDimitry Andric     RequiresExprBits.IsSatisfied = IsSatisfied;
572bdd1243dSDimitry Andric   }
573bdd1243dSDimitry Andric 
getRequiresKWLoc()57455e4f9d5SDimitry Andric   SourceLocation getRequiresKWLoc() const {
57555e4f9d5SDimitry Andric     return RequiresExprBits.RequiresKWLoc;
57655e4f9d5SDimitry Andric   }
57755e4f9d5SDimitry Andric 
getLParenLoc()578*5f757f3fSDimitry Andric   SourceLocation getLParenLoc() const { return LParenLoc; }
getRParenLoc()579*5f757f3fSDimitry Andric   SourceLocation getRParenLoc() const { return RParenLoc; }
getRBraceLoc()58055e4f9d5SDimitry Andric   SourceLocation getRBraceLoc() const { return RBraceLoc; }
58155e4f9d5SDimitry Andric 
classof(const Stmt * T)58255e4f9d5SDimitry Andric   static bool classof(const Stmt *T) {
58355e4f9d5SDimitry Andric     return T->getStmtClass() == RequiresExprClass;
58455e4f9d5SDimitry Andric   }
58555e4f9d5SDimitry Andric 
getBeginLoc()58655e4f9d5SDimitry Andric   SourceLocation getBeginLoc() const LLVM_READONLY {
58755e4f9d5SDimitry Andric     return RequiresExprBits.RequiresKWLoc;
58855e4f9d5SDimitry Andric   }
getEndLoc()58955e4f9d5SDimitry Andric   SourceLocation getEndLoc() const LLVM_READONLY {
59055e4f9d5SDimitry Andric     return RBraceLoc;
59155e4f9d5SDimitry Andric   }
59255e4f9d5SDimitry Andric 
59355e4f9d5SDimitry Andric   // Iterators
children()59455e4f9d5SDimitry Andric   child_range children() {
59555e4f9d5SDimitry Andric     return child_range(child_iterator(), child_iterator());
59655e4f9d5SDimitry Andric   }
children()59755e4f9d5SDimitry Andric   const_child_range children() const {
59855e4f9d5SDimitry Andric     return const_child_range(const_child_iterator(), const_child_iterator());
59955e4f9d5SDimitry Andric   }
60055e4f9d5SDimitry Andric };
60155e4f9d5SDimitry Andric 
60255e4f9d5SDimitry Andric } // namespace clang
60355e4f9d5SDimitry Andric 
60455e4f9d5SDimitry Andric #endif // LLVM_CLANG_AST_EXPRCONCEPTS_H
605