Author: hubert.reinterpretcast Date: Thu Feb 9 20:46:19 2017 New Revision: 294697
URL: http://llvm.org/viewvc/llvm-project?rev=294697&view=rev Log: [Concepts] Class template associated constraints Summary: This adds associated constraints as a property of class templates. An error is produced if redeclarations are not similarly constrained. Reviewers: rsmith, faisalv, aaron.ballman Reviewed By: rsmith Subscribers: cfe-commits, nwilson Differential Revision: https://reviews.llvm.org/D25674 Added: cfe/trunk/test/CXX/concepts-ts/temp/ cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/ cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/ cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp Modified: cfe/trunk/include/clang/AST/DeclTemplate.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/AST/DeclTemplate.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Modified: cfe/trunk/include/clang/AST/DeclTemplate.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=294697&r1=294696&r2=294697&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclTemplate.h (original) +++ cfe/trunk/include/clang/AST/DeclTemplate.h Thu Feb 9 20:46:19 2017 @@ -344,6 +344,32 @@ public: // Kinds of Templates //===----------------------------------------------------------------------===// +/// \brief Stores the template parameter list and associated constraints for +/// \c TemplateDecl objects that track associated constraints. +class ConstrainedTemplateDeclInfo { + friend TemplateDecl; + +public: + ConstrainedTemplateDeclInfo() : TemplateParams(), AssociatedConstraints() {} + + TemplateParameterList *getTemplateParameters() const { + return TemplateParams; + } + + Expr *getAssociatedConstraints() const { return AssociatedConstraints; } + +protected: + void setTemplateParameters(TemplateParameterList *TParams) { + TemplateParams = TParams; + } + + void setAssociatedConstraints(Expr *AC) { AssociatedConstraints = AC; } + + TemplateParameterList *TemplateParams; + Expr *AssociatedConstraints; +}; + + /// \brief The base class of all kinds of template declarations (e.g., /// class, function, etc.). /// @@ -352,33 +378,53 @@ public: class TemplateDecl : public NamedDecl { void anchor() override; protected: - // This is probably never used. - TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name) + // 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, false), - TemplateParams(nullptr) {} + TemplateParams(CTDI) { + this->setTemplateParameters(Params); + } - // Construct a template decl with the given name and parameters. - // Used when there is not templated element (tt-params). TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params) - : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false), - TemplateParams(Params) {} + : TemplateDecl(nullptr, DK, DC, L, Name, Params) {} // Construct a template decl with name, parameters, and templated element. - TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, + TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC, + SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl) : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl, false), - TemplateParams(Params) {} + 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) {} public: /// Get the list of template parameters TemplateParameterList *getTemplateParameters() const { - return TemplateParams; + const auto *const CTDI = + TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>(); + return CTDI ? CTDI->getTemplateParameters() + : TemplateParams.get<TemplateParameterList *>(); } /// Get the constraint-expression from the associated requires-clause (if any) const Expr *getRequiresClause() const { - return TemplateParams ? TemplateParams->getRequiresClause() : nullptr; + const TemplateParameterList *const TP = getTemplateParameters(); + return TP ? TP->getRequiresClause() : nullptr; + } + + Expr *getAssociatedConstraints() const { + const TemplateDecl *const C = cast<TemplateDecl>(getCanonicalDecl()); + const auto *const CTDI = + C->TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>(); + return CTDI ? CTDI->getAssociatedConstraints() : nullptr; } /// Get the underlying, templated declaration. @@ -391,7 +437,7 @@ public: } SourceRange getSourceRange() const override LLVM_READONLY { - return SourceRange(TemplateParams->getTemplateLoc(), + return SourceRange(getTemplateParameters()->getTemplateLoc(), TemplatedDecl.getPointer()->getSourceRange().getEnd()); } @@ -407,7 +453,29 @@ protected: /// (function or variable) is a concept. llvm::PointerIntPair<NamedDecl *, 1, bool> TemplatedDecl; - TemplateParameterList* TemplateParams; + /// \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<TemplateParameterList *, + ConstrainedTemplateDeclInfo *> + TemplateParams; + + void setTemplateParameters(TemplateParameterList *TParams) { + if (auto *const CTDI = + TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>()) { + CTDI->setTemplateParameters(TParams); + } else { + TemplateParams = TParams; + } + } + + void setAssociatedConstraints(Expr *AC) { + assert(isCanonicalDecl() && + "Attaching associated constraints to non-canonical Decl"); + TemplateParams.get<ConstrainedTemplateDeclInfo *>() + ->setAssociatedConstraints(AC); + } public: /// \brief Initialize the underlying templated declaration and @@ -737,11 +805,17 @@ protected: 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), + Common() {} + RedeclarableTemplateDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl) - : TemplateDecl(DK, DC, L, Name, Params, Decl), redeclarable_base(C), - Common() {} + : RedeclarableTemplateDecl(nullptr, DK, C, DC, L, Name, Params, Decl) {} public: template <class decl_type> friend class RedeclarableTemplate; @@ -1997,10 +2071,16 @@ protected: llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> & 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) - : RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {} + : ClassTemplateDecl(nullptr, C, DC, L, Name, Params, Decl) {} CommonBase *newCommon(ASTContext &C) const override; @@ -2023,12 +2103,14 @@ public: return getTemplatedDecl()->isThisDeclarationADefinition(); } + // FIXME: remove default argument for AssociatedConstraints /// \brief Create a class template node. static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, - NamedDecl *Decl); + NamedDecl *Decl, + Expr *AssociatedConstraints = nullptr); /// \brief Create an empty class template node. static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=294697&r1=294696&r2=294697&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Feb 9 20:46:19 2017 @@ -2287,6 +2287,9 @@ def err_concept_specialized : Error< "%select{function|variable}0 concept cannot be " "%select{explicitly instantiated|explicitly specialized|partially specialized}1">; +def err_template_different_associated_constraints : Error< + "associated constraints differ in template redeclaration">; + // C++11 char16_t/char32_t def warn_cxx98_compat_unicode_type : Warning< "'%0' type specifier is incompatible with C++98">, Modified: cfe/trunk/lib/AST/DeclTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=294697&r1=294696&r2=294697&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclTemplate.cpp (original) +++ cfe/trunk/lib/AST/DeclTemplate.cpp Thu Feb 9 20:46:19 2017 @@ -297,10 +297,18 @@ ClassTemplateDecl *ClassTemplateDecl::Cr SourceLocation L, DeclarationName Name, TemplateParameterList *Params, - NamedDecl *Decl) { + NamedDecl *Decl, + Expr *AssociatedConstraints) { AdoptTemplateParameterList(Params, cast<DeclContext>(Decl)); - ClassTemplateDecl *New = new (C, DC) ClassTemplateDecl(C, DC, L, Name, - Params, 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; } Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=294697&r1=294696&r2=294697&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Feb 9 20:46:19 2017 @@ -45,6 +45,26 @@ clang::getTemplateParamsRange(TemplatePa 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. @@ -1137,6 +1157,9 @@ Sema::CheckClassTemplate(Scope *S, unsig } } + // 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 @@ -1148,6 +1171,29 @@ Sema::CheckClassTemplate(Scope *S, unsig 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, @@ -1250,10 +1296,15 @@ Sema::CheckClassTemplate(Scope *S, unsig 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); + NewClass, ACtoAttach); if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=294697&r1=294696&r2=294697&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Thu Feb 9 20:46:19 2017 @@ -1876,6 +1876,7 @@ DeclID ASTDeclReader::VisitTemplateDecl( DeclID PatternID = ReadDeclID(); NamedDecl *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID)); TemplateParameterList *TemplateParams = Record.readTemplateParameterList(); + // FIXME handle associated constraints D->init(TemplatedDecl, TemplateParams); return PatternID; Added: cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp?rev=294697&view=auto ============================================================================== --- cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp (added) +++ cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp Thu Feb 9 20:46:19 2017 @@ -0,0 +1,65 @@ +// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s + +namespace nodiag { + +template <typename T> requires bool(T()) +struct A; +template <typename U> requires bool(U()) +struct A; + +} // end namespace nodiag + +namespace diag { + +template <typename T> requires true // expected-note{{previous template declaration is here}} +struct A; +template <typename T> struct A; // expected-error{{associated constraints differ in template redeclaration}} + +template <typename T> struct B; // expected-note{{previous template declaration is here}} +template <typename T> requires true // expected-error{{associated constraints differ in template redeclaration}} +struct B; + +template <typename T> requires true // expected-note{{previous template declaration is here}} +struct C; +template <typename T> requires !0 // expected-error{{associated constraints differ in template redeclaration}} +struct C; + +} // end namespace diag + +namespace nodiag { + +struct AA { + template <typename T> requires someFunc(T()) + struct A; +}; + +template <typename T> requires someFunc(T()) +struct AA::A { }; + +struct AAF { + template <typename T> requires someFunc(T()) + friend struct AA::A; +}; + +} // end namespace nodiag + +namespace diag { + +template <unsigned N> +struct TA { + template <template <unsigned> class TT> requires TT<N>::happy // expected-note 2{{previous template declaration is here}} + struct A; + + struct AF; +}; + +template <unsigned N> +template <template <unsigned> class TT> struct TA<N>::A { }; // expected-error{{associated constraints differ in template redeclaration}} + +template <unsigned N> +struct TA<N>::AF { + template <template <unsigned> class TT> requires TT<N + 0>::happy // expected-error{{associated constraints differ in template redeclaration}} + friend struct TA::A; +}; + +} // end namespace diag _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits