diff options
| author | Saar Raz <saar@raz.email> | 2020-01-18 09:11:43 +0200 |
|---|---|---|
| committer | Saar Raz <saar@raz.email> | 2020-01-24 02:28:22 +0200 |
| commit | c96ef5118857ff938aa6d304ccf7c0f9b81bc5ba (patch) | |
| tree | dd3f90c54e9cfd869b0e74b1f6b7bd85e8888094 /clang/include | |
| parent | ab514b91196345ba4c61026e4997871e85ddd97d (diff) | |
| download | bcm5719-llvm-c96ef5118857ff938aa6d304ccf7c0f9b81bc5ba.tar.gz bcm5719-llvm-c96ef5118857ff938aa6d304ccf7c0f9b81bc5ba.zip | |
[Concepts] Requires Expressions
Implement support for C++2a requires-expressions.
Re-commit after compilation failure on some platforms due to alignment issues with PointerIntPair.
Differential Revision: https://reviews.llvm.org/D50360
(cherry picked from commit a0f50d731639350c7a79f140f026c27a18215531)
Diffstat (limited to 'clang/include')
| -rw-r--r-- | clang/include/clang/AST/ASTConcept.h | 1 | ||||
| -rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 31 | ||||
| -rw-r--r-- | clang/include/clang/AST/ExprCXX.h | 94 | ||||
| -rw-r--r-- | clang/include/clang/AST/ExprConcepts.h | 540 | ||||
| -rw-r--r-- | clang/include/clang/AST/RecursiveASTVisitor.h | 25 | ||||
| -rw-r--r-- | clang/include/clang/AST/Stmt.h | 12 | ||||
| -rw-r--r-- | clang/include/clang/AST/StmtVisitor.h | 1 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DeclNodes.td | 1 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticParseKinds.td | 27 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 66 | ||||
| -rw-r--r-- | clang/include/clang/Basic/StmtNodes.td | 1 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Parser.h | 3 | ||||
| -rw-r--r-- | clang/include/clang/Sema/DeclSpec.h | 9 | ||||
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 84 | ||||
| -rw-r--r-- | clang/include/clang/Sema/SemaConcept.h | 7 | ||||
| -rw-r--r-- | clang/include/clang/Serialization/ASTBitCodes.h | 4 |
16 files changed, 800 insertions, 106 deletions
diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h index 896d857d8c9..84a611c14e0 100644 --- a/clang/include/clang/AST/ASTConcept.h +++ b/clang/include/clang/AST/ASTConcept.h @@ -22,6 +22,7 @@ #include <utility> namespace clang { class ConceptDecl; +class ConceptSpecializationExpr; /// \brief The result of a constraint satisfaction check, containing the /// necessary information to diagnose an unsatisfied constraint. diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index b716ea453a5..2e8e31dbf4c 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1893,6 +1893,37 @@ public: static bool classofKind(Kind K) { return K == CXXDeductionGuide; } }; +/// \brief Represents the body of a requires-expression. +/// +/// This decl exists merely to serve as the DeclContext for the local +/// parameters of the requires expression as well as other declarations inside +/// it. +/// +/// \code +/// template<typename T> requires requires (T t) { {t++} -> regular; } +/// \endcode +/// +/// In this example, a RequiresExpr object will be generated for the expression, +/// and a RequiresExprBodyDecl will be created to hold the parameter t and the +/// template argument list imposed by the compound requirement. +class RequiresExprBodyDecl : public Decl, public DeclContext { + RequiresExprBodyDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc) + : Decl(RequiresExprBody, DC, StartLoc), DeclContext(RequiresExprBody) {} + +public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + + static RequiresExprBodyDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc); + + static RequiresExprBodyDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == RequiresExprBody; } +}; + /// Represents a static or instance method of a struct/union/class. /// /// In the terminology of the C++ Standard, these are the (static and diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 2c29409e0ca..cea360d12e9 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -14,7 +14,6 @@ #ifndef LLVM_CLANG_AST_EXPRCXX_H #define LLVM_CLANG_AST_EXPRCXX_H -#include "clang/AST/ASTConcept.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -4836,99 +4835,6 @@ public: } }; -/// \brief Represents the specialization of a concept - evaluates to a prvalue -/// of type bool. -/// -/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the -/// specialization of a concept results in a prvalue of type bool. -class ConceptSpecializationExpr final : public Expr, public ConceptReference, - private llvm::TrailingObjects<ConceptSpecializationExpr, - TemplateArgument> { - friend class ASTStmtReader; - friend TrailingObjects; -public: - using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>; - -protected: - /// \brief The number of template arguments in the tail-allocated list of - /// converted template arguments. - unsigned NumTemplateArgs; - - /// \brief Information about the satisfaction of the named concept with the - /// given arguments. If this expression is value dependent, this is to be - /// ignored. - ASTConstraintSatisfaction *Satisfaction; - - ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS, - SourceLocation TemplateKWLoc, - DeclarationNameInfo ConceptNameInfo, - NamedDecl *FoundDecl, ConceptDecl *NamedConcept, - const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef<TemplateArgument> ConvertedArgs, - const ConstraintSatisfaction *Satisfaction); - - ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs); - -public: - - static ConceptSpecializationExpr * - Create(const ASTContext &C, NestedNameSpecifierLoc NNS, - SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, - NamedDecl *FoundDecl, ConceptDecl *NamedConcept, - const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef<TemplateArgument> ConvertedArgs, - const ConstraintSatisfaction *Satisfaction); - - static ConceptSpecializationExpr * - Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs); - - ArrayRef<TemplateArgument> getTemplateArguments() const { - return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(), - NumTemplateArgs); - } - - /// \brief Set new template arguments for this concept specialization. - void setTemplateArguments(ArrayRef<TemplateArgument> Converted); - - /// \brief Whether or not the concept with the given arguments was satisfied - /// when the expression was created. - /// The expression must not be dependent. - bool isSatisfied() const { - assert(!isValueDependent() - && "isSatisfied called on a dependent ConceptSpecializationExpr"); - return Satisfaction->IsSatisfied; - } - - /// \brief Get elaborated satisfaction info about the template arguments' - /// satisfaction of the named concept. - /// The expression must not be dependent. - const ASTConstraintSatisfaction &getSatisfaction() const { - assert(!isValueDependent() - && "getSatisfaction called on dependent ConceptSpecializationExpr"); - return *Satisfaction; - } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == ConceptSpecializationExprClass; - } - - SourceLocation getBeginLoc() const LLVM_READONLY { - return ConceptName.getBeginLoc(); - } - - SourceLocation getEndLoc() const LLVM_READONLY { - return ArgsAsWritten->RAngleLoc; - } - - // Iterators - child_range children() { - return child_range(child_iterator(), child_iterator()); - } - const_child_range children() const { - return const_child_range(const_child_iterator(), const_child_iterator()); - } -}; - } // namespace clang #endif // LLVM_CLANG_AST_EXPRCXX_H diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h new file mode 100644 index 00000000000..2a64326e860 --- /dev/null +++ b/clang/include/clang/AST/ExprConcepts.h @@ -0,0 +1,540 @@ +//===- ExprConcepts.h - C++2a Concepts expressions --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines Expressions and AST nodes for C++2a concepts. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPRCONCEPTS_H +#define LLVM_CLANG_AST_EXPRCONCEPTS_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConcept.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/Support/TrailingObjects.h" +#include <utility> +#include <string> + +namespace clang { +class ASTStmtReader; +class ASTStmtWriter; + +/// \brief Represents the specialization of a concept - evaluates to a prvalue +/// of type bool. +/// +/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the +/// specialization of a concept results in a prvalue of type bool. +class ConceptSpecializationExpr final : public Expr, public ConceptReference, + private llvm::TrailingObjects<ConceptSpecializationExpr, + TemplateArgument> { + friend class ASTStmtReader; + friend TrailingObjects; +public: + using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>; + +protected: + /// \brief The number of template arguments in the tail-allocated list of + /// converted template arguments. + unsigned NumTemplateArgs; + + /// \brief Information about the satisfaction of the named concept with the + /// given arguments. If this expression is value dependent, this is to be + /// ignored. + ASTConstraintSatisfaction *Satisfaction; + + ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, + DeclarationNameInfo ConceptNameInfo, + NamedDecl *FoundDecl, ConceptDecl *NamedConcept, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef<TemplateArgument> ConvertedArgs, + const ConstraintSatisfaction *Satisfaction); + + ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs); + +public: + + static ConceptSpecializationExpr * + Create(const ASTContext &C, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, + NamedDecl *FoundDecl, ConceptDecl *NamedConcept, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef<TemplateArgument> ConvertedArgs, + const ConstraintSatisfaction *Satisfaction); + + static ConceptSpecializationExpr * + Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs); + + ArrayRef<TemplateArgument> getTemplateArguments() const { + return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(), + NumTemplateArgs); + } + + /// \brief Set new template arguments for this concept specialization. + void setTemplateArguments(ArrayRef<TemplateArgument> Converted); + + /// \brief Whether or not the concept with the given arguments was satisfied + /// when the expression was created. + /// The expression must not be dependent. + bool isSatisfied() const { + assert(!isValueDependent() + && "isSatisfied called on a dependent ConceptSpecializationExpr"); + return Satisfaction->IsSatisfied; + } + + /// \brief Get elaborated satisfaction info about the template arguments' + /// satisfaction of the named concept. + /// The expression must not be dependent. + const ASTConstraintSatisfaction &getSatisfaction() const { + assert(!isValueDependent() + && "getSatisfaction called on dependent ConceptSpecializationExpr"); + return *Satisfaction; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConceptSpecializationExprClass; + } + + SourceLocation getBeginLoc() const LLVM_READONLY { + return ConceptName.getBeginLoc(); + } + + SourceLocation getEndLoc() const LLVM_READONLY { + return ArgsAsWritten->RAngleLoc; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + +namespace concepts { + +/// \brief A static requirement that can be used in a requires-expression to +/// check properties of types and expression. +class Requirement { +public: + // Note - simple and compound requirements are both represented by the same + // class (ExprRequirement). + enum RequirementKind { RK_Type, RK_Simple, RK_Compound, RK_Nested }; +private: + const RequirementKind Kind; + bool Dependent : 1; + bool ContainsUnexpandedParameterPack : 1; + bool Satisfied : 1; +public: + struct SubstitutionDiagnostic { + StringRef SubstitutedEntity; + // FIXME: Store diagnostics semantically and not as prerendered strings. + // Fixing this probably requires serialization of PartialDiagnostic + // objects. + SourceLocation DiagLoc; + StringRef DiagMessage; + }; + + Requirement(RequirementKind Kind, bool IsDependent, + bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) : + Kind(Kind), Dependent(IsDependent), + ContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack), + Satisfied(IsSatisfied) {} + + RequirementKind getKind() const { return Kind; } + + bool isSatisfied() const { + assert(!Dependent && + "isSatisfied can only be called on non-dependent requirements."); + return Satisfied; + } + + void setSatisfied(bool IsSatisfied) { + assert(!Dependent && + "setSatisfied can only be called on non-dependent requirements."); + Satisfied = IsSatisfied; + } + + void setDependent(bool IsDependent) { Dependent = IsDependent; } + bool isDependent() const { return Dependent; } + + void setContainsUnexpandedParameterPack(bool Contains) { + ContainsUnexpandedParameterPack = Contains; + } + bool containsUnexpandedParameterPack() const { + return ContainsUnexpandedParameterPack; + } +}; + +/// \brief A requires-expression requirement which queries the existence of a +/// type name or type template specialization ('type' requirements). +class TypeRequirement : public Requirement { +public: + enum SatisfactionStatus { + SS_Dependent, + SS_SubstitutionFailure, + SS_Satisfied + }; +private: + llvm::PointerUnion<SubstitutionDiagnostic *, TypeSourceInfo *> Value; + SatisfactionStatus Status; +public: + friend ASTStmtReader; + friend ASTStmtWriter; + + /// \brief Construct a type requirement from a type. If the given type is not + /// dependent, this indicates that the type exists and the requirement will be + /// satisfied. Otherwise, the SubstitutionDiagnostic constructor is to be + /// used. + TypeRequirement(TypeSourceInfo *T); + + /// \brief Construct a type requirement when the nested name specifier is + /// invalid due to a bad substitution. The requirement is unsatisfied. + TypeRequirement(SubstitutionDiagnostic *Diagnostic) : + Requirement(RK_Type, false, false, false), Value(Diagnostic), + Status(SS_SubstitutionFailure) {} + + SatisfactionStatus getSatisfactionStatus() const { return Status; } + void setSatisfactionStatus(SatisfactionStatus Status) { + this->Status = Status; + } + + bool isSubstitutionFailure() const { + return Status == SS_SubstitutionFailure; + } + + SubstitutionDiagnostic *getSubstitutionDiagnostic() const { + assert(Status == SS_SubstitutionFailure && + "Attempted to get substitution diagnostic when there has been no " + "substitution failure."); + return Value.get<SubstitutionDiagnostic *>(); + } + + TypeSourceInfo *getType() const { + assert(!isSubstitutionFailure() && + "Attempted to get type when there has been a substitution failure."); + return Value.get<TypeSourceInfo *>(); + } + + static bool classof(const Requirement *R) { + return R->getKind() == RK_Type; + } +}; + +/// \brief A requires-expression requirement which queries the validity and +/// properties of an expression ('simple' and 'compound' requirements). +class ExprRequirement : public Requirement { +public: + enum SatisfactionStatus { + SS_Dependent, + SS_ExprSubstitutionFailure, + SS_NoexceptNotMet, + SS_TypeRequirementSubstitutionFailure, + SS_ConstraintsNotSatisfied, + SS_Satisfied + }; + class ReturnTypeRequirement { + llvm::PointerIntPair< + llvm::PointerUnion<TemplateParameterList *, SubstitutionDiagnostic *>, + 1, bool> + TypeConstraintInfo; + public: + friend ASTStmtReader; + friend ASTStmtWriter; + + /// \brief No return type requirement was specified. + ReturnTypeRequirement() : TypeConstraintInfo(nullptr, 0) {} + + /// \brief A return type requirement was specified but it was a + /// substitution failure. + ReturnTypeRequirement(SubstitutionDiagnostic *SubstDiag) : + TypeConstraintInfo(SubstDiag, 0) {} + + /// \brief A 'type constraint' style return type requirement. + /// \param TPL an invented template parameter list containing a single + /// type parameter with a type-constraint. + // TODO: Can we maybe not save the whole template parameter list and just + // the type constraint? Saving the whole TPL makes it easier to handle in + // serialization but is less elegant. + ReturnTypeRequirement(TemplateParameterList *TPL); + + bool isDependent() const { + return TypeConstraintInfo.getInt(); + } + + bool containsUnexpandedParameterPack() const { + if (!isTypeConstraint()) + return false; + return getTypeConstraintTemplateParameterList() + ->containsUnexpandedParameterPack(); + } + + bool isEmpty() const { + return TypeConstraintInfo.getPointer().isNull(); + } + + bool isSubstitutionFailure() const { + return !isEmpty() && + TypeConstraintInfo.getPointer().is<SubstitutionDiagnostic *>(); + } + + bool isTypeConstraint() const { + return !isEmpty() && + TypeConstraintInfo.getPointer().is<TemplateParameterList *>(); + } + + SubstitutionDiagnostic *getSubstitutionDiagnostic() const { + assert(isSubstitutionFailure()); + return TypeConstraintInfo.getPointer().get<SubstitutionDiagnostic *>(); + } + + const TypeConstraint *getTypeConstraint() const; + + TemplateParameterList *getTypeConstraintTemplateParameterList() const { + assert(isTypeConstraint()); + return TypeConstraintInfo.getPointer().get<TemplateParameterList *>(); + } + }; +private: + llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value; + SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified. + ReturnTypeRequirement TypeReq; + ConceptSpecializationExpr *SubstitutedConstraintExpr; + SatisfactionStatus Status; +public: + friend ASTStmtReader; + friend ASTStmtWriter; + + /// \brief Construct a compound requirement. + /// \param E the expression which is checked by this requirement. + /// \param IsSimple whether this was a simple requirement in source. + /// \param NoexceptLoc the location of the noexcept keyword, if it was + /// specified, otherwise an empty location. + /// \param Req the requirement for the type of the checked expression. + /// \param Status the satisfaction status of this requirement. + ExprRequirement( + Expr *E, bool IsSimple, SourceLocation NoexceptLoc, + ReturnTypeRequirement Req, SatisfactionStatus Status, + ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr); + + /// \brief Construct a compound requirement whose expression was a + /// substitution failure. The requirement is not satisfied. + /// \param E the diagnostic emitted while instantiating the original + /// expression. + /// \param IsSimple whether this was a simple requirement in source. + /// \param NoexceptLoc the location of the noexcept keyword, if it was + /// specified, otherwise an empty location. + /// \param Req the requirement for the type of the checked expression (omit + /// if no requirement was specified). + ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple, + SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {}); + + bool isSimple() const { return getKind() == RK_Simple; } + bool isCompound() const { return getKind() == RK_Compound; } + + bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); } + SourceLocation getNoexceptLoc() const { return NoexceptLoc; } + + SatisfactionStatus getSatisfactionStatus() const { return Status; } + + bool isExprSubstitutionFailure() const { + return Status == SS_ExprSubstitutionFailure; + } + + const ReturnTypeRequirement &getReturnTypeRequirement() const { + return TypeReq; + } + + ConceptSpecializationExpr * + getReturnTypeRequirementSubstitutedConstraintExpr() const { + assert(Status >= SS_TypeRequirementSubstitutionFailure); + return SubstitutedConstraintExpr; + } + + SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const { + assert(isExprSubstitutionFailure() && + "Attempted to get expression substitution diagnostic when there has " + "been no expression substitution failure"); + return Value.get<SubstitutionDiagnostic *>(); + } + + Expr *getExpr() const { + assert(!isExprSubstitutionFailure() && + "ExprRequirement has no expression because there has been a " + "substitution failure."); + return Value.get<Expr *>(); + } + + static bool classof(const Requirement *R) { + return R->getKind() == RK_Compound || R->getKind() == RK_Simple; + } +}; + +/// \brief A requires-expression requirement which is satisfied when a general +/// constraint expression is satisfied ('nested' requirements). +class NestedRequirement : public Requirement { + llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value; + const ASTConstraintSatisfaction *Satisfaction = nullptr; + +public: + friend ASTStmtReader; + friend ASTStmtWriter; + + NestedRequirement(SubstitutionDiagnostic *SubstDiag) : + Requirement(RK_Nested, /*Dependent=*/false, + /*ContainsUnexpandedParameterPack*/false, + /*Satisfied=*/false), Value(SubstDiag) {} + + NestedRequirement(Expr *Constraint) : + Requirement(RK_Nested, /*Dependent=*/true, + Constraint->containsUnexpandedParameterPack()), + Value(Constraint) { + assert(Constraint->isInstantiationDependent() && + "Nested requirement with non-dependent constraint must be " + "constructed with a ConstraintSatisfaction object"); + } + + NestedRequirement(ASTContext &C, Expr *Constraint, + const ConstraintSatisfaction &Satisfaction) : + Requirement(RK_Nested, Constraint->isInstantiationDependent(), + Constraint->containsUnexpandedParameterPack(), + Satisfaction.IsSatisfied), + Value(Constraint), + Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {} + + bool isSubstitutionFailure() const { + return Value.is<SubstitutionDiagnostic *>(); + } + + SubstitutionDiagnostic *getSubstitutionDiagnostic() const { + assert(isSubstitutionFailure() && + "getSubstitutionDiagnostic() may not be called when there was no " + "substitution failure."); + return Value.get<SubstitutionDiagnostic *>(); + } + + Expr *getConstraintExpr() const { + assert(!isSubstitutionFailure() && "getConstraintExpr() may not be called " + "on nested requirements with " + "substitution failures."); + return Value.get<Expr *>(); + } + + const ASTConstraintSatisfaction &getConstraintSatisfaction() const { + assert(!isSubstitutionFailure() && "getConstraintSatisfaction() may not be " + "called on nested requirements with " + "substitution failures."); + return *Satisfaction; + } + + static bool classof(const Requirement *R) { + return R->getKind() == RK_Nested; + } +}; + +} // namespace concepts + +/// C++2a [expr.prim.req]: +/// A requires-expression provides a concise way to express requirements on +/// template arguments. A requirement is one that can be checked by name +/// lookup (6.4) or by checking properties of types and expressions. +/// [...] +/// A requires-expression is a prvalue of type bool [...] +class RequiresExpr final : public Expr, + llvm::TrailingObjects<RequiresExpr, ParmVarDecl *, + concepts::Requirement *> { + friend TrailingObjects; + friend class ASTStmtReader; + + unsigned NumLocalParameters; + unsigned NumRequirements; + RequiresExprBodyDecl *Body; + SourceLocation RBraceLoc; + + unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const { + return NumLocalParameters; + } + + unsigned numTrailingObjects(OverloadToken<concepts::Requirement *>) const { + return NumRequirements; + } + + RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, + ArrayRef<ParmVarDecl *> LocalParameters, + ArrayRef<concepts::Requirement *> Requirements, + SourceLocation RBraceLoc); + RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters, + unsigned NumRequirements); + +public: + static RequiresExpr * + Create(ASTContext &C, SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> LocalParameters, + ArrayRef<concepts::Requirement *> Requirements, + SourceLocation RBraceLoc); + static RequiresExpr * + Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters, + unsigned NumRequirements); + + ArrayRef<ParmVarDecl *> getLocalParameters() const { + return {getTrailingObjects<ParmVarDecl *>(), NumLocalParameters}; + } + + RequiresExprBodyDecl *getBody() const { return Body; } + + ArrayRef<concepts::Requirement *> getRequirements() const { + return {getTrailingObjects<concepts::Requirement *>(), NumRequirements}; + } + + /// \brief Whether or not the requires clause is satisfied. + /// The expression must not be dependent. + bool isSatisfied() const { + assert(!isValueDependent() + && "isSatisfied called on a dependent RequiresExpr"); + return RequiresExprBits.IsSatisfied; + } + + SourceLocation getRequiresKWLoc() const { + return RequiresExprBits.RequiresKWLoc; + } + + SourceLocation getRBraceLoc() const { return RBraceLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == RequiresExprClass; + } + + SourceLocation getBeginLoc() const LLVM_READONLY { + return RequiresExprBits.RequiresKWLoc; + } + SourceLocation getEndLoc() const LLVM_READONLY { + return RBraceLoc; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_EXPRCONCEPTS_H
\ No newline at end of file diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index f8ab8e451d8..4633122aba4 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -23,6 +23,7 @@ #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" @@ -2138,6 +2139,8 @@ DEF_TRAVERSE_DECL(ParmVarDecl, { TRY_TO(TraverseStmt(D->getDefaultArg())); }) +DEF_TRAVERSE_DECL(RequiresExprBodyDecl, {}) + #undef DEF_TRAVERSE_DECL // ----------------- Stmt traversal ----------------- @@ -2709,6 +2712,28 @@ DEF_TRAVERSE_STMT(ConceptSpecializationExpr, { TRY_TO(TraverseConceptReference(*S)); }) +DEF_TRAVERSE_STMT(RequiresExpr, { + TRY_TO(TraverseDecl(S->getBody())); + for (ParmVarDecl *Parm : S->getLocalParameters()) + TRY_TO(TraverseDecl(Parm)); + for (concepts::Requirement *Req : S->getRequirements()) + if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) { + if (!TypeReq->isSubstitutionFailure()) + TRY_TO(TraverseTypeLoc(TypeReq->getType()->getTypeLoc())); + } else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) { + if (!ExprReq->isExprSubstitutionFailure()) + TRY_TO(TraverseStmt(ExprReq->getExpr())); + auto &RetReq = ExprReq->getReturnTypeRequirement(); + if (RetReq.isTypeConstraint()) + TRY_TO(TraverseTemplateParameterListHelper( + RetReq.getTypeConstraintTemplateParameterList())); + } else { + auto *NestedReq = cast<concepts::NestedRequirement>(Req); + if (!NestedReq->isSubstitutionFailure()) + TRY_TO(TraverseStmt(NestedReq->getConstraintExpr())); + } +}) + // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, {}) DEF_TRAVERSE_STMT(FixedPointLiteral, {}) diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index eaacb1a5b25..253b7694199 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -910,6 +910,17 @@ protected: SourceLocation NameLoc; }; + class RequiresExprBitfields { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend class RequiresExpr; + + unsigned : NumExprBits; + + unsigned IsSatisfied : 1; + SourceLocation RequiresKWLoc; + }; + //===--- C++ Coroutines TS bitfields classes ---===// class CoawaitExprBitfields { @@ -1008,6 +1019,7 @@ protected: UnresolvedMemberExprBitfields UnresolvedMemberExprBits; CXXNoexceptExprBitfields CXXNoexceptExprBits; SubstNonTypeTemplateParmExprBitfields SubstNonTypeTemplateParmExprBits; + RequiresExprBitfields RequiresExprBits; // C++ Coroutines TS expressions CoawaitExprBitfields CoawaitBits; diff --git a/clang/include/clang/AST/StmtVisitor.h b/clang/include/clang/AST/StmtVisitor.h index d3be93d228c..3e5155199ea 100644 --- a/clang/include/clang/AST/StmtVisitor.h +++ b/clang/include/clang/AST/StmtVisitor.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_AST_STMTVISITOR_H #define LLVM_CLANG_AST_STMTVISITOR_H +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index c2c23237285..d5bbc604819 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -100,5 +100,6 @@ def OMPThreadPrivate : DeclNode<Decl>; def OMPAllocate : DeclNode<Decl>; def OMPRequires : DeclNode<Decl>; def Empty : DeclNode<Decl>; +def RequiresExprBody : DeclNode<Decl>, DeclContext; def LifetimeExtendedTemporary : DeclNode<Decl>; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 41f788e7d9b..105ed7bf6c8 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -744,6 +744,33 @@ def err_friend_explicit_instantiation : Error< def err_explicit_instantiation_enum : Error< "enumerations cannot be explicitly instantiated">; def err_expected_template_parameter : Error<"expected template parameter">; +def note_ill_formed_requires_expression_outside_template : Note< + "requires expression outside a template declaration may not contain invalid " + "types or expressions">; +def err_empty_requires_expr : Error< + "a requires expression must contain at least one requirement">; +def err_requires_expr_parameter_list_ellipsis : Error< + "varargs not allowed in requires expression">; +def err_requires_expr_type_req_illegal_identifier : Error< + "expected identifier or template-id in type requirement">; +def err_requires_expr_type_req_template_args_on_non_template : Error< + "template arguments provided for non-template '%0'">; +def err_expected_semi_requirement : Error< + "expected ';' at end of requirement">; +def err_requires_expr_missing_arrow : Error< + "expected '->' before expression type requirement">; +def err_requires_expr_expected_type_constraint : Error< + "expected concept name with optional arguments">; +def err_requires_expr_simple_requirement_noexcept : Error< + "'noexcept' can only be used in a compound requirement (with '{' '}' around " + "the expression)">; +def err_requires_expr_simple_requirement_unexpected_tok : Error< + "unexpected %0 after expression; did you intend to use a compound " + "requirement (with '{' '}' around the expression)?">; +def warn_requires_expr_in_simple_requirement : Warning< + "this requires expression will only be checked for syntactic validity; did " + "you intend to place it in a nested requirement? (add another 'requires' " + "before the expression)">, InGroup<DiagGroup<"requires-expression">>; def err_missing_dependent_template_keyword : Error< "use 'template' keyword to treat '%0' as a dependent template name">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 7d8231d140e..82649ddf8ab 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2102,12 +2102,21 @@ def err_auto_not_allowed : Error< "|in template argument|in typedef|in type alias|in function return type" "|in conversion function type|here|in lambda parameter" "|in type allocated by 'new'|in K&R-style function parameter" - "|in template parameter|in friend declaration}1">; + "|in template parameter|in friend declaration" + "|in requires expression parameter}1">; +def err_auto_not_allowed_in_return_type_requirement : Error< + "%select{'auto'|'decltype(auto)'|'__auto_type'}0 not allowed in expression " + "type requirement">; def err_dependent_deduced_tst : Error< "typename specifier refers to " "%select{class template|function template|variable template|alias template|" "template template parameter|template}0 member in %1; " "argument deduction not allowed here">; +def err_deduced_tst : Error< + "typename specifier refers to " + "%select{class template|function template|variable template|alias template|" + "template template parameter|template}0; argument deduction not allowed " + "here">; def err_auto_not_allowed_var_inst : Error< "'auto' variable template instantiation is not allowed">; def err_auto_var_requires_init : Error< @@ -2590,19 +2599,56 @@ def note_constraints_not_satisfied : Note< def note_substituted_constraint_expr_is_ill_formed : Note< "because substituted constraint expression is ill-formed%0">; def note_atomic_constraint_evaluated_to_false : Note< - "%select{and |because }0'%1' evaluated to false">; + "%select{and|because}0 '%1' evaluated to false">; def note_concept_specialization_constraint_evaluated_to_false : Note< - "%select{and |because }0'%1' evaluated to false">; + "%select{and|because}0 '%1' evaluated to false">; def note_single_arg_concept_specialization_constraint_evaluated_to_false : Note< - "%select{and |because }0%1 does not satisfy %2">; + "%select{and|because}0 %1 does not satisfy %2">; def note_atomic_constraint_evaluated_to_false_elaborated : Note< - "%select{and |because }0'%1' (%2 %3 %4) evaluated to false">; + "%select{and|because}0 '%1' (%2 %3 %4) evaluated to false">; def err_constrained_virtual_method : Error< "virtual function cannot have a requires clause">; def err_trailing_requires_clause_on_deduction_guide : Error< "deduction guide cannot have a requires clause">; def err_reference_to_function_with_unsatisfied_constraints : Error< "invalid reference to function %0: constraints not satisfied">; +def note_requires_expr_ill_formed_expr : Note< + "expression is invalid: %0">; +def note_requires_expr_no_implicit_conversion : Note< + "no implicit conversion exists between expression type %0 and expected type " + "%1">; +def err_requires_expr_local_parameter_default_argument : Error< + "default arguments not allowed for parameters of a requires expression">; +def err_requires_expr_parameter_referenced_in_evaluated_context : Error< + "constraint variable %0 cannot be used in an evaluated context">; +def note_expr_requirement_expr_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid: %2">; +def note_expr_requirement_expr_unknown_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid">; +def note_expr_requirement_noexcept_not_met : Note< + "%select{and|because}0 '%1' may throw an exception">; +def note_expr_requirement_type_requirement_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid: %2">; +def note_expr_requirement_type_requirement_unknown_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid">; +def note_expr_requirement_constraints_not_satisfied : Note< + "%select{and|because}0 type constraint '%1' was not satisfied:">; +def note_expr_requirement_constraints_not_satisfied_simple : Note< + "%select{and|because}0 %1 does not satisfy %2:">; +def note_type_requirement_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid: %2">; +def note_type_requirement_unknown_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid">; +def err_type_requirement_non_type_template : Error< + "'%0' refers to a %select{class template|function template|" + "variable template|alias template|template template parameter|template}1, " + "not a type template">; +def err_type_requirement_no_such_type : Error< + "'%0' does not name a type">; +def note_nested_requirement_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid: %2">; +def note_nested_requirement_unknown_substitution_error : Note< + "%select{and|because}0 '%1' would be invalid">; def note_ambiguous_atomic_constraints : Note< "similar constraint expressions not considered equivalent; constraint " "expressions cannot be considered equivalent unless they originate from the " @@ -4588,6 +4634,8 @@ def note_template_type_alias_instantiation_here : Note< "in instantiation of template type alias %0 requested here">; def note_template_exception_spec_instantiation_here : Note< "in instantiation of exception specification for %0 requested here">; +def note_template_requirement_instantiation_here : Note< + "in instantiation of requirement here">; def warn_var_template_missing : Warning<"instantiation of variable %q0 " "required here, but no definition is available">, InGroup<UndefinedVarTemplate>; @@ -4623,6 +4671,8 @@ def note_template_default_arg_checking : Note< "while checking a default template argument used here">; def note_concept_specialization_here : Note< "while checking the satisfaction of concept '%0' requested here">; +def note_nested_requirement_here : Note< + "while checking the satisfaction of nested requirement requested here">; def note_checking_constraints_for_template_id_here : Note< "while checking constraint satisfaction for template '%0' required here">; def note_checking_constraints_for_var_spec_id_here : Note< @@ -4756,8 +4806,12 @@ def err_typename_nested_not_found_requirement : Error< "declaration">; def err_typename_nested_not_type : Error< "typename specifier refers to non-type member %0 in %1">; -def note_typename_refers_here : Note< +def err_typename_not_type : Error< + "typename specifier refers to non-type %0">; +def note_typename_member_refers_here : Note< "referenced member %0 is declared here">; +def note_typename_refers_here : Note< + "referenced %0 is declared here">; def err_typename_missing : Error< "missing 'typename' prior to dependent type name '%0%1'">; def err_typename_missing_template : Error< diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 294993298a1..41923cddc49 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -164,6 +164,7 @@ def CoyieldExpr : StmtNode<CoroutineSuspendExpr>; // C++2a Concepts expressions def ConceptSpecializationExpr : StmtNode<Expr>; +def RequiresExpr : StmtNode<Expr>; // Obj-C Expressions. def ObjCStringLiteral : StmtNode<Expr>; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 182024ea510..41f46861d08 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1933,6 +1933,7 @@ private: //===--------------------------------------------------------------------===// // C++ Concepts + ExprResult ParseRequiresExpression(); void ParseTrailingRequiresClause(Declarator &D); //===--------------------------------------------------------------------===// @@ -2771,7 +2772,7 @@ private: Declarator &D, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo); void ParseParameterDeclarationClause( - Declarator &D, + DeclaratorContext DeclaratorContext, ParsedAttributes &attrs, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo, SourceLocation &EllipsisLoc); diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index aceec9cbe1c..1222549161e 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1757,7 +1757,8 @@ enum class DeclaratorContext { TemplateArgContext, // Any template argument (in template argument list). TemplateTypeArgContext, // Template type argument (in default argument). AliasDeclContext, // C++11 alias-declaration. - AliasTemplateContext // C++11 alias-declaration template. + AliasTemplateContext, // C++11 alias-declaration template. + RequiresExprContext // C++2a requires-expression. }; @@ -1981,6 +1982,7 @@ public: case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TrailingReturnContext: case DeclaratorContext::TrailingReturnVarContext: + case DeclaratorContext::RequiresExprContext: return true; } llvm_unreachable("unknown context kind!"); @@ -2003,6 +2005,7 @@ public: case DeclaratorContext::TemplateParamContext: case DeclaratorContext::CXXCatchContext: case DeclaratorContext::ObjCCatchContext: + case DeclaratorContext::RequiresExprContext: return true; case DeclaratorContext::TypeNameContext: @@ -2039,6 +2042,7 @@ public: case DeclaratorContext::MemberContext: case DeclaratorContext::PrototypeContext: case DeclaratorContext::TemplateParamContext: + case DeclaratorContext::RequiresExprContext: // Maybe one day... return false; @@ -2116,6 +2120,7 @@ public: case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TrailingReturnContext: + case DeclaratorContext::RequiresExprContext: return false; } llvm_unreachable("unknown context kind!"); @@ -2337,6 +2342,7 @@ public: case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TrailingReturnContext: case DeclaratorContext::TrailingReturnVarContext: + case DeclaratorContext::RequiresExprContext: return false; } llvm_unreachable("unknown context kind!"); @@ -2370,6 +2376,7 @@ public: case DeclaratorContext::TrailingReturnContext: case DeclaratorContext::TrailingReturnVarContext: case DeclaratorContext::TemplateTypeArgContext: + case DeclaratorContext::RequiresExprContext: return false; case DeclaratorContext::BlockContext: diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4789fad8956..0f02c0f9d2b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -21,6 +21,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExternalASTSource.h" @@ -6282,13 +6283,17 @@ public: /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied. + /// \param First whether this is the first time an unsatisfied constraint is + /// diagnosed for this error. void - DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction); + DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction &Satisfaction, + bool First = true); /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied. void - DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction& Satisfaction); + DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction &Satisfaction, + bool First = true); /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied because it was ill-formed. @@ -7262,7 +7267,17 @@ public: SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, - SourceLocation IILoc); + SourceLocation IILoc, + TypeSourceInfo **TSI, + bool DeducedTSTContext); + + QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, + SourceLocation KeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo &II, + SourceLocation IILoc, + bool DeducedTSTContext = true); + TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, SourceLocation Loc, @@ -7282,11 +7297,52 @@ public: const TemplateArgument *Args, unsigned NumArgs); - // Concepts + //===--------------------------------------------------------------------===// + // C++ Concepts + //===--------------------------------------------------------------------===// Decl *ActOnConceptDefinition( Scope *S, MultiTemplateParamsArg TemplateParameterLists, IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr); + RequiresExprBodyDecl * + ActOnStartRequiresExpr(SourceLocation RequiresKWLoc, + ArrayRef<ParmVarDecl *> LocalParameters, + Scope *BodyScope); + void ActOnFinishRequiresExpr(); + concepts::Requirement *ActOnSimpleRequirement(Expr *E); + concepts::Requirement *ActOnTypeRequirement( + SourceLocation TypenameKWLoc, CXXScopeSpec &SS, SourceLocation NameLoc, + IdentifierInfo *TypeName, TemplateIdAnnotation *TemplateId); + concepts::Requirement *ActOnCompoundRequirement(Expr *E, + SourceLocation NoexceptLoc); + concepts::Requirement * + ActOnCompoundRequirement( + Expr *E, SourceLocation NoexceptLoc, CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstraint, unsigned Depth); + concepts::Requirement *ActOnNestedRequirement(Expr *Constraint); + concepts::ExprRequirement * + BuildExprRequirement( + Expr *E, bool IsSatisfied, SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement); + concepts::ExprRequirement * + BuildExprRequirement( + concepts::Requirement::SubstitutionDiagnostic *ExprSubstDiag, + bool IsSatisfied, SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement); + concepts::TypeRequirement *BuildTypeRequirement(TypeSourceInfo *Type); + concepts::TypeRequirement * + BuildTypeRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag); + concepts::NestedRequirement *BuildNestedRequirement(Expr *E); + concepts::NestedRequirement * + BuildNestedRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag); + ExprResult ActOnRequiresExpr(SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, + ArrayRef<ParmVarDecl *> LocalParameters, + ArrayRef<concepts::Requirement *> Requirements, + SourceLocation ClosingBraceLoc); + //===--------------------------------------------------------------------===// // C++ Variadic Templates (C++0x [temp.variadic]) //===--------------------------------------------------------------------===// @@ -7933,6 +7989,13 @@ public: /// template which was deferred until it was needed. ExceptionSpecInstantiation, + /// We are instantiating a requirement of a requires expression. + RequirementInstantiation, + + /// We are checking the satisfaction of a nested requirement of a requires + /// expression. + NestedRequirementConstraintsCheck, + /// We are declaring an implicit special member function. DeclaringSpecialMember, @@ -8254,6 +8317,19 @@ public: ParameterMappingSubstitution, NamedDecl *Template, SourceRange InstantiationRange); + /// \brief Note that we are substituting template arguments into a part of + /// a requirement of a requires expression. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + concepts::Requirement *Req, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are checking the satisfaction of the constraint + /// expression inside of a nested requirement. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + concepts::NestedRequirement *Req, ConstraintsCheck, + SourceRange InstantiationRange = SourceRange()); + /// Note that we have finished instantiating this template. void Clear(); diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h index acd1e604211..7fc42a4816e 100644 --- a/clang/include/clang/Sema/SemaConcept.h +++ b/clang/include/clang/Sema/SemaConcept.h @@ -13,10 +13,17 @@ #ifndef LLVM_CLANG_SEMA_SEMACONCEPT_H #define LLVM_CLANG_SEMA_SEMACONCEPT_H +#include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" +#include <string> +#include <utility> + namespace clang { class Sema; diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 1bfcbda8c9f..44a12c875da 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1403,6 +1403,9 @@ namespace serialization { /// An LifetimeExtendedTemporaryDecl record. DECL_LIFETIME_EXTENDED_TEMPORARY, + /// A RequiresExprBodyDecl record. + DECL_REQUIRES_EXPR_BODY, + /// An ObjCTypeParamDecl record. DECL_OBJC_TYPE_PARAM, @@ -1785,6 +1788,7 @@ namespace serialization { EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr EXPR_CXX_FOLD, // CXXFoldExpr EXPR_CONCEPT_SPECIALIZATION,// ConceptSpecializationExpr + EXPR_REQUIRES, // RequiresExpr // CUDA EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr |

