Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -1580,392 +1580,673 @@ return SourceRange(); } -/// \brief Match the given template parameter lists to the given scope -/// specifier, returning the template parameter list that applies to the -/// name. -/// -/// \param DeclStartLoc the start of the declaration that has a scope -/// specifier or a template parameter list. -/// -/// \param DeclLoc The location of the declaration itself. -/// -/// \param SS the scope specifier that will be matched to the given template -/// parameter lists. This scope specifier precedes a qualified name that is -/// being declared. -/// -/// \param TemplateId The template-id following the scope specifier, if there -/// is one. Used to check for a missing 'template<>'. -/// -/// \param ParamLists the template parameter lists, from the outermost to the -/// innermost template parameter lists. -/// -/// \param IsFriend Whether to apply the slightly different rules for -/// matching template parameters to scope specifiers in friend -/// declarations. -/// -/// \param IsExplicitSpecialization will be set true if the entity being -/// declared is an explicit specialization, false otherwise. -/// -/// \returns the template parameter list, if any, that corresponds to the -/// name that is preceded by the scope specifier @p SS. This template -/// parameter list may have template parameters (if we're declaring a -/// template) or may have no template parameters (if we're declaring a -/// template specialization), or may be NULL (if what we're declaring isn't -/// itself a template). -TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( - SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, - TemplateIdAnnotation *TemplateId, - ArrayRef ParamLists, bool IsFriend, - bool &IsExplicitSpecialization, bool &Invalid) { - IsExplicitSpecialization = false; - Invalid = false; - - // The sequence of nested types to which we will match up the template - // parameter lists. We first build this list by starting with the type named - // by the nested-name-specifier and walking out until we run out of types. - SmallVector NestedTypes; - QualType T; - if (SS.getScopeRep()) { - if (CXXRecordDecl *Record - = dyn_cast_or_null(computeDeclContext(SS, true))) - T = Context.getTypeDeclType(Record); + +namespace { + class MatchTemplateParametersToScopeSpecifierDiagnoser; +} + +// This class is an implementation abstraction that separates out all +// the diagnostic details of Sema::MatchTemplateParametersToScopeSpecifier +// and collects it into a class. +class ::MatchTemplateParametersToScopeSpecifierDiagnoser { + Sema &S; + const CXXScopeSpec &SS; + const ArrayRef TemplateParameterLists; + const SourceLocation DeclLoc; + const SourceLocation DeclStartLoc; +public: + MatchTemplateParametersToScopeSpecifierDiagnoser( + Sema &S, const CXXScopeSpec &SS, + ArrayRef TemplateParameterLists, + SourceLocation DeclLoc, SourceLocation DeclStartLoc, bool = false) + : S(S), SS(SS), TemplateParameterLists(TemplateParameterLists), + DeclLoc(DeclLoc), DeclStartLoc(DeclStartLoc) {} + + // We don't have a template header, but we should. + void diagnoseMissingEmptyTPL(const QualType CurType) const { + diagnoseMissingEmptyTPL( + getRangeOfTypeInNestedNameSpecifier(S.Context, CurType, SS)); + } + + // We don't have a template header, but we should. + void diagnoseMissingEmptyTPL(const SourceRange TemplateIdAngleOrTypeRange) + const { + SourceLocation ExpectedTemplateLoc; + if (!TemplateParameterLists.empty()) + ExpectedTemplateLoc = TemplateParameterLists[0]->getTemplateLoc(); else - T = QualType(SS.getScopeRep()->getAsType(), 0); + ExpectedTemplateLoc = DeclStartLoc; + + S.Diag(DeclLoc, diag::err_template_spec_needs_header) + << TemplateIdAngleOrTypeRange + << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); } - - // If we found an explicit specialization that prevents us from needing - // '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) { - ExplicitSpecLoc = Spec->getLocation(); - break; - } - } else if (Record->getTemplateSpecializationKind() - == TSK_ExplicitSpecialization) { - ExplicitSpecLoc = Record->getLocation(); - break; - } - - if (TypeDecl *Parent = dyn_cast(Record->getParent())) - T = Context.getTypeDeclType(Parent); - else - T = QualType(); - continue; - } - - if (const TemplateSpecializationType *TST - = T->getAs()) { - if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) { - if (TypeDecl *Parent = dyn_cast(Template->getDeclContext())) - T = Context.getTypeDeclType(Parent); - else - T = QualType(); - continue; - } - } - - // Look one step prior in a dependent template specialization type. - if (const DependentTemplateSpecializationType *DependentTST - = T->getAs()) { - if (NestedNameSpecifier *NNS = DependentTST->getQualifier()) - T = QualType(NNS->getAsType(), 0); - else - T = QualType(); - continue; - } - - // Look one step prior in a dependent name type. - if (const DependentNameType *DependentName = T->getAs()){ - if (NestedNameSpecifier *NNS = DependentName->getQualifier()) - T = QualType(NNS->getAsType(), 0); - else - T = QualType(); - continue; - } - - // Retrieve the parent of an enumeration type. - if (const EnumType *EnumT = T->getAs()) { - // FIXME: Forward-declared enums require a TSK_ExplicitSpecialization - // check here. - EnumDecl *Enum = EnumT->getDecl(); - - // Get to the parent type. - if (TypeDecl *Parent = dyn_cast(Enum->getParent())) - T = Context.getTypeDeclType(Parent); - else - T = QualType(); - continue; - } - T = QualType(); + void diagnoseExpectedEmptyTPLHasParameters( + const QualType CurType, const TemplateParameterList *const CurTPL) const { + assert(CurTPL); + S.Diag(CurTPL->getTemplateLoc(), + diag::err_template_param_list_matches_nontemplate) + << CurType << SourceRange(CurTPL->getLAngleLoc(), CurTPL->getRAngleLoc()) + << getRangeOfTypeInNestedNameSpecifier(S.Context, CurType, SS); } - // Reverse the nested types list, since we want to traverse from the outermost - // to the innermost while checking template-parameter-lists. - std::reverse(NestedTypes.begin(), NestedTypes.end()); + void diagnoseMissingNonEmptyTPL(QualType CurType) const { + S.Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) + << CurType << getRangeOfTypeInNestedNameSpecifier(S.Context, CurType, SS); - // C++0x [temp.expl.spec]p17: - // A member or a member template may be nested within many - // enclosing class templates. In an explicit specialization for - // such a member, the member declaration shall be preceded by a - // template<> for each enclosing class template that is - // explicitly specialized. - bool SawNonEmptyTemplateParameterList = false; - auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) { - if (SawNonEmptyTemplateParameterList) { - Diag(DeclLoc, diag::err_specialize_member_of_template) - << !Recovery << Range; - Invalid = true; - IsExplicitSpecialization = false; + } + void + diagnoseInvalidPositionOfEmptyTPL(const TemplateParameterList *CurTPL) const { + S.Diag(DeclLoc, diag::err_specialize_member_of_template) + << /* Temporary Fix */ 1 << CurTPL->getSourceRange(); + } + void diagnoseExtraTemplateHeaders(const TemplateParameterList *CurTPL, + const TemplateParameterList *PenultimateTPL, + const bool AllExplicitSpecHeaders) const { + S.Diag(CurTPL->getTemplateLoc(), + AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers + : diag::err_template_spec_extra_headers) + << SourceRange(CurTPL->getTemplateLoc(), + PenultimateTPL->getRAngleLoc()); + } + + void diagnoseExplicitSpecializationDoesNotNeedTPL( + SourceLocation ExplicitSpecLoc, QualType InnerMostNestedType) const { + S.Diag(ExplicitSpecLoc, + diag::note_explicit_template_spec_does_not_need_header) + << InnerMostNestedType; + } +}; + +namespace { + class MatchTemplateParametersToScopeSpecifierImpl; +} + + +// This class is an implementation abstraction that was born during +// a refactoring of Sema::MatchTemplateParametersToScopeSpecifier to accomplish +// the following: +// - disentangle some of the implementation details into constituent functions +// that do a better job of doing 'one' thing. +// - indicate that the various functions are associated +// FIXME: If any of the functions below can be reused, please use your discretion +// and promote them into Sema or Context as appropriate. + +class ::MatchTemplateParametersToScopeSpecifierImpl { + + static bool isExplicitlySpecializedTemploidOrFullySpecializedTemplate( + const CXXRecordDecl *Record) { + // + // template struct A { + // template struct B { }; + // struct B2; + // }; + // template<> + // struct A { template struct B3 { }; }; ==> A true + // template<> template + // struct A::B { }; ==> A & B false + // template<> struct A::B3 { }; // B3 true + // template <> struct A::B2 { }; // B2 true + // + if (Record->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && + !isa(Record)) { + + assert(([](const CXXRecordDecl *Record) { + // We are either a fully specialized template class ... + if (const ClassTemplateSpecializationDecl *Spec = + dyn_cast(Record)) { + if (!isa(Spec) && + Spec->getSpecializationKind() == TSK_ExplicitSpecialization) { + assert(Spec->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization && + "Why would CTSD->getSpecializationKind and " + "RD->getTemplateSpecializationKind be out of sync!"); + return true; + } + } else if (Record->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization) { + // ... or we are an explicitly specialized member class. + assert( + Record->getInstantiatedFromMemberClass() && + "This must be a temploid class - that is a non-template member " + "class of an enclosing template class"); + assert(!Record->getDescribedClassTemplate()); + return true; + } + return false; + })(Record)); + return true; } - return false; }; - auto DiagnoseMissingExplicitSpecialization = [&] (SourceRange Range) { - // Check that we can have an explicit specialization here. - if (CheckExplicitSpecialization(Range, true)) - return true; + // Converts a scope specifier into a vector of types (outermost type has index + // 0) that require template parameter lists. Stops adding types once it + // hits an explicitly specialized member that does not require a template + // parameter list. + static SmallVector + splitScopeSpecifierIntoTypesForTPLMatching( + Sema & SemaRef, const CXXScopeSpec &ScopeSpecifier) { + // The sequence of nested types to which we will match up the template + // parameter lists. We first build this list by starting with the type named + // by the nested-name-specifier and walking out until we run out of types. + SmallVector NestedTypes; + QualType T; + if (ScopeSpecifier.getScopeRep()) { + if (CXXRecordDecl *Record = dyn_cast_or_null( + SemaRef.computeDeclContext(ScopeSpecifier, true))) + T = SemaRef.Context.getTypeDeclType(Record); + else + T = QualType(ScopeSpecifier.getScopeRep()->getAsType(), 0); + } - // We don't have a template header, but we should. - SourceLocation ExpectedTemplateLoc; - if (!ParamLists.empty()) - ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc(); - else - ExpectedTemplateLoc = DeclStartLoc; + 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. We do not + // need + // any more parameter lists to match once we've hit one of these. + if (isExplicitlySpecializedTemploidOrFullySpecializedTemplate(Record)) + break; - Diag(DeclLoc, diag::err_template_spec_needs_header) - << Range - << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); - return false; - }; + if (TypeDecl *Parent = dyn_cast(Record->getParent())) + T = SemaRef.Context.getTypeDeclType(Parent); + else + T = QualType(); + continue; + } - unsigned ParamIdx = 0; - for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes; - ++TypeIdx) { - T = NestedTypes[TypeIdx]; - - // Whether we expect a 'template<>' header. - bool NeedEmptyTemplateHeader = false; + if (const TemplateSpecializationType *TST = + T->getAs()) { + if (TemplateDecl *Template = + TST->getTemplateName().getAsTemplateDecl()) { + if (TypeDecl *Parent = dyn_cast(Template->getDeclContext())) + T = SemaRef.Context.getTypeDeclType(Parent); + else + T = QualType(); + continue; + } + } - // Whether we expect a template header with parameters. - bool NeedNonemptyTemplateHeader = false; - - // For a dependent type, the set of template parameters that we - // expect to see. - TemplateParameterList *ExpectedTemplateParams = 0; + // Look one step prior in a dependent template specialization type. + if (const DependentTemplateSpecializationType *DependentTST = + T->getAs()) { + if (NestedNameSpecifier *NNS = DependentTST->getQualifier()) + T = QualType(NNS->getAsType(), 0); + else + T = QualType(); + continue; + } + // Look one step prior in a dependent name type. + if (const DependentNameType *DependentName = + T->getAs()) { + if (NestedNameSpecifier *NNS = DependentName->getQualifier()) + T = QualType(NNS->getAsType(), 0); + else + T = QualType(); + continue; + } + + // Retrieve the parent of an enumeration type. + if (const EnumType *EnumT = T->getAs()) { + // FIXME: Forward-declared enums require a TSK_ExplicitSpecialization + // check here. + EnumDecl *Enum = EnumT->getDecl(); + + // Get to the parent type. + if (TypeDecl *Parent = dyn_cast(Enum->getParent())) + T = SemaRef.Context.getTypeDeclType(Parent); + else + T = QualType(); + continue; + } + + T = QualType(); + } + // Reverse the nested types list, since we want to traverse from the + // outermost + // to the innermost while checking template-parameter-lists. + std::reverse(NestedTypes.begin(), NestedTypes.end()); + return NestedTypes; + } + + enum class TemplateParameterListRequirement { None, Empty, NonEmpty }; + + static TemplateParameterListRequirement + determineTemplateParameterListRequirements(const QualType QTy) { // C++0x [temp.expl.spec]p15: - // A member or a member template may be nested within many enclosing - // class templates. In an explicit specialization for such a member, the - // member declaration shall be preceded by a template<> for each + // A member or a member template may be nested within many enclosing + // class templates. In an explicit specialization for such a member, the + // member declaration shall be preceded by a template<> for each // enclosing class template that is explicitly specialized. - if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { - if (ClassTemplatePartialSpecializationDecl *Partial - = dyn_cast(Record)) { - ExpectedTemplateParams = Partial->getTemplateParameters(); - NeedNonemptyTemplateHeader = true; + if (CXXRecordDecl *Record = QTy->getAsCXXRecordDecl()) { + if (ClassTemplatePartialSpecializationDecl *Partial = + dyn_cast(Record)) { + // NeedNonemptyTemplateHeader = true; + return TemplateParameterListRequirement::NonEmpty; } else if (Record->isDependentType()) { if (Record->getDescribedClassTemplate()) { - ExpectedTemplateParams = Record->getDescribedClassTemplate() - ->getTemplateParameters(); - NeedNonemptyTemplateHeader = true; + // NeedNonemptyTemplateHeader = true; + return TemplateParameterListRequirement::NonEmpty; } - } else if (ClassTemplateSpecializationDecl *Spec - = dyn_cast(Record)) { + } else if (ClassTemplateSpecializationDecl *Spec = + dyn_cast(Record)) { // C++0x [temp.expl.spec]p4: // Members of an explicitly specialized class template are defined - // in the same manner as members of normal classes, and not using - // the template<> syntax. - if (Spec->getSpecializationKind() != TSK_ExplicitSpecialization) - NeedEmptyTemplateHeader = true; - else - continue; + // in the same manner as members of normal classes, and not using + // the template<> syntax. + // + // If this is an explicit specialization of a class template + // we do not need any TPLs. + if (Spec->getSpecializationKind() != TSK_ExplicitSpecialization) { + return TemplateParameterListRequirement::Empty; + } + } else if (Record->getTemplateSpecializationKind()) { - if (Record->getTemplateSpecializationKind() - != TSK_ExplicitSpecialization && - TypeIdx == NumTypes - 1) - IsExplicitSpecialization = true; - - continue; + // If this is a non-dependent temploid member we do not need + // any Template Parameter Lists for it. } - } else if (const TemplateSpecializationType *TST - = T->getAs()) { - if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) { - ExpectedTemplateParams = Template->getTemplateParameters(); - NeedNonemptyTemplateHeader = true; + } else if (const TemplateSpecializationType *TST = + QTy->getAs()) { + if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) { + // NeedNonemptyTemplateHeader = true; + return TemplateParameterListRequirement::NonEmpty; } - } else if (T->getAs()) { - // FIXME: We actually could/should check the template arguments here - // against the corresponding template parameter list. - NeedNonemptyTemplateHeader = false; - } - - // C++ [temp.expl.spec]p16: - // In an explicit specialization declaration for a member of a class - // template or a member template that ap- pears in namespace scope, the - // member template and some of its enclosing class templates may remain - // unspecialized, except that the declaration shall not explicitly - // specialize a class member template if its en- closing class templates - // are not explicitly specialized as well. - if (ParamIdx < ParamLists.size()) { - if (ParamLists[ParamIdx]->size() == 0) { - if (CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange(), - false)) - return 0; - } else - SawNonEmptyTemplateParameterList = true; + } else if (QTy->getAs()) { + // NeedNonemptyTemplateHeader = false; + return TemplateParameterListRequirement::None; + } else if (QTy->getAs() || QTy->getAs()) { + // Do nothing. + return TemplateParameterListRequirement::None; + } else { + QTy.dump(); + llvm_unreachable( + "What other type can occur within a nested name specifier?"); } - - if (NeedEmptyTemplateHeader) { - // If we're on the last of the types, and we need a 'template<>' header - // here, then it's an explicit specialization. - if (TypeIdx == NumTypes - 1) - IsExplicitSpecialization = true; + return TemplateParameterListRequirement::None; + }; - if (ParamIdx < ParamLists.size()) { - if (ParamLists[ParamIdx]->size() > 0) { - // The header has template parameters when it shouldn't. Complain. - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - diag::err_template_param_list_matches_nontemplate) - << T - << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), - ParamLists[ParamIdx]->getRAngleLoc()) - << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); - Invalid = true; - return 0; + // Return true if QTy represents: + // - a non-template nested class within an enclosing parent template class + // - and, it was not explicitly specialized (e.g. + // template struct A { struct B { }; }; + // template<> struct A::B { }; <-- explicitly specialized temploid + // A::B <-- non-explicitly specialized temploid + // + static bool isNonExplicitlySpecializedTemploidClass( + const QualType QTy) { + if (const CXXRecordDecl *RD = QTy->getAsCXXRecordDecl()) { + if (!RD->isDependentContext() && + !isa(RD)) { + if (RD->getTemplateSpecializationKind()) { + assert(RD->getInstantiatedFromMemberClass()); + return RD->getTemplateSpecializationKind() != + TSK_ExplicitSpecialization; } - - // Consume this template header. - ++ParamIdx; - continue; } + } + return false; + } + /// Given a QualType (within a nested name specifier), this returns what the + /// template parameter list should look like. + /// + static TemplateParameterList *getExpectedTemplateParameterList( + const QualType QTy) { + if (const CXXRecordDecl *Record = QTy->getAsCXXRecordDecl()) { + if (const auto *PartialSpec = + dyn_cast(Record)) { + return PartialSpec->getTemplateParameters(); + } else if (Record->isDependentType() && + Record->getDescribedClassTemplate()) { + return Record->getDescribedClassTemplate()->getTemplateParameters(); + } + } else if (const auto *TST = QTy->getAs()) { + if (const TemplateDecl *Template = + TST->getTemplateName().getAsTemplateDecl()) + return Template->getTemplateParameters(); + } else if (const auto *DTST = + QTy->getAs()) { + llvm_unreachable( + "How can a DependentTemplateSpecializationType make it here?"); + } + return nullptr; + } + // Returns true if we matched/consumed the the CurTPL. + static inline bool matchEmptyTemplateParameterList( + const TemplateParameterList *const CurTPL, const QualType CurType, + const bool IsFriend, bool &Invalid, + const MatchTemplateParametersToScopeSpecifierDiagnoser &D) { + if (!CurTPL) { + // We don't have a template header, but we should, except for if + // we are declaring a friend. + // For e.g. + // template struct A { + // friend void B::foo(char); + // }; + // if (!IsFriend) - if (DiagnoseMissingExplicitSpecialization( - getRangeOfTypeInNestedNameSpecifier(Context, T, SS))) - return 0; - - continue; + D.diagnoseMissingEmptyTPL(CurType); + return false; + } else if (CurTPL && CurTPL->size() > 0) { + // The header has template parameters when it shouldn't. Complain. + D.diagnoseExpectedEmptyTPLHasParameters(CurType, CurTPL); + Invalid = true; + return false; } + return true; + } - if (NeedNonemptyTemplateHeader) { - // In friend declarations we can have template-ids which don't - // depend on the corresponding template parameter lists. But - // assume that empty parameter lists are supposed to match this - // template-id. - if (IsFriend && T->isDependentType()) { - if (ParamIdx < ParamLists.size() && - DependsOnTemplateParameters(T, ParamLists[ParamIdx])) - ExpectedTemplateParams = 0; - else - continue; - } + // Returns true if we matched/consumed the CurTPL. + static bool matchNonEmptyTemplateParameterList( + Sema & S, TemplateParameterList * const CurTPL, const QualType CurType, + const bool IsFriend, bool &Invalid, + const MatchTemplateParametersToScopeSpecifierDiagnoser &D) { - if (ParamIdx < ParamLists.size()) { - // Check the template parameter list, if we can. - if (ExpectedTemplateParams && - !TemplateParameterListsAreEqual(ParamLists[ParamIdx], - ExpectedTemplateParams, - true, TPL_TemplateMatch)) - Invalid = true; - - if (!Invalid && - CheckTemplateParameterList(ParamLists[ParamIdx], 0, - TPC_ClassTemplateMember)) - Invalid = true; - - ++ParamIdx; - continue; + // In friend declarations we can have template-ids which don't + // depend on the corresponding template parameter lists. But + // assume that empty parameter lists are supposed to match this + // template-id. + if (IsFriend && CurType->isDependentType()) { + if (!CurTPL) { + // template class A { + // friend void B::foo(); + // }; + return false; } - - Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) - << T - << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); - Invalid = true; - continue; + if (!DependsOnTemplateParameters(CurType, CurTPL)) { + // template class A { + // template friend void B::foo(U u); + // }; + // Do not match with B + return false; + } } + if (CurTPL) { + // For a dependent type, the set of template parameters that we + // expect to see. + TemplateParameterList *ExpectedTemplateParams = + getExpectedTemplateParameterList(CurType); + + // Check the template parameter list, if we can. + if (ExpectedTemplateParams && + !S.TemplateParameterListsAreEqual(CurTPL, ExpectedTemplateParams, + true, Sema::TPL_TemplateMatch)) + return !(Invalid = true); + + if (!Invalid && + S.CheckTemplateParameterList(CurTPL, 0, + Sema::TPC_ClassTemplateMember)) + return !(Invalid = true); + + return true; + } + D.diagnoseMissingNonEmptyTPL(CurType); + return !(Invalid = true); } - // If there were at least as many template-ids as there were template - // parameter lists, then there are no template parameter lists remaining for - // the declaration itself. - if (ParamIdx >= ParamLists.size()) { - if (TemplateId && !IsFriend) { - // We don't have a template header for the declaration itself, but we - // should. - IsExplicitSpecialization = true; - DiagnoseMissingExplicitSpecialization(SourceRange(TemplateId->LAngleLoc, - TemplateId->RAngleLoc)); + static bool checkTemplateParameterListSequencing( + ArrayRef TemplateParameterLists, bool &Invalid, + const MatchTemplateParametersToScopeSpecifierDiagnoser &D) { + // C++ [temp.expl.spec]p16: + // In an explicit specialization declaration for a member of a class + // template or a member template that appears in namespace scope, the + // member template and some of its enclosing class templates may remain + // unspecialized, except that the declaration shall not explicitly + // specialize a class member template if its enclosing class templates + // are not explicitly specialized as well. + bool SawNonEmptyTemplateParameterList = false; + for (const auto *CurTPL : TemplateParameterLists) { + const bool IsCurTPLEmpty = CurTPL->size() == 0; - // Fabricate an empty template parameter list for the invented header. - return TemplateParameterList::Create(Context, SourceLocation(), - SourceLocation(), 0, 0, - SourceLocation()); + if (IsCurTPLEmpty && SawNonEmptyTemplateParameterList) { + Invalid = true; + D.diagnoseInvalidPositionOfEmptyTPL(CurTPL); + return true; + } + SawNonEmptyTemplateParameterList = !IsCurTPLEmpty; } - - return 0; + return false; } - // If there were too many template parameter lists, complain about that now. - if (ParamIdx < ParamLists.size() - 1) { + // Check if we have the right number of template parameter lists left + // once we've matched all the nested name specifers to their TPLs. + static bool checkRemainingTemplateParameterLists( + unsigned const NextTPLIdx, + ArrayRef TemplateParameterLists, + ArrayRef NestedTypes, bool &Invalid, + const MatchTemplateParametersToScopeSpecifierDiagnoser &D) { + + // We should have exactly one template parameter list left for the + // declaration. + if (NextTPLIdx == TemplateParameterLists.size() - 1) + return false; + + // If there were at least as many template-ids as there were template + // parameter lists, then there are no template parameter lists remaining for + // the declaration itself. + if (NextTPLIdx >= TemplateParameterLists.size()) + return true; + bool HasAnyExplicitSpecHeader = false; bool AllExplicitSpecHeaders = true; - for (unsigned I = ParamIdx, E = ParamLists.size() - 1; I != E; ++I) { - if (ParamLists[I]->size() == 0) + const unsigned NumTPLs = TemplateParameterLists.size(); + assert(NextTPLIdx < NumTPLs - 1 && "No residual TPLs!"); + for (unsigned I = NextTPLIdx, E = NumTPLs - 1; I != E; ++I) { + if (TemplateParameterLists[I]->size() == 0) HasAnyExplicitSpecHeader = true; else AllExplicitSpecHeaders = false; } - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers - : diag::err_template_spec_extra_headers) - << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), - ParamLists[ParamLists.size() - 2]->getRAngleLoc()); + D.diagnoseExtraTemplateHeaders(TemplateParameterLists[NextTPLIdx], + TemplateParameterLists[NumTPLs - 2], + AllExplicitSpecHeaders); // If there was a specialization somewhere, such that 'template<>' is // not required, and there were any 'template<>' headers, note where the // specialization occurred. - if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader) - Diag(ExplicitSpecLoc, - diag::note_explicit_template_spec_does_not_need_header) - << NestedTypes.back(); - + if (HasAnyExplicitSpecHeader) { + auto GetLocationOfExplicitSpecialization = []( + const ArrayRef NestedTypes) { + // If we found an explicit specialization that prevents us from needing + // 'template<>' headers, this will be set to the location of that + // explicit specialization. + for (const auto &QT : NestedTypes) { + if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) + if (isExplicitlySpecializedTemploidOrFullySpecializedTemplate(RD)) + return RD->getLocation(); + } + return SourceLocation(); + }; + + SourceLocation ExplicitSpecLoc = + GetLocationOfExplicitSpecialization(NestedTypes); + + if (ExplicitSpecLoc.isValid()) { + D.diagnoseExplicitSpecializationDoesNotNeedTPL(ExplicitSpecLoc, + NestedTypes.back()); + } + } // We have a template parameter list with no corresponding scope, which // means that the resulting template declaration can't be instantiated // properly (we'll end up with dependent nodes when we shouldn't). if (!AllExplicitSpecHeaders) Invalid = true; + return false; } - // C++ [temp.expl.spec]p16: - // In an explicit specialization declaration for a member of a class - // template or a member template that ap- pears in namespace scope, the - // member template and some of its enclosing class templates may remain - // unspecialized, except that the declaration shall not explicitly - // specialize a class member template if its en- closing class templates - // are not explicitly specialized as well. - if (ParamLists.back()->size() == 0 && - CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange(), - false)) - return 0; + const MatchTemplateParametersToScopeSpecifierDiagnoser Diagnoser; + const CXXScopeSpec &SS; + const TemplateIdAnnotation *const TemplateId; + ArrayRef TemplateParameterLists; + const bool IsFriend; + Sema &SemaRef; - // Return the last template parameter list, which corresponds to the - // entity being declared. - return ParamLists.back(); +public: + MatchTemplateParametersToScopeSpecifierImpl( + SourceLocation DeclStartLoc, SourceLocation DeclLoc, + const CXXScopeSpec &SS, + const TemplateIdAnnotation *TemplateId, + ArrayRef TemplateParameterLists, + const bool IsFriend, Sema &S) + : Diagnoser(S, SS, TemplateParameterLists, DeclLoc, DeclStartLoc), + SS(SS), TemplateId(TemplateId), TemplateParameterLists(TemplateParameterLists), + IsFriend(IsFriend), SemaRef(S) {} + + TemplateParameterList *match(bool &IsExplicitSpecialization, bool &Invalid) { + IsExplicitSpecialization = false; + Invalid = false; + + // Ensure that empty and non-empty template parameter lists are properly + // sequenced. (For e.g. prohibit an empty tpl once a non-empty tpl has been + // seen). + if (checkTemplateParameterListSequencing(TemplateParameterLists, Invalid, + Diagnoser)) + return nullptr; + + // Split a nested name specifier into a vector of types. + // Outer types are at a lower index (i.e. A::B::C : + // [0] = A, [1] = B, [2] = C) + // if B is explicitly specialized, then do not return A + // since all TPLs will correspond only to types nested within C. + const SmallVector NestedTypes = + splitScopeSpecifierIntoTypesForTPLMatching(SemaRef, SS); + + // C++0x [temp.expl.spec]p17: + // A member or a member template may be nested within many + // enclosing class templates. Iterate through all the types + // and determine the template parameter list requirements + // of each, and ensure they are met. + unsigned CurTPLIdx = 0; + const unsigned NumTPLs = TemplateParameterLists.size(); + for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); + TypeIdx != NumTypes; ++TypeIdx) { + const bool IsInnermostType = TypeIdx == NumTypes - 1; + QualType CurType = NestedTypes[TypeIdx]; + + const TemplateParameterListRequirement TPLRequirement = + determineTemplateParameterListRequirements(CurType); + + // Whether we expect a 'template<>' header. + const bool NeedEmptyTemplateHeader = + TPLRequirement == TemplateParameterListRequirement::Empty; + + // Whether we expect a template header with parameters. + const bool NeedNonemptyTemplateHeader = + TPLRequirement == TemplateParameterListRequirement::NonEmpty; + + if (IsInnermostType) { + if (isNonExplicitlySpecializedTemploidClass(CurType) || + NeedEmptyTemplateHeader) { + // If this is a non-dependent temploid member class that is not + // explicitly specialized, and if it is the innermost type, then we + // must be declaring an explicit specialization of a member of + // that temploid class. + // For e.g. + // template struct A { + // struct B { void foo() { 1; } }; + // }; + // template<> void A::B::foo() { 2; }; + // 'A::B' above is our subject of interest here. + // Or + // If we're on the last of the types, and we need a 'template<>' + // header here, then it's an explicit specialization. + IsExplicitSpecialization = true; + } + } + + TemplateParameterList *const CurTPL = + CurTPLIdx < NumTPLs ? TemplateParameterLists[CurTPLIdx] : nullptr; + bool TPLMatched = false; + if (NeedEmptyTemplateHeader) { + TPLMatched = matchEmptyTemplateParameterList(CurTPL, CurType, IsFriend, + Invalid, Diagnoser); + + } else if (NeedNonemptyTemplateHeader) { + TPLMatched = matchNonEmptyTemplateParameterList( + SemaRef, CurTPL, CurType, IsFriend, Invalid, Diagnoser); + } + + // Consume the current TPL if it has been used. + if (CurTPL && TPLMatched) + ++CurTPLIdx; + } + // If there were too many or too few TPLs complain about that. + if (checkRemainingTemplateParameterLists(CurTPLIdx, TemplateParameterLists, + NestedTypes, Invalid, Diagnoser)) { + if (CurTPLIdx >= TemplateParameterLists.size()) { + if (TemplateId && !IsFriend) { + // We don't have a template header for the declaration itself, but we + // should. + IsExplicitSpecialization = true; + Invalid = true; + Diagnoser.diagnoseMissingEmptyTPL( + SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)); + // Fabricate an empty template parameter list for the invented header. + return TemplateParameterList::Create(SemaRef.Context, SourceLocation(), + SourceLocation(), 0, 0, + SourceLocation()); + } + } + } + + // Return the last template parameter list, which corresponds to the + // entity being declared. Even if Invalid return the last TPL - this + // can help with error recovery. + TemplateParameterList *const NextTPL = + CurTPLIdx < TemplateParameterLists.size() + ? TemplateParameterLists.back() + : nullptr; + return NextTPL; + } +}; + + +/// \brief Match the given template parameter lists to the given scope +/// specifier, returning the template parameter list that applies to the +/// name. +/// +/// \param DeclStartLoc the start of the declaration that has a scope +/// specifier or a template parameter list. +/// +/// \param DeclLoc The location of the declaration itself. +/// +/// \param SS the scope specifier that will be matched to the given template +/// parameter lists. This scope specifier precedes a qualified name that is +/// being declared. +/// +/// \param TemplateId The template-id following the scope specifier, if there +/// is one. Used to check for a missing 'template<>'. +/// +/// \param ParamLists the template parameter lists, from the outermost to the +/// innermost template parameter lists. +/// +/// \param IsFriend Whether to apply the slightly different rules for +/// matching template parameters to scope specifiers in friend +/// declarations. +/// +/// \param IsExplicitSpecialization will be set true if the entity being +/// declared is an explicit specialization, false otherwise. +/// +/// \returns the template parameter list, if any, that corresponds to the +/// name that is preceded by the scope specifier @p SS. This template +/// parameter list may have template parameters (if we're declaring a +/// template) or may have no template parameters (if we're declaring a +/// template specialization), or may be NULL (if what we're declaring isn't +/// itself a template). +TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( + SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, + TemplateIdAnnotation *TemplateId, + ArrayRef ParamLists, bool IsFriend, + bool &IsExplicitSpecialization, bool &Invalid) { + return MatchTemplateParametersToScopeSpecifierImpl( + DeclStartLoc, DeclLoc, SS, TemplateId, ParamLists, IsFriend, *this) + .match(IsExplicitSpecialization, Invalid); } void Sema::NoteAllFoundTemplates(TemplateName Name) {