Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -287,12 +287,16 @@ TemplateTemplateParmDecl *getParam() const { return Parm; } - void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Parm); } + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) { + Profile(ID, C, Parm); + } static void Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &C, TemplateTemplateParmDecl *Parm); }; - mutable llvm::FoldingSet + mutable llvm::ContextualFoldingSet CanonTemplateTemplateParms; TemplateTemplateParmDecl * Index: include/clang/AST/ASTNodeTraverser.h =================================================================== --- include/clang/AST/ASTNodeTraverser.h +++ include/clang/AST/ASTNodeTraverser.h @@ -493,6 +493,10 @@ } void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { + if (const auto *TC = D->getTypeConstraint()) + if (TC->wereArgumentsSpecified()) + for (const auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments()) + dumpTemplateArgumentLoc(ArgLoc); if (D->hasDefaultArgument()) Visit(D->getDefaultArgument(), SourceRange(), D->getDefaultArgStorage().getInheritedFrom(), @@ -500,6 +504,8 @@ } void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { + if (const auto *TC = D->getPlaceholderTypeConstraint()) + Visit(TC->getImmediatelyDeclaredConstraint()); if (D->hasDefaultArgument()) Visit(D->getDefaultArgument(), SourceRange(), D->getDefaultArgStorage().getInheritedFrom(), Index: include/clang/AST/DeclTemplate.h =================================================================== --- include/clang/AST/DeclTemplate.h +++ include/clang/AST/DeclTemplate.h @@ -51,6 +51,7 @@ class TemplateDecl; class TemplateTemplateParmDecl; class TemplateTypeParmDecl; +class ConceptDecl; class UnresolvedSetImpl; class VarTemplateDecl; class VarTemplatePartialSpecializationDecl; @@ -81,20 +82,24 @@ /// pack. unsigned ContainsUnexpandedParameterPack : 1; - /// Whether this template parameter list has an associated requires-clause + /// Whether this template parameter list has a requires clause. unsigned HasRequiresClause : 1; + /// Whether any of the template parameters has constrained-parameter + /// constraint-expression. + unsigned HasConstrainedParameters : 1; + protected: - TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc, - ArrayRef Params, SourceLocation RAngleLoc, - Expr *RequiresClause); + TemplateParameterList(const ASTContext& C, SourceLocation TemplateLoc, + SourceLocation LAngleLoc, ArrayRef Params, + SourceLocation RAngleLoc, Expr *RequiresClause); size_t numTrailingObjects(OverloadToken) const { return NumParams; } size_t numTrailingObjects(OverloadToken) const { - return HasRequiresClause; + return HasRequiresClause ? 1 : 0; } public: @@ -158,14 +163,22 @@ return ContainsUnexpandedParameterPack; } + /// Determine whether this template parameter list contains a parameter pack. + bool hasParameterPack() const { + for (const NamedDecl *P : asArray()) + if (P->isParameterPack()) + return true; + return false; + } + /// The constraint-expression of the associated requires-clause. Expr *getRequiresClause() { - return HasRequiresClause ? *getTrailingObjects() : nullptr; + return HasRequiresClause ? getTrailingObjects()[0] : nullptr; } /// The constraint-expression of the associated requires-clause. const Expr *getRequiresClause() const { - return HasRequiresClause ? *getTrailingObjects() : nullptr; + return HasRequiresClause ? getTrailingObjects()[0] : nullptr; } /// \brief All associated constraints derived from this template parameter @@ -203,15 +216,16 @@ >::type storage; public: - FixedSizeTemplateParameterListStorage(SourceLocation TemplateLoc, + FixedSizeTemplateParameterListStorage(const ASTContext &C, + SourceLocation TemplateLoc, SourceLocation LAngleLoc, ArrayRef Params, SourceLocation RAngleLoc, Expr *RequiresClause) : FixedSizeStorageOwner( (assert(N == Params.size()), - assert(HasRequiresClause == static_cast(RequiresClause)), - new (static_cast(&storage)) TemplateParameterList( + assert(HasRequiresClause == (RequiresClause != nullptr)), + new (static_cast(&storage)) TemplateParameterList(C, TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause))) {} }; @@ -1085,15 +1099,113 @@ unsigned getIndex() const { return Position; } }; +/// \brief Common data class for constructs that reference concepts with +/// template arguments. +class ConceptReference { +protected: + // \brief The optional nested name specifier used when naming the concept. + NestedNameSpecifierLoc NestedNameSpec; + + /// \brief The location of the template keyword, if specified when naming the + /// concept. + SourceLocation TemplateKWLoc; + + /// \brief The concept name used. + DeclarationNameInfo ConceptName; + + /// \brief The declaration found by name lookup when the expression was + /// created. + /// Can differ from NamedConcept when, for example, the concept was found + /// through a UsingShadowDecl. + NamedDecl *FoundDecl; + + /// \brief The concept named. + ConceptDecl *NamedConcept; + + /// \brief The template argument list source info used to specialize the + /// concept. + const ASTTemplateArgumentListInfo *ArgsAsWritten; + +public: + + ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, + DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, + const ASTTemplateArgumentListInfo *ArgsAsWritten) : + NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc), + ConceptName(ConceptNameInfo), FoundDecl(FoundDecl), + NamedConcept(NamedConcept), ArgsAsWritten(ArgsAsWritten) {} + + ConceptReference() : NestedNameSpec(), TemplateKWLoc(), ConceptName(), + FoundDecl(nullptr), NamedConcept(nullptr), ArgsAsWritten(nullptr) {} + + const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { + return NestedNameSpec; + } + + const DeclarationNameInfo &getConceptNameInfo() const { return ConceptName; } + + SourceLocation getConceptNameLoc() const { + return getConceptNameInfo().getLoc(); + } + + SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; } + + NamedDecl *getFoundDecl() const { + return FoundDecl; + } + + ConceptDecl *getNamedConcept() const { + return NamedConcept; + } + + const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { + return ArgsAsWritten; + } +}; + +class TypeConstraint : public ConceptReference { + /// \brief The immediately-declared constraint expression introduced by this + /// type-constraint. + Expr *ImmediatelyDeclaredConstraint = nullptr; + +public: + TypeConstraint(NestedNameSpecifierLoc NNS, + DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + Expr *ImmediatelyDeclaredConstraint) : + ConceptReference(NNS, /*TemplateKWLoc=*/SourceLocation(), ConceptNameInfo, + FoundDecl, NamedConcept, ArgsAsWritten), + ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint) {} + + /// \brief Whether or not template arguments were specified in the type + // constraint construct. + bool wereArgumentsSpecified() const { + return ArgsAsWritten != nullptr; + } + + /// \brief Get the immediately-declared constraint expression introduced by + /// this type-constraint, that is - the constraint expression that is added to + /// the associated constraints of the enclosing declaration in practice. + Expr *getImmediatelyDeclaredConstraint() const { + return ImmediatelyDeclaredConstraint; + } + + void print(llvm::raw_ostream &OS, PrintingPolicy Policy) const; +}; + /// Declaration of a template type parameter. /// /// For example, "T" in /// \code /// template class vector; /// \endcode -class TemplateTypeParmDecl : public TypeDecl { +class TemplateTypeParmDecl final : public TypeDecl, + private llvm::TrailingObjects { /// Sema creates these on the stack during auto type deduction. friend class Sema; + friend TrailingObjects; /// Whether this template type parameter was declaration with /// the 'typename' keyword. @@ -1101,6 +1213,14 @@ /// If false, it was declared with the 'class' keyword. bool Typename : 1; + /// Whether this template type parameter has a type-constraint construct. + bool HasTypeConstraint : 1; + + /// Whether the type constraint has been initialized. This can be false if the + /// constraint was not initialized yet or if there was an error forming the + /// type constriant. + bool TypeConstraintInitialized : 1; + /// The default template argument, if any. using DefArgStorage = DefaultArgStorage; @@ -1108,8 +1228,9 @@ TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc, SourceLocation IdLoc, IdentifierInfo *Id, - bool Typename) - : TypeDecl(TemplateTypeParm, DC, IdLoc, Id, KeyLoc), Typename(Typename) {} + bool Typename, bool HasTypeConstraint) + : TypeDecl(TemplateTypeParm, DC, IdLoc, Id, KeyLoc), Typename(Typename), + HasTypeConstraint(HasTypeConstraint), TypeConstraintInitialized(false) {} public: static TemplateTypeParmDecl *Create(const ASTContext &C, DeclContext *DC, @@ -1117,15 +1238,22 @@ SourceLocation NameLoc, unsigned D, unsigned P, IdentifierInfo *Id, bool Typename, - bool ParameterPack); + bool ParameterPack, + bool HasTypeConstraint); static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C, unsigned ID); + static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C, + unsigned ID, + bool HasTypeConstraint); /// Whether this template type parameter was declared with /// the 'typename' keyword. /// - /// If not, it was declared with the 'class' keyword. - bool wasDeclaredWithTypename() const { return Typename; } + /// If not, it was either declared with the 'class' keyword or with a + /// type-constraint (see hasTypeConstraint()). + bool wasDeclaredWithTypename() const { + return Typename && !HasTypeConstraint; + } const DefArgStorage &getDefaultArgStorage() const { return DefaultArgument; } @@ -1182,6 +1310,34 @@ /// Returns whether this is a parameter pack. bool isParameterPack() const; + /// Returns the type constraint associated with this template parameter (if + /// any). + const TypeConstraint *getTypeConstraint() const { + return TypeConstraintInitialized ? getTrailingObjects() : + nullptr; + } + + void setTypeConstraint(NestedNameSpecifierLoc NNS, + DeclarationNameInfo NameInfo, NamedDecl *FoundDecl, + ConceptDecl *CD, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + Expr *ImmediatelyDeclaredConstraint); + + /// Determine whether this template parameter has a type-constraint. + bool hasTypeConstraint() const { + return HasTypeConstraint; + } + + /// \brief Get the associated-constraints of this template parameter. + /// This will either be the immediately-introduced constraint or empty. + /// + /// Use this instead of getConstraintExpression for concepts APIs that + /// accept an ArrayRef of constraint expressions. + void getAssociatedConstraints(llvm::SmallVectorImpl &AC) const { + if (HasTypeConstraint) + AC.push_back(getTypeConstraint()->getImmediatelyDeclaredConstraint()); + } + SourceRange getSourceRange() const override LLVM_READONLY; // Implement isa/cast/dyncast/etc. @@ -1367,6 +1523,33 @@ return TypesAndInfos[I].second; } + /// Return the type-constraint in the placeholder type of this non-type + /// template parameter (if any). + TypeConstraint *getPlaceholderTypeConstraint() const { + // TODO: Concepts: Implement once we have actual placeholders with type + // constraints. + return nullptr; + } + + /// Determine whether this non-type template parameter's type has a + /// placeholder with a type-constraint. + bool hasPlaceholderTypeConstraint() const { + // TODO: Concepts: Implement once we have actual placeholders with type + // constraints. + return false; + } + + /// \brief Get the associated-constraints of this template parameter. + /// This will either be a vector of size 1 containing the immediately-declared + /// constraint introduced by the placeholder type, or an empty vector. + /// + /// Use this instead of getPlaceholderImmediatelyDeclaredConstraint for + /// concepts APIs that accept an ArrayRef of constraint expressions. + void getAssociatedConstraints(llvm::SmallVectorImpl &AC) const { + if (TypeConstraint *TC = getPlaceholderTypeConstraint()) + AC.push_back(TC->getImmediatelyDeclaredConstraint()); + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == NonTypeTemplateParm; } @@ -3030,6 +3213,10 @@ ConstraintExpr->getEndLoc()); } + bool isTypeConcept() const { + return isa(getTemplateParameters()->getParam(0)); + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Concept; } Index: include/clang/AST/ExprCXX.h =================================================================== --- include/clang/AST/ExprCXX.h +++ include/clang/AST/ExprCXX.h @@ -4529,7 +4529,7 @@ /// /// 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, +class ConceptSpecializationExpr final : public Expr, public ConceptReference, private llvm::TrailingObjects { friend class ASTStmtReader; @@ -4538,30 +4538,6 @@ using SubstitutionDiagnostic = std::pair; protected: - - // \brief The optional nested name specifier used when naming the concept. - NestedNameSpecifierLoc NestedNameSpec; - - /// \brief The location of the template keyword, if specified when naming the - /// concept. - SourceLocation TemplateKWLoc; - - /// \brief The location of the concept name in the expression. - SourceLocation ConceptNameLoc; - - /// \brief The declaration found by name lookup when the expression was - /// created. - /// Can differ from NamedConcept when, for example, the concept was found - /// through a UsingShadowDecl. - NamedDecl *FoundDecl; - - /// \brief The concept named. - ConceptDecl *NamedConcept; - - /// \brief The template argument list source info used to specialize the - /// concept. - const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr; - /// \brief The number of template arguments in the tail-allocated list of /// converted template arguments. unsigned NumTemplateArgs; @@ -4571,10 +4547,10 @@ /// ignored. ConstraintSatisfaction Satisfaction; - ConceptSpecializationExpr(ASTContext &C, NestedNameSpecifierLoc NNS, + ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, - SourceLocation ConceptNameLoc, NamedDecl *FoundDecl, - ConceptDecl *NamedConcept, + DeclarationNameInfo ConceptNameInfo, + NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, ArrayRef ConvertedArgs, ConstraintSatisfaction Satisfaction); @@ -4584,8 +4560,8 @@ public: static ConceptSpecializationExpr * - Create(ASTContext &C, NestedNameSpecifierLoc NNS, - SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc, + Create(const ASTContext &C, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, ArrayRef ConvertedArgs, @@ -4594,27 +4570,11 @@ static ConceptSpecializationExpr * Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs); - const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { - return NestedNameSpec; - } - - NamedDecl *getFoundDecl() const { - return FoundDecl; - } - - ConceptDecl *getNamedConcept() const { - return NamedConcept; - } - ArrayRef getTemplateArguments() const { return ArrayRef(getTrailingObjects(), NumTemplateArgs); } - const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { - return ArgsAsWritten; - } - /// \brief Set new template arguments for this concept specialization. void setTemplateArguments(const ASTTemplateArgumentListInfo *ArgsAsWritten, ArrayRef Converted); @@ -4641,15 +4601,14 @@ this->Satisfaction = std::move(Satisfaction); } - SourceLocation getConceptNameLoc() const { return ConceptNameLoc; } - - SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; } - static bool classof(const Stmt *T) { return T->getStmtClass() == ConceptSpecializationExprClass; } - SourceLocation getBeginLoc() const LLVM_READONLY { return ConceptNameLoc; } + SourceLocation getBeginLoc() const LLVM_READONLY { + return ConceptName.getBeginLoc(); + } + SourceLocation getEndLoc() const LLVM_READONLY { return ArgsAsWritten->RAngleLoc; } Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -1759,9 +1759,8 @@ // D is the "T" in something like // template