Index: include/clang/AST/DeclTemplate.h =================================================================== --- include/clang/AST/DeclTemplate.h +++ include/clang/AST/DeclTemplate.h @@ -664,7 +664,7 @@ /// \brief Note that this member template is a specialization. void setMemberSpecialization() { - assert(getCommonPtr()->InstantiatedFromMember.getPointer() && + assert(isa(getDeclContext()) && "Only member templates can be member template specializations"); getCommonPtr()->InstantiatedFromMember.setInt(true); } @@ -801,8 +801,9 @@ /// retrieved by an earlier call to findSpecialization(). void addSpecialization(FunctionTemplateSpecializationInfo* Info, void *InsertPos); +public: + -public: /// Get the underlying function declaration of the template. FunctionDecl *getTemplatedDecl() const { return static_cast(TemplatedDecl); @@ -1771,9 +1772,11 @@ void setMemberSpecialization() { ClassTemplatePartialSpecializationDecl *First = cast(getFirstDecl()); - assert(First->InstantiatedFromMember.getPointer() && + + assert(isa(First->getDeclContext()) && "Only member templates can be member template specializations"); - return First->InstantiatedFromMember.setInt(true); + + First->InstantiatedFromMember.setInt(true); } /// Retrieves the injected specialization type for this partial @@ -2623,7 +2626,7 @@ void setMemberSpecialization() { VarTemplatePartialSpecializationDecl *First = cast(getFirstDecl()); - assert(First->InstantiatedFromMember.getPointer() && + assert(isa(First->getDeclContext()) && "Only member templates can be member template specializations"); return First->InstantiatedFromMember.setInt(true); } Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3300,6 +3300,9 @@ def err_partial_spec_ordering_ambiguous : Error< "ambiguous partial specializations of %0">; def note_partial_spec_match : Note<"partial specialization matches %0">; +def err_explicit_spec_ordering_ambiguous : Error< + "ambiguous explicit specializations of %0">; +def note_explicit_spec_match : Note<"explicit specialization matches %0">; def err_partial_spec_redeclared : Error< "class template partial specialization %0 cannot be redeclared">; def note_prev_partial_spec_here : Note< Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -356,6 +356,34 @@ /// full expression. llvm::SmallPtrSet MaybeODRUseExprs; + // Set of all the constexpr variable templates whose values have + // been used - this helps us distinguish those variable template + // specializations who had their initializers instantiated because + // they were needed for 'auto' deduction vs those that were needed + // because their value was used. We can not explicitly specialize + // those whose value was actually used - such as the dimension of + // an inclass array member etc. + llvm::SmallPtrSet + ConstexprVarTemplateSpecsValueUsed; + + // Set of all dummy (invented) non-type template argument expressions that are + // generated when comparing and substituting into dependent class scope + // function explicit specializations. + // TreeTransform and TemplateArgumentDeduction needs to be able to identify + // these nodes so as to handle them specially. + llvm::SmallPtrSet InventedDummyNonTypeTemplateArguments; + + // FIXME: This hack tracks the instantiation patterns of method + // specializations being declared, so that when substituting into the + // CXXMethodDecl we can distinguish whether we are in overload resolution vs + // doing deduction while declaring a specialization to see if the + // specialization is well formed. A better way is to let the + // TemplateDeclInstantiator know when declarations are being finalized either + // during the overload-resolution context of a function call vs or while they + // are being declared. + + std::vector PatternOfMethodSpecializationBeingDeclared; + /// \brief Stack containing information about each of the nested /// function, block, and method scopes that are currently active. /// @@ -5276,7 +5304,8 @@ DeclResult ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, - StorageClass SC, bool IsPartialSpecialization); + StorageClass SC, bool IsPartialSpecialization, + MultiTemplateParamsArg TemplateParameterLists); DeclResult CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, @@ -5336,6 +5365,10 @@ const TemplateArgumentListInfo &ExplicitTemplateArgs, LookupResult &Previous); + bool checkDependentClassScopeFunctionExplicitSpecialization( + FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, + LookupResult &Previous); + bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous); @@ -6042,6 +6075,9 @@ TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2); + + // Given a set of function templates, retrieve the most specialized template + // as an iterator into the set, or end. UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, TemplateSpecCandidateSet &FailedCandidates, @@ -6051,6 +6087,18 @@ const PartialDiagnostic &CandidateDiag, bool Complain = true, QualType TargetType = QualType()); + ClassTemplateSpecializationDecl * + getBestExplicitSpecialization(bool &Ambiguous, + ClassTemplateDecl *Template, + ArrayRef TemplateArgs, + SourceLocation PointOfInstantiation); + + VarTemplateSpecializationDecl * + getBestExplicitSpecialization(bool &Ambiguous, + VarTemplateDecl *Template, + ArrayRef TemplateArgs, + SourceLocation PointOfInstantiation); + ClassTemplatePartialSpecializationDecl * getMoreSpecializedPartialSpecialization( ClassTemplatePartialSpecializationDecl *PS1, @@ -6061,6 +6109,33 @@ VarTemplatePartialSpecializationDecl *PS1, VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); + // Given a primary template and the supplied template arguments, return in the + // form of a tuple: + // 1) the best partial specialization + // 2) the deduced argument list (can incorporate default arguments not explicitly supplied) + // 3) and whether the returned partial specialization is ambiguous. + // If the partial specialization decl is null, none was found, use the primary. + + std::tuple + getMostSpecializedPartialSpecialization( + ClassTemplateDecl *D, const TemplateArgumentList &TemplateArgs, + SourceLocation PointOfInstantiation); + + std::tuple + getMostSpecializedPartialSpecialization( + VarTemplateDecl *D, const TemplateArgumentList &TemplateArgs, + SourceLocation PointOfInstantiation); + + // Given a var/class/function template declaration - primary, partial, or + // explicit retrieve the template parameter lists associated with the + // declaration - including all outer scopes if defined inline. + SmallVector + getTemplateParameterListsOfDeclaration(const Decl *D); + + unsigned getNumberOfEmptyTemplateParameterLists(const Decl *D); + void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, @@ -6082,7 +6157,9 @@ getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost = nullptr, bool RelativeToPrimary = false, - const FunctionDecl *Pattern = nullptr); + const FunctionDecl *Pattern = nullptr, + const ArrayRef TPLsOfDeclBeingSubstituted = + ArrayRef()); /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { Index: include/clang/Sema/SemaInternal.h =================================================================== --- include/clang/Sema/SemaInternal.h +++ include/clang/Sema/SemaInternal.h @@ -18,6 +18,7 @@ #include "clang/AST/ASTContext.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" +#include "clang/Sema/TemplateDeduction.h" namespace clang { @@ -62,6 +63,13 @@ Var->markUsed(SemaRef.Context); } +Sema::TemplateDeductionResult +DeduceTemplateArgumentsByTypeMatchForExplicitSpecializations( + Sema &S, FunctionTemplateDecl *PrimaryTemplate, + CXXMethodDecl *SubstitutedExplicitSpecialization, + TemplateArgumentListInfo *SubstitutedExplicitTemplateArgs, + sema::TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced); } #endif Index: include/clang/Sema/Template.h =================================================================== --- include/clang/Sema/Template.h +++ include/clang/Sema/Template.h @@ -371,21 +371,6 @@ Sema::LateInstantiatedAttrVec* LateAttrs; LocalInstantiationScope *StartingScope; - /// \brief A list of out-of-line class template partial - /// specializations that will need to be instantiated after the - /// enclosing class's instantiation is complete. - SmallVector, 4> - OutOfLinePartialSpecs; - - /// \brief A list of out-of-line variable template partial - /// specializations that will need to be instantiated after the - /// enclosing variable's instantiation is complete. - /// FIXME: Verify that this is needed. - SmallVector< - std::pair, 4> - OutOfLineVarPartialSpecs; - public: TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs) @@ -419,6 +404,9 @@ #include "clang/AST/DeclNodes.inc" // A few supplemental visitor functions. + Decl * + VisitFunctionTemplateDecl(FunctionTemplateDecl *D, + bool IsCheckingDependentClassScopeSpecialization); Decl *VisitCXXMethodDecl(CXXMethodDecl *D, TemplateParameterList *TemplateParams, bool IsClassScopeSpecialization = false); @@ -442,40 +430,6 @@ LocalInstantiationScope *getStartingScope() const { return StartingScope; } - typedef - SmallVectorImpl > - ::iterator - delayed_partial_spec_iterator; - - typedef SmallVectorImpl >::iterator - delayed_var_partial_spec_iterator; - - /// \brief Return an iterator to the beginning of the set of - /// "delayed" partial specializations, which must be passed to - /// InstantiateClassTemplatePartialSpecialization once the class - /// definition has been completed. - delayed_partial_spec_iterator delayed_partial_spec_begin() { - return OutOfLinePartialSpecs.begin(); - } - - delayed_var_partial_spec_iterator delayed_var_partial_spec_begin() { - return OutOfLineVarPartialSpecs.begin(); - } - - /// \brief Return an iterator to the end of the set of - /// "delayed" partial specializations, which must be passed to - /// InstantiateClassTemplatePartialSpecialization once the class - /// definition has been completed. - delayed_partial_spec_iterator delayed_partial_spec_end() { - return OutOfLinePartialSpecs.end(); - } - - delayed_var_partial_spec_iterator delayed_var_partial_spec_end() { - return OutOfLineVarPartialSpecs.end(); - } - // Helper functions for instantiating methods. TypeSourceInfo *SubstFunctionType(FunctionDecl *D, SmallVectorImpl &Params); Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -1749,13 +1749,18 @@ if (isOutOfLine() && (hasInit() || // If the first declaration is out-of-line, this may be an - // instantiation of an out-of-line partial specialization of a variable - // template for which we have not yet instantiated the initializer. + // instantiation of an out-of-line partial or explicit specialization + // of a variable template for which we have not yet instantiated + // the initializer. (getFirstDecl()->isOutOfLine() ? getTemplateSpecializationKind() == TSK_Undeclared : getTemplateSpecializationKind() != TSK_ExplicitSpecialization) || - isa(this))) + // isa(this) || + // Since Both partial and explicit specializations are marked + // TSK_ExplicitSpecializations, we handle them both here. + (isa(this) && + getTemplateSpecializationKind() == TSK_ExplicitSpecialization))) return Definition; else return DeclarationOnly; Index: lib/AST/DeclTemplate.cpp =================================================================== --- lib/AST/DeclTemplate.cpp +++ lib/AST/DeclTemplate.cpp @@ -428,10 +428,12 @@ P = getPartialSpecializations().begin(), PEnd = getPartialSpecializations().end(); P != PEnd; ++P) { - if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) - return P->getMostRecentDecl(); + if (ClassTemplatePartialSpecializationDecl *ProtoPSpec = + P->getInstantiatedFromMember()) { + if (ProtoPSpec->getCanonicalDecl() == DCanon) + return P->getMostRecentDecl(); + } } - return 0; } @@ -855,6 +857,7 @@ return Result; } + //===----------------------------------------------------------------------===// // FriendTemplateDecl Implementation //===----------------------------------------------------------------------===// @@ -1045,8 +1048,9 @@ P = getPartialSpecializations().begin(), PEnd = getPartialSpecializations().end(); P != PEnd; ++P) { - if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) - return P->getMostRecentDecl(); + if (P->getInstantiatedFromMember()) + if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) + return P->getMostRecentDecl(); } return 0; Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -2852,12 +2852,100 @@ QualType MergedT; if (getLangOpts().CPlusPlus) { + const bool IsMemberVariableTemplateBeingExplicitlySpecialized = + ([](VarDecl *New, VarDecl *Old) { + if (VarTemplateDecl *NewVT = New->getDescribedVarTemplate()) { + VarTemplateDecl *OldVT = Old->getDescribedVarTemplate(); + assert(OldVT && "If the new declaration is a variable template, so " + "should the old template be!"); + // FIXME: There is no way to safely call getInstFromMemTempl or + // isMemberSpecialization on NewVT - since both those functions + // have the side-effect of creating a shared Common ptr + // that is not correctly wired up if the Old and New vars + // need to be redecl connected. Consider passing in the + // IsExplicitSpecialization determination in + // Sema::ActOnVariableDeclarator + // into MergeVarDeclTypes (i.e. current function). + return !!OldVT->getInstantiatedFromMemberTemplate(); + } + return false; + }(New, Old)); + if (New->getType()->isUndeducedType()) { // We don't know what the new type is until the initializer is attached. return; } else if (Context.hasSameType(New->getType(), Old->getType())) { - // These could still be something that needs exception specs checked. - return MergeVarDeclExceptionSpecs(New, Old); + // If this is a member variable template, make sure the primary + // template has not been used. + // template struct A { + // template static constexpr int b = 3; + // template static constexpr int b = 30; + // int m[b]; + // }; + // template<> template + // constexpr int A::b = 10; + // + // The above is not fine since the partial specialization is used + // and when we explicitly specialize the primary template had it been + // seen before the use, it would have been used, and not the partial + // specialization. + if (IsMemberVariableTemplateBeingExplicitlySpecialized) { + VarTemplateDecl *NewVT = New->getDescribedVarTemplate(); + VarTemplateDecl *OldVT = Old->getDescribedVarTemplate(); + // The specialization that conflicts with this explicit + // specialization. + VarTemplateSpecializationDecl *InstConflictVSpec = nullptr; + const bool PrimaryTemplateWasUsedOrPartialSpecializationReferenced = + [OldVT, Old, &InstConflictVSpec](Sema & SemaRef) { + for (VarTemplateSpecializationDecl *VSpec : + OldVT->specializations()) { + + // If any specialization was referenced - we can + // not subsequently explicitly specialize the primary template. + + // If any specialization was instantiated using a partial + // specialization - it might have a different type, so we + // can not use it. + // FIXME: check the type, if it does have a diff type we can not + // explicitly specialize the primary template. Although, you + // would have to instantiate NewVT with the template arguments + // of VSpec to be sure - for now since this has not been + // discussed by core - if a specialization uses a non-explicitly + // specialized partial spec, we do not allow explicit spec of + // the primary. + + if (VSpec->isUsed() || + SemaRef.ConstexprVarTemplateSpecsValueUsed.count(VSpec) || + VSpec->getSpecializedTemplateOrPartial() + .is()) { + InstConflictVSpec = VSpec; + return true; + } + } + return false; + }(*this); + if (!PrimaryTemplateWasUsedOrPartialSpecializationReferenced) + return MergeVarDeclExceptionSpecs(New, Old); + else { + // Complain that we are trying to explicitly specialize a variable + // member template after it has already been used and its initializer + // has been instantiated! + // FIXME: In case of a partial specialization being referenced and + // then a primary template being explicitly specialized, the diagnostic + // is misleading. + SourceRange Range(New->getLocStart(), New->getLocEnd()); + Diag(New->getLocation(), diag::err_specialization_after_instantiation) + << New->getName() << Range; + + Diag(InstConflictVSpec->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << 0; + return New->setInvalidDecl(); + } + } else { + // These could still be something that needs exception specs checked. + return MergeVarDeclExceptionSpecs(New, Old); + } } // C++ [basic.link]p10: // [...] the types specified by all declarations referring to a given @@ -2882,6 +2970,38 @@ Old->getType()->isObjCObjectPointerType()) { MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType()); + } else if (IsMemberVariableTemplateBeingExplicitlySpecialized) { + // If we are adding an explicit specialization of a variable template, + // set the old type to the new type - only if the old template has + // not been instantiated - for e.g. + // template struct A { + // template static constexpr int b = 1; + // decltype(b) constexpr foo() { return 0; }; + // decltype(b) member; + // }; + // template<> template + // constexpr float A::b = 2.0; + // - When A is implicitly instantiated, prior to the new 'b' + // variable template being declared the old 'b' instantiated in + // A gets used in the definition of A and so can not + // be explicitly specialized again. + // FIXME: the diagnostic should state that a different specialization + // type is being specified. + VarTemplateDecl *OldVT = Old->getDescribedVarTemplate(); + if (OldVT->spec_begin() == OldVT->spec_end()) { + Old->setType(New->getType()); + return; + } + + VarTemplateSpecializationDecl *InstConflictVSpec = *OldVT->spec_begin(); + SourceRange Range(New->getLocStart(), New->getLocEnd()); + Diag(New->getLocation(), diag::err_specialization_after_instantiation) + << New->getName() << Range; + + Diag(InstConflictVSpec->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << 0; + return New->setInvalidDecl(); } } else { // C 6.2.7p2: @@ -3238,8 +3358,38 @@ CXXScopeSpec &SS = DS.getTypeSpecScope(); bool IsExplicitSpecialization = !TemplateParams.empty() && TemplateParams.back()->size() == 0; + + // We allow (re-)declarations of member template specializations at namespace + // scope. + // Per C++-N3936 [14.5.5 temp.class.spec]p5 + // A class template partial specialization may be declared or redeclared in + // any namespace scope in which its definition may be defined (14.5.1 and + // 14.5.2). + // template struct A { + // template struct B { }; + // }; + // template template struct A::B; #1 + // template<> template struct A::B; #2 + // template<> template<> struct A::B; #3 + const bool + IsMemberTemplateSpecializationDeclarationSansDefinition = [&Tag, &SS] { + const auto *const RD = dyn_cast_or_null(Tag); + if (RD && SS.isNotEmpty() && isa(RD->getDeclContext()) && + !RD->isCompleteDefinition()) { + // Catch #1, #2 above. + if (isa(RD)) + return true; + // Catch #3 above. + if (isa(RD) && + RD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return true; + } + return false; + }(); + if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() && - !IsExplicitInstantiation && !IsExplicitSpecialization) { + !IsExplicitInstantiation && !IsExplicitSpecialization && + !IsMemberTemplateSpecializationDeclarationSansDefinition) { // Per C++ [dcl.type.elab]p1, a class declaration cannot have a // nested-name-specifier unless it is an explicit instantiation // or an explicit specialization. @@ -5284,7 +5434,7 @@ : SourceLocation(); DeclResult Res = ActOnVarTemplateSpecialization( S, D, TInfo, TemplateKWLoc, TemplateParams, SC, - IsPartialSpecialization); + IsPartialSpecialization, TemplateParamLists); if (Res.isInvalid()) return 0; NewVD = cast(Res.get()); @@ -5506,9 +5656,16 @@ NewVD->setInvalidDecl(); } - if (!IsVariableTemplateSpecialization) + if (!IsVariableTemplateSpecialization) { D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); - + + // We must do this AFTER previous-decl links have been set through + // CheckVariableDeclaration, or else the common-stuff that should + // be reshared across redecls gets miswired. + if (IsExplicitSpecialization && NewTemplate) { + NewTemplate->setMemberSpecialization(); + } + } if (NewTemplate) { VarTemplateDecl *PrevVarTemplate = NewVD->getPreviousDecl() @@ -7184,13 +7341,21 @@ Previous)) NewFD->setInvalidDecl(); } else if (isFunctionTemplateSpecialization) { - if (CurContext->isDependentContext() && CurContext->isRecord() + DeclContext *const SemanticDC = NewFD->getDeclContext(); + if (SemanticDC->isDependentContext() && SemanticDC->isRecord() && !isFriend) { isDependentClassScopeExplicitSpecialization = true; - Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ? - diag::ext_function_specialization_in_class : - diag::err_function_specialization_in_class) - << NewFD->getDeclName(); + // In C++14+ per DR727 - explicit specializations are allowed at class + // scope. + if (!getLangOpts().CPlusPlus1y) { + Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ? + diag::ext_function_specialization_in_class : + diag::err_function_specialization_in_class) + << NewFD->getDeclName(); + } else if (checkDependentClassScopeFunctionExplicitSpecialization( + NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : 0), + Previous)) + NewFD->setInvalidDecl(); } else if (CheckFunctionTemplateSpecialization(NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : 0), Previous)) @@ -7217,6 +7382,12 @@ } } else if (isExplicitSpecialization && isa(NewFD)) { + // template struct A { + // template U* foo(U*, T*) { return 0; } + // }; + // template<> template + // U* A::foo(U*, int*) { return 0; } + // if (CheckMemberSpecialization(NewFD, Previous)) NewFD->setInvalidDecl(); } @@ -7228,11 +7399,11 @@ if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint()) CheckMSVCRTEntryPoint(NewFD); - - if (!NewFD->isInvalidDecl()) - D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, + } + if (!NewFD->isInvalidDecl()) + D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization)); - } + assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && @@ -7285,7 +7456,8 @@ // Qualified decls generally require a previous declaration. if (D.getCXXScopeSpec().isSet()) { // ...with the major exception of templated-scope or - // dependent-scope friend declarations. + // dependent-scope friend declarations and explicit + // specializations of member function templates. // TODO: we currently also suppress this check in dependent // contexts because (1) the parameter depth will be off when @@ -7298,6 +7470,9 @@ D.getCXXScopeSpec().getScopeRep()->isDependent() || CurContext->isDependentContext())) { // ignore these + } else if (isDependentClassScopeExplicitSpecialization && + NewFD->isOutOfLine()) { + // these can be first declared out of line - so ignore these. } else { // The user tried to provide an out-of-line definition for a // function that is a member of a class or namespace, but there @@ -7441,7 +7616,7 @@ if (isDependentClassScopeExplicitSpecialization) { ClassScopeFunctionSpecializationDecl *NewSpec = ClassScopeFunctionSpecializationDecl::Create( - Context, CurContext, SourceLocation(), + Context, CurContext, NewFD->getLocStart(), cast(NewFD), HasExplicitTemplateArgs, TemplateArgs); CurContext->addDecl(NewSpec); @@ -8288,10 +8463,34 @@ // data members we also need to check whether there was an in-class // declaration with an initializer. if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) { - Diag(Init->getExprLoc(), diag::err_static_data_member_reinitialization) - << VDecl->getDeclName(); - Diag(PrevInit->getInit()->getExprLoc(), diag::note_previous_initializer) << 0; - return; + // ... except for static constexpr auto variable templates if they are + // being explicitly specialized. + if (const bool + IsNotAutoVarMemberTemplateBeingExplicitlySpecialized = + !([](Sema &SemaRef, VarDecl *VDecl) { + if (VarTemplateDecl *NewVT = + VDecl->getDescribedVarTemplate()) { + const bool IsMemberTemplateBeingExplicitlySpecialized = + NewVT->isMemberSpecialization(); + const bool IsAutoVarTemplate = + VDecl->getType()->getContainedAutoType(); + return IsMemberTemplateBeingExplicitlySpecialized && + IsAutoVarTemplate; + } + return false; + })(*this, VDecl)) { + Diag(Init->getExprLoc(), diag::err_static_data_member_reinitialization) + << VDecl->getDeclName(); + Diag(PrevInit->getInit()->getExprLoc(), diag::note_previous_initializer) << 0; + return; + } else { + // Adjust the initializer of the previous instantiated-from member decls + // since it has been supplanted by the explicit specialization. + for (auto *D : VDecl->redecls()) { + if (D == PrevInit) + D->setInit(Init); + } + } } if (VDecl->hasLocalStorage()) Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12284,6 +12284,24 @@ // Do not defer instantiations of variables which could be used in a // constant expression. SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var); + // Mark specializations of variable templates that are constexpr + // and evaluated - so that we can distinguish that the initializer + // was instantiated not just for auto type deduction (in the cases + // where we need to know if the variable was truly referenced so + // we can not explicitly specialize it after the fact). + // For e.g. + // template struct A { + // template + // static constexpr auto b = U{1}; <-- #1 + // int mem[b]; <-- #2 + // }; + // template<> template + // constexpt auto A::b = U{2}; <-- #3. + // if #2 is commented out, the above should be ok, else + // #1 is marked as used below, and prevents declaration of #3. + // + if (auto *VSpec = dyn_cast(Var)) + SemaRef.ConstexprVarTemplateSpecsValueUsed.insert(VSpec); } else { SemaRef.PendingInstantiations .push_back(std::make_pair(Var, PointOfInstantiation)); Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -1638,17 +1638,19 @@ // 'template<>' headers, this will be set to the location of that // explicit specialization. SourceLocation ExplicitSpecLoc; - + while (!T.isNull()) { NestedTypes.push_back(T); - // Retrieve the parent of a record type. if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { - // If this type is an explicit specialization, we're done. - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast(Record)) { - if (!isa(Spec) && - Spec->getSpecializationKind() == TSK_ExplicitSpecialization) { + // If this type is an explicit specialization within a non-dependent + // context, we're done. + if (ClassTemplateSpecializationDecl *Spec = + dyn_cast(Record)) { + if (!isa(Spec) && + Spec->getSpecializationKind() == TSK_ExplicitSpecialization && + !Spec->isDependentContext() + ) { ExplicitSpecLoc = Spec->getLocation(); break; } @@ -1723,10 +1725,11 @@ // explicitly specialized. bool SawNonEmptyTemplateParameterList = false; - auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) { - if (SawNonEmptyTemplateParameterList) { - Diag(DeclLoc, diag::err_specialize_member_of_template) - << !Recovery << Range; + auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery, + bool IsLastTPL) { + if (SawNonEmptyTemplateParameterList && !IsLastTPL) { + Diag(DeclLoc, diag::err_specialize_member_of_template) << !Recovery + << Range; Invalid = true; IsExplicitSpecialization = false; return true; @@ -1737,7 +1740,7 @@ auto DiagnoseMissingExplicitSpecialization = [&] (SourceRange Range) { // Check that we can have an explicit specialization here. - if (CheckExplicitSpecialization(Range, true)) + if (CheckExplicitSpecialization(Range, true, false)) return true; // We don't have a template header, but we should. @@ -1824,7 +1827,7 @@ if (ParamIdx < ParamLists.size()) { if (ParamLists[ParamIdx]->size() == 0) { if (CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange(), - false)) + false, ParamLists.size() == ParamIdx + 1)) return 0; } else SawNonEmptyTemplateParameterList = true; @@ -1961,7 +1964,7 @@ // are not explicitly specialized as well. if (ParamLists.back()->size() == 0 && CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange(), - false)) + false, true)) return 0; // Return the last template parameter list, which corresponds to the @@ -2087,7 +2090,9 @@ // TODO: in theory this could be a simple hashtable lookup; most // changes to CurContext don't change the set of current // instantiations. - if (isa(Template)) { + if (ClassTemplateDecl *ClassTemplate = + dyn_cast(Template)) { + bool IsInjectedType = false; for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) { // If we get out to a namespace, we're done. if (Ctx->isFileContext()) break; @@ -2107,7 +2112,6 @@ QualType ICNT = Context.getTypeDeclType(Record); QualType Injected = cast(ICNT) ->getInjectedSpecializationType(); - if (CanonType != Injected->getCanonicalTypeInternal()) continue; @@ -2115,9 +2119,23 @@ // class name type of the record we just found. assert(ICNT.isCanonical()); CanonType = ICNT; + IsInjectedType = true; break; } + if (!IsInjectedType) { + // If not the injected type of the current template, search for + // a specialization (such as a class scope explicit specialization + // within a dependent context) + void *InsertPos = nullptr; + ClassTemplateSpecializationDecl *Decl + = ClassTemplate->findSpecialization(Converted.data(), Converted.size(), + InsertPos); + if (Decl) { + CanonType = Context.getTypeDeclType(Decl); + } + } } + } else if (ClassTemplateDecl *ClassTemplate = dyn_cast(Template)) { // Find the class template specialization declaration that @@ -2128,9 +2146,20 @@ InsertPos); if (!Decl) { // This is the first time we have referenced this class template - // specialization. Create the canonical declaration and add it to - // the set of specializations. - Decl = ClassTemplateSpecializationDecl::Create(Context, + // specialization. Check if we have an explicit specialization. + bool Ambiguous = false; + Decl = getBestExplicitSpecialization( + Ambiguous, ClassTemplate, + ArrayRef(Converted.data(), Converted.size()), + TemplateLoc); + + if (Ambiguous) + return QualType(); + + if (!Decl) { + // Create the canonical declaration and add it to + // the set of specializations. + Decl = ClassTemplateSpecializationDecl::Create(Context, ClassTemplate->getTemplatedDecl()->getTagKind(), ClassTemplate->getDeclContext(), ClassTemplate->getTemplatedDecl()->getLocStart(), @@ -2138,6 +2167,8 @@ ClassTemplate, Converted.data(), Converted.size(), 0); + + } ClassTemplate->AddSpecialization(Decl, InsertPos); if (ClassTemplate->isOutOfLine()) Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext()); @@ -2404,7 +2435,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, VarDecl::StorageClass SC, - bool IsPartialSpecialization) { + bool IsPartialSpecialization, + MultiTemplateParamsArg TemplateParameterLists) { // D must be variable template id. assert(D.getName().getKind() == UnqualifiedId::IK_TemplateId && "Variable template specialization is declared with a template it."); @@ -2537,15 +2569,35 @@ Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC, Converted.data(), Converted.size(), TemplateArgs); - - if (!PrevPartial) + + const bool HasEmptyTemplateParameterLists = ([]( + ArrayRef TPLs) { + for (auto *TPL : TPLs) + if (!TPL->size()) + return true; + return false; + })(TemplateParameterLists); + + if (!PrevPartial) VarTemplate->AddPartialSpecialization(Partial, InsertPos); + Specialization = Partial; - + + if (HasEmptyTemplateParameterLists && PrevPartial) { + // This is an error: Explicitly specialized partial specializations can + // not have previous declaration for variable templates, since each + // explicitly specialized partial specialization has to be a definition. + // We do not need to do anything about this here - since this gets + // caught by the machinery that checks for invalidity of redefinitions. + assert(CurContext != PrevPartial->/*getSemanticDC*/getDeclContext() && + "A redefintion of a variable template, though invalid and marked " + "as such later, should only be possible when we are declaring it " + "out of line"); + } // If we are providing an explicit specialization of a member variable // template specialization, make a note of that. - if (PrevPartial && PrevPartial->getInstantiatedFromMember()) - PrevPartial->setMemberSpecialization(); + if (HasEmptyTemplateParameterLists) + Partial->setMemberSpecialization(); // Check that all of the template parameters of the variable template // partial specialization are deducible from the template @@ -2573,6 +2625,44 @@ } } } + // Check to see if VarTemplateDecl has any instantiations (make sure + // they are implicitly instantiated and not explicit specializations) that + // would use this partial specialization, and if so, this is an error! + if (!PrevDecl) { + VarTemplateSpecializationDecl *const InstThatWouldHaveUsedPartialSpec = + ([VarTemplate, Partial](SourceLocation PointOfInstantiation, + Sema &SemaRef) { + for (VarTemplateSpecializationDecl *Spec : + VarTemplate->specializations()) { + if (Spec->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization) + continue; + const TemplateArgumentList &TemplateArgs = + Spec->getTemplateArgs(); + TemplateDeductionInfo Info(PointOfInstantiation); + if (Sema::TemplateDeductionResult Result = + SemaRef.DeduceTemplateArguments(Partial, TemplateArgs, + Info)) { + /* we could not have used this partial specialization so + * ignore...*/ + } else { + return Spec; + } + } + return (VarTemplateSpecializationDecl *)nullptr; + }(D.getLocStart(), *this)); + + if (InstThatWouldHaveUsedPartialSpec) { + SourceRange Range(TemplateNameLoc, RAngleLoc); + Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) + << Name << Range; + + Diag(InstThatWouldHaveUsedPartialSpec->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << 0; + } + } + } else { // Create a new class template specialization declaration node for // this explicit specialization or friend declaration. @@ -2647,21 +2737,12 @@ return Specialization; } -namespace { -/// \brief A partial specialization whose template arguments have matched -/// a given template-id. -struct PartialSpecMatchResult { - VarTemplatePartialSpecializationDecl *Partial; - TemplateArgumentList *Args; -}; -} - DeclResult Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation TemplateNameLoc, const TemplateArgumentListInfo &TemplateArgs) { assert(Template && "A variable template id without template?"); - + const SourceLocation PointOfInstantiation = TemplateNameLoc; // Check that the template argument list is well-formed for this template. SmallVector Converted; if (CheckTemplateArgumentList( @@ -2672,12 +2753,24 @@ // Find the variable template specialization declaration that // corresponds to these arguments. + void *InsertPos = 0; if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization( Converted.data(), Converted.size(), InsertPos)) // If we already have a variable template specialization, return it. return Spec; - + + bool AmbiguousExplicitSpec = false; + + if (VarTemplateSpecializationDecl *Spec = getBestExplicitSpecialization( + AmbiguousExplicitSpec, Template, Converted, PointOfInstantiation)) { + if (AmbiguousExplicitSpec) { + Spec->setInvalidDecl(); + return true; + } + Template->AddSpecialization(Spec, InsertPos); + return Spec; + } // This is the first time we have referenced this variable template // specialization. Create the canonical declaration and add it to // the set of specializations, based on the closest partial specialization @@ -2685,11 +2778,10 @@ VarDecl *InstantiationPattern = Template->getTemplatedDecl(); TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); - TemplateArgumentList *InstantiationArgs = &TemplateArgList; - bool AmbiguousPartialSpec = false; - typedef PartialSpecMatchResult MatchResult; - SmallVector Matched; - SourceLocation PointOfInstantiation = TemplateNameLoc; + const TemplateArgumentList *InstantiationArgs = &TemplateArgList; + + + TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); // 1. Attempt to find the closest partial specialization that this @@ -2702,74 +2794,23 @@ // Perhaps better after unification of DeduceTemplateArguments() and // getMoreSpecializedPartialSpecialization(). bool InstantiationDependent = false; + bool AmbiguousPartialSpec = false; + if (!TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, InstantiationDependent)) { - - SmallVector PartialSpecs; - Template->getPartialSpecializations(PartialSpecs); - - for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { - VarTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; - TemplateDeductionInfo Info(FailedCandidates.getLocation()); - - if (TemplateDeductionResult Result = - DeduceTemplateArguments(Partial, TemplateArgList, Info)) { - // Store the failed-deduction information for use in diagnostics, later. - // TODO: Actually use the failed-deduction info? - FailedCandidates.addCandidate() - .set(Partial, MakeDeductionFailureInfo(Context, Result, Info)); - (void)Result; - } else { - Matched.push_back(PartialSpecMatchResult()); - Matched.back().Partial = Partial; - Matched.back().Args = Info.take(); - } - } - - if (Matched.size() >= 1) { - SmallVector::iterator Best = Matched.begin(); - if (Matched.size() == 1) { - // -- If exactly one matching specialization is found, the - // instantiation is generated from that specialization. - // We don't need to do anything for this. - } else { - // -- If more than one matching specialization is found, the - // partial order rules (14.5.4.2) are used to determine - // whether one of the specializations is more specialized - // than the others. If none of the specializations is more - // specialized than all of the other matching - // specializations, then the use of the variable template is - // ambiguous and the program is ill-formed. - for (SmallVector::iterator P = Best + 1, - PEnd = Matched.end(); - P != PEnd; ++P) { - if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, - PointOfInstantiation) == - P->Partial) - Best = P; - } - - // Determine if the best partial specialization is more specialized than - // the others. - for (SmallVector::iterator P = Matched.begin(), - PEnd = Matched.end(); - P != PEnd; ++P) { - if (P != Best && getMoreSpecializedPartialSpecialization( - P->Partial, Best->Partial, - PointOfInstantiation) != Best->Partial) { - AmbiguousPartialSpec = true; - break; - } - } - } - + VarTemplatePartialSpecializationDecl *BestPartialSpec = nullptr; + const TemplateArgumentList *BestPartialDeducedArgs = nullptr; + std::tie(BestPartialSpec, BestPartialDeducedArgs, AmbiguousPartialSpec) = + getMostSpecializedPartialSpecialization(Template, TemplateArgList, + PointOfInstantiation); + // Determine the best partial specialization to use, if one exists. + // If the search was ambiguous, then complain, mark + // AmbiguousPartialSpec as true and return one of the ambiguous + // specializations - so that we can error gracefully. + if (BestPartialSpec) { // Instantiate using the best variable template partial specialization. - InstantiationPattern = Best->Partial; - InstantiationArgs = Best->Args; - } else { - // -- If no match is found, the instantiation is generated - // from the primary template. - // InstantiationPattern = Template->getTemplatedDecl(); + InstantiationPattern = BestPartialSpec; + InstantiationArgs = BestPartialDeducedArgs; } } @@ -2782,20 +2823,10 @@ Converted, TemplateNameLoc, InsertPos /*, LateAttrs, StartingScope*/); if (!Decl) return true; - + Template->AddSpecialization(Decl, InsertPos); if (AmbiguousPartialSpec) { - // Partial ordering did not produce a clear winner. Complain. + // Partial ordering did not produce a clear winner. Decl->setInvalidDecl(); - Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous) - << Decl; - - // Print the matching partial specializations. - for (SmallVector::iterator P = Matched.begin(), - PEnd = Matched.end(); - P != PEnd; ++P) - Diag(P->Partial->getLocation(), diag::note_partial_spec_match) - << getTemplateArgumentBindingsText( - P->Partial->getTemplateParameters(), *P->Args); return true; } @@ -3619,6 +3650,113 @@ return None; } +// Check whether we can expand the invented dummy template arguments (used +// during analysis of explicit function specializations within a class scope +// dependent context) into the remaining template parameters. + +template +bool canDummyPackExpansionExtendIntoRemainingTemplateParameters( + Sema &SemaRef, TemplateParameterDecl *TemplateParam, + TemplateParameterList *TemplateParams, TemplateDecl *Template, + const TemplateArgumentListInfo &TemplateArgs) { + + struct DummyTemplateArgAdapter { + static DeclRefExpr * + getDummyPackArgument(NonTypeTemplateParmDecl *NTTP, + const TemplateArgument &PotentiallyDummyTAPack, + Sema &S) { + if (PotentiallyDummyTAPack.getKind() == TemplateArgument::Expression) { + SubstNonTypeTemplateParmExpr *DummyExpr = + dyn_cast( + PotentiallyDummyTAPack.getAsExpr()); + if (DummyExpr && isa(DummyExpr->getReplacement()) && + S.InventedDummyNonTypeTemplateArguments.count( + cast(DummyExpr->getReplacement()))) + return cast(DummyExpr->getReplacement()); + } + return nullptr; + } + + static bool isSameKindOfTemplateParameter(DeclRefExpr *DummyArg, + NamedDecl *NextParam, + Sema &SemaRef) { + return isa(NextParam) && + SemaRef.Context.hasSameType( + DummyArg->getType(), + cast(NextParam)->getType()); + } + static CXXRecordDecl * + getDummyPackArgument(TemplateTypeParmDecl *TTP, + const TemplateArgument &PotentiallyDummyTAPack, + Sema &) { + if (PotentiallyDummyTAPack.getKind() == TemplateArgument::Type) { + QualType UDummyTy = PotentiallyDummyTAPack.getAsType(); + if (auto *RD = UDummyTy->getAsCXXRecordDecl()) { + if (RD->isImplicit() && RD->getName().startswith("$dummy-") && + RD->getName().endswith("-pack")) + return RD; + } + } + return nullptr; + } + static bool isSameKindOfTemplateParameter(CXXRecordDecl *DummyArg, + NamedDecl *NextParam, Sema &) { + return isa(NextParam); + } + static TemplateDecl * + getDummyPackArgument(TemplateTemplateParmDecl *TTP, + const TemplateArgument &PotentiallyDummyTAPack, + Sema &) { + if (PotentiallyDummyTAPack.getKind() == TemplateArgument::Template) { + TemplateDecl *TD = + PotentiallyDummyTAPack.getAsTemplate().getAsTemplateDecl(); + if (TD->isImplicit() && TD->getName().startswith("$dummy-") && + TD->getName().endswith("-pack")) + return TD; + } + return nullptr; + } + static bool isSameKindOfTemplateParameter(TemplateDecl *DummyArg, + NamedDecl *NextParam, + Sema &SemaRef) { + if (TemplateTemplateParmDecl *NextTD = + dyn_cast(NextParam)) { + // Make sure that the template parameter lists are compatible. + TemplateParameterList *DummyTPL = DummyArg->getTemplateParameters(); + TemplateParameterList *NextTPL = NextTD->getTemplateParameters(); + if (SemaRef.TemplateParameterListsAreEqual( + DummyTPL, NextTPL, /*Complain*/ false, + Sema::TPL_TemplateTemplateArgumentMatch, NextTD->getLocation())) + return true; + } + return false; + } + }; + + TemplateParameterList *Params = Template->getTemplateParameters(); + const unsigned NumParams = Params->size(); + const unsigned NumArgs = TemplateArgs.size(); + // If we have runout of template arguments, check to see if we have a dummy + // pack expansion that we can expand into the remaining template arguments + bool CanExpandDummyPacksToFillRemainingTemplateParameters = false; + if (NumParams > NumArgs) { + TemplateArgumentLoc LastTA = TemplateArgs[NumArgs - 1]; + const TemplateArgument &PotentiallyDummyTAPack = LastTA.getArgument(); + if (auto *DummyArg = DummyTemplateArgAdapter::getDummyPackArgument( + TemplateParam, PotentiallyDummyTAPack, SemaRef)) { + CanExpandDummyPacksToFillRemainingTemplateParameters = true; + assert(Params->getParam(NumArgs) == TemplateParam); + for (unsigned I = NumArgs; I < NumParams; ++I) { + if (!DummyTemplateArgAdapter::isSameKindOfTemplateParameter( + DummyArg, Params->getParam(I), SemaRef)) { + CanExpandDummyPacksToFillRemainingTemplateParameters = false; + break; + } + } + } + } + return CanExpandDummyPacksToFillRemainingTemplateParameters; +} /// \brief Check that the given template argument list is well-formed /// for specializing the given template. bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, @@ -3786,9 +3924,17 @@ // (when the template parameter was part of a nested template) into // the default argument. if (TemplateTypeParmDecl *TTP = dyn_cast(*Param)) { - if (!TTP->hasDefaultArgument()) - return diagnoseArityMismatch(*this, Template, TemplateLoc, + if (!TTP->hasDefaultArgument()) { + // Check if we have a dummy-pack that we can extend-by-any as needed. + // dummy-packs are synthesized during checking explicit specializations + // of member template functions within a dependent class (i.e. class + // template) + if (canDummyPackExpansionExtendIntoRemainingTemplateParameters( + *this, TTP, Params, Template, TemplateArgs)) + return false; + return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs); + } TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this, Template, @@ -3803,9 +3949,17 @@ ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*Param)) { - if (!NTTP->hasDefaultArgument()) + if (!NTTP->hasDefaultArgument()) { + // Check if we have a dummy-pack that we can extend-by-any as needed. + // dummy-packs are synthesized during checking explicit specializations + // of member template functions within a dependent class (i.e. class + // template) + if (canDummyPackExpansionExtendIntoRemainingTemplateParameters( + *this, NTTP, Params, Template, TemplateArgs)) + return false; return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs); + } ExprResult E = SubstDefaultTemplateArgument(*this, Template, TemplateLoc, @@ -3821,9 +3975,17 @@ TemplateTemplateParmDecl *TempParm = cast(*Param); - if (!TempParm->hasDefaultArgument()) + if (!TempParm->hasDefaultArgument()) { + // Check if we have a dummy-pack that we can extend-by-any. + // dummy-packs are synthesized during checking explicit specializations + // of member template functions within a dependent class (i.e. class + // template) + if (canDummyPackExpansionExtendIntoRemainingTemplateParameters( + *this, TempParm, Params, Template, TemplateArgs)) + return false; return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs); + } NestedNameSpecifierLoc QualifierLoc; TemplateName Name = SubstDefaultTemplateArgument(*this, Template, @@ -5648,13 +5810,15 @@ } if (S.CurContext->isRecord() && !IsPartialSpecialization) { - if (S.getLangOpts().MicrosoftExt) { + // Explicit specializations are allowed in class scope post DR727 + // that was accepted by EWG as a DR post C++11/14. + if (S.getLangOpts().MicrosoftExt || S.getLangOpts().CPlusPlus1y) { // Do not warn for class scope explicit specialization during // instantiation, warning was already emitted during pattern // semantic analysis. - if (!S.ActiveTemplateInstantiations.size()) - S.Diag(Loc, diag::ext_function_specialization_in_class) - << Specialized; + if (!S.ActiveTemplateInstantiations.size() && + !S.getLangOpts().CPlusPlus1y) + S.Diag(Loc, diag::ext_function_specialization_in_class) << Specialized; } else { S.Diag(Loc, diag::err_template_spec_decl_class_scope) << Specialized; @@ -5887,15 +6051,10 @@ return false; } - -DeclResult -Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, - TagUseKind TUK, - SourceLocation KWLoc, - SourceLocation ModulePrivateLoc, - TemplateIdAnnotation &TemplateId, - AttributeList *Attr, - MultiTemplateParamsArg TemplateParameterLists) { +DeclResult Sema::ActOnClassTemplateSpecialization( + Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, + SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId, + AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists) { assert(TUK != TUK_Reference && "References are not specializations"); CXXScopeSpec &SS = TemplateId.SS; @@ -6133,13 +6292,20 @@ if (!PrevPartial) ClassTemplate->AddPartialSpecialization(Partial, InsertPos); + Specialization = Partial; - + const bool HasEmptyTemplateParameterLists = ([]( + const ArrayRef TemplateParameterLists) { + for (const auto *CurTPL : TemplateParameterLists) + if (!CurTPL->size()) + return true; + return false; + })(TemplateParameterLists); // If we are providing an explicit specialization of a member class // template specialization, make a note of that. - if (PrevPartial && PrevPartial->getInstantiatedFromMember()) - PrevPartial->setMemberSpecialization(); - + if (HasEmptyTemplateParameterLists) + (PrevPartial ? PrevPartial : Partial)->setMemberSpecialization(); + // Check that all of the template parameters of the class template // partial specialization are deducible from the template // arguments. If not, this class template partial specialization @@ -6168,6 +6334,48 @@ } } } + // Check to see if ClassTemplateDecl has any instantiations (make sure + // they are implicitly instantiated and not explicit specializations!) that + // would use this partial specialization, and if so, this is an error! + if (!PrevDecl) { + ClassTemplateSpecializationDecl *const + InstThatWouldHaveUsedPartialSpec = ([]( + ClassTemplateDecl *ClassTemplate, + ClassTemplatePartialSpecializationDecl *Partial, + SourceLocation PointOfInstantiation, Sema &SemaRef) { + for (ClassTemplateSpecializationDecl *Spec : + ClassTemplate->specializations()) { + if (Spec->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization) + continue; + // Unlike for Variable Templates - unless the definition has been + // generated, we can declare a partial specialization after a + // 'mention' that has not required an instantiation. + if (!Spec->isCompleteDefinition()) + continue; + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + TemplateDeductionInfo Info(PointOfInstantiation); + if (Sema::TemplateDeductionResult Result = + SemaRef.DeduceTemplateArguments(Partial, TemplateArgs, + Info)) { + /* we could not have used this partial specialization so ignore...*/ + } else { + return Spec; + } + } + return static_cast(nullptr); + }(ClassTemplate, Partial, TemplateId.TemplateNameLoc, *this)); + + if (InstThatWouldHaveUsedPartialSpec) { + SourceRange Range(TemplateNameLoc, RAngleLoc); + Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) + << Name << Range; + + Diag(InstThatWouldHaveUsedPartialSpec->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << 0; + } + } } else { // Create a new class template specialization declaration node for // this explicit specialization or friend declaration. @@ -6582,6 +6790,472 @@ return false; } +namespace { + +// Used to create a key for the invented type that is used to determine +// whether an explicit specialization of a member template function +// within a dependent context (class template) is well-formed. +struct InventedTemplateArgKey { + unsigned Depth; + unsigned Index; + std::string Postfix; + InventedTemplateArgKey() : Depth(0), Index(0) {} + InventedTemplateArgKey(unsigned D, unsigned I, const std::string &P) + : Depth(D), Index(I), Postfix(P) {} + + bool operator<(const InventedTemplateArgKey &Rhs) const { + const InventedTemplateArgKey &Lhs = *this; + // First sort based on depth, then level, then prefix. + if (Lhs.Depth < Rhs.Depth) + return true; + // Depths are equal so use level... + if (Lhs.Depth == Rhs.Depth) { + if (Lhs.Index < Rhs.Index) + return true; + // FIXME: I think we can drop the comparison dependence on Postfix. + if (Lhs.Index == Rhs.Index) + return Lhs.Postfix < Rhs.Postfix; + } + return false; + } +}; + +// Invent a type uniqued to the depth and index of the template parameter we +// will be substituting into. +inline QualType getInventedDependentType(Sema &SemaRef, + DeclContext *DependentDC, + SourceLocation PointOfInstantiation, + unsigned Depth, unsigned Index, + std::string Postfix = "") { + + InventedTemplateArgKey MKey(Depth, Index, Postfix); + // FIXME: Move this into ASTContext & CXXRecordDecl (i.e + // CreateUniqueRecordType(D, L, P) etc. and add isSyntheticUniqueDependentType + // or some such named function into CXXRecorDecl so that FindInstantiatedDecl + // can query this property directly. + static std::map + InventedRecordDeclMap; + const CXXRecordDecl *InventedRD = nullptr; + // Create the name and record type and add to the map. + if (!(InventedRD = InventedRecordDeclMap[MKey])) { + assert(DependentDC->isDependentContext()); + // Create a name for the invented unique type. + std::string InventedDummyTypeName = "$dummy-"; + llvm::raw_string_ostream ss(InventedDummyTypeName); + ss << Depth; + ss << "-" << Index; + if (Postfix.length()) + ss << "-" << Postfix; + ss.flush(); + + IdentifierInfo &InventedTypeII = + SemaRef.Context.Idents.get(InventedDummyTypeName.c_str()); + auto *RD = CXXRecordDecl::Create(SemaRef.Context, TTK_Class, DependentDC, + PointOfInstantiation, PointOfInstantiation, + &InventedTypeII, nullptr); + RD->setImplicit(true); + InventedRD = RD; + InventedRecordDeclMap[MKey] = InventedRD; + } + return SemaRef.Context.getRecordType(InventedRD); +} +inline DeclRefExpr * +getInventedDependentExpr(Sema &SemaRef, DeclContext *DependentDC, + SourceLocation PointOfInstantiation, + NonTypeTemplateParmDecl *NonTypeParam) { + + const bool IsPack = NonTypeParam->isParameterPack(); + InventedTemplateArgKey MKey(NonTypeParam->getDepth(), + NonTypeParam->getIndex(), IsPack ? "pack" : ""); + + static std::map InventedExprMap; + if (DeclRefExpr *DRE = InventedExprMap[MKey]) + return DRE; + + if (IsPack) { + // If this is a pack, create an invented non-pack non-type-parm so that + // it doesn't force our DRE to contain an unexpanded pack when + // this dependent expression is substituted into packs. + NonTypeParam = NonTypeTemplateParmDecl::Create( + SemaRef.Context, NonTypeParam->getDeclContext(), + NonTypeParam->getLocStart(), NonTypeParam->getInnerLocStart(), + NonTypeParam->getDepth(), NonTypeParam->getIndex(), + NonTypeParam->getIdentifier(), NonTypeParam->getType(), + /*IsPack*/ false, NonTypeParam->getTypeSourceInfo()); + } + DeclRefExpr *DRE = DeclRefExpr::Create( + SemaRef.Context, NestedNameSpecifierLoc(), SourceLocation(), NonTypeParam, + false, DeclarationNameInfo(DeclarationName(NonTypeParam->getIdentifier()), + NonTypeParam->getLocation()), + NonTypeParam->getType(), VK_RValue); + SemaRef.InventedDummyNonTypeTemplateArguments.insert(DRE); + DRE->setValueDependent(true); + DRE->setTypeDependent(true); + DRE->setInstantiationDependent(true); + InventedExprMap[MKey] = DRE; + return DRE; +} + +inline ClassTemplateDecl * +getInventedDependentTemplate(Sema &SemaRef, DeclContext *DependentDC, + SourceLocation PointOfInstantiation, + const TemplateTemplateParmDecl *TemplParam) { + const bool IsPack = TemplParam->isParameterPack(); + QualType InventedTy = getInventedDependentType( + SemaRef, DependentDC, PointOfInstantiation, TemplParam->getDepth(), + TemplParam->getIndex(), IsPack ? "-pack" : ""); + const CXXRecordDecl *InventedClass = InventedTy->getAsCXXRecordDecl(); + static std::map + InventedTemplateMap; + if (ClassTemplateDecl *InventedTempl = InventedTemplateMap[InventedClass]) + return InventedTempl; + + // Create a name for the invented unique template. + std::string InventedDummyTemplName = "$dummy-"; + llvm::raw_string_ostream ss(InventedDummyTemplName); + ss << TemplParam->getDepth(); + ss << "-" << TemplParam->getIndex() << "-template" << (IsPack ? "-pack" : ""); + ss.flush(); + + IdentifierInfo &InventedTemplII = + SemaRef.Context.Idents.get(InventedDummyTemplName.c_str()); + DeclarationName UniqueTemplName(&InventedTemplII); + ClassTemplateDecl *InventedTempl = ClassTemplateDecl::Create( + SemaRef.Context, DependentDC, PointOfInstantiation, UniqueTemplName, + TemplParam->getTemplateParameters(), + const_cast(InventedClass), nullptr); + InventedTempl->setImplicit(true); + InventedTemplateMap[InventedClass] = InventedTempl; + return InventedTempl; +} + +// The type synthesized for a pack needs to be stored in a TemplateArgument +// that needs to have a life time that extends beyond the call of the +// calling function. +// FIXME: We could return a unique_ptr that can be held as long as the vector. +const TemplateArgument &getInventedTypeAsTemplateArgument(QualType InventedTy) { + static std::map InventedTArgMap; + CXXRecordDecl *Key = InventedTy->getAsCXXRecordDecl(); + assert(Key); + TemplateArgument &Val = InventedTArgMap[Key]; + if (Val.isNull()) + Val = TemplateArgument(InventedTy); + return Val; +} + +// The template synthesized for a pack needs to be stored in a TemplateArgument +// that needs to have a life time that extends beyond the call of the +// calling function. +// FIXME: We could return a unique_ptr that can be held as long as the vector. +const TemplateArgument & +getInventedTemplateAsTemplateArgument(ClassTemplateDecl *InventedTempl) { + static std::map InventedTArgMap; + TemplateArgument &Val = InventedTArgMap[InventedTempl]; + if (Val.isNull()) + Val = TemplateArgument(TemplateName(InventedTempl)); + return Val; +} + +const TemplateArgument & +getInventedExprAsTemplateArgument(DeclRefExpr *InventedDRE) { + static std::map InventedTArgMap; + TemplateArgument &Val = InventedTArgMap[InventedDRE]; + if (Val.isNull()) + Val = TemplateArgument(InventedDRE); + return Val; +} +} + +namespace { +SmallVector +getInventedTemplateArguments(Sema &SemaRef, + TemplateDecl *TD, + SourceLocation PointOfInstantiation) { + SmallVector TArgs; + TemplateParameterList *CurTPL = TD->getTemplateParameters(); + + static DeclContext *DependentDC = ([&] { + // Create a dummy dependent decl context that will contain all the dummy + // template arguments we invent. + const char *InventedDummyDCPatternName = "$dummy-declcontext-pattern"; + const char *InventedDummyDCTemplName = "$dummy-declcontext-template"; + + IdentifierInfo &InventedTypeII = + SemaRef.Context.Idents.get(InventedDummyDCPatternName); + auto *InventedRD = CXXRecordDecl::Create( + SemaRef.Context, TTK_Class, SemaRef.Context.getTranslationUnitDecl(), + PointOfInstantiation, PointOfInstantiation, &InventedTypeII, nullptr); + + DeclarationName UniqueTemplName( + &SemaRef.Context.Idents.get(InventedDummyDCTemplName)); + auto *InventedTempl = ClassTemplateDecl::Create( + SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(), + PointOfInstantiation, UniqueTemplName, + TemplateParameterList::Create(SemaRef.Context, SourceLocation(), + SourceLocation(), nullptr, 0, + SourceLocation()), + const_cast(InventedRD), nullptr); + + InventedRD->setDescribedClassTemplate(InventedTempl); + InventedRD->setImplicit(); + InventedTempl->setImplicit(); + return InventedRD; + })(); + + for (NamedDecl *ND : CurTPL->asArray()) { + if (TemplateTypeParmDecl *TypeParam = dyn_cast(ND)) { + // Generate a unique dependent type to substitute for this template param. + const bool IsPack = TypeParam->isParameterPack(); + QualType InventedTy = getInventedDependentType( + SemaRef, DependentDC, PointOfInstantiation, TypeParam->getDepth(), + TypeParam->getIndex(), IsPack ? "pack" : ""); + const TemplateArgument &TArg = getInventedTypeAsTemplateArgument(InventedTy); + TArgs.push_back(IsPack ? TemplateArgument(&TArg, 1) : TArg); + } else if (NonTypeTemplateParmDecl *NonTypeParam = + dyn_cast(ND)) { + const bool IsPack = NonTypeParam->isParameterPack(); + DeclRefExpr *InventedDRE = getInventedDependentExpr(SemaRef, DependentDC, PointOfInstantiation, NonTypeParam); + const TemplateArgument &TArg = getInventedExprAsTemplateArgument(InventedDRE); + TArgs.push_back(IsPack ? TemplateArgument(&TArg, 1) : TArg); + + } else if (TemplateTemplateParmDecl *TemplParam = + dyn_cast(ND)) { + const TemplateArgument &InventedTemplArg = + getInventedTemplateAsTemplateArgument(getInventedDependentTemplate( + SemaRef, DependentDC, PointOfInstantiation, TemplParam)); + TArgs.push_back(TemplParam->isParameterPack() + ? TemplateArgument(&InventedTemplArg, 1) + : InventedTemplArg); + } + } + return TArgs; +} +} // end anynoymous ns + +/// \brief Perform semantic analysis for the given dependent member function +/// explicit template specialization. +/// +/// For e.g.: +/// +/// \code +/// template \ class A { +/// template \ U* foo(U*, T*) { return 0; }; +/// template<> char* foo(int*, float*, char*); <-- this should be an error +/// }; +/// \endcode +/// +/// The potential analysis that can be done here: +/// - try and deduce only the template parameters at that level +/// - all other parameters should match exactly +/// - we can not just rely on the number of parameters - since we can have variadic templates +/// + +bool Sema::checkDependentClassScopeFunctionExplicitSpecialization( + FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, + LookupResult &Previous) { + // The set of function template specializations that could match this + // explicit function template specialization. + UnresolvedSet<8> Candidates; + TemplateSpecCandidateSet FailedCandidates(FD->getLocation()); + // Retrieve the actual template from the the dummy specialization. + std::map MapDummySpecToRealTemplate; + // A pointer to the dummy explicit template args. + TemplateArgumentListInfo *DummyExplicitTemplateArgs = nullptr; + // A temporary object that DummyExplicitTemplateArgs will point to if needed. + TemplateArgumentListInfo DummyExplicitTemplateArgsOnStack; + + // We need to store each template arg vector so that we can pass + // a reference to each vector to OuterTemplateArgs. + SmallVector, 4> TemplateArgsVectors; + MultiLevelTemplateArgumentList OuterTemplateArgs; + // Climb through all dependent contexts that are templates and + // invent arguments for each of their template parameter lists. + DeclContext *ParentDC = FD->getDeclContext(); + while (ParentDC && ParentDC->isDependentContext()) { + assert([&] { + if (!isa(ParentDC)) + if (Decl *D = dyn_cast(ParentDC)) + D->dump(); + assert(isa(ParentDC) && + "A dependent decl context must be a CXXRecordDecl!"); + return true; + }()); + CXXRecordDecl *RD = dyn_cast(ParentDC); + if (TemplateDecl *TD = RD->getDescribedClassTemplate()) { + TemplateArgsVectors.push_back(getInventedTemplateArguments( + *this, TD, /*PointOfInstantiation*/FD->getLocStart())); + OuterTemplateArgs.addOuterTemplateArguments(TemplateArgsVectors.back()); + } + ParentDC = ParentDC->getParent(); + } + + DeclContext *FDLookupContext = FD->getDeclContext()->getRedeclContext(); + for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); + I != E; ++I) { + NamedDecl *Ovl = (*I)->getUnderlyingDecl(); + if (FunctionTemplateDecl *FunTmpl = dyn_cast(Ovl)) { + // Only consider templates found within the same semantic lookup scope as + // FD. + if (!FDLookupContext->InEnclosingNamespaceSetOf( + Ovl->getDeclContext()->getRedeclContext())) + continue; + + // When matching a constexpr member function template specialization + // against the primary template, we don't yet know whether the + // specialization has an implicit 'const' (because we don't know whether + // it will be a static member function until we know which template it + // specializes), so adjust it now assuming it specializes this template. + QualType FT = FD->getType(); + if (FD->isConstexpr()) { + CXXMethodDecl *OldMD = + dyn_cast(FunTmpl->getTemplatedDecl()); + if (OldMD && OldMD->isConst()) { + const FunctionProtoType *FPT = FT->castAs(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.TypeQuals |= Qualifiers::Const; + FT = Context.getFunctionType(FPT->getReturnType(), + FPT->getParamTypes(), EPI); + } + } + + // C++ [temp.expl.spec]p11: + // A trailing template-argument can be left unspecified in the + // template-id naming an explicit function template specialization + // provided it can be deduced from the function argument type. + // Perform template argument deduction to determine whether we may be + // specializing this template. + // FIXME: It is somewhat wasteful to build + TemplateDeductionInfo Info(FailedCandidates.getLocation()); + FunctionDecl *Specialization = 0; + CXXMethodDecl *DummyFD = nullptr; + + auto *DummyFTD = ([&DummyFD, &DummyExplicitTemplateArgs, + &DummyExplicitTemplateArgsOnStack, + ExplicitTemplateArgs, &OuterTemplateArgs]( + Sema &SemaRef, SourceLocation PointOfInstantiation, + FunctionTemplateDecl *FTD, CXXMethodDecl *ExplicitFD) { + + Sema::InstantiatingTemplate Inst(SemaRef, PointOfInstantiation, FTD); + // If we have exceeded the maximum recursion instantiation depth, + // return + // null. + // FIXME: What diagnostic should we emit here? + if (Inst.isInvalid()) + return static_cast(FTD); + + // Enter the DeclContext that contains the partial spec we will be + // substituting into ... + // We don't use PushDeclContext because we don't have a scope. + Sema::ContextRAII SavedContext(SemaRef, FTD->getDeclContext()); + + EnterExpressionEvaluationContext EvalContext(SemaRef, + Sema::Unevaluated); + + Sema::SFINAETrap IntroduceSFINAE(SemaRef, true); + if (ExplicitTemplateArgs && !DummyExplicitTemplateArgs) { + // Substitue into the explicitly specified template arguments. + DummyExplicitTemplateArgs = &DummyExplicitTemplateArgsOnStack; + DummyExplicitTemplateArgs->setLAngleLoc( + ExplicitTemplateArgs->getLAngleLoc()); + DummyExplicitTemplateArgs->setRAngleLoc( + ExplicitTemplateArgs->getRAngleLoc()); + if (SemaRef.Subst(ExplicitTemplateArgs->getArgumentArray(), + ExplicitTemplateArgs->size(), + DummyExplicitTemplateArgsOnStack, + OuterTemplateArgs)) + return static_cast(nullptr); + } + TemplateDeclInstantiator DeclInstantiator( + SemaRef, FTD->getDeclContext(), OuterTemplateArgs); + + auto *NewFTD = cast_or_null( + DeclInstantiator.VisitFunctionTemplateDecl(FTD, true)); + // Set access temporarily for now - we will update access + // once the parent template has been selected. + ExplicitFD->setAccess(FTD->getAccess()); + DummyFD = cast_or_null( + DeclInstantiator.VisitCXXMethodDecl(ExplicitFD, nullptr, true)); + return NewFTD; + }(*this, FD->getLocStart(), + cast(FunTmpl->getFirstDecl()), + cast(FD))); + if (!DummyFTD || !DummyFD) + continue; + + if (TemplateDeductionResult TDK = DeduceTemplateArguments( + DummyFTD, DummyExplicitTemplateArgs, DummyFD->getType(), + Specialization, Info)) { + // Template argument deduction failed; record why it failed, so + // that we can provide nifty diagnostics. + FailedCandidates.addCandidate() + .set(FunTmpl->getTemplatedDecl(), + MakeDeductionFailureInfo(Context, TDK, Info)); + (void)TDK; + continue; + } + MapDummySpecToRealTemplate[Specialization] = FunTmpl; + // Record this candidate. + Candidates.addDecl(Specialization, I.getAccess()); + } + } + + // Find the most specialized function template. + UnresolvedSetIterator Result = getMostSpecialized( + Candidates.begin(), Candidates.end(), FailedCandidates, + FD->getLocation(), + PDiag(diag::err_function_template_spec_no_match) << FD->getDeclName(), + PDiag(diag::err_function_template_spec_ambiguous) + << FD->getDeclName() << (ExplicitTemplateArgs != 0), + PDiag(diag::note_function_template_spec_matched)); + + if (Result == Candidates.end()) { + FD->setInvalidDecl(); + return true; + } + + FunctionDecl *DummySpecialization = cast(*Result); + FunctionTemplateDecl *RealTemplate = + MapDummySpecToRealTemplate[DummySpecialization]; + + FunctionTemplateSpecializationInfo *DummySpecInfo = + DummySpecialization->getTemplateSpecializationInfo(); + void *InsertPos = 0; + + // FIXME: + // We should transform all references to dummy-types within the + // deduced template arguments back into their corresponding template types + // - so that if the explicit specialization is specialized using outer + // template parameters - we refer to them and not to the dummy-types. + // - the way to do this is to use the type-transformer and where + // ever we find a dummy-type or dummy-expr or dummy-template + // based on its depth and index we replace it with its outer + // corresponding template parameter. + // - look at SemaTemplateDeduction.cpp::SubstituteAutoTransform + // to replace a dummy type with its template parameter type + // - look at Type.cpp::GetContainedAutoVisitor to check if a dummy + // type is present within a template-argument. + // [Note: that above visitors will need to be adapted and must handle + // dummy-nontypes and dummy-templates] + // We should maintain a mapping from dummy-exprs to original exprs + // dummy-types to original template parameter types & dummy-types to + // original tempalte type parameters - so that we can substitute them + // back in. + // Currently within the deduced arguments is the only place where references + // to these dummy arguments persist. The only purpose they serve is to + // early detect redefinitions. + if (FunctionDecl *PrevSpec = RealTemplate->findSpecialization( + DummySpecInfo->TemplateArguments->data(), + DummySpecInfo->TemplateArguments->size(), InsertPos)) { + Previous.clear(); + Previous.addDecl(PrevSpec); + } else { + FD->setFunctionTemplateSpecialization( + RealTemplate, DummySpecInfo->TemplateArguments, InsertPos, + TSK_ExplicitSpecialization, ExplicitTemplateArgs, FD->getLocation()); + } + return false; +} + /// \brief Perform semantic analysis for the given function template /// specialization. /// @@ -6646,6 +7320,24 @@ // FIXME: It is somewhat wasteful to build TemplateDeductionInfo Info(FailedCandidates.getLocation()); FunctionDecl *Specialization = 0; + struct MethodSpecBeingDeclaredRAII { + Sema &SemaRef; + MethodSpecBeingDeclaredRAII(CXXMethodDecl *PatternOfMethodBeingDeclared, + Sema &S) + : SemaRef(S) { + SemaRef.PatternOfMethodSpecializationBeingDeclared.push_back( + PatternOfMethodBeingDeclared); + } + ~MethodSpecBeingDeclaredRAII() { + SemaRef.PatternOfMethodSpecializationBeingDeclared.pop_back(); + } + }; + std::unique_ptr MethodSpecBeingDeclaredRAIIObj; + if (isa(FD) && + isa(FunTmpl->getTemplatedDecl())) + MethodSpecBeingDeclaredRAIIObj.reset(new MethodSpecBeingDeclaredRAII( + cast(FunTmpl->getTemplatedDecl()), *this)); + if (TemplateDeductionResult TDK = DeduceTemplateArguments( cast(FunTmpl->getFirstDecl()), ExplicitTemplateArgs, FT, Specialization, Info)) { Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -139,7 +139,7 @@ /// \brief If the given expression is of a form that permits the deduction /// of a non-type template parameter, return the declaration of that /// non-type template parameter. -static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) { +static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E, Sema &S) { // If we are within an alias template, the expression may have undergone // any number of parameter substitutions already. while (1) { @@ -152,9 +152,11 @@ break; } - if (DeclRefExpr *DRE = dyn_cast(E)) + if (DeclRefExpr *DRE = dyn_cast(E)) { + if (S.InventedDummyNonTypeTemplateArguments.count(DRE)) + return nullptr; return dyn_cast(DRE->getDecl()); - + } return 0; } @@ -338,6 +340,7 @@ return Sema::TDK_Success; } + /// \brief Deduce the value of the given non-type template parameter /// from the given type- or value-dependent expression. /// @@ -352,7 +355,6 @@ "Cannot deduce non-type template argument with depth > 0"); assert((Value->isTypeDependent() || Value->isValueDependent()) && "Expression template argument must be type- or value-dependent."); - DeducedTemplateArgument NewDeduced(Value); DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, Deduced[NTTP->getIndex()], @@ -1327,7 +1329,7 @@ // Determine the array bound is something we can deduce. NonTypeTemplateParmDecl *NTTP - = getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr()); + = getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr(), S); if (!NTTP) return Sema::TDK_Success; @@ -1587,7 +1589,7 @@ // Perform deduction on the vector size, if we can. NonTypeTemplateParmDecl *NTTP - = getDeducedParameterFromExpr(VectorParam->getSizeExpr()); + = getDeducedParameterFromExpr(VectorParam->getSizeExpr(), S); if (!NTTP) return Sema::TDK_Success; @@ -1609,7 +1611,7 @@ // Perform deduction on the vector size, if we can. NonTypeTemplateParmDecl *NTTP - = getDeducedParameterFromExpr(VectorParam->getSizeExpr()); + = getDeducedParameterFromExpr(VectorParam->getSizeExpr(), S); if (!NTTP) return Sema::TDK_Success; @@ -1636,6 +1638,37 @@ llvm_unreachable("Invalid Type Class!"); } +namespace clang { +Sema::TemplateDeductionResult +DeduceTemplateArgumentsByTypeMatchForExplicitSpecializations( + Sema &S, FunctionTemplateDecl *PrimaryTemplate, + CXXMethodDecl *SubstitutedExplicitSpecialization, + TemplateArgumentListInfo *SubstitutedExplicitTemplateArgs, + TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced) { + TemplateParameterList *TemplateParams = + PrimaryTemplate->getTemplateParameters(); + QualType PrimaryTemplateType = PrimaryTemplate->getTemplatedDecl()->getType(); + QualType ExplicitSpecType = SubstitutedExplicitSpecialization->getType(); + ExplicitSpecType = + S.adjustCCAndNoReturn(ExplicitSpecType, PrimaryTemplateType); + if (SubstitutedExplicitTemplateArgs) { + LocalInstantiationScope NewInstScope(S, false); + SmallVector ParamTypes; + if (Sema::TemplateDeductionResult Result = + S.SubstituteExplicitTemplateArguments( + PrimaryTemplate, *SubstitutedExplicitTemplateArgs, Deduced, + ParamTypes, &PrimaryTemplateType, Info)) + return Result; + } + + Deduced.resize(TemplateParams->size()); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, PrimaryTemplateType, ExplicitSpecType, Info, Deduced, + TDF_TopLevelParameterTypeList); +} +} + static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, @@ -1716,7 +1749,7 @@ case TemplateArgument::Expression: { if (NonTypeTemplateParmDecl *NTTP - = getDeducedParameterFromExpr(Param.getAsExpr())) { + = getDeducedParameterFromExpr(Param.getAsExpr(), S)) { if (Arg.getKind() == TemplateArgument::Integral) return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsIntegral(), @@ -2925,8 +2958,10 @@ if (!Specialization || Specialization->isInvalidDecl()) return TDK_SubstitutionFailure; - assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() == - FunctionTemplate->getCanonicalDecl()); + // FIXME: If a specialization is generated from a dependent scope explicit + // specialization of a member template - check to make sure its ancestor + // template - via getInstantiationOfMemberFunction - returns a specialization + // of the member template which this template is instantiated from. // If the template argument list is owned by the function template // specialization, release it. @@ -3601,6 +3636,10 @@ if (!ArgFunctionType.isNull()) { unsigned TDF = TDF_TopLevelParameterTypeList; if (InOverloadResolution) TDF |= TDF_InOverloadResolution; + + + + // Deduce template arguments from the function type. if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, @@ -4560,21 +4599,39 @@ return SpecEnd; } -/// \brief Returns the more specialized class template partial specialization -/// according to the rules of partial ordering of class template partial -/// specializations (C++ [temp.class.order]). -/// -/// \param PS1 the first class template partial specialization -/// -/// \param PS2 the second class template partial specialization -/// -/// \returns the more specialized class template partial specialization. If -/// neither partial specialization is more specialized, returns NULL. -ClassTemplatePartialSpecializationDecl * -Sema::getMoreSpecializedPartialSpecialization( - ClassTemplatePartialSpecializationDecl *PS1, - ClassTemplatePartialSpecializationDecl *PS2, - SourceLocation Loc) { +namespace { + struct GetMoreSpecializedPartialSpecializationImpl; +} +// Implementation details of getMoreSpecializedPartialSpecializationImpl +struct ::GetMoreSpecializedPartialSpecializationImpl{ + + static QualType getTypeOfPartialSpecialization( + ClassTemplatePartialSpecializationDecl *PS) { + return PS->getInjectedSpecializationType(); + } + + static QualType + getTypeOfPartialSpecialization(VarTemplatePartialSpecializationDecl *PS) { + TemplateName Name(PS->getSpecializedTemplate()); + ASTContext &Context = PS->getASTContext(); + TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); + return Context.getTemplateSpecializationType(CanonTemplate, + PS->getTemplateArgs().data(), + PS->getTemplateArgs().size()); + + } + + +}; + +template +PartialSpecializationDecl * +getMoreSpecializedPartialSpecializationImpl(PartialSpecializationDecl *PS1, + PartialSpecializationDecl *PS2, + SourceLocation Loc, Sema &SemaRef) { + + SmallVector Deduced; + TemplateDeductionInfo Info(Loc); // C++ [temp.class.order]p1: // For two class template partial specializations, the first is at least as // specialized as the second if, given the following rewrite to two @@ -4599,46 +4656,103 @@ // know that every template parameter is deducible from the class // template partial specialization's template arguments, for // example. - SmallVector Deduced; - TemplateDeductionInfo Info(Loc); + + QualType PT1 = GetMoreSpecializedPartialSpecializationImpl:: + getTypeOfPartialSpecialization(PS1); + QualType PT2 = GetMoreSpecializedPartialSpecializationImpl:: + getTypeOfPartialSpecialization(PS2); - QualType PT1 = PS1->getInjectedSpecializationType(); - QualType PT2 = PS2->getInjectedSpecializationType(); - // Determine whether PS1 is at least as specialized as PS2 Deduced.resize(PS2->getTemplateParameters()->size()); - bool Better1 = !DeduceTemplateArgumentsByTypeMatch(*this, + bool Better1 = !DeduceTemplateArgumentsByTypeMatch(SemaRef, PS2->getTemplateParameters(), PT2, PT1, Info, Deduced, TDF_None, /*PartialOrdering=*/true, /*RefParamComparisons=*/0); if (Better1) { SmallVector DeducedArgs(Deduced.begin(),Deduced.end()); - InstantiatingTemplate Inst(*this, Loc, PS2, DeducedArgs, Info); + Sema::InstantiatingTemplate Inst(SemaRef, Loc, PS2, DeducedArgs, Info); Better1 = !::FinishTemplateArgumentDeduction( - *this, PS2, PS1->getTemplateArgs(), Deduced, Info); + SemaRef, PS2, PS1->getTemplateArgs(), Deduced, Info); } // Determine whether PS2 is at least as specialized as PS1 Deduced.clear(); Deduced.resize(PS1->getTemplateParameters()->size()); bool Better2 = !DeduceTemplateArgumentsByTypeMatch( - *this, PS1->getTemplateParameters(), PT1, PT2, Info, Deduced, TDF_None, + SemaRef, PS1->getTemplateParameters(), PT1, PT2, Info, Deduced, TDF_None, /*PartialOrdering=*/true, /*RefParamComparisons=*/0); if (Better2) { SmallVector DeducedArgs(Deduced.begin(), Deduced.end()); - InstantiatingTemplate Inst(*this, Loc, PS1, DeducedArgs, Info); + Sema::InstantiatingTemplate Inst(SemaRef, Loc, PS1, DeducedArgs, Info); Better2 = !::FinishTemplateArgumentDeduction( - *this, PS1, PS2->getTemplateArgs(), Deduced, Info); + SemaRef, PS1, PS2->getTemplateArgs(), Deduced, Info); } + // Neither is better than the other, so if one is more specialized than the + // other based on the number of empty template parameter lists, choose that. + // This tie breaker can be used in such scenarios: + // + // template struct O { + // template struct L { + // int p; + // }; + // template struct L { + // int k; + // }; + // }; + // + // struct HasType { + // typedef HasType *type; + // }; + // + // template <> template struct O::L { + // int j; + // }; + // + // int x0 = O::L().j; + // In this instance, both partials make it through to this step since + // neither maps to a previous declaration of the other. + if (Better1 == Better2) { + auto GetPrototypePartialSpecialization = [](PartialSpecializationDecl *D) { + PartialSpecializationDecl *It = D; + while (It->getInstantiatedFromMember()) { + if (It->isMemberSpecialization()) + return It; + It = It->getInstantiatedFromMember(); + } + return It; + }; + unsigned NumOfEmptyTPLSin1 = SemaRef.getNumberOfEmptyTemplateParameterLists( + GetPrototypePartialSpecialization(PS1)); + unsigned NumOfEmptyTPLSin2 = SemaRef.getNumberOfEmptyTemplateParameterLists( + GetPrototypePartialSpecialization(PS2)); + if (NumOfEmptyTPLSin1 == NumOfEmptyTPLSin2) + return 0; + else + return (NumOfEmptyTPLSin1 > NumOfEmptyTPLSin2) ? PS1 : PS2; + } - if (Better1 == Better2) - return 0; - return Better1 ? PS1 : PS2; } +/// \brief Returns the more specialized class template partial specialization +/// according to the rules of partial ordering of class template partial +/// specializations (C++ [temp.class.order]). +/// +/// \param PS1 the first class template partial specialization +/// +/// \param PS2 the second class template partial specialization +/// +/// \returns the more specialized class template partial specialization. If +/// neither partial specialization is more specialized, returns NULL. +ClassTemplatePartialSpecializationDecl * +Sema::getMoreSpecializedPartialSpecialization( + ClassTemplatePartialSpecializationDecl *PS1, + ClassTemplatePartialSpecializationDecl *PS2, + SourceLocation Loc) { + return getMoreSpecializedPartialSpecializationImpl(PS1, PS2, Loc, *this); +} /// TODO: Unify with ClassTemplatePartialSpecializationDecl version? /// May require unifying ClassTemplate(Partial)SpecializationDecl and @@ -4649,56 +4763,12 @@ Sema::getMoreSpecializedPartialSpecialization( VarTemplatePartialSpecializationDecl *PS1, VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc) { - SmallVector Deduced; - TemplateDeductionInfo Info(Loc); - assert(PS1->getSpecializedTemplate() == PS2->getSpecializedTemplate() && + assert(PS1->getSpecializedTemplate()->getCanonicalDecl() == + PS2->getSpecializedTemplate()->getCanonicalDecl() && "the partial specializations being compared should specialize" " the same template."); - TemplateName Name(PS1->getSpecializedTemplate()); - TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); - QualType PT1 = Context.getTemplateSpecializationType( - CanonTemplate, PS1->getTemplateArgs().data(), - PS1->getTemplateArgs().size()); - QualType PT2 = Context.getTemplateSpecializationType( - CanonTemplate, PS2->getTemplateArgs().data(), - PS2->getTemplateArgs().size()); - - // Determine whether PS1 is at least as specialized as PS2 - Deduced.resize(PS2->getTemplateParameters()->size()); - bool Better1 = !DeduceTemplateArgumentsByTypeMatch( - *this, PS2->getTemplateParameters(), PT2, PT1, Info, Deduced, TDF_None, - /*PartialOrdering=*/true, - /*RefParamComparisons=*/0); - if (Better1) { - SmallVector DeducedArgs(Deduced.begin(), - Deduced.end()); - InstantiatingTemplate Inst(*this, Loc, PS2, DeducedArgs, Info); - Better1 = !::FinishTemplateArgumentDeduction(*this, PS2, - PS1->getTemplateArgs(), - Deduced, Info); - } - - // Determine whether PS2 is at least as specialized as PS1 - Deduced.clear(); - Deduced.resize(PS1->getTemplateParameters()->size()); - bool Better2 = !DeduceTemplateArgumentsByTypeMatch(*this, - PS1->getTemplateParameters(), - PT1, PT2, Info, Deduced, TDF_None, - /*PartialOrdering=*/true, - /*RefParamComparisons=*/0); - if (Better2) { - SmallVector DeducedArgs(Deduced.begin(),Deduced.end()); - InstantiatingTemplate Inst(*this, Loc, PS1, DeducedArgs, Info); - Better2 = !::FinishTemplateArgumentDeduction(*this, PS1, - PS2->getTemplateArgs(), - Deduced, Info); - } - - if (Better1 == Better2) - return 0; - - return Better1? PS1 : PS2; + return getMoreSpecializedPartialSpecializationImpl(PS1, PS2, Loc, *this); } static void Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -31,6 +31,10 @@ // Template Instantiation Support //===----------------------------------------------------------------------===/ +//===----------------------------------------------------------------------===/ +// Template Instantiation Support +//===----------------------------------------------------------------------===/ + /// \brief Retrieve the template argument list(s) that should be used to /// instantiate the definition of the given declaration. /// @@ -48,20 +52,31 @@ /// instantiating the definition of the given declaration, \p D. This is /// used to determine the proper set of template instantiation arguments for /// friend function template specializations. -MultiLevelTemplateArgumentList -Sema::getTemplateInstantiationArgs(NamedDecl *D, - const TemplateArgumentList *Innermost, - bool RelativeToPrimary, - const FunctionDecl *Pattern) { +/// +/// \param TPLsOfDeclBeingSubstituted If non-empty, indicates the +/// template-parameter-lists of the prototype declaration whose pattern is +/// being used to instantiate 'D'. +/// + +MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( + NamedDecl *D, const TemplateArgumentList *Innermost, bool RelativeToPrimary, + const FunctionDecl *Pattern, + ArrayRef TPLsOfDeclBeingSubstituted) { // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; + // Track the decl context with the TPLsOfDeclBeingSubstituted. Each time a TPL + // is consumed off that array - increment this. + // '0' is the current innermost DeclContext. It is used to determine the + // index within TPLsOfDeclBeingSubstituted if supplied. + unsigned TPLsDeclContextTracker = 0; if (Innermost) Result.addOuterTemplateArguments(Innermost); DeclContext *Ctx = dyn_cast(D); if (!Ctx) { Ctx = D->getDeclContext(); + ++TPLsDeclContextTracker; // Add template arguments from a variable template instantiation. if (VarTemplateSpecializationDecl *Spec = @@ -104,27 +119,60 @@ return Result; } } - } - + } while (!Ctx->isFileContext()) { + TemplateParameterList *const CurTPL = [&] { + const int NumberOfTPLsOfDeclBeingSubstituted = + TPLsOfDeclBeingSubstituted.size(); + const int CurTPLIndex = + NumberOfTPLsOfDeclBeingSubstituted + ? NumberOfTPLsOfDeclBeingSubstituted - 1 - TPLsDeclContextTracker + : -1; + return CurTPLIndex >= 0 ? TPLsOfDeclBeingSubstituted[CurTPLIndex] + : nullptr; + }(); // Add template arguments from a class template instantiation. if (ClassTemplateSpecializationDecl *Spec = dyn_cast(Ctx)) { - // We're done when we hit an explicit specialization. - if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && - !isa(Spec)) + // We're done when we hit an explicit specialization and we don't have + // the TPLs of the declaration being substituted to determine if specializations + // from ancestral templates are appropriate for use. + if ((Spec->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa(Spec))) { + // If the ctx is an explicit declaration or if the declaration of the + // pattern that will be used for instantiation has an empty tpl at this + // level, it clearly does not need to be substituted into it at this + // level. + // For e.g. consider the pattern declaration #1 below: + // template struct A { + // template struct B { + // }; + // }; + // template<> template struct A::B { }; #1 + // + // If we have a TPL at this level and it is empty, consume it via incrementing OuterDeclContextIndex. + if (CurTPL) { + if (!CurTPL->size()) + ++TPLsDeclContextTracker; + goto loop_next; + } break; - - Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); - - // If this class template specialization was instantiated from a + } + // If the tpl of the decl being substituted into is empty, ignore the + // template arguments at that level and continue with the outer ones. + // For e.g. + // template template<> + // struct A::B { ... }; + // while instantiating A::B --> ignore the + if (!CurTPL || CurTPL->size()) + Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); + // If this class template specialization was instantiated from a // specialized member that is a class template, we're done. assert(Spec->getSpecializedTemplate() && "No class template?"); if (Spec->getSpecializedTemplate()->isMemberSpecialization()) break; - } - // Add template arguments from a function template specialization. - else if (FunctionDecl *Function = dyn_cast(Ctx)) { + } else if (FunctionDecl *Function = dyn_cast(Ctx)) { + // Add template arguments from a function template specialization. if (!RelativeToPrimary && (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && @@ -169,12 +217,13 @@ const TemplateSpecializationType *TST = cast(Context.getCanonicalType(T)); Result.addOuterTemplateArguments( - llvm::makeArrayRef(TST->getArgs(), TST->getNumArgs())); + llvm::makeArrayRef(TST->getArgs(), TST->getNumArgs())); if (ClassTemplate->isMemberSpecialization()) break; } } - + ++TPLsDeclContextTracker; +loop_next: Ctx = Ctx->getParent(); RelativeToPrimary = false; } @@ -182,6 +231,7 @@ return Result; } + bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const { switch (Kind) { case TemplateInstantiation: @@ -1184,7 +1234,6 @@ type = arg.getIntegralType(); } if (result.isInvalid()) return ExprError(); - Expr *resultExpr = result.take(); return SemaRef.Owned(new (SemaRef.Context) SubstNonTypeTemplateParmExpr(type, @@ -1284,8 +1333,12 @@ // Handle references to non-type template parameters and non-type template // parameter packs. if (NonTypeTemplateParmDecl *NTTP = dyn_cast(D)) { - if (NTTP->getDepth() < TemplateArgs.getNumLevels()) + if (NTTP->getDepth() < TemplateArgs.getNumLevels()) { + // Do nothing to invented dummy template arguments. + if (getSema().InventedDummyNonTypeTemplateArguments.count(E)) + return ExprResult(E); return TransformTemplateParmRefExpr(E, NTTP); + } // We have a non-type template parameter that isn't fully substituted; // FindInstantiatedDecl will find it in the local instantiation scope. @@ -1971,8 +2024,13 @@ Instantiation->setInvalidDecl(); continue; } + // Do not eagerly transform partial or explicit specialization declarations. + Decl *NewMember = nullptr; + if (!isa(Member) && + !isa(Member) && + !isa(Member)) + NewMember = Instantiator.Visit(Member); - Decl *NewMember = Instantiator.Visit(Member); if (NewMember) { if (FieldDecl *Field = dyn_cast(NewMember)) { Fields.push_back(Field); @@ -2077,32 +2135,6 @@ if (!Instantiation->isInvalidDecl()) { // Perform any dependent diagnostics from the pattern. PerformDependentDiagnostics(Pattern, TemplateArgs); - - // Instantiate any out-of-line class template partial - // specializations now. - for (TemplateDeclInstantiator::delayed_partial_spec_iterator - P = Instantiator.delayed_partial_spec_begin(), - PEnd = Instantiator.delayed_partial_spec_end(); - P != PEnd; ++P) { - if (!Instantiator.InstantiateClassTemplatePartialSpecialization( - P->first, P->second)) { - Instantiation->setInvalidDecl(); - break; - } - } - - // Instantiate any out-of-line variable template partial - // specializations now. - for (TemplateDeclInstantiator::delayed_var_partial_spec_iterator - P = Instantiator.delayed_var_partial_spec_begin(), - PEnd = Instantiator.delayed_var_partial_spec_end(); - P != PEnd; ++P) { - if (!Instantiator.InstantiateVarTemplatePartialSpecialization( - P->first, P->second)) { - Instantiation->setInvalidDecl(); - break; - } - } } // Exit the scope of this instantiation. @@ -2182,14 +2214,651 @@ } namespace { - /// \brief A partial specialization whose template arguments have matched - /// a given template-id. + // Help map types from Class/Var Partial specailizations back to their + // template decls - without requiring an inheritance relationship. + struct TemplateDeclTypeMapper { + static VarTemplateDecl + getTypeOfPrimaryTemplate(VarTemplatePartialSpecializationDecl *); + static ClassTemplateDecl + getTypeOfPrimaryTemplate(ClassTemplatePartialSpecializationDecl *); + static CXXRecordDecl getTypeOfPatternDecl(ClassTemplateDecl *); + static ClassTemplatePartialSpecializationDecl + getTypeOfPartialSpecializationDecl(ClassTemplateDecl *); + static ClassTemplateSpecializationDecl + getTypeOfExplicitSpecializationDecl(ClassTemplateDecl *); + + static VarDecl getTypeOfPatternDecl(VarTemplateDecl *); + static VarTemplatePartialSpecializationDecl + getTypeOfPartialSpecializationDecl(VarTemplateDecl *); + static VarTemplateSpecializationDecl + getTypeOfExplicitSpecializationDecl(VarTemplateDecl *); + static ClassTemplateDecl *getDescribedTemplate(const CXXRecordDecl *D) { + return D->getDescribedClassTemplate(); + } + static VarTemplateDecl *getDescribedTemplate(const VarDecl *D) { + return D->getDescribedVarTemplate(); + } + + static FunctionDecl getTypeOfPatternDecl(FunctionTemplateDecl *); + + }; + +template +std::tuple(nullptr))) *> +getInnermostTemplateParameterListAndPatternDecl(const Decl *D) { + typedef decltype(TemplateDeclTypeMapper::getTypeOfPatternDecl( + static_cast(nullptr))) PatternDecl; + + typedef decltype(TemplateDeclTypeMapper::getTypeOfPartialSpecializationDecl( + static_cast(nullptr))) PartialSpecializationDecl; + + typedef decltype(TemplateDeclTypeMapper::getTypeOfExplicitSpecializationDecl( + static_cast(nullptr))) ExplicitSpecializationDecl; + + TemplateParameterList *InnerMostTPL = nullptr; + const PatternDecl *PatternD = nullptr; + + if (auto *TD = dyn_cast(D)) { + InnerMostTPL = TD->getTemplateParameters(); + PatternD = TD->getTemplatedDecl(); + } else if (auto *PSD = dyn_cast(D)) { + InnerMostTPL = PSD->getTemplateParameters(); + PatternD = PSD; + } else if (auto *ESD = dyn_cast(D)) { + if (ESD->isExplicitSpecialization()) { + // If this was declared as an explicit specialization, all the TPLs + // are included in the getTemplateParameterList(i) info... + InnerMostTPL = 0; + PatternD = ESD; + } else { + // If this is implicitly instantiated, then use the template + // parameter lists of the template that we were instantiated from. + auto PrimaryOrPartialTemplate = ESD->getSpecializedTemplateOrPartial(); + if (PrimaryOrPartialTemplate.is()) + return getInnermostTemplateParameterListAndPatternDecl< + PrimaryTemplateDecl>( + PrimaryOrPartialTemplate.get()); + return getInnermostTemplateParameterListAndPatternDecl< + PrimaryTemplateDecl>(ESD->getSpecializedTemplate()); + } + } else if (auto *PD = dyn_cast(D)) { + if (PrimaryTemplateDecl *TD = + TemplateDeclTypeMapper::getDescribedTemplate(PD)) { + PatternD = PD; + InnerMostTPL = TD->getTemplateParameters(); + } else { + //PD->dump(); + //llvm_unreachable( + // "The above decl must be a pattern decl of some template!"); + } + } + return std::make_tuple(InnerMostTPL, PatternD); +} + +std::tuple +getInnermostTemplateParameterListAndPatternDeclIfFunctionDecl(const Decl *D) { + + TemplateParameterList *InnerMostTPL = nullptr; + const FunctionDecl *PatternD = nullptr; + + if (const auto *TD = dyn_cast(D)) { + InnerMostTPL = TD->getTemplateParameters(); + PatternD = TD->getTemplatedDecl(); + } else if (const FunctionDecl *FD = dyn_cast(D)) { + if (FD->getDescribedFunctionTemplate()) + return getInnermostTemplateParameterListAndPatternDeclIfFunctionDecl( + FD->getDescribedFunctionTemplate()); + else if (FD->isFunctionTemplateSpecialization()) { + return getInnermostTemplateParameterListAndPatternDeclIfFunctionDecl( + FD->getPrimaryTemplate()); + } + } else if (const auto *CFD = + dyn_cast(D)) { + D->dump(); + llvm_unreachable("We do not know how to process class scope function specialization decl!"); + } + return std::make_tuple(InnerMostTPL, PatternD); +} + +template +void getTemplateParameterListsOfOutOfLineDeclImpl( + TagOrDeclaratorTy *D, SmallVectorImpl &TPLs) { + + for (unsigned I = 0; I != D->getNumTemplateParameterLists(); ++I) + TPLs.push_back(D->getTemplateParameterList(I)); +} + +template +void getTemplateParameterListsOfOutOfLineDecl( + const llvm::PointerUnion &TagOrDeclaratorPattern, + SmallVectorImpl &TPLs) { + if (TagOrDeclaratorPattern.is()) + return getTemplateParameterListsOfOutOfLineDeclImpl( + TagOrDeclaratorPattern.get(), TPLs); + else + return getTemplateParameterListsOfOutOfLineDeclImpl( + TagOrDeclaratorPattern.get(), TPLs); +} +} // end anonymous ns + +SmallVector +Sema::getTemplateParameterListsOfDeclaration(const Decl *D) { + SmallVector TPLs; + llvm::PointerUnion PatternDecl; + TemplateParameterList *InnerMostTPL = 0; + std::tie(InnerMostTPL, PatternDecl) = + getInnermostTemplateParameterListAndPatternDecl(D); + if (!PatternDecl) + std::tie(InnerMostTPL, PatternDecl) = + getInnermostTemplateParameterListAndPatternDecl(D); + if (!PatternDecl) + std::tie(InnerMostTPL, PatternDecl) = + getInnermostTemplateParameterListAndPatternDeclIfFunctionDecl(D); + // Now that we have our original Decl separated into the PatternDecl and + // any Innermost TPL of the template, determine whether we have enclosing + // templates, and add their TPLs to this template. + if (PatternDecl) { + // Add any enclosing template parameter lists ... + if (!D->isOutOfLine()) { + if (const DeclContext *ParentDC = D->getDeclContext()) { + if (isa(ParentDC)) { + auto ParentTPLs = getTemplateParameterListsOfDeclaration( + cast(ParentDC)); + TPLs.append(ParentTPLs.begin(), ParentTPLs.end()); + } + } + } else { // For out of line declarations use the PatternDecl. + getTemplateParameterListsOfOutOfLineDecl(PatternDecl, TPLs); + } + if (InnerMostTPL) + TPLs.push_back(InnerMostTPL); + } + return TPLs; +} + +unsigned Sema::getNumberOfEmptyTemplateParameterLists(const Decl *D) { + unsigned num = 0; + for (auto *tpl : getTemplateParameterListsOfDeclaration(D)) { + if (!tpl->size()) + ++num; + } + return num; +} + +namespace { +// See definition below for comments. +template class BestSpecializationFinder; +} + +// A class that abstracts out the search for all partial specializations +// linked to a primary template. This checks for explicitly specialized +// partial specializations and if the primary template is not explicitly +// specialized, it checks for non-explicitly specialized partial +// specializations. It substitutes the appropriate template arguments +// from outer scopes as necessary. Additionally, it checks to see if +// it can determine the most specialized partial specialization, and if not +// informs of ambiguity. +// +// Parameterization supports the two kinds of partial specialization +// declarations allowed in C++: +// - ClassTemplatePartialSpecializationDecl +// - VarTemplatePartialSpecializationDecl + +template class ::BestSpecializationFinder { + + typedef decltype(TemplateDeclTypeMapper::getTypeOfPartialSpecializationDecl( + static_cast(nullptr))) PartialSpecializationDecl; + + typedef decltype(TemplateDeclTypeMapper::getTypeOfExplicitSpecializationDecl( + static_cast(nullptr))) ExplicitSpecializationDecl; + // Clang represents explicit specialization AST nodes and any instantiation + // of a template node with the same type. We differentiate based on the + // kind of the specialization it is and whether it is an instantiation. + typedef decltype(TemplateDeclTypeMapper::getTypeOfExplicitSpecializationDecl( + static_cast(nullptr))) TemplateSpecializationDecl; + + Sema &SemaRef; + PrimaryTemplateDecl *const TemplateBeingInstantiated; + CXXRecordDecl *const ParentClassOfTemplateBeingInstantiated; + struct PartialSpecMatchResult { - ClassTemplatePartialSpecializationDecl *Partial; - TemplateArgumentList *Args; + PartialSpecializationDecl *const Partial; + TemplateArgumentList *const Args; + PartialSpecMatchResult() : Partial(nullptr), Args(nullptr) {} + PartialSpecMatchResult(PartialSpecializationDecl *Partial, + TemplateArgumentList *Args) + : Partial(Partial), Args(Args) {} }; + +public: + BestSpecializationFinder(Sema & S, PrimaryTemplateDecl * CurTemplate) + : SemaRef(S), TemplateBeingInstantiated(CurTemplate), + ParentClassOfTemplateBeingInstantiated( + isa(CurTemplate->getDeclContext()) + ? cast(CurTemplate->getDeclContext()) + ->getCanonicalDecl() + : 0) {} + // A convenience typedef for partial and explicit specialization vectors + typedef SmallVector PartialSpecVectorTy; + typedef SmallVector ExplicitSpecVectorTy; + + template + PartialOrExplicitSpecializationDecl *substOuterTemplateArgs( + PartialOrExplicitSpecializationDecl *Spec, + SourceLocation PointOfInstantiation) const { + + clang::MultiLevelTemplateArgumentList OuterTemplateArgs = + SemaRef.getTemplateInstantiationArgs( + TemplateBeingInstantiated, nullptr, false, nullptr, + SemaRef.getTemplateParameterListsOfDeclaration(Spec)); + + Sema::InstantiatingTemplate Inst(SemaRef, PointOfInstantiation, Spec); + // If we have exceeded the maximum recursion instantiation depth, return + // null. + // FIXME: What diagnostic should we emit here? + if (Inst.isInvalid()) + return nullptr; + + // Enter the DeclContext that contains the partial spec we will be + // substituting into ... + // We don't use PushDeclContext because we don't have a scope. + Sema::ContextRAII SavedContext(SemaRef, + ParentClassOfTemplateBeingInstantiated); + + EnterExpressionEvaluationContext EvalContext(SemaRef, + Sema::PotentiallyEvaluated); + + Sema::SFINAETrap IntroduceSFINAE(SemaRef, true); + + TemplateDeclInstantiator DeclInstantiator( + SemaRef, ParentClassOfTemplateBeingInstantiated, OuterTemplateArgs); + + return cast_or_null( + DeclInstantiator.Visit(Spec)); + } + +private: + // Iterate through all Ancestor templates and find all partial + // specializations from each one. + PartialSpecVectorTy getAllPartialSpecializationsFromAncestorTemplates() + const { + + PartialSpecVectorTy AllPartialSpecs; + PrimaryTemplateDecl *TemplateIt = TemplateBeingInstantiated; + while (PrimaryTemplateDecl *const AncestorTemplate = + TemplateIt->getInstantiatedFromMemberTemplate()) { + PartialSpecVectorTy PSpecs; + AncestorTemplate->getPartialSpecializations(PSpecs); + AllPartialSpecs.append(PSpecs.begin(), PSpecs.end()); + TemplateIt = AncestorTemplate; + } + return AllPartialSpecs; + } + + // Iterate through all Ancestor templates and find all explicit + // specializations from each one. + ExplicitSpecVectorTy getAllExplicitSpecializationsFromAncestorTemplates() + const { + ExplicitSpecVectorTy AllExplicitSpecs; + PrimaryTemplateDecl *TemplateIt = TemplateBeingInstantiated; + while (PrimaryTemplateDecl *const AncestorTemplate = + TemplateIt->getInstantiatedFromMemberTemplate()) { + for (auto *Specs : AncestorTemplate->specializations()) { + if (Specs->isExplicitSpecialization()) + AllExplicitSpecs.push_back(Specs); + } + TemplateIt = AncestorTemplate; + } + return AllExplicitSpecs; + } + // Iterate through the partial specializations associated with all ancestor + // templates + // - substitute the outer enclosing arguments of the nested + // TemplateBeingInstanted. + PartialSpecVectorTy getRelevantPartialSpecializationsFromAncestorTemplates( + SourceLocation PointOfInstantiation) const { + PartialSpecVectorTy AllPartialSpecs = + getAllPartialSpecializationsFromAncestorTemplates(); + PartialSpecVectorTy RelevantPartialSpecs; + for (PartialSpecializationDecl *const APSpec : AllPartialSpecs) { + if (PartialSpecializationDecl *PSD = + substOuterTemplateArgs(APSpec, PointOfInstantiation)) { + RelevantPartialSpecs.push_back(PSD); + } + } + return RelevantPartialSpecs; + } + + // Iterate through the explicit specializations associated with all ancestor + // templates + // - substitute the outer enclosing arguments of the nested + // TemplateBeingInstanted. + ExplicitSpecVectorTy getRelevantExplicitSpecializationsFromAncestorTemplates( + SourceLocation PointOfInstantiation) const { + auto AllExplicitSpecs = getAllExplicitSpecializationsFromAncestorTemplates(); + ExplicitSpecVectorTy RelevantExplicitSpecs; + for (ExplicitSpecializationDecl *const AESpec : AllExplicitSpecs) { + if (ExplicitSpecializationDecl *ESD = + substOuterTemplateArgs(AESpec, PointOfInstantiation)) { + RelevantExplicitSpecs.push_back(ESD); + } + } + return RelevantExplicitSpecs; + } + /// \brief Retrieve all the partial specializations associated with 'D'. + /// If D is not explicitly specialized, retrieve partial specializations + /// from the original template (substituting into the outer template + /// parameters as necessary at point-of-instantiation). + PartialSpecVectorTy + getAllPartialSpecializationsFromWhichToSelectTheMostSpecializedTemplate( + SourceLocation POI) const { + + PartialSpecVectorTy AllPartialSpecs; + TemplateBeingInstantiated->getPartialSpecializations(AllPartialSpecs); + // 14.5.5.3/2 [temp.class.spec.mfunc]: + // '... If the primary member template is explicitly specialized for a given + // (implicit) specialization of the enclosing class template, the partial + // specializations of the member template are ignored for this + // specialization of the enclosing class template. If a partial + // specialization of the member template is explicitly specialized for a + // given (implicit) specialization of the enclosing class template, the + // primary member template and its other partial specializations are still + // considered for this specialization of the enclosing class template. + // + // i.e: If the primary member template is an explicit specialization that is + // specialized as a member template itself, do not consider any partial + // specializations that have not themselves been similarly explicitly + // specialized. For e.g. + // template struct L { + // template struct M { int i; }; // #1 + // template struct M { int j; }; // #2 + // }; + // template<> template + // struct L::M { int k; }; // #3 + // + // template<> template + // struct L::M { int l; }; // #4 + // For the primary template at #4, consider #3 but not #2 + if (!TemplateBeingInstantiated->isMemberSpecialization()) { + PartialSpecVectorTy APSpecs = + getRelevantPartialSpecializationsFromAncestorTemplates(POI); + AllPartialSpecs.append(APSpecs.begin(), APSpecs.end()); + } + return AllPartialSpecs; + } + + ExplicitSpecVectorTy + getAllExplicitSpecializationsFromWhichToSelectTheMostSpecializedTemplate( + SourceLocation POI) const { + + ExplicitSpecVectorTy AllExplicitSpecs; + for (auto *Spec : TemplateBeingInstantiated->specializations()) + if (Spec->isExplicitSpecialization()) + AllExplicitSpecs.push_back(Spec); + // FIXME: This comment is wrong! + // i.e: If the primary member template is an explicit specialization that is + // specialized as a member template itself, do not consider any partial + // specializations that have not themselves been similarly explicitly + // specialized. For e.g. + // template struct L { + // template struct M { int i; }; // #1 + // template struct M { int j; }; // #2 + // }; + // template<> template + // struct L::M { int k; }; // #3 + // + // template<> template + // struct L::M { int l; }; // #4 + // For the primary template at #4, consider #3 but not #2 + if (!TemplateBeingInstantiated->isMemberSpecialization()) { + auto AESpecs = + getRelevantExplicitSpecializationsFromAncestorTemplates(POI); + AllExplicitSpecs.append(AESpecs.begin(), AESpecs.end()); + } + return AllExplicitSpecs; + } + + // Given template args, craft a templateid name using the + // TemplateBeingInstantiated. + std::string makeUnqualifiedTemplateIdName( + const TemplateArgumentList &TemplateArgs) const { + auto Policy = SemaRef.getPrintingPolicy(); + std::string out; + llvm::raw_string_ostream OS(out); + TemplateBeingInstantiated->getNameForDiagnostic(OS, Policy, + /*Qualified*/ false); + TemplateSpecializationType::PrintTemplateArgumentList( + OS, TemplateArgs.data(), TemplateArgs.size(), Policy); + OS.flush(); + return out; + } + + void complainPartialSpecializationSearchWasAmbiguous( + const TemplateArgumentList &TemplateArgs, + ArrayRef Matched, + SourceLocation PointOfInstantiation) const { + // Partial ordering did not produce a clear winner. Complain. + assert(Matched.size() > 1); + SemaRef.Diag(PointOfInstantiation, + diag::err_partial_spec_ordering_ambiguous) + << makeUnqualifiedTemplateIdName(TemplateArgs); + + // Print the matching partial specializations. + for (SmallVectorImpl::const_iterator + P = Matched.begin(), + PEnd = Matched.end(); + P != PEnd; ++P) + SemaRef.Diag(P->Partial->getLocation(), diag::note_partial_spec_match) + << SemaRef.getTemplateArgumentBindingsText( + P->Partial->getTemplateParameters(), *P->Args); + } + void complainExplicitSpecializationSearchWasAmbiguous( + const TemplateArgumentList &TemplateArgs, + const ExplicitSpecVectorTy &Matched, + SourceLocation PointOfInstantiation) const { + // Partial ordering did not produce a clear winner. Complain. + assert(Matched.size() > 1); + SemaRef.Diag(PointOfInstantiation, + diag::err_explicit_spec_ordering_ambiguous) + << makeUnqualifiedTemplateIdName(TemplateArgs); + + // Print the matching explicit specializations. + for (auto *ESpec : Matched) + SemaRef.Diag(ESpec->getLocation(), diag::note_explicit_spec_match) + << ESpec; + } + +public: + ExplicitSpecializationDecl *getBestExplicitSpecialization( + bool &Ambiguous, ArrayRef TemplateArgs, + SourceLocation PointOfInstantiation) { + // These are ordered so that member explicit specializations + // from the most specialized context are at a lower index + // than those in a less specialized context. + // template struct A { + // template struct B { + // template struct C { }; + // }; + // }; + // template template template<> + // struct A::B::C { ... } + // template template template<> + // struct A::B::C { ... } + // template template template<> + // struct A::B::C { ... } + // template<> template<> template<> + // struct A::B::C { }; <-- this is ordered ahead + ExplicitSpecVectorTy AllExplicitSpecs = + getAllExplicitSpecializationsFromWhichToSelectTheMostSpecializedTemplate( + PointOfInstantiation); + ExplicitSpecVectorTy Matched; + const llvm::FoldingSetNodeID TemplateArgsID = [&] { + llvm::FoldingSetNodeID ID; + ExplicitSpecializationDecl::Profile(ID, TemplateArgs.data(), + TemplateArgs.size(), + SemaRef.getASTContext()); + return ID; + }(); + for (auto *ESpec : AllExplicitSpecs) { + llvm::FoldingSetNodeID ID; + ExplicitSpecializationDecl::Profile(ID, ESpec->getTemplateArgs().data(), + ESpec->getTemplateArgs().size(), + SemaRef.getASTContext()); + if (ID == TemplateArgsID) + Matched.push_back(ESpec); + } + if (!Matched.size()) + return nullptr; + if (Matched.size() == 1) + return Matched.back(); + + std::sort(Matched.begin(), Matched.end(), + [this](ExplicitSpecializationDecl *D1, + ExplicitSpecializationDecl *D2) { + return SemaRef.getNumberOfEmptyTemplateParameterLists(D1) > + SemaRef.getNumberOfEmptyTemplateParameterLists(D2); + }); + const unsigned NumEmptyTPLs1 = + SemaRef.getNumberOfEmptyTemplateParameterLists(Matched[0]); + const unsigned NumEmptyTPLs2 = + SemaRef.getNumberOfEmptyTemplateParameterLists(Matched[1]); + if (NumEmptyTPLs1 == NumEmptyTPLs2) { + complainExplicitSpecializationSearchWasAmbiguous(Matched[0]->getTemplateArgs(), Matched, + PointOfInstantiation); + Ambiguous = true; + } + return Matched[0]; + } + + PartialSpecMatchResult getBestPartialSpecialization( + bool &Ambiguous, const TemplateArgumentList &TemplateArgs, + SourceLocation PointOfInstantiation) { + PartialSpecVectorTy PartialSpecs = + getAllPartialSpecializationsFromWhichToSelectTheMostSpecializedTemplate( + PointOfInstantiation); + if (!PartialSpecs.size()) + return PartialSpecMatchResult(); + + // Store all the matched partial specializations, so that in case of + // ambiguity we can emit an informative diagnostic. + SmallVector Matched; + TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); + for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { + PartialSpecializationDecl *Partial = PartialSpecs[I]; + TemplateDeductionInfo Info(FailedCandidates.getLocation()); + if (Sema::TemplateDeductionResult Result = + SemaRef.DeduceTemplateArguments(Partial, TemplateArgs, Info)) { + // Store the failed-deduction information for use in diagnostics, later. + // TODO: Actually use the failed-deduction info? + FailedCandidates.addCandidate().set( + Partial, MakeDeductionFailureInfo(SemaRef.Context, Result, Info)); + (void)Result; + } else { + Matched.push_back(PartialSpecMatchResult(Partial, Info.take())); + } + } + + // If we're dealing with a member template where the template parameters + // have been instantiated, this provides the original template parameters + // from which the member template's parameters were instantiated. + + if (Matched.size() >= 1) { + SmallVectorImpl::iterator Best = Matched.begin(); + if (Matched.size() == 1) { + // -- If exactly one matching specialization is found, the + // instantiation is generated from that specialization. + // We don't need to do anything for this. + } else { + // -- If more than one matching specialization is found, the + // partial order rules (14.5.4.2) are used to determine + // whether one of the specializations is more specialized + // than the others. If none of the specializations is more + // specialized than all of the other matching + // specializations, then the use of the class template is + // ambiguous and the program is ill-formed. + for (SmallVectorImpl::iterator + P = Best + 1, + PEnd = Matched.end(); + P != PEnd; ++P) { + if (SemaRef.getMoreSpecializedPartialSpecialization( + P->Partial, Best->Partial, PointOfInstantiation) == + P->Partial) + Best = P; + } + + // Determine if the best partial specialization is more specialized than + // the others. + Ambiguous = false; + for (SmallVectorImpl::iterator + P = Matched.begin(), + PEnd = Matched.end(); + P != PEnd; ++P) { + if (P != Best && + SemaRef.getMoreSpecializedPartialSpecialization( + P->Partial, Best->Partial, PointOfInstantiation) != + Best->Partial) { + Ambiguous = true; + complainPartialSpecializationSearchWasAmbiguous( + TemplateArgs, Matched, PointOfInstantiation); + return *Best; + } + } + } + return *Best; + } + return PartialSpecMatchResult(); + } +}; + +std::tuple +Sema::getMostSpecializedPartialSpecialization( + ClassTemplateDecl *Template, const TemplateArgumentList &TemplateArgs, + SourceLocation PointOfInstantiation) { + bool Ambiguous = false; + auto PartialSpecAndTemplateArgs = + BestSpecializationFinder( + *this, Template).getBestPartialSpecialization(Ambiguous, TemplateArgs, + PointOfInstantiation); + return std::make_tuple(PartialSpecAndTemplateArgs.Partial, + PartialSpecAndTemplateArgs.Args, Ambiguous); } +std::tuple +Sema::getMostSpecializedPartialSpecialization( + VarTemplateDecl *Template, const TemplateArgumentList &TemplateArgs, + SourceLocation PointOfInstantiation) { + bool Ambiguous = false; + auto PartialSpecAndTemplateArgs = + BestSpecializationFinder( + *this, Template).getBestPartialSpecialization(Ambiguous, TemplateArgs, + PointOfInstantiation); + return std::make_tuple(PartialSpecAndTemplateArgs.Partial, + PartialSpecAndTemplateArgs.Args, Ambiguous); +} + +ClassTemplateSpecializationDecl * +Sema::getBestExplicitSpecialization(bool &Ambiguous, + ClassTemplateDecl *Template, + ArrayRef TemplateArgs, + SourceLocation PointOfInstantiation) { + return BestSpecializationFinder(*this, Template) + .getBestExplicitSpecialization(Ambiguous, TemplateArgs, + PointOfInstantiation); +} + +VarTemplateSpecializationDecl * +Sema::getBestExplicitSpecialization(bool &Ambiguous, VarTemplateDecl *Template, + ArrayRef TemplateArgs, + SourceLocation PointOfInstantiation) { + return BestSpecializationFinder(*this, Template) + .getBestExplicitSpecialization(Ambiguous, TemplateArgs, + PointOfInstantiation); +} + bool Sema::InstantiateClassTemplateSpecialization( SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, @@ -2228,8 +2897,7 @@ return true; ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate(); - CXXRecordDecl *Pattern = 0; - + // C++ [temp.class.spec.match]p1: // When a class template is used in a context that requires an // instantiation of the class, it is necessary to determine @@ -2238,93 +2906,21 @@ // matching the template arguments of the class template // specialization with the template argument lists of the partial // specializations. - typedef PartialSpecMatchResult MatchResult; - SmallVector Matched; - SmallVector PartialSpecs; - Template->getPartialSpecializations(PartialSpecs); - TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); - for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { - ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; - TemplateDeductionInfo Info(FailedCandidates.getLocation()); - if (TemplateDeductionResult Result - = DeduceTemplateArguments(Partial, - ClassTemplateSpec->getTemplateArgs(), - Info)) { - // Store the failed-deduction information for use in diagnostics, later. - // TODO: Actually use the failed-deduction info? - FailedCandidates.addCandidate() - .set(Partial, MakeDeductionFailureInfo(Context, Result, Info)); - (void)Result; - } else { - Matched.push_back(PartialSpecMatchResult()); - Matched.back().Partial = Partial; - Matched.back().Args = Info.take(); - } + ClassTemplatePartialSpecializationDecl *BestPartialSpec = nullptr; + const TemplateArgumentList *BestPartialDeducedArgs = nullptr; + bool PartialSpecIsAmbiguous = false; + std::tie(BestPartialSpec, BestPartialDeducedArgs, PartialSpecIsAmbiguous) = + getMostSpecializedPartialSpecialization( + Template, ClassTemplateSpec->getTemplateArgs(), PointOfInstantiation); + if (PartialSpecIsAmbiguous) { + ClassTemplateSpec->setInvalidDecl(); + return true; } - - // If we're dealing with a member template where the template parameters - // have been instantiated, this provides the original template parameters - // from which the member template's parameters were instantiated. - - if (Matched.size() >= 1) { - SmallVectorImpl::iterator Best = Matched.begin(); - if (Matched.size() == 1) { - // -- If exactly one matching specialization is found, the - // instantiation is generated from that specialization. - // We don't need to do anything for this. - } else { - // -- If more than one matching specialization is found, the - // partial order rules (14.5.4.2) are used to determine - // whether one of the specializations is more specialized - // than the others. If none of the specializations is more - // specialized than all of the other matching - // specializations, then the use of the class template is - // ambiguous and the program is ill-formed. - for (SmallVectorImpl::iterator P = Best + 1, - PEnd = Matched.end(); - P != PEnd; ++P) { - if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, - PointOfInstantiation) - == P->Partial) - Best = P; - } - - // Determine if the best partial specialization is more specialized than - // the others. - bool Ambiguous = false; - for (SmallVectorImpl::iterator P = Matched.begin(), - PEnd = Matched.end(); - P != PEnd; ++P) { - if (P != Best && - getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, - PointOfInstantiation) - != Best->Partial) { - Ambiguous = true; - break; - } - } - - if (Ambiguous) { - // Partial ordering did not produce a clear winner. Complain. - ClassTemplateSpec->setInvalidDecl(); - Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous) - << ClassTemplateSpec; - - // Print the matching partial specializations. - for (SmallVectorImpl::iterator P = Matched.begin(), - PEnd = Matched.end(); - P != PEnd; ++P) - Diag(P->Partial->getLocation(), diag::note_partial_spec_match) - << getTemplateArgumentBindingsText( - P->Partial->getTemplateParameters(), - *P->Args); - - return true; - } - } - + CXXRecordDecl *Pattern = 0; + if (BestPartialSpec) { // Instantiate using the best class template partial specialization. - ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->Partial; + ClassTemplatePartialSpecializationDecl *OrigPartialSpec = + BestPartialSpec; while (OrigPartialSpec->getInstantiatedFromMember()) { // If we've found an explicit specialization of this class template, // stop here and use that as the pattern. @@ -2335,7 +2931,8 @@ } Pattern = OrigPartialSpec; - ClassTemplateSpec->setInstantiationOf(Best->Partial, Best->Args); + ClassTemplateSpec->setInstantiationOf(BestPartialSpec, + BestPartialDeducedArgs); } else { // -- If no matches are found, the instantiation is generated // from the primary template. @@ -2352,11 +2949,13 @@ Pattern = OrigTemplate->getTemplatedDecl(); } - bool Result = InstantiateClass(PointOfInstantiation, ClassTemplateSpec, - Pattern, - getTemplateInstantiationArgs(ClassTemplateSpec), - TSK, - Complain); + bool Result = InstantiateClass( + PointOfInstantiation, ClassTemplateSpec, Pattern, + getTemplateInstantiationArgs( + ClassTemplateSpec, /*Innermost*/ nullptr, /*RelativeToPrimary*/ false, + /*FunctionPattern*/ nullptr, + getTemplateParameterListsOfDeclaration(Pattern)), + TSK, Complain); return Result; } Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -22,6 +22,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Template.h" +#include "clang/Sema/TemplateDeduction.h" using namespace clang; @@ -965,18 +966,6 @@ } Owner->addDecl(Inst); - - if (!PrevClassTemplate) { - // Queue up any out-of-line partial specializations of this member - // class template; the client will force their instantiation once - // the enclosing class has been instantiated. - SmallVector PartialSpecs; - D->getPartialSpecializations(PartialSpecs); - for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) - if (PartialSpecs[I]->getFirstDecl()->isOutOfLine()) - OutOfLinePartialSpecs.push_back(std::make_pair(Inst, PartialSpecs[I])); - } - return Inst; } @@ -1048,18 +1037,6 @@ Owner->addDecl(Inst); - if (!PrevVarTemplate) { - // Queue up any out-of-line partial specializations of this member - // variable template; the client will force their instantiation once - // the enclosing class has been instantiated. - SmallVector PartialSpecs; - D->getPartialSpecializations(PartialSpecs); - for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) - if (PartialSpecs[I]->getFirstDecl()->isOutOfLine()) - OutOfLineVarPartialSpecs.push_back( - std::make_pair(Inst, PartialSpecs[I])); - } - return Inst; } @@ -1086,6 +1063,10 @@ Decl * TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + return VisitFunctionTemplateDecl(D, false); +} +Decl *TemplateDeclInstantiator::VisitFunctionTemplateDecl( + FunctionTemplateDecl *D, bool IsCheckingDependentClassScopeSpecialization) { // Create a local instantiation scope for this function template, which // will contain the instantiations of the template parameters and then get // merged with the local instantiation scope for the function template @@ -1126,9 +1107,9 @@ InstTemplate->setInstantiatedFromMemberTemplate(D); // Make declarations visible in the appropriate context. - if (!isFriend) { + if (!isFriend && !IsCheckingDependentClassScopeSpecialization) { Owner->addDecl(InstTemplate); - } else if (InstTemplate->getDeclContext()->isRecord() && + } else if (isFriend && InstTemplate->getDeclContext()->isRecord() && !D->getPreviousDecl()) { SemaRef.CheckFriendAccess(InstTemplate); } @@ -1497,10 +1478,165 @@ return Function; } -Decl * -TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, - TemplateParameterList *TemplateParams, - bool IsClassScopeSpecialization) { + +namespace { +class MethodSpecializationFinder; +} + +class ::MethodSpecializationFinder { + Sema &SemaRef; + FunctionTemplateDecl *TemplateBeingInstantiated; + CXXRecordDecl *ParentClassOfTemplateBeingInstantiated; + typedef SmallVector ExplicitSpecVectorTy; + mutable std::map + SubstitutedExplicitTemplateArgsMap; + CXXMethodDecl *substOuterTemplateArgs( + CXXMethodDecl *Spec, SourceLocation PointOfInstantiation) const { + + clang::MultiLevelTemplateArgumentList OuterTemplateArgs = + SemaRef.getTemplateInstantiationArgs( + TemplateBeingInstantiated, nullptr, false, nullptr, + SemaRef.getTemplateParameterListsOfDeclaration(Spec)); + + Sema::InstantiatingTemplate Inst(SemaRef, PointOfInstantiation, Spec); + // If we have exceeded the maximum recursion instantiation depth, return + // null. + // FIXME: What diagnostic should we emit here? + if (Inst.isInvalid()) + return nullptr; + + // Enter the DeclContext that contains the partial spec we will be + // substituting into ... + // We don't use PushDeclContext because we don't have a scope. + Sema::ContextRAII SavedContext(SemaRef, + ParentClassOfTemplateBeingInstantiated); + + EnterExpressionEvaluationContext EvalContext(SemaRef, Sema::Unevaluated); + + Sema::SFINAETrap IntroduceSFINAE(SemaRef, true); + + TemplateDeclInstantiator DeclInstantiator( + SemaRef, ParentClassOfTemplateBeingInstantiated, OuterTemplateArgs); + // Transform any explicitly specified + FunctionTemplateSpecializationInfo *SpecFSI = Spec->getTemplateSpecializationInfo(); + if (SpecFSI->TemplateArgumentsAsWritten) { + TemplateArgumentListInfo &SubstArgs = + SubstitutedExplicitTemplateArgsMap[Spec]; + if (SemaRef.Subst(SpecFSI->TemplateArgumentsAsWritten->getTemplateArgs(), + SpecFSI->TemplateArgumentsAsWritten->NumTemplateArgs, + SubstArgs, OuterTemplateArgs)) + return nullptr; + } + return cast_or_null( + DeclInstantiator.VisitCXXMethodDecl(Spec, 0, true)); + } + ExplicitSpecVectorTy getAllExplicitSpecializationsFromAncestorTemplates() + const { + ExplicitSpecVectorTy AllExplicitSpecs; + FunctionTemplateDecl *TemplateIt = TemplateBeingInstantiated; + while (FunctionTemplateDecl *const AncestorTemplate = + TemplateIt->getInstantiatedFromMemberTemplate()) { + for (FunctionDecl *Spec : AncestorTemplate->specializations()) { + assert(isa(Spec)); + assert(Spec->getTemplateSpecializationInfo() || Spec->isInvalidDecl()); + + if (!Spec->isInvalidDecl() && + Spec->getTemplateSpecializationInfo()->isExplicitSpecialization()) + AllExplicitSpecs.push_back(cast(Spec)); + } + TemplateIt = AncestorTemplate; + } + return AllExplicitSpecs; + } + + // Iterate through the explicit specializations associated with all ancestor + // templates + // - substitute the outer enclosing arguments of the nested + // TemplateBeingInstanted. + ExplicitSpecVectorTy getRelevantExplicitSpecializationsFromAncestorTemplates( + SourceLocation PointOfInstantiation) const { + auto AllExplicitSpecs = + getAllExplicitSpecializationsFromAncestorTemplates(); + ExplicitSpecVectorTy RelevantExplicitSpecs; + for (CXXMethodDecl *const AESpec : AllExplicitSpecs) { + if (CXXMethodDecl *ESD = + substOuterTemplateArgs(AESpec, PointOfInstantiation)) { + RelevantExplicitSpecs.push_back(ESD); + } + } + return RelevantExplicitSpecs; + } + +public: + MethodSpecializationFinder(Sema &SemaRef, + FunctionTemplateDecl *TemplateBeingInstantiated) + : SemaRef(SemaRef), TemplateBeingInstantiated(TemplateBeingInstantiated), + ParentClassOfTemplateBeingInstantiated( + cast(TemplateBeingInstantiated->getDeclContext())) {} + ExplicitSpecVectorTy getMatchingExplicitSpecializations( + SourceLocation POI, ArrayRef TArgs) const { + const llvm::FoldingSetNodeID DesiredSpecID = ([&] { + llvm::FoldingSetNodeID ID; + FunctionTemplateSpecializationInfo::Profile( + ID, TArgs.data(), TArgs.size(), SemaRef.Context); + return ID; + }()); + ExplicitSpecVectorTy MatchingSpecs; + for (CXXMethodDecl *Spec : + getRelevantExplicitSpecializationsFromAncestorTemplates(POI)) { + + assert(!Spec->isDependentContext()); + assert(Spec->getInstantiatedFromMemberFunction() && + "This specialization must have been instantiated from an explicit " + "specialization"); + assert(isa(Spec->getInstantiatedFromMemberFunction())); + CXXMethodDecl *ProtoSpec = + cast(Spec->getInstantiatedFromMemberFunction()); + + // This contains deduced arguments info only at the innermost function + // specialization level - that is those arguments deduced against the + // member template to form the explicit specialization. + FunctionTemplateSpecializationInfo *ProtoFSI = + ProtoSpec->getTemplateSpecializationInfo(); + assert(ProtoFSI && "This specialization must have been instantiated from " + "an explicit specialization"); + + // FIXME: If ProtoFSI has any dependent template arguments (i.e. it has + // dummy arguments substituted in), only then do we need + // to deduce the template arguments. + + SmallVector DeducedArgs; + sema::TemplateDeductionInfo DeductionInfo(POI); + Sema::TemplateDeductionResult Result = + clang::DeduceTemplateArgumentsByTypeMatchForExplicitSpecializations( + SemaRef, TemplateBeingInstantiated, Spec, + // Pass in any substituted template arguments explicitly specified + (ProtoFSI->TemplateArgumentsAsWritten + ? &SubstitutedExplicitTemplateArgsMap[ProtoSpec] + : nullptr), + DeductionInfo, DeducedArgs); + // This must succeed - we are only doing this to harvest out the deduced + // arguments. + assert(Result == Sema::TDK_Success); + // Convert the array of DeducedTemplateArguments into an array of + // TemplateArguments so that we don't clobber any data when + // crawling the array for determining its hash. + SmallVector TemplateArgs; + for (const auto &DTA : DeducedArgs) + TemplateArgs.push_back(DTA); + llvm::FoldingSetNodeID SpecID; + FunctionTemplateSpecializationInfo::Profile( + SpecID, TemplateArgs.data(), TemplateArgs.size(), SemaRef.Context); + if (SpecID == DesiredSpecID) + MatchingSpecs.push_back(Spec); + } + return MatchingSpecs; + } +}; + +Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( + CXXMethodDecl *D, TemplateParameterList *TemplateParams, + bool IsClassScopeSpecialization) { FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); if (FunctionTemplate && !TemplateParams) { // We are creating a function template specialization from a function @@ -1517,6 +1653,49 @@ // If we already have a function template specialization, return it. if (SpecFunc) return SpecFunc; + // Search for explicit specializations from instantiated from + // member templates. + // Only do this if we are not declaring a dependent class scope explicit + // specialization but rather trying to use one. + // - i.e. the decl context can not be dependent. + // FIXME: This is an ugly hack - see comment in Sema.h for one suggestion + // regarding a more robust fix. + auto IsUndergoingTemplateArgumentDeductionWhileMethodSpecializationBeingDeclared = + [](CXXMethodDecl *Pattern, Sema &S) { + if (S.PatternOfMethodSpecializationBeingDeclared.size()) + return S.PatternOfMethodSpecializationBeingDeclared.back() + ->getCanonicalDecl() == Pattern->getCanonicalDecl(); + return false; + }; + if (!D->getDeclContext()->isDependentContext() && + !FunctionTemplate->isMemberSpecialization() && + !IsUndergoingTemplateArgumentDeductionWhileMethodSpecializationBeingDeclared( + D, SemaRef)) { + Sema::ActiveTemplateInstantiation &CurInstantiation = + SemaRef.ActiveTemplateInstantiations.back(); + SourceLocation PointOfInstantiation = + CurInstantiation.PointOfInstantiation; + MethodSpecializationFinder MSF(SemaRef, FunctionTemplate); + SmallVector ExplicitSpecs = + MSF.getMatchingExplicitSpecializations( + CurInstantiation.PointOfInstantiation, Innermost); + if (const unsigned NumMatches = ExplicitSpecs.size()) { + CXXMethodDecl *MatchedExplicitDecl = ExplicitSpecs.back(); + if (NumMatches == 1) + return MatchedExplicitDecl; + SemaRef.Diag(PointOfInstantiation, + diag::err_explicit_spec_ordering_ambiguous) + << FunctionTemplate; + + // FIXME: Since we are in a SFINAE context? Is that why these do not get + // printed? :( + for (auto *ESpec : ExplicitSpecs) + SemaRef.Diag(ESpec->getLocation(), diag::note_explicit_spec_match) + << ESpec; + MatchedExplicitDecl->setInvalidDecl(); + return MatchedExplicitDecl; + } + } } bool isFriend; @@ -1717,8 +1896,7 @@ Previous.clear(); } - if (!IsClassScopeSpecialization) - SemaRef.CheckFunctionDeclaration(0, Method, Previous, false); + SemaRef.CheckFunctionDeclaration(0, Method, Previous, false); if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); @@ -2436,8 +2614,8 @@ // Add this partial specialization to the set of class template partial // specializations. - if (!PrevDecl) - InstClassTemplate->AddSpecialization(InstD, InsertPos); + //if (!PrevDecl) + // InstClassTemplate->AddSpecialization(InstD, InsertPos); // Substitute the nested name specifier, if any. if (SubstQualifier(D, InstD)) @@ -2468,15 +2646,17 @@ InstD->setTemplateKeywordLoc(D->getTemplateKeywordLoc()); Owner->addDecl(InstD); - + // Instantiate the members of the class-scope explicit specialization eagerly. // We don't have support for lazy instantiation of an explicit specialization // yet, and MSVC eagerly instantiates in this case. - if (D->isThisDeclarationADefinition() && - SemaRef.InstantiateClass(D->getLocation(), InstD, D, TemplateArgs, - TSK_ImplicitInstantiation, - /*Complain=*/true)) - return 0; + // FIXME: Should this be allowed only in microsoft mode, now that we support + // relaxed instantiation of class scope explicit specializations. + //if (D->isThisDeclarationADefinition() && + // SemaRef.InstantiateClass(D->getLocation(), InstD, D, TemplateArgs, + // TSK_ImplicitInstantiation, + // /*Complain=*/true)) + // return 0; return InstD; } @@ -2505,16 +2685,10 @@ const_cast(VarTemplateArgsInfo), false, Converted)) return 0; - + // Find the variable template specialization declaration that // corresponds to these arguments. - void *InsertPos = 0; - if (VarTemplateSpecializationDecl *VarSpec = VarTemplate->findSpecialization( - Converted.data(), Converted.size(), InsertPos)) - // If we already have a variable template specialization, return it. - return VarSpec; - - return VisitVarTemplateSpecializationDecl(VarTemplate, D, InsertPos, + return VisitVarTemplateSpecializationDecl(VarTemplate, D, nullptr, VarTemplateArgsInfo, Converted); } @@ -2522,7 +2696,7 @@ VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos, const TemplateArgumentListInfo &TemplateArgsInfo, llvm::ArrayRef Converted) { - + // If this is the variable for an anonymous struct or union, // instantiate the anonymous struct/union type first. if (const RecordType *RecordTy = D->getType()->getAs()) @@ -2542,24 +2716,22 @@ << D->isStaticDataMember() << DI->getType(); return 0; } - + // Build the instantiated declaration - VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create( + VarTemplateSpecializationDecl *NewVar = VarTemplateSpecializationDecl::Create( SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(), Converted.size()); - Var->setTemplateArgsInfo(TemplateArgsInfo); - if (InsertPos) - VarTemplate->AddSpecialization(Var, InsertPos); - + NewVar->setTemplateArgsInfo(TemplateArgsInfo); + // Substitute the nested name specifier, if any. - if (SubstQualifier(D, Var)) + if (SubstQualifier(D, NewVar)) return 0; - SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, + SemaRef.BuildVariableInstantiation(NewVar, D, TemplateArgs, LateAttrs, Owner, StartingScope); - return Var; + return NewVar; } Decl *TemplateDeclInstantiator::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) { @@ -2699,30 +2871,6 @@ InstTemplateArgs, CanonType); - if (PrevDecl) { - // We've already seen a partial specialization with the same template - // parameters and template arguments. This can happen, for example, when - // substituting the outer template arguments ends up causing two - // class template partial specializations of a member class template - // to have identical forms, e.g., - // - // template - // struct Outer { - // template struct Inner; - // template struct Inner; - // template struct Inner; - // }; - // - // Outer outer; // error: the partial specializations of Inner - // // have the same signature. - SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared) - << WrittenTy->getType(); - SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here) - << SemaRef.Context.getTypeDeclType(PrevDecl); - return 0; - } - - // Create the class template partial specialization declaration. ClassTemplatePartialSpecializationDecl *InstPartialSpec = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, @@ -2743,10 +2891,6 @@ InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); - - // Add this partial specialization to the set of class template partial - // specializations. - ClassTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0); return InstPartialSpec; } @@ -2817,31 +2961,6 @@ TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo( TemplateName(VarTemplate), PartialSpec->getLocation(), InstTemplateArgs, CanonType); - - if (PrevDecl) { - // We've already seen a partial specialization with the same template - // parameters and template arguments. This can happen, for example, when - // substituting the outer template arguments ends up causing two - // variable template partial specializations of a member variable template - // to have identical forms, e.g., - // - // template - // struct Outer { - // template pair p; - // template pair p; - // template pair p; - // }; - // - // Outer outer; // error: the partial specializations of Inner - // // have the same signature. - SemaRef.Diag(PartialSpec->getLocation(), - diag::err_var_partial_spec_redeclared) - << WrittenTy->getType(); - SemaRef.Diag(PrevDecl->getLocation(), - diag::note_var_prev_partial_spec_here); - return 0; - } - // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType( PartialSpec->getTypeSourceInfo(), TemplateArgs, @@ -2873,8 +2992,7 @@ // Add this partial specialization to the set of variable template partial // specializations. The instantiation of the initializer is not necessary. - VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0); - + SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs, LateAttrs, Owner, StartingScope); @@ -3422,7 +3540,8 @@ Sema::ContextRAII savedContext(*this, Function); MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Function, 0, false, PatternDecl); + getTemplateInstantiationArgs(Function, 0, false, PatternDecl, + getTemplateParameterListsOfDeclaration(PatternDecl)); addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, TemplateArgs); @@ -3726,9 +3845,7 @@ VarTemplateSpecializationDecl *VarSpec = dyn_cast(Var); VarDecl *PatternDecl = 0, *Def = 0; - MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Var); - + MultiLevelTemplateArgumentList TemplateArgs; if (VarSpec) { // If this is a variable template specialization, make sure that it is // non-dependent, then find its instantiation pattern. @@ -3738,37 +3855,109 @@ "Only instantiate variable template specializations that are " "not type-dependent"); (void)InstantiationDependent; + const bool IsInstantiatedFromDependentExplicitSpecialization = + ([](VarTemplateSpecializationDecl *VarSpec) { + if (auto *OldVarSpec = VarSpec->getInstantiatedFromStaticDataMember()) + return OldVarSpec->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization && + !isa(OldVarSpec); + return false; + }(VarSpec)); - // Find the variable initialization that we'll be substituting. If the - // pattern was instantiated from a member template, look back further to - // find the real pattern. - assert(VarSpec->getSpecializedTemplate() && - "Specialization without specialized template?"); - llvm::PointerUnion PatternPtr = - VarSpec->getSpecializedTemplateOrPartial(); - if (PatternPtr.is()) { - VarTemplatePartialSpecializationDecl *Tmpl = - PatternPtr.get(); - while (VarTemplatePartialSpecializationDecl *From = - Tmpl->getInstantiatedFromMember()) { - if (Tmpl->isMemberSpecialization()) - break; + // If this was instantiated from an explicit specialization declared within + // a dependent context (i.e. within a class template) - the pattern is the + // explicit specialization's pattern. + if (IsInstantiatedFromDependentExplicitSpecialization) { + PatternDecl = VarSpec->getInstantiatedFromStaticDataMember(); + } else { + // Find the variable initialization that we'll be substituting. If the + // pattern was instantiated from a member template, look back further to + // find the real pattern. + assert(VarSpec->getSpecializedTemplate() && + "Specialization without specialized template?"); + llvm::PointerUnion PatternPtr = + VarSpec->getSpecializedTemplateOrPartial(); + // Now check to see if we explicitly declared a new partial specialization + // with the same type. + VarTemplatePartialSpecializationDecl *NewPartialSpec = nullptr; + const TemplateArgumentList *NewPartialSpecDeducedArgs = nullptr; + bool NewPartialSpecIsAmbiguous = false; + std::tie(NewPartialSpec, NewPartialSpecDeducedArgs, + NewPartialSpecIsAmbiguous) = + getMostSpecializedPartialSpecialization( + VarSpec->getSpecializedTemplate(), VarSpec->getTemplateArgs(), + VarSpec->getPointOfInstantiation()); + if (NewPartialSpecIsAmbiguous) + return; + // FIXME: Check undeduced types here correctly. + // If we have a new partial spec, it better have the same type + if (NewPartialSpec) { + // If this instance was not instantiated from a partial specialization, + // or + // was instantiated from a different partial specialization ... + if (!PatternPtr.is() || + PatternPtr.get() != + NewPartialSpec) { + void *InsertPos = nullptr; + VarTemplateDecl *Template = VarSpec->getSpecializedTemplate(); + const TemplateArgumentListInfo &TemplateArgs = + VarSpec->getTemplateArgsInfo(); + SourceLocation TemplateNameLoc = VarSpec->getPointOfInstantiation(); + // Check that the template argument list is well-formed for this + // template. + SmallVector Converted; + if (CheckTemplateArgumentList( + Template, TemplateNameLoc, + const_cast(TemplateArgs), false, + Converted)) + return; + VarTemplateSpecializationDecl *NewVarSpec = + BuildVarTemplateInstantiation( + VarSpec->getSpecializedTemplate(), NewPartialSpec, + *NewPartialSpecDeducedArgs, VarSpec->getTemplateArgsInfo(), + Converted, TemplateNameLoc, + InsertPos /*, LateAttrs, StartingScope*/); - Tmpl = From; + if (!Context.hasSameType(NewVarSpec->getType(), VarSpec->getType())) { + // FIXME: Complain/Emit diagnostic that states we can not use a + // partial + // specialization that instantiates to a different type. + return; + } + } } - PatternDecl = Tmpl; - } else { - VarTemplateDecl *Tmpl = PatternPtr.get(); - while (VarTemplateDecl *From = - Tmpl->getInstantiatedFromMemberTemplate()) { - if (Tmpl->isMemberSpecialization()) - break; - Tmpl = From; + if (NewPartialSpec || + PatternPtr.is()) { + VarTemplatePartialSpecializationDecl *Tmpl = + NewPartialSpec + ? NewPartialSpec + : PatternPtr.get(); + while (VarTemplatePartialSpecializationDecl *From = + Tmpl->getInstantiatedFromMember()) { + if (Tmpl->isMemberSpecialization()) + break; + + Tmpl = From; + } + PatternDecl = Tmpl; + } else { + VarTemplateDecl *Tmpl = PatternPtr.get(); + while (VarTemplateDecl *From = + Tmpl->getInstantiatedFromMemberTemplate()) { + if (Tmpl->isMemberSpecialization()) + break; + + Tmpl = From; + } + PatternDecl = Tmpl->getTemplatedDecl(); } - PatternDecl = Tmpl->getTemplatedDecl(); } + TemplateArgs = getTemplateInstantiationArgs( + Var, /*Innermost*/ nullptr, /*RelativeToPrimary*/ false, + /*Function-Pattern*/ nullptr, + getTemplateParameterListsOfDeclaration(PatternDecl)); // If this is a static data member template, there might be an // uninstantiated initializer on the declaration. If so, instantiate @@ -3839,6 +4028,8 @@ assert(PatternDecl && "data member was not instantiated from a template?"); assert(PatternDecl->isStaticDataMember() && "not a static data member?"); Def = PatternDecl->getOutOfLineDefinition(); + + TemplateArgs = getTemplateInstantiationArgs(Var); } // If we don't have a definition of the variable template, we won't perform @@ -4379,14 +4570,15 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs) { DeclContext *ParentDC = D->getDeclContext(); - // FIXME: Parmeters of pointer to functions (y below) that are themselves + + // FIXME: Parmeters of pointer to functions (y below) that are themselves // parameters (p below) can have their ParentDC set to the translation-unit - // - thus we can not consistently check if the ParentDC of such a parameter + // - thus we can not consistently check if the ParentDC of such a parameter // is Dependent or/and a FunctionOrMethod. - // For e.g. this code, during Template argument deduction tries to + // For e.g. this code, during Template argument deduction tries to // find an instantiated decl for (T y) when the ParentDC for y is - // the translation unit. - // e.g. template void Foo(auto (*p)(T y) -> decltype(y())) {} + // the translation unit. + // e.g. template void Foo(auto (*p)(T y) -> decltype(y())) {} // float baz(float(*)()) { return 0.0; } // Foo(baz); // The better fix here is perhaps to ensure that a ParmVarDecl, by the time @@ -4402,6 +4594,13 @@ isa(D) || isa(D) || (ParentDC->isFunctionOrMethod() && ParentDC->isDependentContext()) || (isa(D) && cast(D)->isLambda())) { + + // Skip all the dummy template arguments that were invented to check + // specializations (i.e. explicit member function specializations) within + // a dependent context. They should remain invisible to the generated + // AST. + if (D->isImplicit() && D->getName().slice(0, 7) == "$dummy-") + return D; // D is a local of some kind. Look into the map of local // declarations to their instantiations. typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5264,6 +5264,30 @@ return InstantiateClassTemplateSpecialization(Loc, ClassTemplateSpec, TSK_ImplicitInstantiation, /*Complain=*/!Diagnoser.Suppressed); + else if (ClassTemplateSpec->getSpecializationKind() == + TSK_ExplicitSpecialization && + !ClassTemplateSpec->getDefinition() && + ClassTemplateSpec->getInstantiatedFromMemberClass()) { + // If this is a member template explicit specialization of + // an enclosing class template, it might still need its + // outer referenced template arguments substituted into. + // template struct A { + // template struct B; + // template<> struct B { + // T *t; + // }; + // }; + // + CXXRecordDecl *Pattern = + ClassTemplateSpec->getInstantiatedFromMemberClass(); + return InstantiateClass( + Pattern->getLocation(), ClassTemplateSpec, Pattern, + getTemplateInstantiationArgs( + ClassTemplateSpec, nullptr, false, nullptr, + getTemplateParameterListsOfDeclaration(Pattern)), + TSK_ImplicitInstantiation, + /*Complain=*/true); + } } else if (CXXRecordDecl *Rec = dyn_cast(Record->getDecl())) { CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass(); Index: test/CXX/drs/dr0xx.cpp =================================================================== --- test/CXX/drs/dr0xx.cpp +++ test/CXX/drs/dr0xx.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -Wno-bind-to-temporary-copy // RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -DCPP1Y namespace dr1 { // dr1: no namespace X { extern "C" void dr1_f(int a = 1); } @@ -475,7 +475,11 @@ namespace dr44 { // dr44: yes struct A { template void f(); +#ifndef CPP1Y template<> void f<0>(); // expected-error {{explicit specialization of 'f' in class scope}} +#else + template<> void f<0>(); +#endif }; } Index: test/CXX/drs/dr5xx.cpp =================================================================== --- test/CXX/drs/dr5xx.cpp +++ test/CXX/drs/dr5xx.cpp @@ -98,19 +98,19 @@ template struct S {}; template int v = 0; // expected-error 0-1{{extension}} - template struct S; - template int v; + template struct S; //expected-note{{first required here}} + template int v; //expected-note{{first required here}} - S s; - int k = v; + S s; //expected-note{{first required here}} + int k = v; //expected-note{{first required here}} // FIXME: These are both ill-formed. - template struct S {}; - template int v = 0; // expected-error 0-1{{extension}} + template struct S {}; //expected-error{{after instantiation}} + template int v = 0; //expected-error{{after instantiation}} // FIXME: These are both ill-formed. - template struct S {}; - template int v = 0; // expected-error 0-1{{extension}} + template struct S {}; //expected-error{{after instantiation}} + template int v = 0; //expected-error{{after instantiation}} } namespace dr518 { // dr518: yes c++11 Index: test/CXX/temp/temp.decls/temp.class.spec/p6.cpp =================================================================== --- test/CXX/temp/temp.decls/temp.class.spec/p6.cpp +++ test/CXX/temp/temp.decls/temp.class.spec/p6.cpp @@ -37,13 +37,17 @@ // Check for conflicts during template instantiation. template struct Outer { - template struct Inner; - template struct Inner {}; // expected-note{{previous}} - template struct Inner {}; // expected-error{{cannot be redeclared}} + template struct Inner { }; + template struct Inner {}; //expected-note{{matches}} + template struct Inner {}; //expected-note{{matches}} }; -Outer outer; // expected-note{{instantiation}} +Outer outer; +Outer::Inner inner47; + +Outer::Inner inner1; //expected-error{{ambiguous}} + // Test specialization of class template partial specialization members. template<> template struct X0::Inner0 { Index: test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp =================================================================== --- test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp +++ test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCPP1Y template struct A { void f(T); template void g1(T, X1); @@ -29,10 +30,18 @@ template struct Test{ template + #ifdef CPP1Y + void get(U i) {} //expected-note{{could not match}} + #else void get(U i) {} + #endif }; template template <> - void Test::get(double i) {} // expected-error{{cannot specialize (with 'template<>') a member of an unspecialized template}} + #ifdef CPP1Y + void Test::get(double i) {} //expected-error{{no function template matches}} + #else + void Test::get(double i) {} //expected-error{{within class scope}} + #endif } Index: test/SemaCXX/cxx1y-variable-templates_in_class.cpp =================================================================== --- test/SemaCXX/cxx1y-variable-templates_in_class.cpp +++ test/SemaCXX/cxx1y-variable-templates_in_class.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -verify -fsyntax-only %s -Wno-c++11-extensions -Wno-c++1y-extensions -DPRECXX11 // RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only -Wno-c++1y-extensions %s -// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s +// DISABLE: %clang_cc1 -std=c++1y -verify -fsyntax-only %s #define CONST const @@ -15,8 +15,8 @@ template static CONST T right = 5; template CONST int right; // expected-error {{member 'right' declared as a template}} template CONST float right = 5; // expected-error {{member 'right' declared as a template}} - template<> static CONST int right = 7; // expected-error {{explicit specialization of 'right' in class scope}} - template<> static CONST float right; // expected-error {{explicit specialization of 'right' in class scope}} + template<> static CONST int right = 7; //expected-error{{explicit specialization}} + template<> static CONST float right; //expected-error{{explicit specialization}} template static CONST int right; // expected-error {{template specialization requires 'template<>'}} \ // expected-error {{explicit specialization of 'right' in class scope}} }; @@ -214,10 +214,10 @@ template class D0a { template static U Data; - template static CONST U Data = U(10); // expected-note {{previous definition is here}} + template static CONST U Data = U(10); }; template<> - template U D0a::Data = U(100); // expected-error {{redefinition of 'Data'}} + template U D0a::Data = U(100); // FIXME: We should accept this, and the corresponding case for class // templates. @@ -228,12 +228,12 @@ template class D1 { template static U Data; - template static CONST U Data = U(10); // expected-note {{previous definition is here}} + template static CONST U Data = U(10); }; template<> template U D1::Data = U(10); template<> - template U D1::Data = U(100); // expected-error{{redefinition of 'Data'}} + template U D1::Data = U(100); } namespace definition_after_outer_instantiation { @@ -252,11 +252,11 @@ // is instantiated. This is kind of implied by [temp.class.spec.mfunc]/2, // and matches our behavior for member class templates, but it's not clear // that this is intentional. See PR17294 and core-24030. - static_assert(S::V2 == 456, ""); // FIXME expected-error {{}} - static_assert(S::V2 == 789, ""); // expected-error {{}} + static_assert(S::V2 == 456, ""); + //static_assert(S::V2 == 789, ""); template template const int S::V2 = 789; - static_assert(S::V2 == 789, ""); // FIXME expected-error {{}} + static_assert(S::V2 == 789, ""); // All is OK if the partial specialization is declared before the implicit // instantiation of the class template specialization. Index: test/SemaCXX/cxx1y-variable-templates_top_level.cpp =================================================================== --- test/SemaCXX/cxx1y-variable-templates_top_level.cpp +++ test/SemaCXX/cxx1y-variable-templates_top_level.cpp @@ -212,7 +212,7 @@ CONST int pi2 = 3; // expected-note {{partial specialization matches [with T = int]}} void foo() { - int a = pi2; // expected-error {{ambiguous partial specializations of 'pi2'}} + int a = pi2; // expected-error {{ambiguous partial specializations of pi2}} } } @@ -285,8 +285,9 @@ template CONST int pi2 = 1; - template CONST int pi2; - template CONST int pi2 = 2; + template CONST int pi2; //expected-note {{instantiation first required here}} + // FIXME: this diagnostic should say partial specialization + template CONST int pi2 = 2; //expected-error {{explicit specialization of 'pi2' after instantiation}} } #ifndef PRECXX11 Index: test/SemaTemplate/explicit-specialization-member.cpp =================================================================== --- test/SemaTemplate/explicit-specialization-member.cpp +++ test/SemaTemplate/explicit-specialization-member.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s template struct X0 { typedef T* type; @@ -38,22 +38,22 @@ template template - void Baz::bar() { // expected-note {{couldn't infer template argument 'N'}} + void Baz::bar() { // disable-expected-note {{couldn't infer template argument 'N'}} } // FIXME: We shouldn't try to match this against a prior declaration if // template parameter matching failed. template void Baz::bar<0>() { // expected-error {{cannot specialize a member of an unspecialized template}} \ - // expected-error {{no function template matches}} + // expected-error {{within class scope}} } } namespace PR19340 { template struct Helper { - template static void func(const T *m) {} // expected-note {{failed template argument deduction}} + template static void func(const T *m) {} // disable-expected-note {{failed template argument deduction}} }; template void Helper::func<2>() {} // expected-error {{cannot specialize a member}} \ - // expected-error {{no function template matches}} + // expected-error {{within class scope}} } Index: test/SemaTemplate/member-templates.cpp =================================================================== --- test/SemaTemplate/member-templates.cpp +++ test/SemaTemplate/member-templates.cpp @@ -0,0 +1,1540 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -emit-llvm-only %s +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fms-extensions %s -DMS_EXTENSIONS +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING + + + +namespace out_of_class_explicit_specialization_that_is_a_partial_spec_declaration { +template struct A { + template struct B {}; + template struct B : B { + template struct C; + template struct C { }; + }; +}; + +template<> template<> template +struct A::B::C { + typedef int type; +}; + +A::B::C::type abc; //expected-error {{no type}} +A::B::C::type use_out_of_class_partial_spec; + +} // end ns + +namespace test_if_explicit_partial_specializations_are_used { +template struct A { + template struct B {}; + template struct B : B { + template struct C { }; + }; +}; + +template<> template struct A::B { + typedef char type2; +}; + +template<> template struct A::B : B { + typedef int type3; +}; + + +A::B::type2 x1; +A::B::type3 x2; +A::B::type2 x3; + +A::B::type x4; //expected-error{{type}} +namespace swap_order_of_primary_and_partial { +template struct A { + template struct B {}; + template struct B : B { + template struct C { }; + }; +}; + + +template<> template struct A::B : B { + typedef int type3; +}; + +template<> template struct A::B { + typedef char type2; +}; + + +A::B::type2 x1; +A::B::type3 x2; +A::B::type2 x3; + +A::B::type x4; //expected-error{{type}} + +}// end ns + +} // end ns + + +namespace test_no_out_class_primary { +template struct A { + template struct B { int in_primary; }; + template struct B { + int in_partial3; + }; +}; + +template<> template struct A::B { + int out_int_partial1; +}; + +template<> template struct A::B { + int out_int_partial2; +}; + +template template struct A::B { + int out_partial4; +}; +//int x0 = A::B().out_int_primary; +int x0 = A::B().in_primary; +int x1 = A::B().out_int_partial1; +int x2 = A::B().out_int_partial2; +int x3 = A::B().in_partial3; +int x4 = A::B().out_partial4; +} + + +namespace test_out_class_primary_106_102 { +template struct A { + template struct B { int in_primary; }; + template struct B { + int in_partial3; + }; +}; + +template<> template struct A::B { + int out_int_primary; +}; +template<> template struct A::B { + int out_int_partial1; +}; + +template<> template struct A::B { + int out_int_partial2; +}; + +template template struct A::B { + int out_partial4; +}; +int x0 = A::B().out_int_primary; +int x1 = A::B().out_int_partial1; +int x2 = A::B().out_int_partial2; +int x3 = A::B().out_int_partial2; +int x4 = A::B().out_int_partial2; +namespace try_char_instead_of_int { +int x0 = A::B().in_primary; +int x1 = A::B().in_primary; +int x2 = A::B().in_primary; +int x3 = A::B().in_partial3; +int x4 = A::B().out_partial4; + +} //end inner ns +} + + +namespace test_out_class_primary_swap_order_106 { +template struct A { + template struct B { int in_primary; }; + template struct B { + int in_partial3; + }; +}; + +template<> template struct A::B { + int out_int_partial1; +}; + + +template<> template struct A::B { + int out_int_primary; +}; + +template<> template struct A::B { + int out_int_partial2; +}; + +template template struct A::B { + int out_partial4; +}; +int x0 = A::B().out_int_primary; +int x1 = A::B().out_int_partial1; +int x2 = A::B().out_int_partial2; +int x3 = A::B().out_int_partial2; +int x4 = A::B().out_int_partial2; + +namespace try_char_instead_of_int { +int x0 = A::B().in_primary; +int x1 = A::B().in_primary; +int x2 = A::B().in_primary; +int x3 = A::B().in_partial3; +int x4 = A::B().out_partial4; + +} //end inner ns +} + +namespace test_nested_member_partial_specs_3deep_180 { +template struct X { + template struct Y { + template struct Z { + int l; + }; + template struct Z { + int k; + }; + }; + }; + + template + template + template + struct X::Y::Z { + int j; + }; + + template<>template<> + template + struct X::Y::Z { + int i; + }; + + void a() + { + int x = X::Y::Z<0,int>().k; + x = X::Y::Z<0,int>().k; + x = X::Y::Z<0,char>().i; + x = X::Y::Z<0,char*>().j; + + } +} // end ns + + +namespace test_nested_member_partial_specs_3deep_180_swap_order1 { + template struct X { + template struct Y { + template struct Z { + int l; + }; + template struct Z { + int k; + }; + }; + }; + + template<>template<> + template + struct X::Y::Z { + int i; + }; + + template + template + template + struct X::Y::Z { + int j; + }; + + void a() + { + int x = X::Y::Z<0,int>().k; + x = X::Y::Z<0,int>().k; + x = X::Y::Z<0,char>().i; + x = X::Y::Z<0,char*>().j; + + } +} // end ns + +namespace test_no_instantiation_of_partial_specs_if_primary_is_specialized { + +template struct O { + template struct L; + //template struct L { int k; }; +}; + + +struct HasType { typedef HasType* type; }; +struct HasNoType { }; + +template template +struct O::L { int k; }; + + +template<> template +struct O::L { + int j; +}; + +int x0 = O::L().j; +int x1 = O::L().k; +} + + +namespace test_no_instantiation_of_partial_specs_if_primary_is_specialized_2 { + +template struct O { + template struct L; + template struct L { int k; }; +}; + + +struct HasType { typedef HasType* type; }; +struct HasNoType { }; + + +//template<> template +//struct O::L { int j; }; + +template template +struct O::L { int k; }; + +template<> template +struct O::L { + int l; +}; + +template<> template +struct O::L { + int j; +}; + + +//template +//template +//struct O::L { int k; }; + +//template<> template +//struct O::L { int j; }; + +int x0 = O::L().l; +int x1 = O::L().j; + +} + +namespace test_select_explicitly_specialized_partial_member_specs_if_ambiguous_317 { + +template struct O { + template struct L; + template struct L { int k; }; +}; + + +struct HasType { typedef HasType* type; }; +struct HasNoType { }; + + +template<> template +struct O::L { int j; }; + +template template +struct O::L { int k; }; + +template<> template +struct O::L { + int l; +}; + +template<> template +struct O::L { + int m; +}; + + +//template +//template +//struct O::L { int k; }; + +//template<> template +//struct O::L { int j; }; + +int x0 = O::L().j; +int x1 = O::L().m; + +} + + +namespace test_similar_partial_specs_if_but_use_explicit_specialized_359 { + +template struct O { + template struct L { int p; }; + template struct L { int k; }; +}; + + +struct HasType { typedef HasType* type; }; +struct HasNoType { }; + + +//template<> template +//struct O::L { int j; }; + +template template +struct O::L { int k2; }; + +template<> template +struct O::L { + int j; +}; + + +//template +//template +//struct O::L { int k; }; + +//template<> template +//struct O::L { int j; }; + +int x0 = O::L().j; +int x1 = O::L().p; +int x2 = O::L().p; +} + +namespace check_redefinitions { + +namespace ns1 { + +template struct O { + template struct L; + template struct L { int k; }; //expected-note{{previous definition}} +}; + +template template +struct O::L { //expected-error{{redefinition}} + int k; +}; + +} // end ns + + +namespace ns2 { + +template struct O { + template struct L; + template struct L { int k; }; +}; + +template<> +template +struct O::L { //expected-note{{previous}} + +}; +template<> +template +struct O::L { //expected-error{{redefinition}} + int k; +}; + +} // end ns + +} // end ns check_redefinitions + + +namespace TEST_PARTIAL_SPECS_434 { +template struct A { + template struct B { + U* u1; + }; + template struct C { + U1 *u1; + U2 *u2; + }; +}; + +template<> +template +struct A::B; +template<> +template +struct A::B { + U* u2; +}; +template<> +template +struct A::B; + +template +template +struct A::B; +template +template +struct A::B { + U* u3; +}; +template +template +struct A::B; + +template +template +struct A::B { + U* u4; +}; + +template<> +template +struct A::B { + U* u5; +}; +char *x1 = A::B{}.u5; +char *x2 = A::B{}.u2; +char *x3 = A::B{}.u4; + +template +template +struct A::C { + U1 *u3; +}; + +template +template +struct A::C { + U1 *u4; +}; + +char *x4 = A::C{}.u3; +struct HasType { + using type = int; +}; +char *x5 = A::C{}.u4; + +template template +struct A::B; + +template template +struct A::B { }; + +template<> template +struct A::B { + U* u510; +}; + +template<> template +struct A::B { + U* u515; +}; +char ***x6 = A::B{}.u515; + +} + + +namespace variable_template_tests { + +namespace ns1 { +template struct X { }; + +template +struct A { + template + static X u1; +}; + +template +template +X A::u1 = X{}; + +template +template +X A::u1 = X{}; + +template<> +template +X A::u1 = X{}; + +template<> +template +X A::u1 = X{}; + +template<> +template +X A::u1 = X{}; + +template +template +X A::u1 = X{}; + +X a1 = A::u1; +// choose the explicitly specialized partial specialization template +X a2 = A::u1; +X a479 = A::u1; +X a480 = A::u1; +X a481 = A::u1; +X a482 = A::u1; +X a483 = A::u1; +} + +namespace test_52_fv { +template struct X { }; + +template +struct A { + template + static constexpr X u1 = X{}; + auto f() { return u1; } +}; + +template<> template +constexpr X A::u1 = X{}; +template template +constexpr X A::u1 = X{}; + + +template<> template +constexpr X A::u1 = X{}; + + +X x65 = A::u1; +X x65_1 = A::u1; + +X x65_2 = A::u1; + + +X x67 = A::u1; + +X x70 = A{}.f(); +} + + +namespace test_explicit_spec_of_var_template { +template struct X { }; + +template +struct A { + template + static constexpr X u1 = X{}; + template + static constexpr X u1 = X{}; +}; + +template<> template +constexpr X A::u1 = X{}; + +template template +constexpr X A::u1; +template<> template +constexpr X A::u1 = X{}; + + +template template +constexpr X A::u1 = X{}; + + +template<> template +constexpr X A::u1 = X{}; + + +X x65 = A::u1; +X x65_1 = A::u1; + +X x65_2 = A::u1; +X x110 = A::u1; +X x116 = A::u1; +} + +namespace ns641_variable_templates { +template struct X { int n; X(int n) : n(n) { } }; + +template +struct A { + template + static X u1; + + using ptrtype = decltype(u1); //expected-note{{required here}} + + ptrtype foo() const { return u1; } +}; + +template<> template +X A::u1 = X{2}; //expected-error{{after instantiation}} + + +} + +} + +namespace vt_use_primary_template_before_explicit_specialization { +namespace ns1 { +template +struct A { + template + static constexpr int u1 = 1; + + int arr[u1]; //expected-note{{required here}} +}; + +template<> template +constexpr int A::u1 = 2; //expected-error{{after instantiation}} +} //end ns1 + +namespace ns2 { + +template +struct A { + template + static constexpr int u1 = 1; + template + static constexpr double u1 = 10; + + decltype(u1) member; //expected-note{{required here}} +}; + +template<> template +constexpr int A::u1 = 2; //expected-error{{after instantiation}} + +} + + +namespace ns3 { +template +struct A { + template + static constexpr int u1 = 1; + template + static constexpr int u1 = 10; + + //decltype(u1) member; + decltype(u1) member2; +}; + +template<> template +constexpr int A::u1 = 2; + +} + +namespace specialize_with_same_type { + +template +struct A { + template + static T u1; + + decltype(u1) member2; + +}; +template template +T A::u1 = 1; + +template<> template +short A::u1 = 2; // this is ok because same type +} + +namespace specialize_with_same_template_type { +template struct X { }; + +template +struct A { + template + static X u1; + decltype(u1) member2; +}; + +template template +X A::u1 = X{}; + +//template template +//X A::u1 = X{}; + + +template<> template +X A::u1 = X{}; // this is ok because same type +} +} + +namespace variable_templates_713 { +namespace auto_deduce_to_same_type { + +template +struct A { + template + static T u1; + + decltype(u1) member2; //expected-note{{required here}} + +}; +template template +T A::u1 = 1; + +template<> template +auto A::u1 = 2; + +template<> template +auto A::u1 = 2.0; //expected-error{{after instantiation}} + +} // end ns + +namespace auto_deduce_to_same_type2 { + + +template +struct A { + template + static constexpr auto u1 = 1; + + decltype(u1) member2; //expected-note{{required here}} + +}; + +template<> template +constexpr auto A::u1 = 3; + +template<> template +constexpr auto A::u1 = 3.0; //expected-error{{after instantiation}} + +namespace multiple_decls_and_lambda_as_member { + +template +struct A { + template + static int L; +}; + +template template +int A::L = 0; + +template template +auto A::L = [](T *, U *u) { return u; }; + +char *pc = A::L((int *)0, (char*)0); +} +} + +namespace cannot_define_partial_specs_twice { + +template +struct A { + template + static constexpr U u1 = 1; + template + static constexpr U u1 = 2; +}; + +template<> template +int A::u1; //expected-note{{previous definition}} + +template<> template +int A::u1 = 5; //expected-error{{redefinition}} + +} + +} + +//--------------------------------EXPLICIT SPECIALIZATION-------------------- +namespace define_explicit_specs_inline_and_outline { + +template struct A { + template struct B; + template<> struct B; +}; + +template +template<> +struct A::B { //expected-note{{matches}} + T* tb; +}; + +template +template<> +struct A::B { //expected-note{{matches}} + T* tb2; +}; + +int *x = A::B{}.tb; +int *x1 = A::B{}.tb2; +char *x2 = A::B{}.tb2; //expected-error{{ambiguous}} + +namespace check_sfinaeability_of_explicit_spec { +template struct A { + template struct B { + T *tb0; + U *ub0; + }; + template<> struct B; +}; + +template +template<> +struct A::B { //expected-note{{matches}} + T* tb1; +}; + +template +template<> +struct A::B { //expected-note{{matches}} + T* tb2; +}; + +template +struct HasType { + using type = T; +}; + +int *x = A::B{}.tb0; +int *x1 = A::B{}.tb2; +char *x2 = A::B{}.tb2; + +HasType *x3 = A>::B{}.tb1; +HasType *x4 = A>::B{}.tb2; +HasType *x5 = A>::B{}.tb2; //expected-error{{ambiguous}} + +} +namespace explicit_spec_3_deep_887 { + +template struct A { + template struct B; + template<> struct B; +}; + +template +template<> +struct A::B { //expected-note{{matches}} + T* tb; + template struct C; +}; +template +template<> +struct A::B { //expected-note{{matches}} + T* tb2; + template struct C; +}; +template template<> +struct A::B::C { + T* tc1; +}; +template template<> +struct A::B::C { + T* tc1_912; +}; + +template template<> +struct A::B::C<0> { + T* tc2; +}; + + +template template<> +struct A::B::C<10> { + T* tc3; +}; +int *x1 = A::B::C{}.tc1; +int *x2 = A::B::C<0>{}.tc2; +char *x3 = A::B{}; //expected-error{{ambiguous}} +short *x4 = A::B::C<0>{}.tc2; +short *x5 = A::B::C{}.tc1; +short *x6 = A::B::C{}.tc1_912; +short *x7 = A::B::C<10>{}.tc3; + +} + +namespace partial_and_explicit_spec_3_deep_935 { + +template struct A { + template struct B; + template<> struct B; +}; + +template +template<> +struct A::B { //expected-note{{matches}} + T* tb; + template struct C; +}; +template +template<> +struct A::B { + T* tb1_951; + template struct C { + T* tc1_953; + V* vc1_954; + }; +}; +template +template +struct A::B { + T* tb0_952; + U* ub0_952; + template struct C; +}; + +template +template template<> +struct A::B::C { + T* tb1_967; + U* ub1_968; +}; + +template +template<> +struct A::B { //expected-note{{matches}} + T* tb2; + template struct C; +}; +template template<> +struct A::B::C { + T* tc1; +}; +template template<> +struct A::B::C { + T* tc1_912; +}; + +template template<> +struct A::B::C<0> { + T* tc2; +}; + + +template template<> +struct A::B::C<10> { + T* tc3; +}; +int *x1 = A::B::C{}.tc1; +int *x2 = A::B::C<0>{}.tc2; +char *x3 = A::B{}; //expected-error{{ambiguous}} +short *x4 = A::B::C<0>{}.tc2; +short *x5 = A::B::C{}.tc1; +short *x6 = A::B::C{}.tc1_912; +short *x7 = A::B::C<10>{}.tc3; +short *x8 = A::B::C{}.tb1_967; +float *x9 = A::B::C{}.vc1_954; + + +} +namespace member_function_templates_1009 { +template struct A { + template struct B; +}; + +template +template<> +struct A::B { + T* tb; + template struct C; +}; + +template +template<> +struct A::B { + T* tb2; + + template struct C; +}; + +template template<> +struct A::B::C { + T* tc1; + template W* foo(W); + template T* foo(W*, T*) { + return nullptr; + } +}; + +template template<> +struct A::B::C<0> { + T* tc2; + T* foo(T*) { return 0; } //expected-note{{parameter here}} +}; + + +template template<> +struct A::B::C<10> { + T* tc3; +}; + +template template +W* A::B::C::foo(W) { + return (W*)(T*)nullptr; +} + +float *ip = A::B::C{}.foo(3.2F); +char *ip2 = A::B::C{}.foo((float*)0, (char*)0); +int *ip3 = A::B::C{}.foo((float*)0, (int*)0); +short *ip4 = A::B::C<0>{}.foo((float*)0); //expected-error{{float *}} + +} +namespace nontemplate_parent_class_members { + struct A { + template struct B { + template struct C; + }; + }; + template template<> struct A::B::C { + U* cu; + }; + char *x = A::B::C{}.cu; +} +namespace member_template_function_explicit_spec_1072 { +template struct A { + template U* foo(U*, T*) { return 0; } +}; + +template<> template +U* A::foo(U*, int*) { return 0; } +template<> template<> +float* A::foo(float*, short*) { return 0; } + + +} +namespace member_template_function_explicit_spec_semantic_checking_1084 { +template struct A { + template U* foo(U*, typename T::type *); + + template<> int* foo(int*, typename T::type *) { return 0; } +}; +} + +namespace redefinition_explicit_member_template_func_1092 { + +template struct A { + template U* foo(U*, T*); + template U* foo(U*, typename T::type *, const T (&a)[N], T*/*, X*/); + + template<> int *foo(int*, T*) { return 0; } //expected-note 2{{previous}} + template<> int *foo(int*, typename T::type *, const T (&)[N], T*) { return 0; } + template<> int *foo(int*, T*) { return 0; } //expected-error{{redeclared}} \ + expected-error{{redefinition}} + +}; + + +} + +namespace member_template_function_explicit_pack1 { +template struct X { }; +namespace type_pack { + +template struct A { + template class UU> void bar(UU) { } + template<> void bar(X) { } +}; +} +namespace template_pack { + +template struct W; +template struct X; + +template class SS, class S> class ... TTs> struct A { + + template class UU, class U> U* bar(TTs ... tts) { return 0; } + template<> int* bar(TTs ...) { return 0; } + template<> char* bar(TTs ...) { return 0; } + template<> char* bar(TTs ...) { return 0; } + + template class UU, class U> U* bar2(TTs ... tts) { return 0; } //expected-note{{substitution failure}} + template<> int* bar2(TTs ...) { return 0; } + template<> char* bar2(TTs ...) { return 0; } + template<> char* bar2(TTs ...) { return 0; } //expected-error{{no function template matches}} + +}; + +} +namespace nontype_args { +template struct X { }; + +template struct A { + + template U* foo(U (&)[O]) { return 0; } //expected-note{{failed template argument deduction}} + template<> float* foo(float (&)[O]) { return 0; } + template<> short* foo(short (&)[N]) { return 0; } //expected-error{{no function template matches}} + + template class UU> int bar(UU) { return 0; } // 1 + + template class UU> int bar(UU) { return 0; } // 2 + // Matches 1 + template<> int bar(X) { return 0; } + // Matches 2 + template<> int bar(X) { return 0; } + + +}; +namespace nontype_packs { + +template struct X { }; +template struct A { + template class UU> int foo(UU) { return 0; } + template<> int foo(X) { return 0; } +}; + +namespace nested_types_1164 { + +template struct X { }; + +template +struct A { + struct A1 { + + template + struct B { + struct B1 { + template class VV> int foo(VV, T*) { return 0; } //expected-note{{could not match}} + template<> int foo(X, T*) { return 0; } + template<> int foo(X, T*) { return 0; } //expected-error{{no function template matches}} + + }; + }; + }; +}; +} // end nested_types_1164 + +namespace nested_types_1185 { + +template struct X { }; + +template +struct A { + struct A1 { + + template + struct B { + struct B1 { + template class VV> int foo(VV, T*, U**) { return 0; } + template<> int foo(X, T*, U**) { return 0; } //expected-error{{no function template matches}} + + }; + }; + }; +}; +} // end nested_types_1185 + +namespace check_template_template_param_nested { +template< + template class VV1, + template class VV2 + > struct X { }; +template struct A { + struct A1 { + template class ... UUs> + struct B { + struct B1 { + template< + template< + template class VV1, + template class VV2 + > class VVV + > int foo(VVV) { return 0; } + template<> int foo(X) { return 0; } + }; + }; + }; +}; + +namespace ns1 { +template< + template class VV1, + template class VV2 + > struct X { }; +template struct A { + struct A1 { + template class ... UUs> + struct B { + struct B1 { + template< + template< + template class VV1, + template class VV2 + > class VVV + > int foo(VVV) { return 0; } + template<> int foo(X) { return 0; } + }; + }; + }; +}; + +} + +namespace ns2 { +template< + template class VV1, + template class VV2 + > struct X { }; +template struct A { + struct A1 { + template class ... UUs> + struct B { + struct B1 { + template< + template< + template class VV1, + template class VV2 + > class VVV + > int foo(VVV) { return 0; } + template<> int foo(X) { return 0; } + }; + }; + }; +}; +} + +namespace ns3 { +#ifdef FIXME_1275 +// This should not be an error! +template< + template class VV1, + template class VV2 + > struct X { }; +template struct A { + struct A1 { + template class ... UUs> + struct B { + struct B1 { + template< + template< + template class VV1, + template class VV2 + > class VVV + > int foo(VVV) { return 0; } + template<> int foo(X) { return 0; } + }; + }; + }; +}; +#endif +} + + +} // end check_template_template_param_nested + +} // end ns nontype_packs +} // end ns nontype_args +} // end member_template_function_explicit_pack1 + +namespace check_redefinition_errors_1307 { + +template struct A { + template V* foo(V*, T*) { return 0; } + template<> typename T::type* foo(typename T::type*, T*) //expected-note{{previous}} + { return (T*)0; } +}; + +template template<> +typename T::type* A::foo(typename T::type*, T*) //expected-error{{redefinition}} +{ return (T*)0; } + +namespace ns1_1319 { +template struct A { + template V* foo(V*, T*) { return 0; } +}; + +template template<> +char* A::foo(char*, T*) { return (char*)(T*)0; } + +char *pc = A{}.foo((char*)0, (int*)0); + +} // end ns1_1319 +} // end ns check_redefinition_errors_1307 +namespace ambiguous_explicit_specs_upon_substitution_1331 { + template struct A { + template V* foo(V*, T*) { return 0; } //expected-note{{ambiguous explicit specialization}} +}; + + +template template<> +char* A::foo(char*, T*) { return (char*)(T*)0; } + +template template<> +T* A::foo(T*, T*) { return (T*)1; } + + + +char *pc = A{}.foo((char*)0, (int*)0); +char *pc2 = A{}.foo((char*)0, (char*)0); //expected-error{{no matching}} + +} // end ns ambiguous_explicit_specs_upon_substitution_1331 +namespace explicitly_specialized_member_template_function_as_template { +template struct A { + template constexpr int foo(V*, T*) { return 0; } +}; + + +template template<> +constexpr int A::foo(char*, T*) { return 1; } + +template template<> +constexpr int A::foo(T*, T*) { return 2; } + +template<> template +constexpr int A::foo(V*, float*) { return 3; } + +template<> template<> +constexpr int A::foo(short*, float*) { return 4; } + + +static_assert(A{}.foo((char*)0, (int*)0) == 1, ""); +static_assert(A{}.foo((short*)0, (short*)0) == 2, ""); +static_assert(A{}.foo((char*)0, (float*)0) == 3, ""); +static_assert(A{}.foo((short*)0, (float*)0) == 4, ""); + +namespace ns1 { + +template struct A { + template constexpr int foo(T*) { return 0; } //expected-note{{ambiguous}} +}; + +template template<> +constexpr int A::foo(T*) { return 1; } + +template template<> +constexpr int A::foo(T*) { return 2; } + +template<> template +constexpr int A::foo(float*) { return 3; } + +template<> template<> +constexpr int A::foo(float*) { return 4; } + +template template<> +constexpr int A::foo(T*) { return 5; } + +template<> template<> +constexpr int A::foo(char*) { return 6; } + +template template<> +constexpr int A::foo(T*) { return 7; } + + +static_assert(A{}.foo((short*)0) == 1, ""); +static_assert(A{}.foo((short*)0) == 2, ""); +static_assert(A{}.foo((float*)0) == 3, ""); +static_assert(A{}.foo((float*)0) == 3, ""); +static_assert(A{}.foo((float*)0) == 4, ""); +static_assert(A{}.foo((short*)0) == 5, ""); +static_assert(A{}.foo((char*)0) == 6, ""); +static_assert(A{}.foo((char*)0) == 7, ""); +static_assert(A{}.foo((char*)0) == 7, ""); //expected-error{{no matching}} + +} // end ns1 + +namespace ns2 { + +template struct A { + template struct B { + template struct C { + template constexpr int f(W1*, W2*, T*, U*, V*) { return 0; } + template<> constexpr int f(V*, V*, T*, U*, V*) { return 1; } //expected-note{{previous}} + }; + }; +}; +template template template template<> +constexpr int A::B::C::f(T*, V*, T*, U*, V*) { return 2; } + +template template template template<> +constexpr int A::B::C::f(V*, V*, T*, U*, V*) { return 3; } //expected-error{{redefinition}} + +} // end ns2 + +namespace ns3 { + +template struct A { + template struct B { + template struct C { + template constexpr int f(W1*, W2*, T*, U*, V*) { return 0; } //expected-note{{ambiguous}} + template<> constexpr int f(V*, V*, T*, U*, V*) { return 1; } + }; + }; +}; +template template template template<> +constexpr int A::B::C::f(T*, V*, T*, U*, V*) { return 2; } + +constexpr int *ip = 0; +constexpr char *cp = 0; +constexpr float *fp = 0; +constexpr short *sp = 0; + +static_assert(A::B::C{}.f(sp, sp, ip, cp, sp) == 1, ""); +static_assert(A::B::C{}.f(ip, sp, ip, cp, sp) == 2, ""); +static_assert(A::B::C{}.f(ip, ip, ip, cp, sp) == 0, ""); +static_assert(A::B::C{}.f(ip, ip, ip, ip, ip) == 0, ""); //expected-error{{no matching}} + +} // end ns3 +} +} // end ns define_explicit_specs_inline_and_outline + +namespace +member_var_templates_explicit_specializations_at_class_scope_1458 { + +namespace ns1 { +template struct A { + template static constexpr T var = 1; + template static constexpr T var = 2; + template<> static constexpr T var = 3; +}; +template template +constexpr T A::var; +template template +constexpr T A::var; +template template<> +constexpr T A::var; + +template<> template +constexpr int A::var = 4; + +// disable the use of all other specializations for A +template<> template +constexpr int A::var = 5; + + +template<> template +constexpr int A::var = 7; + +template<> template +constexpr int A::var = 6; + + +template<> template +constexpr int A::var = 8; + +template<> template<> +constexpr int A::var = 9; + + +template<> template<> +constexpr int A::var = 10; + +template<> template<> +constexpr int A::var = 11; + + +static_assert(A::var == 3, ""); +static_assert(A::var == 1, ""); +static_assert(A::var == 2, ""); +static_assert(A::var == 1, ""); +static_assert(A::var == 3, ""); +static_assert(A::var == 4, ""); +static_assert(A::var == 5, ""); +static_assert(A::var == 5, ""); +static_assert(A::var == 5, ""); + +static_assert(A::var == 7, ""); +static_assert(A::var == 6, ""); +static_assert(A::var == 8, ""); +static_assert(A::var == 9, ""); +static_assert(A::var == 10, ""); +static_assert(A::var == 11, ""); + + + + + +} +namespace ns2 { +template struct A { + template struct B { + template struct C { + template static constexpr int var = 1; + template<> static constexpr int var = 2; + }; + }; +}; + +static_assert(A::B::C::var == 2, ""); + +} // end ns2 + +} // end var_templates_class_scope_... + Index: test/SemaTemplate/ms-class-specialization-class-scope.cpp =================================================================== --- test/SemaTemplate/ms-class-specialization-class-scope.cpp +++ test/SemaTemplate/ms-class-specialization-class-scope.cpp @@ -29,12 +29,12 @@ public: template struct X { typedef int x; }; - typename X::x a; // expected-note {{implicit instantiation first required here}} + typename X::x a; //expected-error{{no type named 'x'}} - template<> struct X; // expected-error {{explicit specialization of 'X' after instantiation}} - template<> struct X; // expected-note {{forward declaration}} + template<> struct X { }; + template<> struct X { }; - typename X::x b; // expected-error {{incomplete type 'B::X' named in nested name specifier}} + typename X::x b; //expected-error{{no type named 'x'}} template<> struct X { typedef int y; @@ -42,8 +42,9 @@ typename X::y c; - template<> struct X {}; // expected-note {{previous definition is here}} - template<> struct X {}; // expected-error {{redefinition of 'X'}} + template<> struct X {}; // expected-note {{matches}} + template<> struct X {}; // expected-note {{matches}} }; -B b; // expected-note {{in instantiation of}} +B b; //expected-note {{in instantiation of}} +B::X b2; //expected-error {{ambiguous}} \ No newline at end of file