Index: include/clang/AST/DeclTemplate.h =================================================================== --- include/clang/AST/DeclTemplate.h +++ include/clang/AST/DeclTemplate.h @@ -368,8 +368,6 @@ /// \brief Stores the template parameter list and associated constraints for /// \c TemplateDecl objects that track associated constraints. class ConstrainedTemplateDeclInfo { - friend TemplateDecl; - public: ConstrainedTemplateDeclInfo() = default; @@ -379,13 +377,14 @@ Expr *getAssociatedConstraints() const { return AssociatedConstraints; } -protected: void setTemplateParameters(TemplateParameterList *TParams) { TemplateParams = TParams; } void setAssociatedConstraints(Expr *AC) { AssociatedConstraints = AC; } +protected: + TemplateParameterList *TemplateParams = nullptr; Expr *AssociatedConstraints = nullptr; }; @@ -400,54 +399,33 @@ void anchor() override; protected: + // Construct a template decl with name, parameters, and templated element. + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl); + // Construct a template decl with the given name and parameters. // Used when there is no templated element (e.g., for tt-params). - TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC, - SourceLocation L, DeclarationName Name, - TemplateParameterList *Params) - : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr), - TemplateParams(CTDI) { - this->setTemplateParameters(Params); - } - TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params) - : TemplateDecl(nullptr, DK, DC, L, Name, Params) {} - - // Construct a template decl with name, parameters, and templated element. - TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC, - SourceLocation L, DeclarationName Name, - TemplateParameterList *Params, NamedDecl *Decl) - : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl), - TemplateParams(CTDI) { - this->setTemplateParameters(Params); - } - - TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, - TemplateParameterList *Params, NamedDecl *Decl) - : TemplateDecl(nullptr, DK, DC, L, Name, Params, Decl) {} + : TemplateDecl(DK, DC, L, Name, Params, nullptr) {} public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + /// Get the list of template parameters TemplateParameterList *getTemplateParameters() const { const auto *const CTDI = - TemplateParams.dyn_cast(); + TemplateParams.getPointer().dyn_cast(); return CTDI ? CTDI->getTemplateParameters() - : TemplateParams.get(); - } - - /// Get the constraint-expression from the associated requires-clause (if any) - const Expr *getRequiresClause() const { - const TemplateParameterList *const TP = getTemplateParameters(); - return TP ? TP->getRequiresClause() : nullptr; + : TemplateParams.getPointer().get(); } - Expr *getAssociatedConstraints() const { - const TemplateDecl *const C = cast(getCanonicalDecl()); - const auto *const CTDI = - C->TemplateParams.dyn_cast(); - return CTDI ? CTDI->getAssociatedConstraints() : nullptr; - } + /// \brief Get the total constraint-expression associated with this template, + /// including constraint-expressions derived from the requires-clause, + /// trailing requires-clause (for functions and methods) and constrained + /// template parameters. + Expr *getAssociatedConstraints(); /// Get the underlying, templated declaration. NamedDecl *getTemplatedDecl() const { return TemplatedDecl; } @@ -466,38 +444,32 @@ protected: NamedDecl *TemplatedDecl; - /// \brief The template parameter list and optional requires-clause - /// associated with this declaration; alternatively, a - /// \c ConstrainedTemplateDeclInfo if the associated constraints of the - /// template are being tracked by this particular declaration. - llvm::PointerUnion - TemplateParams; + /// \brief If the int part is true, this declaration is the canonical + /// declaration, and the associated constraints for it have been calculated. + /// If any constraints were found, the pointer part will contain a + /// \c ConstrainedTemplateDeclInfo with the collected associated constraints. + /// Otherwise, this will just contain the template parameter list. + llvm::PointerIntPair, 1, + bool> TemplateParams; void setTemplateParameters(TemplateParameterList *TParams) { - if (auto *const CTDI = - TemplateParams.dyn_cast()) { + if (auto *const CTDI = TemplateParams.getPointer() + .dyn_cast()) { CTDI->setTemplateParameters(TParams); } else { - TemplateParams = TParams; + TemplateParams.setPointer(TParams); } } - void setAssociatedConstraints(Expr *AC) { - assert(isCanonicalDecl() && - "Attaching associated constraints to non-canonical Decl"); - TemplateParams.get() - ->setAssociatedConstraints(AC); - } - public: /// \brief Initialize the underlying templated declaration and /// template parameters. void init(NamedDecl *templatedDecl, TemplateParameterList* templateParams) { assert(!TemplatedDecl && "TemplatedDecl already set!"); - assert(!TemplateParams && "TemplateParams already set!"); + assert(!TemplateParams.getPointer() && "TemplateParams already set!"); TemplatedDecl = templatedDecl; - TemplateParams = templateParams; + TemplateParams.setPointer(templateParams); } }; @@ -822,17 +794,10 @@ virtual CommonBase *newCommon(ASTContext &C) const = 0; // Construct a template decl with name, parameters, and templated element. - RedeclarableTemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, - ASTContext &C, DeclContext *DC, SourceLocation L, - DeclarationName Name, TemplateParameterList *Params, - NamedDecl *Decl) - : TemplateDecl(CTDI, DK, DC, L, Name, Params, Decl), redeclarable_base(C) - {} - RedeclarableTemplateDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl) - : RedeclarableTemplateDecl(nullptr, DK, C, DC, L, Name, Params, Decl) {} + : TemplateDecl(DK, DC, L, Name, Params, Decl), redeclarable_base(C) {} public: friend class ASTDeclReader; @@ -1897,8 +1862,14 @@ class ClassTemplatePartialSpecializationDecl : public ClassTemplateSpecializationDecl { - /// \brief The list of template parameters - TemplateParameterList* TemplateParams = nullptr; + /// \brief If the int part is true, this declaration is the canonical + /// declaration, and the associated constraints for it have been calculated. + /// If any constraints were found, the pointer part will contain a + /// \c ConstrainedTemplateDeclInfo with the collected associated constraints. + /// Otherwise, this will just contain the template parameter list. + llvm::PointerIntPair, 1, + bool> TemplateParams; /// \brief The source info for the template arguments as written. /// FIXME: redundant with TypeAsWritten? @@ -1953,9 +1924,18 @@ /// Get the list of template parameters TemplateParameterList *getTemplateParameters() const { - return TemplateParams; + const auto *const CTDI = + TemplateParams.getPointer().dyn_cast(); + return CTDI ? CTDI->getTemplateParameters() + : TemplateParams.getPointer().get(); } + /// \brief Get the total constraint-expression associated with this template, + /// including constraint-expressions derived from the requires-clause, + /// trailing requires-clause (for functions and methods) and constrained + /// template parameters. + Expr *getAssociatedConstraints(); + /// Get the template arguments as written. const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { return ArgsAsWritten; @@ -2084,16 +2064,10 @@ llvm::FoldingSetVector & getPartialSpecializations(); - ClassTemplateDecl(ConstrainedTemplateDeclInfo *CTDI, ASTContext &C, - DeclContext *DC, SourceLocation L, DeclarationName Name, - TemplateParameterList *Params, NamedDecl *Decl) - : RedeclarableTemplateDecl(CTDI, ClassTemplate, C, DC, L, Name, Params, - Decl) {} - ClassTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl) - : ClassTemplateDecl(nullptr, C, DC, L, Name, Params, Decl) {} + : RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {} CommonBase *newCommon(ASTContext &C) const override; @@ -2125,8 +2099,7 @@ SourceLocation L, DeclarationName Name, TemplateParameterList *Params, - NamedDecl *Decl, - Expr *AssociatedConstraints = nullptr); + NamedDecl *Decl); /// \brief Create an empty class template node. static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -2740,8 +2713,14 @@ class VarTemplatePartialSpecializationDecl : public VarTemplateSpecializationDecl { - /// \brief The list of template parameters - TemplateParameterList *TemplateParams = nullptr; + /// \brief If the int part is true, this declaration is the canonical + /// declaration, and the associated constraints for it have been calculated. + /// If any constraints were found, the pointer part will contain a + /// \c ConstrainedTemplateDeclInfo with the collected associated constraints. + /// Otherwise, this will just contain the template parameter list. + llvm::PointerIntPair, 1, + bool> TemplateParams; /// \brief The source info for the template arguments as written. /// FIXME: redundant with TypeAsWritten? @@ -2791,7 +2770,10 @@ /// Get the list of template parameters TemplateParameterList *getTemplateParameters() const { - return TemplateParams; + const auto *const CTDI = + TemplateParams.getPointer().dyn_cast(); + return CTDI ? CTDI->getTemplateParameters() + : TemplateParams.getPointer().get(); } /// Get the template arguments as written. @@ -2799,6 +2781,12 @@ return ArgsAsWritten; } + /// \brief Get the total constraint-expression associated with this template, + /// including constraint-expressions derived from the requires-clause, + /// trailing requires-clause (for functions and methods) and constrained + /// template parameters. + Expr *getAssociatedConstraints(); + /// \brief Retrieve the member variable template partial specialization from /// which this particular variable template partial specialization was /// instantiated. @@ -3037,11 +3025,9 @@ protected: Expr *ConstraintExpr; - ConceptDecl(DeclContext *DC, - SourceLocation L, DeclarationName Name, - TemplateParameterList *Params, - Expr *ConstraintExpr) - : TemplateDecl(nullptr, Concept, DC, L, Name, Params), + ConceptDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, Expr *ConstraintExpr) + : TemplateDecl(Concept, DC, L, Name, Params), ConstraintExpr(ConstraintExpr) {}; public: static ConceptDecl *Create(ASTContext &C, DeclContext *DC, Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -1594,9 +1594,11 @@ bool RecursiveASTVisitor::TraverseTemplateParameterListHelper( TemplateParameterList *TPL) { if (TPL) { - for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); - I != E; ++I) { - TRY_TO(TraverseDecl(*I)); + for (NamedDecl *D : *TPL) { + TRY_TO(TraverseDecl(D)); + } + if (Expr *RequiresClause = TPL->getRequiresClause()) { + TRY_TO(TraverseStmt(RequiresClause)); } } return true; Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -5581,7 +5581,12 @@ /// A diagnostic is emitted if it is not, and false is returned. bool CheckConstraintExpression(Expr *CE); - // ParseObjCStringLiteral - Parse Objective-C string literals. + /// \brief Check that the associated constraints of a template declaration + /// match the associated constraints of an older declaration of which it is a + /// redeclaration + bool CheckRedeclarationConstraintMatch(const Expr *OldAC, const Expr *NewAC); + + // ParseObjCStringLiteral - Parse Objective-C string literals. ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ArrayRef Strings); Index: lib/AST/DeclTemplate.cpp =================================================================== --- lib/AST/DeclTemplate.cpp +++ lib/AST/DeclTemplate.cpp @@ -70,6 +70,8 @@ } if (RequiresClause) { *getTrailingObjects() = RequiresClause; + if (RequiresClause->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; } } @@ -146,6 +148,65 @@ } // namespace clang +static ConstrainedTemplateDeclInfo * +collectAssociatedConstraints(ASTContext& C, TemplateParameterList *Params) { + // TODO: Instead of calling getRequiresClause - write and call a + // TemplateParameterList member function calculateAssociatedConstraints, which + // will also fetch constraint-expressions from constrained-parameters. + Expr *AssociatedConstraints = Params->getRequiresClause(); + // TODO: Collect function requires clause, if any. + if (AssociatedConstraints) { + ConstrainedTemplateDeclInfo *CTDI = new (C) ConstrainedTemplateDeclInfo; + CTDI->setAssociatedConstraints(AssociatedConstraints); + CTDI->setTemplateParameters(Params); + return CTDI; + } + return nullptr; +} + +// This function exists outside TemplateDecl because +// '*TemplatePartialSpecializationDecls' need this code too, and are not derived +// from the former. +Expr * +getOrCollectAssociatedConstraints(ASTContext& C, + llvm::PointerIntPair< + llvm::PointerUnion, + 1, bool>& TemplateParamsMember) { + if (!TemplateParamsMember.getInt()) { + TemplateParamsMember.setInt(true); + ConstrainedTemplateDeclInfo *CTDI = + collectAssociatedConstraints(C, TemplateParamsMember.getPointer() + .get()); + if (CTDI) { + TemplateParamsMember.setPointer(CTDI); + return CTDI->getAssociatedConstraints(); + } + return nullptr; + } + const auto *const CTDI = TemplateParamsMember.getPointer() + .dyn_cast(); + return CTDI ? CTDI->getAssociatedConstraints() : nullptr; +} + +//===----------------------------------------------------------------------===// +// TemplateDecl Implementation +//===----------------------------------------------------------------------===// + +TemplateDecl::TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName Name, TemplateParameterList *Params, + NamedDecl *Decl) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl), + TemplateParams(Params, false) {} + + +Expr *TemplateDecl::getAssociatedConstraints() { + return getOrCollectAssociatedConstraints(getASTContext(), + cast(getCanonicalDecl())->TemplateParams); +} + +void TemplateDecl::anchor() {} + //===----------------------------------------------------------------------===// // RedeclarableTemplateDecl Implementation //===----------------------------------------------------------------------===// @@ -308,19 +369,10 @@ SourceLocation L, DeclarationName Name, TemplateParameterList *Params, - NamedDecl *Decl, - Expr *AssociatedConstraints) { + NamedDecl *Decl) { AdoptTemplateParameterList(Params, cast(Decl)); - if (!AssociatedConstraints) { - return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl); - } - - ConstrainedTemplateDeclInfo *const CTDI = new (C) ConstrainedTemplateDeclInfo; - ClassTemplateDecl *const New = - new (C, DC) ClassTemplateDecl(CTDI, C, DC, L, Name, Params, Decl); - New->setAssociatedConstraints(AssociatedConstraints); - return New; + return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl); } ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, @@ -680,12 +732,6 @@ POI); } -//===----------------------------------------------------------------------===// -// TemplateDecl Implementation -//===----------------------------------------------------------------------===// - -void TemplateDecl::anchor() {} - //===----------------------------------------------------------------------===// // ClassTemplateSpecializationDecl Implementation //===----------------------------------------------------------------------===// @@ -838,8 +884,8 @@ ClassTemplatePartialSpecialization, TK, DC, StartLoc, IdLoc, SpecializedTemplate, Args, PrevDecl), - TemplateParams(Params), ArgsAsWritten(ArgInfos), - InstantiatedFromMember(nullptr, false) { + TemplateParams(Params, false), + ArgsAsWritten(ArgInfos), InstantiatedFromMember(nullptr, false) { AdoptTemplateParameterList(Params, this); } @@ -876,6 +922,12 @@ return Result; } +Expr* ClassTemplatePartialSpecializationDecl::getAssociatedConstraints() { + return getOrCollectAssociatedConstraints(getASTContext(), + cast(getCanonicalDecl()) + ->TemplateParams); +} + //===----------------------------------------------------------------------===// // FriendTemplateDecl Implementation //===----------------------------------------------------------------------===// @@ -1131,7 +1183,7 @@ : VarTemplateSpecializationDecl(VarTemplatePartialSpecialization, Context, DC, StartLoc, IdLoc, SpecializedTemplate, T, TInfo, S, Args), - TemplateParams(Params), ArgsAsWritten(ArgInfos), + TemplateParams(Params, false), ArgsAsWritten(ArgInfos), InstantiatedFromMember(nullptr, false) { // TODO: The template parameters should be in DC by now. Verify. // AdoptTemplateParameterList(Params, DC); @@ -1161,6 +1213,12 @@ return new (C, ID) VarTemplatePartialSpecializationDecl(C); } +Expr* VarTemplatePartialSpecializationDecl::getAssociatedConstraints() { + return getOrCollectAssociatedConstraints(getASTContext(), + cast(getCanonicalDecl()) + ->TemplateParams); +} + static TemplateParameterList * createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) { // typename T Index: lib/Sema/SemaConcept.cpp =================================================================== --- lib/Sema/SemaConcept.cpp +++ lib/Sema/SemaConcept.cpp @@ -41,4 +41,18 @@ } } return true; +} + +bool Sema::CheckRedeclarationConstraintMatch(const Expr *OldAC, + const Expr *NewAC) { + if (!(NewAC || OldAC)) + return true; // Nothing to check; no mismatch. + if (NewAC && OldAC) { + llvm::FoldingSetNodeID OldACInfo, NewACInfo; + NewAC->Profile(NewACInfo, Context, /*Canonical=*/true); + OldAC->Profile(OldACInfo, Context, /*Canonical=*/true); + if (NewACInfo == OldACInfo) + return true; // All good; no mismatch. + } + return false; } \ No newline at end of file Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -45,26 +45,6 @@ return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc()); } -namespace clang { -/// \brief [temp.constr.decl]p2: A template's associated constraints are -/// defined as a single constraint-expression derived from the introduced -/// constraint-expressions [ ... ]. -/// -/// \param Params The template parameter list and optional requires-clause. -/// -/// \param FD The underlying templated function declaration for a function -/// template. -static Expr *formAssociatedConstraints(TemplateParameterList *Params, - FunctionDecl *FD); -} - -static Expr *clang::formAssociatedConstraints(TemplateParameterList *Params, - FunctionDecl *FD) { - // FIXME: Concepts: collect additional introduced constraint-expressions - assert(!FD && "Cannot collect constraints from function declaration yet."); - return Params->getRequiresClause(); -} - /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns NULL. @@ -1269,9 +1249,6 @@ } } - // TODO Memory management; associated constraints are not always stored. - Expr *const CurAC = formAssociatedConstraints(TemplateParams, nullptr); - if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. Skip this check // for a friend in a dependent context: the template parameter list itself @@ -1283,29 +1260,6 @@ TPL_TemplateMatch)) return true; - // Check for matching associated constraints on redeclarations. - const Expr *const PrevAC = PrevClassTemplate->getAssociatedConstraints(); - const bool RedeclACMismatch = [&] { - if (!(CurAC || PrevAC)) - return false; // Nothing to check; no mismatch. - if (CurAC && PrevAC) { - llvm::FoldingSetNodeID CurACInfo, PrevACInfo; - CurAC->Profile(CurACInfo, Context, /*Canonical=*/true); - PrevAC->Profile(PrevACInfo, Context, /*Canonical=*/true); - if (CurACInfo == PrevACInfo) - return false; // All good; no mismatch. - } - return true; - }(); - - if (RedeclACMismatch) { - Diag(CurAC ? CurAC->getLocStart() : NameLoc, - diag::err_template_different_associated_constraints); - Diag(PrevAC ? PrevAC->getLocStart() : PrevClassTemplate->getLocation(), - diag::note_template_prev_declaration) << /*declaration*/0; - return true; - } - // C++ [temp.class]p4: // In a redeclaration, partial specialization, explicit // specialization or explicit instantiation of a class template, @@ -1408,15 +1362,10 @@ AddMsStructLayoutForRecord(NewClass); } - // Attach the associated constraints when the declaration will not be part of - // a decl chain. - Expr *const ACtoAttach = - PrevClassTemplate && ShouldAddRedecl ? nullptr : CurAC; - ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, - NewClass, ACtoAttach); + NewClass); if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); @@ -2001,6 +1950,19 @@ if (OldParams) OldParam = OldParams->begin(); + // TODO: Concepts: Replace getRequiresClause with getAssociatedConstraints + // when we have it. + if (OldParams && + !CheckRedeclarationConstraintMatch(OldParams->getRequiresClause(), + NewParams->getRequiresClause())) { + Diag(NewParams->getTemplateLoc(), + diag::err_template_different_associated_constraints); + Diag(OldParams->getTemplateLoc(), diag::note_template_prev_declaration) + << /*declaration*/0; + + Invalid = true; + } + bool RemoveDefaultArguments = false; for (TemplateParameterList::iterator NewParam = NewParams->begin(), NewParamEnd = NewParams->end(); @@ -2181,16 +2143,14 @@ // We were missing some default arguments at the end of the list, so remove // all of the default arguments. if (RemoveDefaultArguments) { - for (TemplateParameterList::iterator NewParam = NewParams->begin(), - NewParamEnd = NewParams->end(); - NewParam != NewParamEnd; ++NewParam) { - if (TemplateTypeParmDecl *TTP = dyn_cast(*NewParam)) + for (NamedDecl *NewParam : *NewParams) { + if (TemplateTypeParmDecl *TTP = dyn_cast(NewParam)) TTP->removeDefaultArgument(); else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast(*NewParam)) + = dyn_cast(NewParam)) NTTP->removeDefaultArgument(); else - cast(*NewParam)->removeDefaultArgument(); + cast(NewParam)->removeDefaultArgument(); } } Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3138,14 +3138,19 @@ if (Invalid) return nullptr; - // Note: we substitute into associated constraints later - Expr *const UninstantiatedRequiresClause = L->getRequiresClause(); + Expr *InstRequiresClause = nullptr; + if (Expr *E = L->getRequiresClause()) { + ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs); + if (Res.isInvalid() || !Res.isUsable()) { + return nullptr; + } + InstRequiresClause = Res.get(); + } TemplateParameterList *InstL = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(), L->getLAngleLoc(), Params, - L->getRAngleLoc(), - UninstantiatedRequiresClause); + L->getRAngleLoc(), InstRequiresClause); return InstL; } Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -8664,10 +8664,13 @@ Params.reserve(NumParams); while (NumParams--) Params.push_back(ReadDeclAs(F, Record, Idx)); + // TODO: Concepts: Constrained parameters + + bool HasRequiresClause = Record[Idx++]; + Expr *RequiresClause = HasRequiresClause ? ReadExpr(F) : nullptr; - // TODO: Concepts TemplateParameterList *TemplateParams = TemplateParameterList::Create( - getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, nullptr); + getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause); return TemplateParams; } Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -1965,7 +1965,6 @@ DeclID PatternID = ReadDeclID(); NamedDecl *TemplatedDecl = cast_or_null(Reader.GetDecl(PatternID)); TemplateParameterList *TemplateParams = Record.readTemplateParameterList(); - // FIXME handle associated constraints D->init(TemplatedDecl, TemplateParams); return PatternID; @@ -1991,6 +1990,7 @@ // If this is the first declaration of the template, fill in the information // for the 'common' pointer. + Expr *AssociatedConstraints = nullptr; if (ThisDeclID == Redecl.getFirstID()) { if (RedeclarableTemplateDecl *RTD = ReadDeclAs()) { @@ -2000,11 +2000,23 @@ if (Record.readInt()) D->setMemberSpecialization(); } + bool HasAssociatedConstraints = Record.readInt(); + if (HasAssociatedConstraints) { + AssociatedConstraints = Record.readExpr(); + } } DeclID PatternID = VisitTemplateDecl(D); D->IdentifierNamespace = Record.readInt(); + D->TemplateParams.setInt(true); + if (AssociatedConstraints) { + auto *CTDI = new (Reader.getContext()) ConstrainedTemplateDeclInfo; + CTDI->setTemplateParameters(D->getTemplateParameters()); + CTDI->setAssociatedConstraints(AssociatedConstraints); + D->TemplateParams.setPointer(CTDI); + } + mergeRedeclarable(D, Redecl, PatternID); // If we merged the template with a prior declaration chain, merge the common @@ -2132,7 +2144,8 @@ ClassTemplatePartialSpecializationDecl *D) { RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D); - D->TemplateParams = Record.readTemplateParameterList(); + TemplateParameterList *Params = Record.readTemplateParameterList(); + D->TemplateParams.setPointer(Params); D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); // These are read/set from/to the first declaration. @@ -2140,6 +2153,15 @@ D->InstantiatedFromMember.setPointer( ReadDeclAs()); D->InstantiatedFromMember.setInt(Record.readInt()); + bool HasAssociatedConstraints = Record.readInt(); + D->TemplateParams.setInt(true); + if (HasAssociatedConstraints) { + Expr *AssociatedConstraints = Record.readExpr(); + auto *CTDI = new (Reader.getContext()) ConstrainedTemplateDeclInfo; + CTDI->setTemplateParameters(Params); + CTDI->setAssociatedConstraints(AssociatedConstraints); + D->TemplateParams.setPointer(CTDI); + } } } @@ -2233,7 +2255,8 @@ VarTemplatePartialSpecializationDecl *D) { RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D); - D->TemplateParams = Record.readTemplateParameterList(); + TemplateParameterList *Params = Record.readTemplateParameterList(); + D->TemplateParams.setPointer(Params); D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); // These are read/set from/to the first declaration. @@ -2241,6 +2264,16 @@ D->InstantiatedFromMember.setPointer( ReadDeclAs()); D->InstantiatedFromMember.setInt(Record.readInt()); + + bool HasAssociatedConstraints = Record.readInt(); + D->TemplateParams.setInt(true); + if (HasAssociatedConstraints) { + Expr *AssociatedConstraints = Record.readExpr(); + auto *CTDI = new (Reader.getContext()) ConstrainedTemplateDeclInfo; + CTDI->setTemplateParameters(Params); + CTDI->setAssociatedConstraints(AssociatedConstraints); + D->TemplateParams.setPointer(CTDI); + } } } Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -5850,10 +5850,16 @@ AddSourceLocation(TemplateParams->getTemplateLoc()); AddSourceLocation(TemplateParams->getLAngleLoc()); AddSourceLocation(TemplateParams->getRAngleLoc()); - // TODO: Concepts + Record->push_back(TemplateParams->size()); for (const auto &P : *TemplateParams) - AddDeclRef(P); + AddDeclRef(P); // TODO: Concepts - constrained parameters. + if (const Expr *RequiresClause = TemplateParams->getRequiresClause()) { + Record->push_back(true); + AddStmt(const_cast(RequiresClause)); + } else { + Record->push_back(false); + } } /// \brief Emit a template argument list. Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -1402,6 +1402,12 @@ Record.AddDeclRef(D->getInstantiatedFromMemberTemplate()); if (D->getInstantiatedFromMemberTemplate()) Record.push_back(D->isMemberSpecialization()); + + Expr *AssociatedConstraints = D->getAssociatedConstraints(); + Record.push_back(AssociatedConstraints != nullptr); + if (AssociatedConstraints) { + Record.AddStmt(AssociatedConstraints); + } } VisitTemplateDecl(D); @@ -1463,6 +1469,11 @@ if (D->getPreviousDecl() == nullptr) { Record.AddDeclRef(D->getInstantiatedFromMember()); Record.push_back(D->isMemberSpecialization()); + Expr *AssociatedConstraints = D->getAssociatedConstraints(); + Record.push_back(AssociatedConstraints != nullptr); + if (AssociatedConstraints) { + Record.AddStmt(AssociatedConstraints); + } } Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION; @@ -1523,6 +1534,11 @@ if (D->getPreviousDecl() == nullptr) { Record.AddDeclRef(D->getInstantiatedFromMember()); Record.push_back(D->isMemberSpecialization()); + Expr *AssociatedConstraints = D->getAssociatedConstraints(); + Record.push_back(AssociatedConstraints != nullptr); + if (AssociatedConstraints) { + Record.AddStmt(AssociatedConstraints); + } } Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION; Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp =================================================================== --- test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp +++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s namespace nodiag { @@ -33,7 +33,7 @@ struct A; }; -template requires someFunc(T()) +template requires someFunc(U()) struct AA::A { }; struct AAF { @@ -47,18 +47,26 @@ template struct TA { - template