Index: include/clang/AST/DeclTemplate.h =================================================================== --- include/clang/AST/DeclTemplate.h +++ include/clang/AST/DeclTemplate.h @@ -1768,9 +1768,23 @@ void setMemberSpecialization() { ClassTemplatePartialSpecializationDecl *First = cast(getFirstDecl()); - assert(First->InstantiatedFromMember.getPointer() && - "Only member templates can be member template specializations"); - return First->InstantiatedFromMember.setInt(true); + + // Partial specializations marked as member specializations can only be + // declared out of line. + assert(!First->InstantiatedFromMember.getPointer() && + "Since we only instantiate partial declarations " + "during selection of the most specialized partial specialization - " + "this should never be true!"); + + assert(First == this && + "When partially specializing a member template out of class " + "this must be the first declaration"); + + assert(this->isOutOfLine() && "Partial specializations explicitly " + "specialized as member templates can only be " + "specified out of line"); + + First->InstantiatedFromMember.setInt(true); } /// Retrieves the injected specialization type for this partial Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -6046,10 +6046,11 @@ // C++ Template Instantiation // - MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, - const TemplateArgumentList *Innermost = 0, - bool RelativeToPrimary = false, - const FunctionDecl *Pattern = 0); + MultiLevelTemplateArgumentList getTemplateInstantiationArgs( + NamedDecl *D, const TemplateArgumentList *Innermost = 0, + bool RelativeToPrimary = false, const FunctionDecl *Pattern = 0, + const ArrayRef TPLsOfDeclBeingSubstituted = + ArrayRef()); /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { Index: include/clang/Sema/Template.h =================================================================== --- include/clang/Sema/Template.h +++ include/clang/Sema/Template.h @@ -371,12 +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 @@ -442,35 +436,16 @@ 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(); Index: lib/AST/DeclTemplate.cpp =================================================================== --- lib/AST/DeclTemplate.cpp +++ lib/AST/DeclTemplate.cpp @@ -428,10 +428,12 @@ P = getPartialSpecializations().begin(), PEnd = getPartialSpecializations().end(); P != PEnd; ++P) { - if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) - return P->getMostRecentDecl(); + if (ClassTemplatePartialSpecializationDecl *ProtoPSpec = + P->getInstantiatedFromMember()) { + if (ProtoPSpec->getCanonicalDecl() == DCanon) + return P->getMostRecentDecl(); + } } - return 0; } @@ -855,6 +857,7 @@ return Result; } + //===----------------------------------------------------------------------===// // FriendTemplateDecl Implementation //===----------------------------------------------------------------------===// Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -3234,8 +3234,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. Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -5878,15 +5878,19 @@ return false; } - -DeclResult -Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, - TagUseKind TUK, - SourceLocation KWLoc, - SourceLocation ModulePrivateLoc, - TemplateIdAnnotation &TemplateId, - AttributeList *Attr, - MultiTemplateParamsArg TemplateParameterLists) { +unsigned getNumberOfEmptyTemplateParameterLists( + const ArrayRef TemplateParameterLists) { + unsigned NumOfEmptyTPLs = 0; + for (const auto *CurTPL : TemplateParameterLists) { + if (!CurTPL->size()) + ++NumOfEmptyTPLs; + } + return NumOfEmptyTPLs; +} +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; @@ -6122,8 +6126,23 @@ TemplateParameterLists.data()); } - if (!PrevPartial) + if (!PrevPartial) { ClassTemplate->AddPartialSpecialization(Partial, InsertPos); + // If this is an out of line partial specialization declaration that is + // first declared out of class, we might not have an instantiated-from + // member - but still need to mark this partial specialization as a + // 'member-specialization'. + // For e.g. + // template struct A { + // template struct B { }; + // }; + // template<> template struct A::B { }; <- mark + if (Partial->getDeclContext() != CurContext && + getNumberOfEmptyTemplateParameterLists(TemplateParameterLists)) { + Partial->setLexicalDeclContext(CurContext); + Partial->setMemberSpecialization(); + } + } Specialization = Partial; // If we are providing an explicit specialization of a member class Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -4633,9 +4633,52 @@ Better2 = !::FinishTemplateArgumentDeduction( *this, 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) { + // FIXME: Once this is moved to either Sema or Context, call it from there. + unsigned getNumberOfEmptyTemplateParameterLists(const Decl *D); - if (Better1 == Better2) - return 0; + auto GetPrototypePartialSpecialization = [](ClassTemplatePartialSpecializationDecl *D) { + ClassTemplatePartialSpecializationDecl *It = D; + while (It->getInstantiatedFromMember()) { + if (It->isMemberSpecialization()) + return It; + It = It->getInstantiatedFromMember(); + } + return It; + }; + unsigned NumOfEmptyTPLSin1 = getNumberOfEmptyTemplateParameterLists( + GetPrototypePartialSpecialization(PS1)); + unsigned NumOfEmptyTPLSin2 = getNumberOfEmptyTemplateParameterLists( + GetPrototypePartialSpecialization(PS2)); + if (NumOfEmptyTPLSin1 == NumOfEmptyTPLSin2) + return 0; + else + return (NumOfEmptyTPLSin1 > NumOfEmptyTPLSin2) ? PS1 : PS2; + } return Better1 ? PS1 : PS2; } Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -31,6 +31,10 @@ // Template Instantiation Support //===----------------------------------------------------------------------===/ +//===----------------------------------------------------------------------===/ +// Template Instantiation Support +//===----------------------------------------------------------------------===/ + /// \brief Retrieve the template argument list(s) that should be used to /// instantiate the definition of the given declaration. /// @@ -48,20 +52,30 @@ /// 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; + // The index of the outer decl context. '0' is the current innermost + // DeclContext. It is used to calculate the index within + // TPLsOfDeclBeingSubstituted if supplied. + unsigned OuterDeclContextIndex = 0; if (Innermost) Result.addOuterTemplateArguments(Innermost); DeclContext *Ctx = dyn_cast(D); if (!Ctx) { Ctx = D->getDeclContext(); + ++OuterDeclContextIndex; // Add template arguments from a variable template instantiation. if (VarTemplateSpecializationDecl *Spec = @@ -104,27 +118,49 @@ return Result; } } - } - + } + while (!Ctx->isFileContext()) { + TemplateParameterList *const CurTPL = [&] { + const int NumberOfTPLsOfDeclBeingSubstituted = + TPLsOfDeclBeingSubstituted.size(); + const int CurTPLIndex = + NumberOfTPLsOfDeclBeingSubstituted + ? NumberOfTPLsOfDeclBeingSubstituted - 1 - OuterDeclContextIndex + : -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)) || + (CurTPL && CurTPL->size() == 0)) { + // 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 + // break; - + } Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); - - // If this class template specialization was instantiated from a + // 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,19 +205,20 @@ 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; } } - Ctx = Ctx->getParent(); + ++OuterDeclContextIndex; RelativeToPrimary = false; } return Result; } + bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const { switch (Kind) { case TemplateInstantiation: @@ -1971,8 +2008,11 @@ Instantiation->setInvalidDecl(); continue; } + // Do not eagerly transform partial specialization declarations. + Decl *NewMember = nullptr; + if (!isa(Member)) + NewMember = Instantiator.Visit(Member); - Decl *NewMember = Instantiator.Visit(Member); if (NewMember) { if (FieldDecl *Field = dyn_cast(NewMember)) { Fields.push_back(Field); @@ -2077,20 +2117,7 @@ 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 @@ -2190,6 +2217,203 @@ }; } + + +SmallVector +getTemplateParameterListsOfDeclaration(const Decl *D) { + SmallVector TPLs; + const TagDecl *PatternDecl = 0; + TemplateParameterList *InnerMostTPL = 0; + + // Separate out the innermost TPL from the pattern - since the pattern is a + // CXXRecordDecl which captures the TPLs the template was declared with, + // and can be used to extract out all the template parameter lists. + + if (auto *CTD = dyn_cast(D)) { + InnerMostTPL = CTD->getTemplateParameters(); + PatternDecl = CTD->getTemplatedDecl(); + } else if (auto *PTSD = dyn_cast(D)) { + InnerMostTPL = PTSD->getTemplateParameters(); + PatternDecl = PTSD; + } else if (auto *CTSD = dyn_cast(D)) { + if (CTSD->isExplicitSpecialization()) { + // If this was declared as an explicit specialization, all the TPLs + // are included in the getTemplateParameterList(i) info... + InnerMostTPL = 0; + PatternDecl = CTSD; + } else { + CTSD->dump(); + llvm_unreachable("A pattern declaration can not be a non-explicit " + "ClassTemplateSpecializationDecl"); + } + } else if (auto *RD = dyn_cast(D)) { + if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) { + PatternDecl = RD; + InnerMostTPL = CTD->getTemplateParameters(); + } + } else { + D->dump(); + llvm_unreachable("Not implemented for all (function/variable) template " + "declarations yet!"); + } + + // 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 (ParentDC->isRecord()) { + if (isa(ParentDC)) { + auto ParentTPLs = getTemplateParameterListsOfDeclaration( + dyn_cast(ParentDC)); + TPLs.append(ParentTPLs.begin(), ParentTPLs.end()); + } + } + } else { // For out of line declarations use the PatternDecl. + for (unsigned I = 0; I != PatternDecl->getNumTemplateParameterLists(); + ++I) + TPLs.push_back(PatternDecl->getTemplateParameterList(I)); + } + if (InnerMostTPL) + TPLs.push_back(InnerMostTPL); + } + return TPLs; +} +// FIXME: Where should this function go? Sema? Context? +unsigned getNumberOfEmptyTemplateParameterLists(const Decl *D) { + unsigned num = 0; + for (auto *tpl : getTemplateParameterListsOfDeclaration(D)) { + if (!tpl->size()) + ++num; + } + return num; +} + +namespace { + + +class ClassTemplatePartialSpecializationFinder { + Sema &SemaRef; + ClassTemplateDecl *const TemplateBeingInstantiated; + CXXRecordDecl *const ParentClassOfTemplateBeingInstantiated; + +public: + typedef SmallVector SpecVectorTy; + + // Iterate through all Ancestor templates and find all partial + // specializations from each one. + + SpecVectorTy getAllPartialSpecializationsFromAncestorTemplates() const { + + SmallVector AllPartialSpecs; + ClassTemplateDecl *ClassTemplateIt = TemplateBeingInstantiated; + while (ClassTemplateDecl *const AncestorClassTemplate = + ClassTemplateIt->getInstantiatedFromMemberTemplate()) { + SpecVectorTy PSpecs; + + AncestorClassTemplate->getPartialSpecializations(PSpecs); + AllPartialSpecs.append(PSpecs.begin(), PSpecs.end()); + ClassTemplateIt = AncestorClassTemplate; + } + return SpecVectorTy(AllPartialSpecs.begin(), AllPartialSpecs.end()); + } + // Iterate through the specializations associated with all ancestor templates + // - substitute the outer enclosing arguments of the nested TemplateBeingInstanted. + // FIXME: If the template is not a member template this should just return + // the list of partial specializations, right ... + SpecVectorTy getRelevantPartialSpecializationsFromAncestorTemplates( + SourceLocation PointOfInstantiation) const { + SpecVectorTy AllPartialSpecs = + getAllPartialSpecializationsFromAncestorTemplates(); + SpecVectorTy RelevantPartialSpecs; + for (ClassTemplatePartialSpecializationDecl *const APSpec : + AllPartialSpecs) { + + clang::MultiLevelTemplateArgumentList OuterTemplateArgs = + SemaRef.getTemplateInstantiationArgs( + TemplateBeingInstantiated, 0, false, 0); + + Sema::InstantiatingTemplate Inst(SemaRef, PointOfInstantiation, APSpec); + // If we have exceeded the maximum recursion instantiation depth, return + // an empty vector. + if (Inst.isInvalid()) + return SpecVectorTy(); + + // 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); + + if (auto *CTPSD = cast_or_null( + DeclInstantiator.Visit(APSpec))) { + RelevantPartialSpecs.push_back(CTPSD); + } + } + return RelevantPartialSpecs; + } + + ClassTemplatePartialSpecializationFinder( + Sema &S, ClassTemplateDecl *CurClassTemplate) + : SemaRef(S), TemplateBeingInstantiated(CurClassTemplate), + ParentClassOfTemplateBeingInstantiated( + isa(CurClassTemplate->getDeclContext()) + ? cast(CurClassTemplate->getDeclContext()) + ->getCanonicalDecl() + : 0) {} + + SpecVectorTy + getAllPartialSpecializationsFromWhichToSelectTheMostSpecializedTemplate( + SourceLocation POI) const { + + SpecVectorTy 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()) { + SpecVectorTy APSpecs = + getRelevantPartialSpecializationsFromAncestorTemplates( + POI); + AllPartialSpecs.append(APSpecs.begin(), APSpecs.end()); + } + return AllPartialSpecs; + } +}; + +} // End anonymous namespace + bool Sema::InstantiateClassTemplateSpecialization( SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, @@ -2228,8 +2452,7 @@ return true; ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate(); - CXXRecordDecl *Pattern = 0; - + // C++ [temp.class.spec.match]p1: // When a class template is used in a context that requires an // instantiation of the class, it is necessary to determine @@ -2238,10 +2461,16 @@ // matching the template arguments of the class template // specialization with the template argument lists of the partial // specializations. + SmallVector PartialSpecs = + ClassTemplatePartialSpecializationFinder(*this, Template) + .getAllPartialSpecializationsFromWhichToSelectTheMostSpecializedTemplate( + PointOfInstantiation); + + CXXRecordDecl *Pattern = 0; + + 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]; @@ -2352,11 +2581,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 @@ -959,18 +959,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; } @@ -2694,30 +2682,6 @@ InstTemplateArgs, CanonType); - if (PrevDecl) { - // We've already seen a partial specialization with the same template - // parameters and template arguments. This can happen, for example, when - // substituting the outer template arguments ends up causing two - // class template partial specializations of a member class template - // to have identical forms, e.g., - // - // template - // struct Outer { - // template struct Inner; - // template struct Inner; - // template struct Inner; - // }; - // - // Outer outer; // error: the partial specializations of Inner - // // have the same signature. - SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared) - << WrittenTy->getType(); - SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here) - << SemaRef.Context.getTypeDeclType(PrevDecl); - return 0; - } - - // Create the class template partial specialization declaration. ClassTemplatePartialSpecializationDecl *InstPartialSpec = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, @@ -2738,10 +2702,6 @@ InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); - - // Add this partial specialization to the set of class template partial - // specializations. - ClassTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0); return InstPartialSpec; } 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/SemaTemplate/member-templates.cpp =================================================================== --- test/SemaTemplate/member-templates.cpp +++ test/SemaTemplate/member-templates.cpp @@ -0,0 +1,519 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y + +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; + +} \ No newline at end of file