Index: include/clang/AST/DeclTemplate.h =================================================================== --- include/clang/AST/DeclTemplate.h +++ include/clang/AST/DeclTemplate.h @@ -665,7 +665,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); } @@ -804,8 +804,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); @@ -1774,9 +1775,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 @@ -2625,7 +2628,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 @@ -3361,6 +3361,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 @@ -361,6 +361,16 @@ /// 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; + /// \brief Stack containing information about each of the nested /// function, block, and method scopes that are currently active. /// @@ -5283,7 +5293,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, @@ -5343,6 +5354,10 @@ const TemplateArgumentListInfo &ExplicitTemplateArgs, LookupResult &Previous); + bool checkDependentClassScopeFunctionExplicitSpecialization( + FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, + LookupResult &Previous); + bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous); @@ -5982,13 +5997,6 @@ QualType OriginalArgType; }; - TemplateDeductionResult - FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, - SmallVectorImpl &Deduced, - unsigned NumExplicitlySpecified, - FunctionDecl *&Specialization, - sema::TemplateDeductionInfo &Info, - SmallVectorImpl const *OriginalCallArgs = nullptr); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, @@ -5997,13 +6005,6 @@ FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info); - TemplateDeductionResult - DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - TemplateArgumentListInfo *ExplicitTemplateArgs, - QualType ArgFunctionType, - FunctionDecl *&Specialization, - sema::TemplateDeductionInfo &Info, - bool InOverloadResolution = false); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, @@ -6049,6 +6050,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, @@ -6058,6 +6062,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, @@ -6068,6 +6084,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, @@ -6089,9 +6132,11 @@ 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. + /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { /// \brief The kind of template instantiation we are performing enum InstantiationKind { @@ -6119,9 +6164,16 @@ /// template argument deduction for either a class template /// partial specialization or a function template. The /// Entity is either a ClassTemplatePartialSpecializationDecl or - /// a FunctionTemplateDecl. + /// VarTemplatePartialSpecializationDecl or a FunctionTemplateDecl. DeducedTemplateArgumentSubstitution, + /// We are substituting template arguments determined as part of + /// template argument deduction performed when an explicit function + /// template specialization is being declared to check whether it is + /// well-formed and corresponds to a primary function template. + /// The Entity is a FunctionTemplateDecl. + SubstitutionWhileCheckingDeclarationOfAnExplicitFunctionSpecialization, + /// We are substituting prior template arguments into a new /// template parameter. The template parameter itself is either a /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. @@ -6189,6 +6241,8 @@ return X.Template == Y.Template && X.TemplateArgs == Y.TemplateArgs; case DefaultTemplateArgumentInstantiation: + case + SubstitutionWhileCheckingDeclarationOfAnExplicitFunctionSpecialization: case ExplicitTemplateArgumentSubstitution: case DeducedTemplateArgumentSubstitution: case DefaultFunctionArgumentInstantiation: @@ -6205,6 +6259,23 @@ } }; + TemplateDeductionResult DeduceTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, + FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, + bool InOverloadResolution = false, + ActiveTemplateInstantiation::InstantiationKind = + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); + + TemplateDeductionResult FinishTemplateArgumentDeduction( + FunctionTemplateDecl *FunctionTemplate, + SmallVectorImpl &Deduced, + unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, + sema::TemplateDeductionInfo &Info, + SmallVectorImpl const *OriginalCallArgs = nullptr, + ActiveTemplateInstantiation::InstantiationKind = + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); + /// \brief List of active template instantiations. /// /// This vector is treated as a stack. As one template instantiation 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 { @@ -86,6 +87,24 @@ return nullptr; } +/// Given a member function specialization and a function template determine the +/// corresponding template arguments that would produce the specialization from +/// the function template. +Sema::TemplateDeductionResult +DeduceTemplateArgumentsFromMemberFunctionSpecialization( + Sema &S, FunctionTemplateDecl *PrimaryTemplate, + CXXMethodDecl *SubstitutedSpecialization, + TemplateArgumentListInfo *SubstitutedExplicitTemplateArgs, + sema::TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced); + +/// Identify a dummy (invented) non-type template argument expression that is +/// generated when comparing and substituting into dependent class scope +/// function explicit specializations. +/// When instantiating templates or deducing template arguments we need to be +/// able to identify these nodes so as to handle them specially. +bool isInventedDummyNonTypeTemplateArgumentExpr(Expr *E); + } #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/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -7930,7 +7930,42 @@ if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly) return false; + // If we have a specialization of a variable member template (within a class + // template specialization) that does not have an initializer and it was + // "instantiated from" an explicitly provided full specialization within a + // class member template - and that proto full specialization does have an + // initializer, that means that this specialization was simply generated + // during consideration of whether that explicitly provided full + // specialization is the best specialization to use for a certain template-id, + // but was not eventually used - so we do not need to emit it. + // For e.g. + // template struct A { + // template static int B; + // }; + // template template + // int A::B{}; + // template template<> + // A A::B{}; + // int x = A::B; + if (const auto *VSD = dyn_cast(VD)) { + if (isa(VSD->getDeclContext()) && + !VSD->getAnyInitializer()) { + // An explicitly provided full specialization is never instantiated from + // another template... + if (!VSD->getInstantiatedFrom()) { + if (const VarDecl *ProtoVD = + VSD->getInstantiatedFromStaticDataMember()) { + if (ProtoVD->getAnyInitializer()) { + const auto *ProtoVSD = cast(ProtoVD); + if (ProtoVSD->isExplicitSpecialization() && + ProtoVSD->getDeclContext()->isDependentContext()) + return false; + } + } + } + } + } // Variables that can be needed in other TUs are required. GVALinkage L = GetGVALinkageForVariable(VD); if (L != GVA_Internal && L != GVA_AvailableExternally && Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -1748,23 +1748,77 @@ // An explicit specialization of a static data member or an explicit // specialization of a static data member template is a definition if the // declaration includes an initializer; otherwise, it is a declaration. - // - // FIXME: How do you declare (but not define) a partial specialization of - // a static data member template outside the containing class? + if (isStaticDataMember()) { - 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. - (getFirstDecl()->isOutOfLine() + const bool IsThisDeclOutOfClass = isOutOfLine(); + const bool HasInit = hasInit(); + const bool IsFirstDeclOutOfLine = getFirstDecl()->isOutOfLine(); + const bool IsFirstDeclInClass = !IsFirstDeclOutOfLine; + + // Identify similar following constructs: + // template struct A + // static constexpr int Var = 1; + // template static constexpr int VarT = 2; + // }; + // + // template<> constexpr int A::Var; # Declaration (sans Init) + // template<> template + // constexpr int A::VarT; # Declaration (sans Init) + const bool IsExplicitlySpecializedMemberOfImplicitlyInstantiatedClassSpec = + ([](const VarDecl *Var) { + const ClassTemplateSpecializationDecl *ParentClassSpec = + dyn_cast(Var->getDeclContext()); + if (!ParentClassSpec || + ParentClassSpec->getTemplateSpecializationKind() != + TSK_ImplicitInstantiation) + return false; + assert(!ParentClassSpec->isDependentContext() && + "An implicitly instantiated class should never be dependent"); + + return Var->isOutOfLine() && !Var->getFirstDecl()->isOutOfLine() && + Var->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization; + }(this)); + + const bool IsPartialOrFullVarTemplateSpecialization = + isa(this) && + getTemplateSpecializationKind() == TSK_ExplicitSpecialization; + // If we are declaring a partial or full specialization out of line + // - and if there already exists a previous in-class declaration, + // then this declaration is automatically a definition. + // - otherwise it is only a definition if it includes an initializer. + // template struct A { + // template static const A var; + // template static const char var; + // }; + // template template + // const char A::var; <-- this is automatically a definition + // template template + // const int A::var; <-- this is a declaration. + // template template + // const int A::var{}; <-- this is a definition since it + // has an initializer. + + const bool IsPartialOrFullVarTemplateSpecWithPreviousInClassDeclaration = + IsThisDeclOutOfClass && IsPartialOrFullVarTemplateSpecialization && + !IsFirstDeclOutOfLine; + + if (IsThisDeclOutOfClass) { + // If we have an initializer that is out of class, this must be a + // definition. + if (HasInit) + return Definition; + if (IsPartialOrFullVarTemplateSpecWithPreviousInClassDeclaration) + return Definition; + if (IsPartialOrFullVarTemplateSpecialization || + IsExplicitlySpecializedMemberOfImplicitlyInstantiatedClassSpec) + return DeclarationOnly; + if (IsFirstDeclOutOfLine ? getTemplateSpecializationKind() == TSK_Undeclared - : getTemplateSpecializationKind() != - TSK_ExplicitSpecialization) || - isa(this))) - return Definition; - else - return DeclarationOnly; + : getTemplateSpecializationKind() != TSK_ExplicitSpecialization) + return Definition; + } + return DeclarationOnly; } // C99 6.7p5: // A definition of an identifier is a declaration for that identifier that Index: lib/AST/DeclTemplate.cpp =================================================================== --- lib/AST/DeclTemplate.cpp +++ lib/AST/DeclTemplate.cpp @@ -429,10 +429,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 nullptr; } @@ -856,6 +858,7 @@ return Result; } + //===----------------------------------------------------------------------===// // FriendTemplateDecl Implementation //===----------------------------------------------------------------------===// @@ -1047,8 +1050,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 nullptr; Index: lib/AST/TemplateBase.cpp =================================================================== --- lib/AST/TemplateBase.cpp +++ lib/AST/TemplateBase.cpp @@ -21,6 +21,7 @@ #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Sema/SemaInternal.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" @@ -274,10 +275,32 @@ getIntegralType().Profile(ID); break; - case Expression: + case Expression: { + // If this expression is a dummy invented expression, use that property when + // hashing since the dummy expression is otherwise very similar to the + // unsubstituted use of the non-type template parameter. + // Without this, an unsubstituted reference to a non-type-template parameter + // can profile to the same ID - which can make it hard to distinguish + // between a transformed reference to a current template versus an + // InjectedTemplateName. + // As an example this is relevant when attempting to determine that the + // A in the function parameter list of the specialization is not a + // reference to the current injected type after it has been transformed with + // a dummy expression: + // template struct A { + // template class TT> constexpr int foo(TT) { + // return 0; + // } + // }; + // template template<> constexpr int A::foo(A) { + // return 1; + // } + // + if (isInventedDummyNonTypeTemplateArgumentExpr(getAsExpr())) + ID.AddBoolean(true); getAsExpr()->Profile(ID, Context, true); break; - + } case Pack: ID.AddInteger(Args.NumArgs); for (unsigned I = 0; I != Args.NumArgs; ++I) Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -2902,12 +2902,104 @@ QualType MergedT; if (getLangOpts().CPlusPlus) { + const bool + IsExplicitlySpecializedPrimaryVarTemplOfImplicitlyInstantiatedClassSpec = + ([](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!"); + // Note, currently 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. + assert(New->getDeclContext() == Old->getDeclContext()); + if (auto *ClassSpec = dyn_cast(New->getDeclContext())) + return ClassSpec->getTemplateSpecializationKind() != + TSK_ExplicitSpecialization && + OldVT->getInstantiatedFromMemberTemplate() && + New->getTemplateSpecializationKind() != + TSK_ExplicitSpecialization; + } + 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 (IsExplicitlySpecializedPrimaryVarTemplOfImplicitlyInstantiatedClassSpec) { + 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 @@ -2932,6 +3024,38 @@ Old->getType()->isObjCObjectPointerType()) { MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType()); + } else if (IsExplicitlySpecializedPrimaryVarTemplOfImplicitlyInstantiatedClassSpec) { + // 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: @@ -3300,8 +3424,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. @@ -5355,7 +5509,7 @@ : SourceLocation(); DeclResult Res = ActOnVarTemplateSpecialization( S, D, TInfo, TemplateKWLoc, TemplateParams, SC, - IsPartialSpecialization); + IsPartialSpecialization, TemplateParamLists); if (Res.isInvalid()) return nullptr; NewVD = cast(Res.get()); @@ -5586,9 +5740,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() @@ -6909,6 +7070,10 @@ // thing to do. // FIXME: For a friend function, we have not marked the function as being // a friend yet, so 'isDependentContext' on the FD doesn't work. + // (This yukkiness must be synchronized with what happens during + // substitution within a member function template declarator (in + // TemplateDeclInstantiator::VisitFunctionTemplateDecl for instance)) + const FunctionProtoType *FPT = NewFD->getType()->castAs(); QualType Result = @@ -7258,13 +7423,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 : nullptr), @@ -7292,6 +7465,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(); } @@ -7303,11 +7482,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) && @@ -7361,7 +7540,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 @@ -7374,6 +7554,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 @@ -7522,9 +7705,11 @@ if (isDependentClassScopeExplicitSpecialization) { ClassScopeFunctionSpecializationDecl *NewSpec = ClassScopeFunctionSpecializationDecl::Create( - Context, CurContext, SourceLocation(), + Context, NewFD->getDeclContext(), NewFD->getLocStart(), cast(NewFD), - HasExplicitTemplateArgs, TemplateArgs); + HasExplicitTemplateArgs, TemplateArgs); + if (CurContext->isFileContext()) + NewSpec->setLexicalDeclContext(CurContext); CurContext->addDecl(NewSpec); AddToScope = false; } @@ -8370,10 +8555,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()) @@ -8714,7 +8923,7 @@ if (Var->isStaticDataMember()) Diag(Var->getLocation(), diag::err_constexpr_static_mem_var_requires_init) - << Var->getDeclName(); + << Var->getDeclName(); else Diag(Var->getLocation(), diag::err_invalid_constexpr_var_decl); Var->setInvalidDecl(); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12393,6 +12393,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 @@ -1633,17 +1633,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; } @@ -1718,10 +1720,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; @@ -1732,7 +1735,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. @@ -1819,7 +1822,7 @@ if (ParamIdx < ParamLists.size()) { if (ParamLists[ParamIdx]->size() == 0) { if (CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange(), - false)) + false, ParamLists.size() == ParamIdx + 1)) return nullptr; } else SawNonEmptyTemplateParameterList = true; @@ -1956,7 +1959,7 @@ // are not explicitly specialized as well. if (ParamLists.back()->size() == 0 && CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange(), - false)) + false, true)) return nullptr; // Return the last template parameter list, which corresponds to the @@ -2082,7 +2085,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; @@ -2102,7 +2107,6 @@ QualType ICNT = Context.getTypeDeclType(Record); QualType Injected = cast(ICNT) ->getInjectedSpecializationType(); - if (CanonType != Injected->getCanonicalTypeInternal()) continue; @@ -2110,9 +2114,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 @@ -2123,9 +2141,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(), @@ -2133,6 +2162,8 @@ ClassTemplate, Converted.data(), Converted.size(), nullptr); + + } ClassTemplate->AddSpecialization(Decl, InsertPos); if (ClassTemplate->isOutOfLine()) Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext()); @@ -2399,7 +2430,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."); @@ -2532,15 +2564,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 @@ -2568,6 +2620,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. @@ -2642,21 +2732,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,7 +2753,18 @@ 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 @@ -2680,11 +2772,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 @@ -2697,74 +2788,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; } } @@ -2777,20 +2817,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; } @@ -3637,6 +3667,112 @@ 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) { + Expr *TemplateArgAsExpr = PotentiallyDummyTAPack.getAsExpr(); + if (isInventedDummyNonTypeTemplateArgumentExpr(TemplateArgAsExpr)) { + assert(isa(TemplateArgAsExpr)); + return cast(cast( + TemplateArgAsExpr)->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, @@ -3804,9 +3940,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, @@ -3821,9 +3965,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, @@ -3839,9 +3991,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, @@ -5683,13 +5843,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; @@ -5922,15 +6084,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; @@ -6151,13 +6308,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 @@ -6186,6 +6350,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. @@ -6600,6 +6806,514 @@ return false; } +bool clang::isInventedDummyNonTypeTemplateArgumentExpr(Expr *E) { + DeclRefExpr *DRE = dyn_cast_or_null(E); + // Check to see if this is a substituted non type template parm + // expression that has been substituted with a dummy expression. + // If so, extract the dummy expression from it as a DeclRefExpr. + if (!DRE) + if (auto *SDRE = dyn_cast_or_null(E)) + DRE = dyn_cast(SDRE->getReplacement()); + if (!DRE) return false; + + if (auto *NTTPD = dyn_cast(DRE->getDecl())) + if (const IdentifierInfo *II = NTTPD->getIdentifier()) + if (NTTPD->isImplicit() && II->getName().slice(0, 7) == "$dummy-") + return true; + 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; + const Type *Ty; + InventedTemplateArgKey() : Depth(0), Index(0), Ty(nullptr) {} + InventedTemplateArgKey(unsigned D, unsigned I, const std::string &P, + const Type *Ty = nullptr) + : Depth(D), Index(I), Postfix(P), Ty(Ty) {} + + 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) { + //if (reinterpret_cast(Lhs.Ty) < reinterpret_cast(Rhs.Ty)) + if (Lhs.Ty < Rhs.Ty) + return true; + if (Lhs.Ty == Rhs.Ty) + 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(); + const unsigned Depth = NonTypeParam->getDepth(); + const unsigned Index = NonTypeParam->getIndex(); + InventedTemplateArgKey MKey(Depth, Index, IsPack ? "pack" : "", + NonTypeParam->getType().getTypePtrOrNull()); + + static std::map InventedExprMap; + if (DeclRefExpr *DRE = InventedExprMap[MKey]) + return DRE; + + std::string InventedDummyDeclName = "$dummy-"; + llvm::raw_string_ostream ss(InventedDummyDeclName); + ss << Depth; + ss << "-" << Index; + if (IsPack) + ss << "-pack"; + ss.flush(); + IdentifierInfo &InventedDeclII = + SemaRef.Context.Idents.get(InventedDummyDeclName.c_str()); + + NonTypeTemplateParmDecl *InventedNonTypeParam = + NonTypeTemplateParmDecl::Create( + SemaRef.Context, NonTypeParam->getDeclContext(), + NonTypeParam->getLocStart(), NonTypeParam->getInnerLocStart(), + NonTypeParam->getDepth(), NonTypeParam->getIndex(), &InventedDeclII, + NonTypeParam->getType(), + /*IsPack*/ false, NonTypeParam->getTypeSourceInfo()); + InventedNonTypeParam->setImplicit(); + QualType InventedExprType = InventedNonTypeParam->getType(); + if (InventedNonTypeParam->getType()->isReferenceType()) + InventedExprType = InventedNonTypeParam->getType().getNonReferenceType(); + DeclRefExpr *DRE = DeclRefExpr::Create( + SemaRef.Context, NestedNameSpecifierLoc(), SourceLocation(), + InventedNonTypeParam, false, + DeclarationNameInfo( + DeclarationName(InventedNonTypeParam->getIdentifier()), + InventedNonTypeParam->getLocation()), + InventedExprType, + InventedNonTypeParam->getType()->isReferenceType() ? VK_LValue + : VK_RValue); + 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, nullptr, + ActiveTemplateInstantiation:: + SubstitutionWhileCheckingDeclarationOfAnExplicitFunctionSpecialization)) { + // 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. /// @@ -6666,7 +7380,9 @@ FunctionDecl *Specialization = nullptr; if (TemplateDeductionResult TDK = DeduceTemplateArguments( cast(FunTmpl->getFirstDecl()), - ExplicitTemplateArgs, FT, Specialization, Info)) { + ExplicitTemplateArgs, FT, Specialization, Info, nullptr, + ActiveTemplateInstantiation:: + SubstitutionWhileCheckingDeclarationOfAnExplicitFunctionSpecialization)) { // Template argument deduction failed; record why it failed, so // that we can provide nifty diagnostics. FailedCandidates.addCandidate() 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) { @@ -151,10 +151,11 @@ else break; } - - if (DeclRefExpr *DRE = dyn_cast(E)) + if (isInventedDummyNonTypeTemplateArgumentExpr(E)) + return nullptr; + if (DeclRefExpr *DRE = dyn_cast(E)) { return dyn_cast(DRE->getDecl()); - + } return nullptr; } @@ -339,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. /// @@ -353,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()], @@ -1376,7 +1377,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; @@ -1636,7 +1637,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; @@ -1658,7 +1659,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; @@ -1685,6 +1686,37 @@ llvm_unreachable("Invalid Type Class!"); } +namespace clang { +Sema::TemplateDeductionResult +DeduceTemplateArgumentsFromMemberFunctionSpecialization( + Sema &S, FunctionTemplateDecl *PrimaryTemplate, + CXXMethodDecl *SubstitutedSpecialization, + TemplateArgumentListInfo *SubstitutedExplicitTemplateArgs, + TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced) { + TemplateParameterList *TemplateParams = + PrimaryTemplate->getTemplateParameters(); + QualType PrimaryTemplateType = PrimaryTemplate->getTemplatedDecl()->getType(); + QualType ExplicitSpecType = SubstitutedSpecialization->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, @@ -1765,7 +1797,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(), @@ -2777,13 +2809,13 @@ /// /// \param OriginalCallArgs If non-NULL, the original call arguments against /// which the deduced argument types should be compared. -Sema::TemplateDeductionResult -Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, - SmallVectorImpl &Deduced, - unsigned NumExplicitlySpecified, - FunctionDecl *&Specialization, - TemplateDeductionInfo &Info, - SmallVectorImpl const *OriginalCallArgs) { +Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( + FunctionTemplateDecl *FunctionTemplate, + SmallVectorImpl &Deduced, + unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, + TemplateDeductionInfo &Info, + SmallVectorImpl const *OriginalCallArgs, + Sema::ActiveTemplateInstantiation::InstantiationKind InstKind) { TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); @@ -2795,9 +2827,7 @@ // actual function declaration. SmallVector DeducedArgs(Deduced.begin(), Deduced.end()); InstantiatingTemplate Inst(*this, Info.getLocation(), FunctionTemplate, - DeducedArgs, - ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution, - Info); + DeducedArgs, InstKind, Info); if (Inst.isInvalid()) return TDK_InstantiationDepth; @@ -2947,8 +2977,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. @@ -3539,13 +3571,12 @@ /// about template argument deduction. /// /// \returns the result of template argument deduction. -Sema::TemplateDeductionResult -Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - TemplateArgumentListInfo *ExplicitTemplateArgs, - QualType ArgFunctionType, - FunctionDecl *&Specialization, - TemplateDeductionInfo &Info, - bool InOverloadResolution) { +Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, + FunctionDecl *&Specialization, TemplateDeductionInfo &Info, + bool InOverloadResolution, + Sema::ActiveTemplateInstantiation::InstantiationKind InstKind) { if (FunctionTemplate->isInvalidDecl()) return TDK_Invalid; @@ -3590,6 +3621,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, @@ -3598,10 +3633,9 @@ return Result; } - if (TemplateDeductionResult Result - = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, - NumExplicitlySpecified, - Specialization, Info)) + if (TemplateDeductionResult Result = FinishTemplateArgumentDeduction( + FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, + Info, nullptr, InstKind)) return Result; // If the function has a deduced return type, deduce it now, so we can check @@ -4539,21 +4573,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 @@ -4578,46 +4630,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=*/nullptr); 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=*/nullptr); 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 nullptr; - 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 @@ -4628,56 +4737,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=*/nullptr); - 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=*/nullptr); - 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 nullptr; - - 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 @@ -48,20 +48,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 +115,64 @@ 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; + + Ctx = Ctx->getParent(); + RelativeToPrimary = false; + continue; + } 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,12 @@ 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; Ctx = Ctx->getParent(); RelativeToPrimary = false; } @@ -182,6 +230,7 @@ return Result; } + bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const { switch (Kind) { case TemplateInstantiation: @@ -190,6 +239,7 @@ case DefaultFunctionArgumentInstantiation: case ExplicitTemplateArgumentSubstitution: case DeducedTemplateArgumentSubstitution: + case SubstitutionWhileCheckingDeclarationOfAnExplicitFunctionSpecialization: case PriorTemplateArgumentSubstitution: return true; @@ -496,19 +546,32 @@ Active->TemplateArgs, Active->NumTemplateArgs) << Active->InstantiationRange; - } else { - FunctionTemplateDecl *FnTmpl - = cast(Active->Entity); + break; + } else if (auto *PartialSpec = + dyn_cast(Active->Entity)) { Diags.Report(Active->PointOfInstantiation, - diag::note_function_template_deduction_instantiation_here) - << FnTmpl - << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(), + diag::note_partial_spec_deduct_instantiation_here) + << PartialSpec->getType() + << getTemplateArgumentBindingsText( + PartialSpec->getTemplateParameters(), Active->TemplateArgs, Active->NumTemplateArgs) << Active->InstantiationRange; + break; } + // Fall through this must be a FunctionTemplateDecl ... + case ActiveTemplateInstantiation:: + SubstitutionWhileCheckingDeclarationOfAnExplicitFunctionSpecialization: { + FunctionTemplateDecl *FnTmpl = cast(Active->Entity); + Diags.Report(Active->PointOfInstantiation, + diag::note_function_template_deduction_instantiation_here) + << FnTmpl + << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(), + Active->TemplateArgs, + Active->NumTemplateArgs) + << Active->InstantiationRange; break; - + } case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: { ParmVarDecl *Param = cast(Active->Entity); FunctionDecl *FD = cast(Param->getDeclContext()); @@ -611,6 +674,8 @@ case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: + case ActiveTemplateInstantiation:: + SubstitutionWhileCheckingDeclarationOfAnExplicitFunctionSpecialization: // We're either substitution explicitly-specified template arguments // or deduced template arguments, so SFINAE applies. assert(Active->DeductionInfo && "Missing deduction info pointer"); @@ -1282,8 +1347,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 (isInventedDummyNonTypeTemplateArgumentExpr(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. @@ -1970,8 +2039,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); @@ -2076,32 +2150,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. @@ -2181,14 +2229,649 @@ } namespace { - /// \brief A partial specialization whose template arguments have matched - /// a given template-id. + // Help map types from Class/Var/Function specailization types back to their + // template decls and patterns within generic algorithms. + struct TemplateDeclGenericAdapter { + 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 *); + + }; + +// Given a template decl, this returns a tuple that contains its immediate +// or innermost template parameter list and the instantiation pattern. +template +std::tuple())) *> +getInnermostTemplateParameterListAndPatternDecl(const Decl *D) { + typedef decltype(TemplateDeclGenericAdapter::getTypeOfPatternDecl( + std::declval())) PatternDecl; + + typedef decltype(TemplateDeclGenericAdapter::getTypeOfPartialSpecializationDecl( + std::declval())) PartialSpecializationDecl; + + typedef decltype(TemplateDeclGenericAdapter::getTypeOfExplicitSpecializationDecl( + std::declval())) 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 = + TemplateDeclGenericAdapter::getDescribedTemplate(PD)) { + PatternD = PD; + InnerMostTPL = TD->getTemplateParameters(); + } + } + 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(TemplateDeclGenericAdapter::getTypeOfPartialSpecializationDecl( + std::declval())) PartialSpecializationDecl; + + typedef decltype(TemplateDeclGenericAdapter::getTypeOfExplicitSpecializationDecl( + std::declval())) 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(TemplateDeclGenericAdapter::getTypeOfExplicitSpecializationDecl( + std::declval())) 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, @@ -2237,93 +2920,20 @@ // 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; - } - } - + 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. @@ -2334,7 +2944,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. @@ -2351,11 +2962,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; @@ -963,18 +964,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; } @@ -1046,18 +1035,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; } @@ -1084,6 +1061,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 @@ -1096,9 +1077,27 @@ return nullptr; FunctionDecl *Instantiated = nullptr; - if (CXXMethodDecl *DMethod = dyn_cast(D->getTemplatedDecl())) - Instantiated = cast_or_null(VisitCXXMethodDecl(DMethod, - InstParams)); + if (CXXMethodDecl *DMethod = dyn_cast(D->getTemplatedDecl())) { + if (Instantiated = cast_or_null(VisitCXXMethodDecl(DMethod, + InstParams))) + if (Instantiated->getReturnType()->isUndeducedType()) { + // If the function template is referenced directly (for instance, as a + // member of the current instantiation), pretend it has a dependent + // type. This is not really justified by the standard, but is the only + // sane thing to do. + // FIXME: For a friend function, we have not marked the function as + // being a friend yet, so 'isDependentContext' on the FD doesn't work. + // (This yukkiness must be synchronized with what happens during + // sema-analysis of a function templates declarator (in + // Sema::ActOnFunctionDeclarator for instance)) + const FunctionProtoType *FPT = + Instantiated->getType()->castAs(); + QualType Result = SemaRef.SubstAutoType(FPT->getReturnType(), + SemaRef.Context.DependentTy); + Instantiated->setType(SemaRef.Context.getFunctionType( + Result, FPT->getParamTypes(), FPT->getExtProtoInfo())); + } + } else Instantiated = cast_or_null(VisitFunctionDecl( D->getTemplatedDecl(), @@ -1124,9 +1123,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); } @@ -1495,10 +1494,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::DeduceTemplateArgumentsFromMemberFunctionSpecialization( + 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 @@ -1515,6 +1669,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) { + return S.ActiveTemplateInstantiations.back().Kind == + Sema::ActiveTemplateInstantiation:: + SubstitutionWhileCheckingDeclarationOfAnExplicitFunctionSpecialization; + }; + + 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; @@ -2435,8 +2632,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)) @@ -2467,15 +2664,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 nullptr; + // 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; } @@ -2504,16 +2703,10 @@ const_cast(VarTemplateArgsInfo), false, Converted)) return nullptr; - + // Find the variable template specialization declaration that // corresponds to these arguments. - void *InsertPos = nullptr; - 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); } @@ -2521,7 +2714,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()) @@ -2541,24 +2734,22 @@ << D->isStaticDataMember() << DI->getType(); return nullptr; } - + // 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 nullptr; - SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, + SemaRef.BuildVariableInstantiation(NewVar, D, TemplateArgs, LateAttrs, Owner, StartingScope); - return Var; + return NewVar; } Decl *TemplateDeclInstantiator::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) { @@ -2698,30 +2889,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 nullptr; - } - - // Create the class template partial specialization declaration. ClassTemplatePartialSpecializationDecl *InstPartialSpec = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, @@ -2742,11 +2909,6 @@ InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); - - // Add this partial specialization to the set of class template partial - // specializations. - ClassTemplate->AddPartialSpecialization(InstPartialSpec, - /*InsertPos=*/nullptr); return InstPartialSpec; } @@ -2817,31 +2979,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 nullptr; - } - // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType( PartialSpec->getTypeSourceInfo(), TemplateArgs, @@ -2873,8 +3010,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=*/nullptr); - + SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs, LateAttrs, Owner, StartingScope); @@ -3430,7 +3566,8 @@ Sema::ContextRAII savedContext(*this, Function); MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl); + getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl, + getTemplateParameterListsOfDeclaration(PatternDecl)); addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, TemplateArgs); @@ -3739,9 +3876,7 @@ VarTemplateSpecializationDecl *VarSpec = dyn_cast(Var); VarDecl *PatternDecl = nullptr, *Def = nullptr; - 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. @@ -3751,37 +3886,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 @@ -3852,6 +4059,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 @@ -4392,14 +4601,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 @@ -4415,6 +4625,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 @@ -5279,6 +5279,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-generic-lambdas-variadics.cpp =================================================================== --- test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp +++ test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks %s +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm-only %s // RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING // RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS // RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING @@ -77,24 +77,4 @@ return 0; } int run = test(); -} // end ns explicit_argument_extension - - - -#ifdef PR18499_FIXED -namespace variadic_expansion { - void f(int &, char &); - - template void g(T &... t) { - f([&a(t)]()->decltype(auto) { - return a; - }() ...); - f([&a(f([&b(t)]()->decltype(auto) { return b; }()...), t)]()->decltype(auto) { - return a; - }()...); - } - - void h(int i, char c) { g(i, c); } -} -#endif - +} // end ns explicit_argument_extension \ No newline at end of file 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 +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s -DCPP1Y #define CONST const @@ -15,12 +15,19 @@ 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; // expected-error {{template specialization requires 'template<>'}} \ - // expected-error {{explicit specialization of 'right' in class scope}} + template<> static CONST int right = 7; + template<> static CONST float right; + template static CONST int right; // expected-error {{template specialization requires 'template<>'}} + +#ifndef CPP1Y + // expected-error@-5 {{explicit specialization of 'right' in class scope}} + // expected-error@-5 {{explicit specialization of 'right' in class scope}} + // expected-error@-5 {{explicit specialization of 'right' in class scope}} +#else + // expected-error@-7 {{duplicate member}} + // expected-note@-10 {{previous declaration is here}} +#endif }; - namespace out_of_line { class B0 { template static CONST T right = T(100); @@ -164,10 +171,20 @@ template constexpr int right; // expected-error {{member 'right' declared as a template}} \ // expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}} template constexpr float right = 5; // expected-error {{non-static data member cannot be constexpr; did you intend to make it static?}} - template<> static constexpr int right = 7; // expected-error {{explicit specialization of 'right' in class scope}} - template<> static constexpr float right; // expected-error {{explicit specialization of 'right' in class scope}} - template static constexpr int right; // expected-error {{template specialization requires 'template<>'}} \ - // expected-error {{explicit specialization of 'right' in class scope}} + template<> static constexpr int right = 7; + template<> static constexpr float right; + template static constexpr int right; // expected-error {{template specialization requires 'template<>'}} + +#ifndef CPP1Y + // expected-error@-5 {{explicit specialization of 'right' in class scope}} + // expected-error@-5 {{explicit specialization of 'right' in class scope}} + // expected-error@-5 {{explicit specialization of 'right' in class scope}} +#else + // expected-error@-7 {{requires an initializer}} + // expected-error@-9 {{requires an initializer}} + // expected-error@-9 {{duplicate member}} + // expected-note@-12 {{previous declaration is here}} +#endif }; } #endif @@ -214,10 +231,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 +245,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 +269,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 == 456, ""); static_assert(S::V2 == 789, ""); // expected-error {{}} 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,2151 @@ +// 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 ok_to_declare_partial_specs_twice { + +template +struct A { + template + static constexpr U u1 = 1; + template + static constexpr U u1 = 2; +}; + +template<> template +int A::u1; + +template<> template +int A::u1 = 5; + +namespace ns1 { + + +template +struct A { + template + static U var; + template + static U var; +}; +template template +U A::var{}; + +template<> template +U** A::var; + +template<> template +U** A::var = nullptr; + +char **pc = A::var; +} + +} //end ns ok_to_declare_partial_specs_twice + +} + +//--------------------------------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 ns1395 { + + +template +struct A { + template U* foo(); //expected-note{{ambiguous}} +}; + +template template<> +char* A::foo() { return 0; } + +template template<> +typename T::type* A::foo() { return 0; } + +char *pc = A{}.foo(); + +struct HasTypeFloat { + using type = float; +}; +struct HasTypeChar { + using type = char; +}; + +float *pf = A{}.foo(); +char *pc2 = A{}.foo(); +//FIXME: This error needs to be better, and it should point to the ambiguous specs not primary template +char *pc3 = A{}.foo(); //expected-error{{no matching member function}} + +} + +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 +namespace ns3_1538 { +template class X { }; +template class Y { }; +template struct A { + template class TT> constexpr int foo(TT*) { return 0; } //expected-note{{ignored: could not match 'pc2' against 'pc'}} +}; + +template template<> +constexpr int A::foo(A*) { return 1; } +template template<> +constexpr int A::foo(Y*) { return 2; } + +char pc; +char pc2; +A<&pc> ap; +X<&pc> xp; +A<&pc> aap; +Y<&pc> yp; + +A<&pc2> ap2; +X<&pc2> xp2; +Y<&pc2> yp2; + + +static_assert(ap.foo(&ap) == 1, ""); +static_assert(ap.foo(&aap) == 1, ""); +static_assert(aap.foo(&ap) == 1, ""); +static_assert(aap.foo(&aap) == 1, ""); + +static_assert(ap.foo(&xp) == 0, ""); +static_assert(ap.foo(&yp) == 2, ""); + +static_assert(ap2.foo(&xp2) == 0, ""); +static_assert(ap2.foo(&yp2) == 2, ""); +static_assert(ap2.foo(&ap2) == 1, ""); + +static_assert(ap2.foo(&ap) == 1, ""); //expected-error{{no matching member function}} + +} //end ns3_1538 +namespace ns4_1577_ref_args { + + +struct X { }; +template struct Y { }; +template struct A { + template class TT> constexpr int foo(TT*) { return 0; } +}; + +template template<> +constexpr int A::foo(A*) { return 1; } + +X x1; +A xa; +Y y; +static_assert(xa.foo(&xa) == 1, ""); +static_assert(xa.foo(&y) == 0, ""); + + +} +} // end var_templates_class_scope_... + + +namespace MemberClassTemplates { +template struct X; + +template struct A { + template struct B { X *h; }; //#1 + template struct B { X *i; }; //#2 + template struct B { X *j; }; //#3 + template<> struct B { X *k; }; //#4 + template<> struct B { X *l; }; //#5 + + template struct B //#6 + { X *lp; }; + template <> struct B //#7 + { X *le; }; +}; + +// Instantiate A, do not error on #2, #3, #6 or #7. +template class A; + +// Add full specialization to an instantiated class's member template +// specialization. +template<> template<> +struct A::B { X *m; }; //#8 + +template<> template +struct A::B { //#9 + X *n; +}; + +template<> template +struct A::B { //#10 + X *o; +}; + +template<> template +struct A::B { //#11 + X *p; +}; +// Preferred specializations must be declared after #11 +template<> template +struct A::B { //#12 + X *p1; +}; + +template<> template<> +struct A::B { //#13 + X *p2; +}; + + +template template<> +struct A::B { //#14 + X *q; +}; + +template template //#15 +struct A::B { + X *r; +}; + +template template //#16 +struct A::B { + X *s; +}; + +X *a1 = A::B{}.h; //#1 + +X *a2 = A::B{}.i; //#2 +X *a3 = A::B{}.j; //#3 +X *a4 = A::B{}.k; //#4 +X *a5 = A::B{}.l; //#5 + +struct HasType { using type = bool*; }; + +X *a6 = A::B{}.lp; //#6 + +X *a7 = + A::B{}.le; //#7 +X *a8 = A::B{}.m; //#8 + +//Below: #9 wins over #15 because it contains more template<> +X *a9 = A::B{}.n; //#9 + +X *a10 = A::B{}.o; //#10 +X *a11 = A::B{}.p; //#11 +X *a12 = A::B{}.p1; //#12 +X *a13 = A::B{}.p2; //#13 +X *a14 = A::B{}.q; //#14 +X *a15 = A::B{}.r; //#15 +X *a16 = A::B{}.s; //#16 + +} // MemberClassTemplates1 + + +namespace MemberClassTemplates2 { + +// Specialization is referenced within the class +template struct A { + template struct B { A *h; }; //#1 + B* foo() { return 0; } + B bar(); +}; +template +template struct A::B { + A *i; +}; + +template +template<> struct A::B { + A *j; +}; + +template<> template<> +struct A::B { + A *k; +}; + +template +template struct A::B { + A *l; +}; + +template<> template +struct A::B { + A *m; +}; + + +decltype(A{}.foo()->i) a1; +decltype(A{}.foo()->h) a2; +decltype(A{}.foo()->k) a3; +decltype(A{}.foo()->m) a4; +decltype(A{}.foo()->l) a5; + + +} // MemberClassTemplates2 + +//* +namespace MemberVarTemplates2 { + +//template struct X { }; +// Specialization is referenced +template struct A { + template static int B; //#1 + decltype(B)* foo() { return 0; } //#2 + template struct C { }; //#3 + C foo2() { return C{}; } //#4 + template<> struct C { }; +}; + +template<> template +int A::B = 0; // Error: Variable template could have changed its type. + +template<> template<> +struct A::C { int i; }; // Not an error since #4 does not + // require a complete type in its + // declaration. +int a0 = A{}.foo2().i; // Not an error - does not require + // instantiation of C until body + // is called. + +template struct A2 { + template struct C { }; + decltype(C{}) foo2() { return C{}; }; // Require C to be complete +}; +//template<> template<> +//struct A2::C { int i; }; // Error. +} // MemberVarTemplates2 +//*/ +namespace MemberVarTemplates { + +template struct X { + enum {N = M}; + const int m; + constexpr X(int m) : m(m) { } + constexpr X() : m(0) { } +}; + +template struct A { + template static constexpr X B = {1}; //#1 + + template static constexpr X B = {2}; //#2 + template static constexpr X B = {3}; //#3 + template<> static constexpr X B = {4}; //#4 + template<> static constexpr X B = {5}; //#5 + + template static constexpr X + B = {6}; //#6 + template <> static constexpr X + B = {7}; //#7 + +}; + +// Instantiate A, do not error on #2, #3, #6 or #7. +template class A; + +// Add full specialization to an instantiated class's member template +// specialization. +template<> template<> +constexpr X A::B = {8}; //#8 + +template<> template +constexpr X A::B = {9}; //#9 + +template<> template +constexpr X A::B = {10}; //#10 + +template<> template +constexpr X A::B = {11}; //#11 + + +// Preferred specializations must be declared after #11 +template<> template +constexpr X A::B = {12}; //#12 + + +template<> template<> +constexpr X A::B = {13}; //#13 + +template template<> +constexpr X A::B = {14}; //#14 +template template //#15 +constexpr X A::B = {15}; + + +constexpr X x1 = A::B; //#1 + +constexpr X x2 = A::B; //#2 +constexpr X x3 = A::B; //#3 + +constexpr X x4 = A::B; //#4 + + +constexpr X x5 = A::B; //#5 + +struct HasType { using type = bool*; }; + +constexpr X x6 = A::B; //#6 +constexpr X x7 = + A::B; //#7 + +constexpr X x8 = A::B; //#8 + +//Below: #9 wins over #15 because it contains more template<> + +constexpr X x9 = A::B; //#9 + +constexpr X x10 = A::B; //#10 + +constexpr X x11 = A::B; //#11 + +constexpr X x12 = A::B; //#12 + +constexpr X x13 = A::B; //#13 + +constexpr X x14 = A::B; //#14 +constexpr X x15 = A::B; //#15 + +} // End MemberVarTemplates + +namespace MemberFunTemplates { + + +using intptr = int*; +using floatptr = float*; +using shortptr = short*; +using charptr = char*; +using doubleptr = double*; +using boolptr = bool*; + +template struct X {}; +template struct A { + template constexpr auto B(U1, U2) { //#1 + return X{}; + } + template constexpr auto B(U1*, U2) { //#2 + return X{}; + } + template constexpr auto B(U1, U2*) { //#3 + return X{}; + } + template<> // #4 -- specializes #1 + constexpr auto B(int, float) { + return X{}; + } + template<> // #5 -- specializes #2 + constexpr auto B(int*, float) { + return X{}; + } + template<> // #6 -- specializes #3 + constexpr auto B(int, float*) { + return X{}; + } + template auto B(U1*, U2*) { //#7 + return X{}; + } + template<> + constexpr auto B(int*, float*) { // #8 -- specializes #7 + return X{}; + } + +}; + +template class A; + +constexpr X x1 = + A{}.B(float{}, double{}); // Use #1 + +constexpr X x2 = + A{}.B(floatptr{}, double{}); // Use #2 + +constexpr X x3 = + A{}.B(float{}, doubleptr{}); // Use #3 + +constexpr X x4 = + A{}.B(int{}, float{}); // Use #4 + + +constexpr X x5 = + A{}.B(intptr{}, float{}); // Use #5 + +constexpr X x6 = + A{}.B(int{}, floatptr{}); // Use #6 + +X x7 = + A{}.B(floatptr{}, doubleptr{}); // Use #7 + +constexpr X x8 = + A{}.B(intptr{}, floatptr{}); // Use #8 + + +} + + +template struct X { using type = T; }; + + +template +struct A { + template void f(typename T::type, U); + template void f(typename T::type, U*); + + template void g(X); + + template void f(typename T::other_type, U); + template void f(typename T::other_type, U*); + + template<> void f(typename T::other_type, int) { } + template<> void f(typename T::type, int*) { } + template<> void g(X); + + template auto f(U) { }; + //using Tdef = T; + //template void f(typename Tdef::type*, U*); + //template<> void f(typename T::type*, char*); +}; + +template +template<> +void A::g(X) { } + +template +template<> auto A::f(typename T::no_op) { return [](T t) { return t; }; } + +template +template<> auto A::f(T*) { return nullptr; }; + +template +struct HasTypes { + using type = T; + using other_type = U; +}; + + +template<> +template +void A>::f(float, U) { } + + + + +template struct A>; + +decltype(nullptr) f1 = A>{}.f((HasTypes*)0); + +namespace Test417 { +template struct A { + template struct B { int i; }; // #1 + template struct B { int j; }; // #2 + template<> struct B { int k; }; // #3 + + template auto foo(U) { return (U*)0; } // #4 + template<> auto foo(typename T::type) { return T{}; } // #5 +}; +template struct A; // OK + +struct HasType { using type = float; }; +float *f = A{}.foo(float{}); // Uses #4 +HasType h = A{}.foo(float{}); // Uses #5a +int a1 = A::B{}.i; +int a2 = A::B{}.j; +int a3 = A::B{}.k; + +} + + + +namespace Test438 { + +template struct A { + template struct B { int i; }; //#0 + template<> struct B { int i2; };//#1 + template static U Var; //#2 (defined at #9) + template auto foo(U) { return 0; }//nullptr; } +}; + +template struct A; + +template<> template +struct A::B { int j; }; //#3 + +template template //#4 +struct A::B { int k; }; + +template<> template //#5 +struct A::B { int l; }; + +template<> template //#6 +struct A::B { int m; }; + +// Is it ok to reorder these? +template<> template //#7 +struct A::B { int n; }; + +template<> template //#8 +struct A::B { int o; }; + +template template //#9 +U A::Var = U{}; + +template<> template //#10 +float* A::Var = 0; + +template<> template //#11 +double* A::Var = 0; + +template template<> //#12 +auto A::foo(short) { return (short*)0; } + +template template<> //#13 +auto A::foo(char) { return (char*)0; } + +template<> template //#14 +auto A::foo(U) { return (float*)0; } + +template template<> //#15 +auto A::foo(int) { return (int**)0; } + +template<> template<> //#16 +auto A::foo(int) { return (int*)0; } + + +int a0 = A::B{}.k; // Use #4 Not #3 +int a1 = A::B{}.i2; // Use #1 Not #4 +int a2 = A::B{}.m; // Use #6 Not #1 + +float *v0 = A::Var; // Use #10 +double *v1 = A::Var; // Use #11 +char v2 = A::Var; // Use #9 + +short *f0 = A{}.foo(short{}); // Use #12 +char *f1 = A{}.foo(char{}); // Use #13 +float *f2 = A{}.foo(char{}); // Use #14 not #13 +int *f3 = A{}.foo(int{}); // Use #16 + +} + + +namespace Test511 { +template struct A { + template struct B { int i; }; //#1 + template struct B { int j; }; //#2 +}; +template<> template +struct A::B { int k; }; //#3 + +template template<> +struct A::B { int l; }; //#4 + +template<> template<> +struct A::B { int m; }; //#5 + +template<> template +struct A::B { int n; }; //#6 + +int a0 = A::B{}.m; //Picks #5 - it has the most empty tpls. +int a1 = A::B{}.l; //Picks #4 (since all specializations are considered since primary was not specialized) + +} + 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