Author: saar.raz Date: Tue Oct 15 11:44:06 2019 New Revision: 374938 URL: http://llvm.org/viewvc/llvm-project?rev=374938&view=rev Log: [Concept] Associated Constraints Infrastructure
Add code to correctly calculate the associated constraints of a template (no enforcement yet). D41284 on Phabricator. Added: cfe/trunk/test/CXX/temp/concept/p4.cpp cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp Modified: cfe/trunk/include/clang/AST/ASTNodeTraverser.h cfe/trunk/include/clang/AST/DeclTemplate.h cfe/trunk/include/clang/AST/RecursiveASTVisitor.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/AST/DeclTemplate.cpp cfe/trunk/lib/Sema/SemaConcept.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp cfe/trunk/lib/Serialization/ASTReader.cpp cfe/trunk/lib/Serialization/ASTReaderDecl.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp cfe/trunk/lib/Serialization/ASTWriterDecl.cpp cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp Modified: cfe/trunk/include/clang/AST/ASTNodeTraverser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTNodeTraverser.h?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTNodeTraverser.h (original) +++ cfe/trunk/include/clang/AST/ASTNodeTraverser.h Tue Oct 15 11:44:06 2019 @@ -237,6 +237,9 @@ public: for (const auto &TP : *TPL) Visit(TP); + + if (const Expr *RC = TPL->getRequiresClause()) + Visit(RC); } void Modified: cfe/trunk/include/clang/AST/DeclTemplate.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclTemplate.h (original) +++ cfe/trunk/include/clang/AST/DeclTemplate.h Tue Oct 15 11:44:06 2019 @@ -168,6 +168,16 @@ public: return HasRequiresClause ? *getTrailingObjects<Expr *>() : nullptr; } + /// \brief All associated constraints derived from this template parameter + /// list, including the requires clause and any constraints derived from + /// constrained-parameters. + /// + /// The constraints in the resulting list are to be treated as if in a + /// conjunction ("and"). + void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const; + + bool hasAssociatedConstraints() const; + SourceLocation getTemplateLoc() const { return TemplateLoc; } SourceLocation getLAngleLoc() const { return LAngleLoc; } SourceLocation getRAngleLoc() const { return RAngleLoc; } @@ -369,33 +379,7 @@ public: // Kinds of Templates //===----------------------------------------------------------------------===// -/// Stores the template parameter list and associated constraints for -/// \c TemplateDecl objects that track associated constraints. -class ConstrainedTemplateDeclInfo { - friend TemplateDecl; - -public: - ConstrainedTemplateDeclInfo() = default; - - 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 = nullptr; - Expr *AssociatedConstraints = nullptr; -}; - - -/// The base class of all kinds of template declarations (e.g., +/// \brief The base class of all kinds of template declarations (e.g., /// class, function, etc.). /// /// The TemplateDecl class stores the list of template parameters and a @@ -404,55 +388,33 @@ class TemplateDecl : public NamedDecl { 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<ConstrainedTemplateDeclInfo *>(); - return CTDI ? CTDI->getTemplateParameters() - : TemplateParams.get<TemplateParameterList *>(); - } - - /// 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; - } - - Expr *getAssociatedConstraints() const { - const auto *const C = cast<TemplateDecl>(getCanonicalDecl()); - const auto *const CTDI = - C->TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>(); - return CTDI ? CTDI->getAssociatedConstraints() : nullptr; + return TemplateParams; } + /// \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. + void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const; + + bool hasAssociatedConstraints() const; + /// Get the underlying, templated declaration. NamedDecl *getTemplatedDecl() const { return TemplatedDecl; } @@ -470,29 +432,10 @@ public: protected: NamedDecl *TemplatedDecl; - - /// 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; + TemplateParameterList *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); + TemplateParams = TParams; } public: @@ -889,17 +832,10 @@ 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) - {} - 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; @@ -2026,6 +1962,20 @@ public: return TemplateParams; } + /// \brief All associated constraints of this partial specialization, + /// including the requires clause and any constraints derived from + /// constrained-parameters. + /// + /// The constraints in the resulting list are to be treated as if in a + /// conjunction ("and"). + void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { + TemplateParams->getAssociatedConstraints(AC); + } + + bool hasAssociatedConstraints() const { + return TemplateParams->hasAssociatedConstraints(); + } + /// Get the template arguments as written. const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { return ArgsAsWritten; @@ -2145,16 +2095,10 @@ 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) - : ClassTemplateDecl(nullptr, C, DC, L, Name, Params, Decl) {} + : RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {} CommonBase *newCommon(ASTContext &C) const override; @@ -2180,14 +2124,12 @@ public: return getTemplatedDecl()->isThisDeclarationADefinition(); } - // FIXME: remove default argument for AssociatedConstraints - /// Create a class template node. + /// \brief Create a class template node. static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, - NamedDecl *Decl, - Expr *AssociatedConstraints = nullptr); + NamedDecl *Decl); /// Create an empty class template node. static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -2862,7 +2804,21 @@ public: return ArgsAsWritten; } - /// Retrieve the member variable template partial specialization from + /// \brief All associated constraints of this partial specialization, + /// including the requires clause and any constraints derived from + /// constrained-parameters. + /// + /// The constraints in the resulting list are to be treated as if in a + /// conjunction ("and"). + void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { + TemplateParams->getAssociatedConstraints(AC); + } + + bool hasAssociatedConstraints() const { + return TemplateParams->hasAssociatedConstraints(); + } + + /// \brief Retrieve the member variable template partial specialization from /// which this particular variable template partial specialization was /// instantiated. /// @@ -3091,11 +3047,9 @@ class ConceptDecl : public TemplateDecl, 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, Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original) +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Tue Oct 15 11:44:06 2019 @@ -1633,9 +1633,11 @@ template <typename Derived> bool RecursiveASTVisitor<Derived>::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; Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Oct 15 11:44:06 2019 @@ -2543,8 +2543,8 @@ def err_non_constant_constraint_expressi def err_non_bool_atomic_constraint : Error< "atomic constraint must be of type 'bool' (found %0)">; -def err_template_different_associated_constraints : Error< - "associated constraints differ in template redeclaration">; +def err_template_different_requires_clause : Error< + "requires clause differs in template redeclaration">; // C++11 char16_t/char32_t def warn_cxx98_compat_unicode_type : Warning< Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue Oct 15 11:44:06 2019 @@ -6058,7 +6058,13 @@ public: Expr *ConstraintExpr, bool &IsSatisfied); - // ParseObjCStringLiteral - Parse Objective-C string literals. + /// 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(TemplateParameterList *Old, + TemplateParameterList *New); + + // ParseObjCStringLiteral - Parse Objective-C string literals. ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ArrayRef<Expr *> Strings); Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Tue Oct 15 11:44:06 2019 @@ -738,7 +738,7 @@ ASTContext::getCanonicalTemplateTemplate cast<TemplateTemplateParmDecl>(*P))); } - assert(!TTP->getRequiresClause() && + assert(!TTP->getTemplateParameters()->getRequiresClause() && "Unexpected requires-clause on template template-parameter"); Expr *const CanonRequiresClause = nullptr; Modified: cfe/trunk/lib/AST/DeclTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclTemplate.cpp (original) +++ cfe/trunk/lib/AST/DeclTemplate.cpp Tue Oct 15 11:44:06 2019 @@ -70,6 +70,8 @@ TemplateParameterList::TemplateParameter } if (RequiresClause) { *getTrailingObjects<Expr *>() = RequiresClause; + if (RequiresClause->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; } } @@ -136,6 +138,18 @@ static void AdoptTemplateParameterList(T } } +void TemplateParameterList:: +getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { + // TODO: Concepts: Collect immediately-introduced constraints. + if (HasRequiresClause) + AC.push_back(getRequiresClause()); +} + +bool TemplateParameterList::hasAssociatedConstraints() const { + // TODO: Concepts: Regard immediately-introduced constraints. + return HasRequiresClause; +} + namespace clang { void *allocateDefaultArgStorageChain(const ASTContext &C) { @@ -145,6 +159,28 @@ void *allocateDefaultArgStorageChain(con } // namespace clang //===----------------------------------------------------------------------===// +// 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) {} + +void TemplateDecl::anchor() {} + +void TemplateDecl:: +getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { + // TODO: Concepts: Append function trailing requires clause. + TemplateParams->getAssociatedConstraints(AC); +} + +bool TemplateDecl::hasAssociatedConstraints() const { + // TODO: Concepts: Regard function trailing requires clause. + return TemplateParams->hasAssociatedConstraints(); +} + +//===----------------------------------------------------------------------===// // RedeclarableTemplateDecl Implementation //===----------------------------------------------------------------------===// @@ -344,19 +380,10 @@ ClassTemplateDecl *ClassTemplateDecl::Cr SourceLocation L, DeclarationName Name, TemplateParameterList *Params, - NamedDecl *Decl, - Expr *AssociatedConstraints) { + NamedDecl *Decl) { AdoptTemplateParameterList(Params, cast<DeclContext>(Decl)); - if (!AssociatedConstraints) { - return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl); - } - - auto *const CTDI = new (C) ConstrainedTemplateDeclInfo; - auto *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, @@ -708,12 +735,6 @@ FunctionTemplateSpecializationInfo *Func } //===----------------------------------------------------------------------===// -// TemplateDecl Implementation -//===----------------------------------------------------------------------===// - -void TemplateDecl::anchor() {} - -//===----------------------------------------------------------------------===// // ClassTemplateSpecializationDecl Implementation //===----------------------------------------------------------------------===// Modified: cfe/trunk/lib/Sema/SemaConcept.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaConcept.cpp?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaConcept.cpp (original) +++ cfe/trunk/lib/Sema/SemaConcept.cpp Tue Oct 15 11:44:06 2019 @@ -122,4 +122,4 @@ Sema::CalculateConstraintSatisfaction(Co IsSatisfied = EvalResult.Val.getInt().getBoolValue(); return false; -} +} \ No newline at end of file Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Oct 15 11:44:06 2019 @@ -45,27 +45,7 @@ clang::getTemplateParamsRange(TemplatePa return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc()); } -namespace clang { -/// [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(); -} - -/// Determine whether the declaration found is acceptable as the name +/// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns null. /// @@ -1533,9 +1513,6 @@ DeclResult Sema::CheckClassTemplate( } } - // 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 @@ -1547,30 +1524,6 @@ DeclResult Sema::CheckClassTemplate( 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->getBeginLoc() : NameLoc, - diag::err_template_different_associated_constraints); - Diag(PrevAC ? PrevAC->getBeginLoc() : 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, @@ -1674,15 +1627,10 @@ DeclResult Sema::CheckClassTemplate( 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); @@ -7266,6 +7214,9 @@ static bool MatchTemplateParameterKind(S TemplateArgLoc); } + // TODO: Concepts: Match immediately-introduced-constraint for type + // constraints + return true; } @@ -7291,6 +7242,15 @@ void DiagnoseTemplateParameterListArityM << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc()); } +static void +DiagnoseTemplateParameterListRequiresClauseMismatch(Sema &S, + TemplateParameterList *New, + TemplateParameterList *Old){ + S.Diag(New->getTemplateLoc(), diag::err_template_different_requires_clause); + S.Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration) + << /*declaration*/0; +} + /// Determine whether the given template parameter lists are /// equivalent. /// @@ -7380,6 +7340,27 @@ Sema::TemplateParameterListsAreEqual(Tem return false; } + if (Kind != TPL_TemplateTemplateArgumentMatch) { + const Expr *NewRC = New->getRequiresClause(); + const Expr *OldRC = Old->getRequiresClause(); + if (!NewRC != !OldRC) { + if (Complain) + DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old); + return false; + } + + if (NewRC) { + llvm::FoldingSetNodeID OldRCID, NewRCID; + OldRC->Profile(OldRCID, Context, /*Canonical=*/true); + NewRC->Profile(NewRCID, Context, /*Canonical=*/true); + if (OldRCID != NewRCID) { + if (Complain) + DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old); + return false; + } + } + } + return true; } @@ -8089,10 +8070,9 @@ Decl *Sema::ActOnConceptDefinition(Scope TemplateParameterLists.front(), ConstraintExpr); - if (NewDecl->getAssociatedConstraints()) { + if (NewDecl->hasAssociatedConstraints()) { // C++2a [temp.concept]p4: // A concept shall not have associated constraints. - // TODO: Make a test once we have actual associated constraints. Diag(NameLoc, diag::err_concept_no_associated_constraints); NewDecl->setInvalidDecl(); } Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Oct 15 11:44:06 2019 @@ -3515,14 +3515,21 @@ TemplateDeclInstantiator::SubstTemplateP if (Invalid) return nullptr; - // Note: we substitute into associated constraints later - Expr *const UninstantiatedRequiresClause = L->getRequiresClause(); + // FIXME: Concepts: Substitution into requires clause should only happen when + // checking satisfaction. + 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; } Modified: cfe/trunk/lib/Serialization/ASTReader.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReader.cpp Tue Oct 15 11:44:06 2019 @@ -9345,9 +9345,11 @@ ASTReader::ReadTemplateParameterList(Mod while (NumParams--) Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx)); - // TODO: Concepts + bool HasRequiresClause = Record[Idx++]; + Expr *RequiresClause = HasRequiresClause ? ReadExpr(F) : nullptr; + TemplateParameterList *TemplateParams = TemplateParameterList::Create( - getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, nullptr); + getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause); return TemplateParams; } Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Tue Oct 15 11:44:06 2019 @@ -2000,7 +2000,6 @@ DeclID ASTDeclReader::VisitTemplateDecl( DeclID PatternID = ReadDeclID(); auto *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID)); TemplateParameterList *TemplateParams = Record.readTemplateParameterList(); - // FIXME handle associated constraints D->init(TemplatedDecl, TemplateParams); return PatternID; @@ -2166,7 +2165,8 @@ void ASTDeclReader::VisitClassTemplatePa ClassTemplatePartialSpecializationDecl *D) { RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D); - D->TemplateParams = Record.readTemplateParameterList(); + TemplateParameterList *Params = Record.readTemplateParameterList(); + D->TemplateParams = Params; D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); // These are read/set from/to the first declaration. @@ -2268,7 +2268,8 @@ void ASTDeclReader::VisitVarTemplatePart VarTemplatePartialSpecializationDecl *D) { RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D); - D->TemplateParams = Record.readTemplateParameterList(); + TemplateParameterList *Params = Record.readTemplateParameterList(); + D->TemplateParams = Params; D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); // These are read/set from/to the first declaration. @@ -2284,6 +2285,7 @@ void ASTDeclReader::VisitTemplateTypePar D->setDeclaredWithTypename(Record.readInt()); + // TODO: Concepts: Immediately introduced constraint if (Record.readInt()) D->setDefaultArgument(GetTypeSourceInfo()); } Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Oct 15 11:44:06 2019 @@ -6070,10 +6070,16 @@ void ASTRecordWriter::AddTemplateParamet AddSourceLocation(TemplateParams->getTemplateLoc()); AddSourceLocation(TemplateParams->getLAngleLoc()); AddSourceLocation(TemplateParams->getRAngleLoc()); - // TODO: Concepts + Record->push_back(TemplateParams->size()); for (const auto &P : *TemplateParams) AddDeclRef(P); + if (const Expr *RequiresClause = TemplateParams->getRequiresClause()) { + Record->push_back(true); + AddStmt(const_cast<Expr*>(RequiresClause)); + } else { + Record->push_back(false); + } } /// Emit a template argument list. Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Tue Oct 15 11:44:06 2019 @@ -1608,7 +1608,7 @@ void ASTDeclWriter::VisitTemplateTypePar VisitTypeDecl(D); Record.push_back(D->wasDeclaredWithTypename()); - + // TODO: Concepts - constrained parameters. bool OwnsDefaultArg = D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); Record.push_back(OwnsDefaultArg); @@ -1638,6 +1638,7 @@ void ASTDeclWriter::VisitNonTypeTemplate Code = serialization::DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK; } else { + // TODO: Concepts - constrained parameters. // Rest of NonTypeTemplateParmDecl. Record.push_back(D->isParameterPack()); bool OwnsDefaultArg = D->hasDefaultArgument() && @@ -1667,6 +1668,7 @@ void ASTDeclWriter::VisitTemplateTemplat Record.AddTemplateParameterList(D->getExpansionTemplateParameters(I)); Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK; } else { + // TODO: Concepts - constrained parameters. // Rest of TemplateTemplateParmDecl. Record.push_back(D->isParameterPack()); bool OwnsDefaultArg = D->hasDefaultArgument() && Added: cfe/trunk/test/CXX/temp/concept/p4.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/concept/p4.cpp?rev=374938&view=auto ============================================================================== --- cfe/trunk/test/CXX/temp/concept/p4.cpp (added) +++ cfe/trunk/test/CXX/temp/concept/p4.cpp Tue Oct 15 11:44:06 2019 @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s + +template<typename T> requires true +concept C = true; // expected-error{{concept cannot have associated constraints}} + +// TODO: Add test for other kinds of associated constraints once we have them. Modified: cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp?rev=374938&r1=374937&r2=374938&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp Tue Oct 15 11:44:06 2019 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s +// RUN: %clang_cc1 -std=c++2a -x c++ -verify %s namespace nodiag { @@ -13,15 +13,15 @@ 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 A; // expected-error{{requires clause differs 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}} +template <typename T> requires true // expected-error{{requires clause differs 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}} +template <typename T> requires !0 // expected-error{{requires clause differs in template redeclaration}} struct C; } // end namespace diag @@ -33,7 +33,7 @@ struct AA { struct A; }; -template <typename T> requires someFunc(T()) +template <typename U> requires someFunc(U()) struct AA::A { }; struct AAF { @@ -47,18 +47,26 @@ namespace diag { template <unsigned N> struct TA { - template <template <unsigned> class TT> requires TT<N>::happy // expected-note 2{{previous template declaration is here}} + template <template <unsigned> class TT> requires TT<N>::happy // expected-note {{previous template declaration is here}} struct A; + template <template <unsigned> class TT> requires TT<N>::happy // expected-note {{previous template declaration is here}} + struct B; + struct AF; }; template <unsigned N> -template <template <unsigned> class TT> struct TA<N>::A { }; // expected-error{{associated constraints differ in template redeclaration}} +template <template <unsigned> class TT> struct TA<N>::A { }; // expected-error{{requires clause differs in template redeclaration}} + + +template <unsigned N> +template <template <unsigned> class TT> requires TT<N + 1>::happy struct TA<N>::B { }; // expected-error{{requires clause differs 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}} + // we do not expect a diagnostic here because the template parameter list is dependent. + template <template <unsigned> class TT> requires TT<N + 0>::happy friend struct TA::A; }; Added: cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp?rev=374938&view=auto ============================================================================== --- cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp (added) +++ cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp Tue Oct 15 11:44:06 2019 @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -std=c++2a -x c++ -verify %s + +namespace nodiag { + +template <typename T> requires bool(T()) +int A(); +template <typename U> requires bool(U()) +int A(); + +} // end namespace nodiag + +namespace diag { + +namespace orig { + template <typename T> requires true + int A(); + template <typename T> + int B(); + template <typename T> requires true + int C(); +} + +template <typename T> +int orig::A(); +// expected-error@-1{{out-of-line declaration of 'A' does not match any declaration in namespace 'diag::orig'}} +template <typename T> requires true +int orig::B(); +// expected-error@-1{{out-of-line declaration of 'B' does not match any declaration in namespace 'diag::orig'}} +template <typename T> requires !0 +int orig::C(); +// expected-error@-1{{out-of-line declaration of 'C' does not match any declaration in namespace 'diag::orig'}} + +} // end namespace diag + +namespace nodiag { + +struct AA { + template <typename T> requires someFunc(T()) + int A(); +}; + +template <typename T> requires someFunc(T()) +int AA::A() { return sizeof(T); } + +} // end namespace nodiag + +namespace diag { + +template <unsigned N> +struct TA { + template <template <unsigned> class TT> requires TT<N>::happy + int A(); +}; + +template <unsigned N> +template <template <unsigned> class TT> int TA<N>::A() { return sizeof(TT<N>); } +// expected-error@-1{{out-of-line definition of 'A' does not match any declaration in 'TA<N>'}} + +} // end namespace diag Added: cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp?rev=374938&view=auto ============================================================================== --- cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp (added) +++ cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp Tue Oct 15 11:44:06 2019 @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -std=c++2a -x c++ -verify %s + +namespace nodiag { + +struct B { + template <typename T> requires bool(T()) + static int A; +}; + +template <typename U> requires bool(U()) +int B::A = int(U()); + +} // end namespace nodiag + +namespace diag { + +struct B { + template <typename T> requires bool(T()) // expected-note{{previous template declaration is here}} + static int A; +}; + +template <typename U> requires !bool(U()) // expected-error{{requires clause differs in template redeclaration}} +int B::A = int(U()); + +} // end namespace diag \ No newline at end of file _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits