Index: include/clang/AST/DeclTemplate.h =================================================================== --- include/clang/AST/DeclTemplate.h +++ include/clang/AST/DeclTemplate.h @@ -662,7 +662,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); } @@ -1768,9 +1768,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 @@ -2619,7 +2621,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/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -356,6 +356,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. /// @@ -5262,7 +5272,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, @@ -6047,6 +6058,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, @@ -6064,10 +6102,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,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) @@ -442,40 +427,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/DeclTemplate.cpp =================================================================== --- lib/AST/DeclTemplate.cpp +++ lib/AST/DeclTemplate.cpp @@ -428,10 +428,12 @@ P = getPartialSpecializations().begin(), PEnd = getPartialSpecializations().end(); P != PEnd; ++P) { - if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) - return P->getMostRecentDecl(); + if (ClassTemplatePartialSpecializationDecl *ProtoPSpec = + P->getInstantiatedFromMember()) { + if (ProtoPSpec->getCanonicalDecl() == DCanon) + return P->getMostRecentDecl(); + } } - return 0; } @@ -855,6 +857,7 @@ return Result; } + //===----------------------------------------------------------------------===// // FriendTemplateDecl Implementation //===----------------------------------------------------------------------===// @@ -1045,8 +1048,9 @@ P = getPartialSpecializations().begin(), PEnd = getPartialSpecializations().end(); P != PEnd; ++P) { - if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) - return P->getMostRecentDecl(); + if (P->getInstantiatedFromMember()) + if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) + return P->getMostRecentDecl(); } return 0; Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -2852,12 +2852,100 @@ QualType MergedT; if (getLangOpts().CPlusPlus) { + const bool IsMemberVariableTemplateBeingExplicitlySpecialized = + ([](VarDecl *New, VarDecl *Old) { + if (VarTemplateDecl *NewVT = New->getDescribedVarTemplate()) { + VarTemplateDecl *OldVT = Old->getDescribedVarTemplate(); + assert(OldVT && "If the new declaration is a variable template, so " + "should the old template be!"); + // FIXME: There is no way to safely call getInstFromMemTempl or + // isMemberSpecialization on NewVT - since both those functions + // have the side-effect of creating a shared Common ptr + // that is not correctly wired up if the Old and New vars + // need to be redecl connected. Consider passing in the + // IsExplicitSpecialization determination in + // Sema::ActOnVariableDeclarator + // into MergeVarDeclTypes (i.e. current function). + return !!OldVT->getInstantiatedFromMemberTemplate(); + } + return false; + }(New, Old)); + if (New->getType()->isUndeducedType()) { // We don't know what the new type is until the initializer is attached. return; } else if (Context.hasSameType(New->getType(), Old->getType())) { - // These could still be something that needs exception specs checked. - return MergeVarDeclExceptionSpecs(New, Old); + // If this is a member variable template, make sure the primary + // template has not been used. + // template struct A { + // template static constexpr int b = 3; + // template static constexpr int b = 30; + // int m[b]; + // }; + // template<> template + // constexpr int A::b = 10; + // + // The above is not fine since the partial specialization is used + // and when we explicitly specialize the primary template had it been + // seen before the use, it would have been used, and not the partial + // specialization. + if (IsMemberVariableTemplateBeingExplicitlySpecialized) { + VarTemplateDecl *NewVT = New->getDescribedVarTemplate(); + VarTemplateDecl *OldVT = Old->getDescribedVarTemplate(); + // The specialization that conflicts with this explicit + // specialization. + VarTemplateSpecializationDecl *InstConflictVSpec = nullptr; + const bool PrimaryTemplateWasUsedOrPartialSpecializationReferenced = + [OldVT, Old, &InstConflictVSpec](Sema & SemaRef) { + for (VarTemplateSpecializationDecl *VSpec : + OldVT->specializations()) { + + // If any specialization was referenced - we can + // not subsequently explicitly specialize the primary template. + + // If any specialization was instantiated using a partial + // specialization - it might have a different type, so we + // can not use it. + // FIXME: check the type, if it does have a diff type we can not + // explicitly specialize the primary template. Although, you + // would have to instantiate NewVT with the template arguments + // of VSpec to be sure - for now since this has not been + // discussed by core - if a specialization uses a non-explicitly + // specialized partial spec, we do not allow explicit spec of + // the primary. + + if (VSpec->isUsed() || + SemaRef.ConstexprVarTemplateSpecsValueUsed.count(VSpec) || + VSpec->getSpecializedTemplateOrPartial() + .is()) { + InstConflictVSpec = VSpec; + return true; + } + } + return false; + }(*this); + if (!PrimaryTemplateWasUsedOrPartialSpecializationReferenced) + return MergeVarDeclExceptionSpecs(New, Old); + else { + // Complain that we are trying to explicitly specialize a variable + // member template after it has already been used and its initializer + // has been instantiated! + // FIXME: In case of a partial specialization being referenced and + // then a primary template being explicitly specialized, the diagnostic + // is misleading. + SourceRange Range(New->getLocStart(), New->getLocEnd()); + Diag(New->getLocation(), diag::err_specialization_after_instantiation) + << New->getName() << Range; + + Diag(InstConflictVSpec->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << 0; + return New->setInvalidDecl(); + } + } else { + // These could still be something that needs exception specs checked. + return MergeVarDeclExceptionSpecs(New, Old); + } } // C++ [basic.link]p10: // [...] the types specified by all declarations referring to a given @@ -2882,6 +2970,38 @@ Old->getType()->isObjCObjectPointerType()) { MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType()); + } else if (IsMemberVariableTemplateBeingExplicitlySpecialized) { + // If we are adding an explicit specialization of a variable template, + // set the old type to the new type - only if the old template has + // not been instantiated - for e.g. + // template struct A { + // template static constexpr int b = 1; + // decltype(b) constexpr foo() { return 0; }; + // decltype(b) member; + // }; + // template<> template + // constexpr float A::b = 2.0; + // - When A is implicitly instantiated, prior to the new 'b' + // variable template being declared the old 'b' instantiated in + // A gets used in the definition of A and so can not + // be explicitly specialized again. + // FIXME: the diagnostic should state that a different specialization + // type is being specified. + VarTemplateDecl *OldVT = Old->getDescribedVarTemplate(); + if (OldVT->spec_begin() == OldVT->spec_end()) { + Old->setType(New->getType()); + return; + } + + VarTemplateSpecializationDecl *InstConflictVSpec = *OldVT->spec_begin(); + SourceRange Range(New->getLocStart(), New->getLocEnd()); + Diag(New->getLocation(), diag::err_specialization_after_instantiation) + << New->getName() << Range; + + Diag(InstConflictVSpec->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << 0; + return New->setInvalidDecl(); } } else { // C 6.2.7p2: @@ -3238,8 +3358,38 @@ CXXScopeSpec &SS = DS.getTypeSpecScope(); bool IsExplicitSpecialization = !TemplateParams.empty() && TemplateParams.back()->size() == 0; + + // We allow (re-)declarations of member template specializations at namespace + // scope. + // Per C++-N3936 [14.5.5 temp.class.spec]p5 + // A class template partial specialization may be declared or redeclared in + // any namespace scope in which its definition may be defined (14.5.1 and + // 14.5.2). + // template struct A { + // template struct B { }; + // }; + // template template struct A::B; #1 + // template<> template struct A::B; #2 + // template<> template<> struct A::B; #3 + const bool + IsMemberTemplateSpecializationDeclarationSansDefinition = [&Tag, &SS] { + const auto *const RD = dyn_cast_or_null(Tag); + if (RD && SS.isNotEmpty() && isa(RD->getDeclContext()) && + !RD->isCompleteDefinition()) { + // Catch #1, #2 above. + if (isa(RD)) + return true; + // Catch #3 above. + if (isa(RD) && + RD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return true; + } + return false; + }(); + if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() && - !IsExplicitInstantiation && !IsExplicitSpecialization) { + !IsExplicitInstantiation && !IsExplicitSpecialization && + !IsMemberTemplateSpecializationDeclarationSansDefinition) { // Per C++ [dcl.type.elab]p1, a class declaration cannot have a // nested-name-specifier unless it is an explicit instantiation // or an explicit specialization. @@ -5284,7 +5434,7 @@ : SourceLocation(); DeclResult Res = ActOnVarTemplateSpecialization( S, D, TInfo, TemplateKWLoc, TemplateParams, SC, - IsPartialSpecialization); + IsPartialSpecialization, TemplateParamLists); if (Res.isInvalid()) return 0; NewVD = cast(Res.get()); @@ -5506,9 +5656,16 @@ NewVD->setInvalidDecl(); } - if (!IsVariableTemplateSpecialization) + if (!IsVariableTemplateSpecialization) { D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); - + + // We must do this AFTER previous-decl links have been set through + // CheckVariableDeclaration, or else the common-stuff that should + // be reshared across redecls gets miswired. + if (IsExplicitSpecialization && NewTemplate) { + NewTemplate->setMemberSpecialization(); + } + } if (NewTemplate) { VarTemplateDecl *PrevVarTemplate = NewVD->getPreviousDecl() @@ -8288,10 +8445,36 @@ // 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 - ignore the previous initializer - + // but make sure that the new type is the same. + + if (const bool + IsNotAutoVarMemberTemplateBeingExplicitlySpecialized = + !([](Sema &SemaRef, VarDecl *VDecl) { + if (VarTemplateDecl *NewVT = + VDecl->getDescribedVarTemplate()) { + const bool IsMemberTemplateBeingExplicitlySpecialized = + NewVT->isMemberSpecialization(); + const bool IsAutoVarTemplate = + VDecl->getType()->getContainedAutoType(); + return IsMemberTemplateBeingExplicitlySpecialized && + IsAutoVarTemplate; + } + return false; + })(*this, VDecl)) { + Diag(Init->getExprLoc(), diag::err_static_data_member_reinitialization) + << VDecl->getDeclName(); + Diag(PrevInit->getInit()->getExprLoc(), diag::note_previous_initializer) << 0; + return; + } else { + // Adjust the initializer of the previous instantiated-from member decls + // since it has been supplanted by the explicit specialization. + for (auto *D : VDecl->redecls()) { + if (D == PrevInit) + D->setInit(Init); + } + } } if (VDecl->hasLocalStorage()) Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12276,6 +12276,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 @@ -2404,7 +2404,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."); @@ -2528,15 +2529,38 @@ 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; - + //assert((!HasEmptyTemplateParameterLists || !PrevPartial) && + // "Explicitly specialized partial specializations can not have " + // "previous declaration for variable templates, since each explicitly " + // "specialized partial specialization has to be a definition"); + 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 @@ -2564,6 +2588,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. @@ -2638,15 +2700,6 @@ 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, @@ -2676,10 +2729,9 @@ VarDecl *InstantiationPattern = Template->getTemplatedDecl(); TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); - TemplateArgumentList *InstantiationArgs = &TemplateArgList; - bool AmbiguousPartialSpec = false; - typedef PartialSpecMatchResult MatchResult; - SmallVector Matched; + const TemplateArgumentList *InstantiationArgs = &TemplateArgList; + + SourceLocation PointOfInstantiation = TemplateNameLoc; TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); @@ -2693,74 +2745,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; } } @@ -2775,18 +2776,8 @@ return true; 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; } @@ -5878,15 +5869,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; @@ -6124,13 +6110,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 @@ -6159,6 +6152,49 @@ } } } + // 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) { + 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. Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -4560,21 +4560,39 @@ return SpecEnd; } -/// \brief Returns the more specialized class template partial specialization -/// according to the rules of partial ordering of class template partial -/// specializations (C++ [temp.class.order]). -/// -/// \param PS1 the first class template partial specialization -/// -/// \param PS2 the second class template partial specialization -/// -/// \returns the more specialized class template partial specialization. If -/// neither partial specialization is more specialized, returns NULL. -ClassTemplatePartialSpecializationDecl * -Sema::getMoreSpecializedPartialSpecialization( - ClassTemplatePartialSpecializationDecl *PS1, - ClassTemplatePartialSpecializationDecl *PS2, - SourceLocation Loc) { +namespace { + struct GetMoreSpecializedPartialSpecializationImpl; +} +// Implementation details of getMoreSpecializedPartialSpecializationImpl +struct ::GetMoreSpecializedPartialSpecializationImpl{ + + static QualType getTypeOfPartialSpecialization( + ClassTemplatePartialSpecializationDecl *PS) { + return PS->getInjectedSpecializationType(); + } + + static QualType + getTypeOfPartialSpecialization(VarTemplatePartialSpecializationDecl *PS) { + TemplateName Name(PS->getSpecializedTemplate()); + ASTContext &Context = PS->getASTContext(); + TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); + return Context.getTemplateSpecializationType(CanonTemplate, + PS->getTemplateArgs().data(), + PS->getTemplateArgs().size()); + + } + + +}; + +template +PartialSpecializationDecl * +getMoreSpecializedPartialSpecializationImpl(PartialSpecializationDecl *PS1, + PartialSpecializationDecl *PS2, + SourceLocation Loc, Sema &SemaRef) { + + SmallVector Deduced; + TemplateDeductionInfo Info(Loc); // C++ [temp.class.order]p1: // For two class template partial specializations, the first is at least as // specialized as the second if, given the following rewrite to two @@ -4599,46 +4617,103 @@ // know that every template parameter is deducible from the class // template partial specialization's template arguments, for // example. - SmallVector Deduced; - TemplateDeductionInfo Info(Loc); + + QualType PT1 = GetMoreSpecializedPartialSpecializationImpl:: + getTypeOfPartialSpecialization(PS1); + QualType PT2 = GetMoreSpecializedPartialSpecializationImpl:: + getTypeOfPartialSpecialization(PS2); - QualType PT1 = PS1->getInjectedSpecializationType(); - QualType PT2 = PS2->getInjectedSpecializationType(); - // Determine whether PS1 is at least as specialized as PS2 Deduced.resize(PS2->getTemplateParameters()->size()); - bool Better1 = !DeduceTemplateArgumentsByTypeMatch(*this, + bool Better1 = !DeduceTemplateArgumentsByTypeMatch(SemaRef, PS2->getTemplateParameters(), PT2, PT1, Info, Deduced, TDF_None, /*PartialOrdering=*/true, /*RefParamComparisons=*/0); if (Better1) { SmallVector DeducedArgs(Deduced.begin(),Deduced.end()); - InstantiatingTemplate Inst(*this, Loc, PS2, DeducedArgs, Info); + Sema::InstantiatingTemplate Inst(SemaRef, Loc, PS2, DeducedArgs, Info); Better1 = !::FinishTemplateArgumentDeduction( - *this, PS2, PS1->getTemplateArgs(), Deduced, Info); + SemaRef, PS2, PS1->getTemplateArgs(), Deduced, Info); } // Determine whether PS2 is at least as specialized as PS1 Deduced.clear(); Deduced.resize(PS1->getTemplateParameters()->size()); bool Better2 = !DeduceTemplateArgumentsByTypeMatch( - *this, PS1->getTemplateParameters(), PT1, PT2, Info, Deduced, TDF_None, + SemaRef, PS1->getTemplateParameters(), PT1, PT2, Info, Deduced, TDF_None, /*PartialOrdering=*/true, /*RefParamComparisons=*/0); if (Better2) { SmallVector DeducedArgs(Deduced.begin(), Deduced.end()); - InstantiatingTemplate Inst(*this, Loc, PS1, DeducedArgs, Info); + Sema::InstantiatingTemplate Inst(SemaRef, Loc, PS1, DeducedArgs, Info); Better2 = !::FinishTemplateArgumentDeduction( - *this, PS1, PS2->getTemplateArgs(), Deduced, Info); + SemaRef, PS1, PS2->getTemplateArgs(), Deduced, Info); } + // Neither is better than the other, so if one is more specialized than the + // other based on the number of empty template parameter lists, choose that. + // This tie breaker can be used in such scenarios: + // + // template struct O { + // template struct L { + // int p; + // }; + // template struct L { + // int k; + // }; + // }; + // + // struct HasType { + // typedef HasType *type; + // }; + // + // template <> template struct O::L { + // int j; + // }; + // + // int x0 = O::L().j; + // In this instance, both partials make it through to this step since + // neither maps to a previous declaration of the other. + if (Better1 == Better2) { + auto GetPrototypePartialSpecialization = [](PartialSpecializationDecl *D) { + PartialSpecializationDecl *It = D; + while (It->getInstantiatedFromMember()) { + if (It->isMemberSpecialization()) + return It; + It = It->getInstantiatedFromMember(); + } + return It; + }; + unsigned NumOfEmptyTPLSin1 = SemaRef.getNumberOfEmptyTemplateParameterLists( + GetPrototypePartialSpecialization(PS1)); + unsigned NumOfEmptyTPLSin2 = SemaRef.getNumberOfEmptyTemplateParameterLists( + GetPrototypePartialSpecialization(PS2)); + if (NumOfEmptyTPLSin1 == NumOfEmptyTPLSin2) + return 0; + else + return (NumOfEmptyTPLSin1 > NumOfEmptyTPLSin2) ? PS1 : PS2; + } - if (Better1 == Better2) - return 0; - return Better1 ? PS1 : PS2; } +/// \brief Returns the more specialized class template partial specialization +/// according to the rules of partial ordering of class template partial +/// specializations (C++ [temp.class.order]). +/// +/// \param PS1 the first class template partial specialization +/// +/// \param PS2 the second class template partial specialization +/// +/// \returns the more specialized class template partial specialization. If +/// neither partial specialization is more specialized, returns NULL. +ClassTemplatePartialSpecializationDecl * +Sema::getMoreSpecializedPartialSpecialization( + ClassTemplatePartialSpecializationDecl *PS1, + ClassTemplatePartialSpecializationDecl *PS2, + SourceLocation Loc) { + return getMoreSpecializedPartialSpecializationImpl(PS1, PS2, Loc, *this); +} /// TODO: Unify with ClassTemplatePartialSpecializationDecl version? /// May require unifying ClassTemplate(Partial)SpecializationDecl and @@ -4649,56 +4724,11 @@ Sema::getMoreSpecializedPartialSpecialization( VarTemplatePartialSpecializationDecl *PS1, VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc) { - SmallVector Deduced; - TemplateDeductionInfo Info(Loc); - + assert(PS1->getSpecializedTemplate() == PS2->getSpecializedTemplate() && "the partial specializations being compared should specialize" - " the same template."); - TemplateName Name(PS1->getSpecializedTemplate()); - TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); - QualType PT1 = Context.getTemplateSpecializationType( - CanonTemplate, PS1->getTemplateArgs().data(), - PS1->getTemplateArgs().size()); - QualType PT2 = Context.getTemplateSpecializationType( - CanonTemplate, PS2->getTemplateArgs().data(), - PS2->getTemplateArgs().size()); - - // Determine whether PS1 is at least as specialized as PS2 - Deduced.resize(PS2->getTemplateParameters()->size()); - bool Better1 = !DeduceTemplateArgumentsByTypeMatch( - *this, PS2->getTemplateParameters(), PT2, PT1, Info, Deduced, TDF_None, - /*PartialOrdering=*/true, - /*RefParamComparisons=*/0); - if (Better1) { - SmallVector DeducedArgs(Deduced.begin(), - Deduced.end()); - InstantiatingTemplate Inst(*this, Loc, PS2, DeducedArgs, Info); - Better1 = !::FinishTemplateArgumentDeduction(*this, PS2, - PS1->getTemplateArgs(), - Deduced, Info); - } - - // Determine whether PS2 is at least as specialized as PS1 - Deduced.clear(); - Deduced.resize(PS1->getTemplateParameters()->size()); - bool Better2 = !DeduceTemplateArgumentsByTypeMatch(*this, - PS1->getTemplateParameters(), - PT1, PT2, Info, Deduced, TDF_None, - /*PartialOrdering=*/true, - /*RefParamComparisons=*/0); - if (Better2) { - SmallVector DeducedArgs(Deduced.begin(),Deduced.end()); - InstantiatingTemplate Inst(*this, Loc, PS1, DeducedArgs, Info); - Better2 = !::FinishTemplateArgumentDeduction(*this, PS1, - PS2->getTemplateArgs(), - Deduced, Info); - } - - if (Better1 == Better2) - return 0; - - return Better1? PS1 : PS2; + " the same template."); + return getMoreSpecializedPartialSpecializationImpl(PS1, PS2, Loc, *this); } static void Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -31,6 +31,10 @@ // Template Instantiation Support //===----------------------------------------------------------------------===/ +//===----------------------------------------------------------------------===/ +// Template Instantiation Support +//===----------------------------------------------------------------------===/ + /// \brief Retrieve the template argument list(s) that should be used to /// instantiate the definition of the given declaration. /// @@ -48,20 +52,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,12 @@ Instantiation->setInvalidDecl(); continue; } + // Do not eagerly transform partial specialization declarations. + Decl *NewMember = nullptr; + if (!isa(Member) && + !isa(Member)) + NewMember = Instantiator.Visit(Member); - Decl *NewMember = Instantiator.Visit(Member); if (NewMember) { if (FieldDecl *Field = dyn_cast(NewMember)) { Fields.push_back(Field); @@ -2077,32 +2118,6 @@ if (!Instantiation->isInvalidDecl()) { // Perform any dependent diagnostics from the pattern. PerformDependentDiagnostics(Pattern, TemplateArgs); - - // Instantiate any out-of-line class template partial - // specializations now. - for (TemplateDeclInstantiator::delayed_partial_spec_iterator - P = Instantiator.delayed_partial_spec_begin(), - PEnd = Instantiator.delayed_partial_spec_end(); - P != PEnd; ++P) { - if (!Instantiator.InstantiateClassTemplatePartialSpecialization( - P->first, P->second)) { - Instantiation->setInvalidDecl(); - break; - } - } - - // Instantiate any out-of-line variable template partial - // specializations now. - for (TemplateDeclInstantiator::delayed_var_partial_spec_iterator - P = Instantiator.delayed_var_partial_spec_begin(), - PEnd = Instantiator.delayed_var_partial_spec_end(); - P != PEnd; ++P) { - if (!Instantiator.InstantiateVarTemplatePartialSpecialization( - P->first, P->second)) { - Instantiation->setInvalidDecl(); - break; - } - } } // Exit the scope of this instantiation. @@ -2182,14 +2197,467 @@ } namespace { - /// \brief A partial specialization whose template arguments have matched - /// a given template-id. + // Help map types from Class/Var Partial specailizations back to their + // template decls - without requiring an inheritance relationship. + struct TemplateDeclTypeMapper { + static VarTemplateDecl + getTypeOfPrimaryTemplate(VarTemplatePartialSpecializationDecl *); + static ClassTemplateDecl + getTypeOfPrimaryTemplate(ClassTemplatePartialSpecializationDecl *); + static CXXRecordDecl getTypeOfPatternDecl(ClassTemplateDecl *); + static ClassTemplatePartialSpecializationDecl + getTypeOfPartialSpecializationDecl(ClassTemplateDecl *); + static ClassTemplateSpecializationDecl + getTypeOfExplicitSpecializationDecl(ClassTemplateDecl *); + + static VarDecl getTypeOfPatternDecl(VarTemplateDecl *); + static VarTemplatePartialSpecializationDecl + getTypeOfPartialSpecializationDecl(VarTemplateDecl *); + static VarTemplateSpecializationDecl + getTypeOfExplicitSpecializationDecl(VarTemplateDecl *); + static ClassTemplateDecl *getDescribedTemplate(const CXXRecordDecl *D) { + return D->getDescribedClassTemplate(); + } + static VarTemplateDecl *getDescribedTemplate(const VarDecl *D) { + return D->getDescribedVarTemplate(); + } + }; +} + +template +std::tuple(nullptr))) *> +getInnermostTemplateParameterListAndPatternDecl(const Decl *D) { + typedef decltype(TemplateDeclTypeMapper::getTypeOfPatternDecl( + static_cast(nullptr))) PatternDecl; + + typedef decltype(TemplateDeclTypeMapper::getTypeOfPartialSpecializationDecl( + static_cast(nullptr))) PartialSpecializationDecl; + + typedef decltype(TemplateDeclTypeMapper::getTypeOfExplicitSpecializationDecl( + static_cast(nullptr))) ExplicitSpecializationDecl; + + TemplateParameterList *InnerMostTPL = nullptr; + const PatternDecl *PatternD = nullptr; + + if (auto *TD = dyn_cast(D)) { + InnerMostTPL = TD->getTemplateParameters(); + PatternD = TD->getTemplatedDecl(); + } else if (auto *PSD = dyn_cast(D)) { + InnerMostTPL = PSD->getTemplateParameters(); + PatternD = PSD; + } else if (auto *ESD = dyn_cast(D)) { + if (ESD->isExplicitSpecialization()) { + // If this was declared as an explicit specialization, all the TPLs + // are included in the getTemplateParameterList(i) info... + InnerMostTPL = 0; + PatternD = ESD; + } else { + ESD->dump(); + llvm_unreachable("A pattern declaration can not be a non-explicit " + "Class/VarTemplateSpecializationDecl"); + } + } else if (auto *PD = dyn_cast(D)) { + if (PrimaryTemplateDecl *TD = + TemplateDeclTypeMapper::getDescribedTemplate(PD)) { + PatternD = PD; + InnerMostTPL = TD->getTemplateParameters(); + } + } + return std::make_tuple(InnerMostTPL, PatternD); +} + +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); + + // 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. + if (PatternDecl.is()) { + auto *PatternDecl2 = PatternDecl.get(); + for (unsigned I = 0; I != PatternDecl2->getNumTemplateParameterLists(); + ++I) + TPLs.push_back(PatternDecl2->getTemplateParameterList(I)); + } else { + auto *PatternDecl2 = PatternDecl.get(); + for (unsigned I = 0; I != PatternDecl2->getNumTemplateParameterLists(); + ++I) + TPLs.push_back(PatternDecl2->getTemplateParameterList(I)); + + } + } + 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 PartialSpecializationFinder; +} + +// 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 ::PartialSpecializationFinder { + + typedef decltype(TemplateDeclTypeMapper::getTypeOfPrimaryTemplate( + static_cast(nullptr))) PrimaryTemplateDecl; + + typedef decltype(TemplateDeclTypeMapper::getTypeOfExplicitSpecializationDecl( + static_cast(nullptr))) TemplateSpecializationDecl; + + Sema &SemaRef; + PrimaryTemplateDecl *const TemplateBeingInstantiated; + CXXRecordDecl *const ParentClassOfTemplateBeingInstantiated; + struct PartialSpecMatchResult { - ClassTemplatePartialSpecializationDecl *Partial; - TemplateArgumentList *Args; + PartialSpecializationDecl *const Partial; + TemplateArgumentList *const Args; + PartialSpecMatchResult() : Partial(nullptr), Args(nullptr) { } + PartialSpecMatchResult(PartialSpecializationDecl *Partial, + TemplateArgumentList *Args) + : Partial(Partial), Args(Args) {} }; + + +public: + PartialSpecializationFinder( + Sema &S, PrimaryTemplateDecl *CurTemplate) + : SemaRef(S), TemplateBeingInstantiated(CurTemplate), + ParentClassOfTemplateBeingInstantiated( + isa(CurTemplate->getDeclContext()) + ? cast(CurTemplate->getDeclContext()) + ->getCanonicalDecl() + : 0) {} + + typedef SmallVector SpecVectorTy; + PartialSpecializationDecl *substOuterTemplateArgs( + PartialSpecializationDecl *APSpec, + SourceLocation PointOfInstantiation) const { + + 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 + // 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(APSpec)); + } + +private: + // Iterate through all Ancestor templates and find all partial + // specializations from each one. + SpecVectorTy getAllPartialSpecializationsFromAncestorTemplates() const { + + SmallVector AllPartialSpecs; + PrimaryTemplateDecl *TemplateIt = TemplateBeingInstantiated; + while (PrimaryTemplateDecl *const AncestorTemplate = + TemplateIt->getInstantiatedFromMemberTemplate()) { + SpecVectorTy PSpecs; + AncestorTemplate->getPartialSpecializations(PSpecs); + AllPartialSpecs.append(PSpecs.begin(), PSpecs.end()); + TemplateIt = AncestorTemplate; + } + 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 (PartialSpecializationDecl *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 *PSD = cast_or_null( + DeclInstantiator.Visit(APSpec))) { + */ + if (PartialSpecializationDecl *PSD = + substOuterTemplateArgs(APSpec, PointOfInstantiation)) { + RelevantPartialSpecs.push_back(PSD); + } + } + return RelevantPartialSpecs; + } + + /// \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). + 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; + } + + // 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); + } + +public: + PartialSpecMatchResult getBestPartialSpecialization( + bool &Ambiguous, const TemplateArgumentList &TemplateArgs, + SourceLocation PointOfInstantiation) { + SpecVectorTy 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 = + PartialSpecializationFinder( + *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 = + PartialSpecializationFinder( + *this, Template).getBestPartialSpecialization(Ambiguous, TemplateArgs, + PointOfInstantiation); + return std::make_tuple(PartialSpecAndTemplateArgs.Partial, + PartialSpecAndTemplateArgs.Args, Ambiguous); +} + + bool Sema::InstantiateClassTemplateSpecialization( SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, @@ -2228,8 +2696,7 @@ return true; ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate(); - CXXRecordDecl *Pattern = 0; - + // C++ [temp.class.spec.match]p1: // When a class template is used in a context that requires an // instantiation of the class, it is necessary to determine @@ -2238,93 +2705,21 @@ // matching the template arguments of the class template // specialization with the template argument lists of the partial // specializations. - typedef PartialSpecMatchResult MatchResult; - SmallVector Matched; - SmallVector PartialSpecs; - Template->getPartialSpecializations(PartialSpecs); - TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); - for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { - ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; - TemplateDeductionInfo Info(FailedCandidates.getLocation()); - if (TemplateDeductionResult Result - = DeduceTemplateArguments(Partial, - ClassTemplateSpec->getTemplateArgs(), - Info)) { - // Store the failed-deduction information for use in diagnostics, later. - // TODO: Actually use the failed-deduction info? - FailedCandidates.addCandidate() - .set(Partial, MakeDeductionFailureInfo(Context, Result, Info)); - (void)Result; - } else { - Matched.push_back(PartialSpecMatchResult()); - Matched.back().Partial = Partial; - Matched.back().Args = Info.take(); - } + ClassTemplatePartialSpecializationDecl *BestPartialSpec = nullptr; + const TemplateArgumentList *BestPartialDeducedArgs = nullptr; + bool PartialSpecIsAmbiguous = false; + std::tie(BestPartialSpec, BestPartialDeducedArgs, PartialSpecIsAmbiguous) = + getMostSpecializedPartialSpecialization( + Template, ClassTemplateSpec->getTemplateArgs(), PointOfInstantiation); + if (PartialSpecIsAmbiguous) { + ClassTemplateSpec->setInvalidDecl(); + return true; } - - // If we're dealing with a member template where the template parameters - // have been instantiated, this provides the original template parameters - // from which the member template's parameters were instantiated. - - if (Matched.size() >= 1) { - SmallVectorImpl::iterator Best = Matched.begin(); - if (Matched.size() == 1) { - // -- If exactly one matching specialization is found, the - // instantiation is generated from that specialization. - // We don't need to do anything for this. - } else { - // -- If more than one matching specialization is found, the - // partial order rules (14.5.4.2) are used to determine - // whether one of the specializations is more specialized - // than the others. If none of the specializations is more - // specialized than all of the other matching - // specializations, then the use of the class template is - // ambiguous and the program is ill-formed. - for (SmallVectorImpl::iterator P = Best + 1, - PEnd = Matched.end(); - P != PEnd; ++P) { - if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, - PointOfInstantiation) - == P->Partial) - Best = P; - } - - // Determine if the best partial specialization is more specialized than - // the others. - bool Ambiguous = false; - for (SmallVectorImpl::iterator P = Matched.begin(), - PEnd = Matched.end(); - P != PEnd; ++P) { - if (P != Best && - getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, - PointOfInstantiation) - != Best->Partial) { - Ambiguous = true; - break; - } - } - - if (Ambiguous) { - // Partial ordering did not produce a clear winner. Complain. - ClassTemplateSpec->setInvalidDecl(); - Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous) - << ClassTemplateSpec; - - // Print the matching partial specializations. - for (SmallVectorImpl::iterator P = Matched.begin(), - PEnd = Matched.end(); - P != PEnd; ++P) - Diag(P->Partial->getLocation(), diag::note_partial_spec_match) - << getTemplateArgumentBindingsText( - P->Partial->getTemplateParameters(), - *P->Args); - - return true; - } - } - + CXXRecordDecl *Pattern = 0; + if (BestPartialSpec) { // Instantiate using the best class template partial specialization. - ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->Partial; + ClassTemplatePartialSpecializationDecl *OrigPartialSpec = + BestPartialSpec; while (OrigPartialSpec->getInstantiatedFromMember()) { // If we've found an explicit specialization of this class template, // stop here and use that as the pattern. @@ -2335,7 +2730,8 @@ } Pattern = OrigPartialSpec; - ClassTemplateSpec->setInstantiationOf(Best->Partial, Best->Args); + ClassTemplateSpec->setInstantiationOf(BestPartialSpec, + BestPartialDeducedArgs); } else { // -- If no matches are found, the instantiation is generated // from the primary template. @@ -2352,11 +2748,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 @@ -965,18 +965,6 @@ } Owner->addDecl(Inst); - - if (!PrevClassTemplate) { - // Queue up any out-of-line partial specializations of this member - // class template; the client will force their instantiation once - // the enclosing class has been instantiated. - SmallVector PartialSpecs; - D->getPartialSpecializations(PartialSpecs); - for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) - if (PartialSpecs[I]->getFirstDecl()->isOutOfLine()) - OutOfLinePartialSpecs.push_back(std::make_pair(Inst, PartialSpecs[I])); - } - return Inst; } @@ -1048,18 +1036,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; } @@ -2699,30 +2675,6 @@ InstTemplateArgs, CanonType); - if (PrevDecl) { - // We've already seen a partial specialization with the same template - // parameters and template arguments. This can happen, for example, when - // substituting the outer template arguments ends up causing two - // class template partial specializations of a member class template - // to have identical forms, e.g., - // - // template - // struct Outer { - // template struct Inner; - // template struct Inner; - // template struct Inner; - // }; - // - // Outer outer; // error: the partial specializations of Inner - // // have the same signature. - SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared) - << WrittenTy->getType(); - SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here) - << SemaRef.Context.getTypeDeclType(PrevDecl); - return 0; - } - - // Create the class template partial specialization declaration. ClassTemplatePartialSpecializationDecl *InstPartialSpec = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, @@ -2743,10 +2695,6 @@ InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); - - // Add this partial specialization to the set of class template partial - // specializations. - ClassTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0); return InstPartialSpec; } @@ -2817,31 +2765,6 @@ TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo( TemplateName(VarTemplate), PartialSpec->getLocation(), InstTemplateArgs, CanonType); - - if (PrevDecl) { - // We've already seen a partial specialization with the same template - // parameters and template arguments. This can happen, for example, when - // substituting the outer template arguments ends up causing two - // variable template partial specializations of a member variable template - // to have identical forms, e.g., - // - // template - // struct Outer { - // template pair p; - // template pair p; - // template pair p; - // }; - // - // Outer outer; // error: the partial specializations of Inner - // // have the same signature. - SemaRef.Diag(PartialSpec->getLocation(), - diag::err_var_partial_spec_redeclared) - << WrittenTy->getType(); - SemaRef.Diag(PrevDecl->getLocation(), - diag::note_var_prev_partial_spec_here); - return 0; - } - // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType( PartialSpec->getTypeSourceInfo(), TemplateArgs, @@ -2873,8 +2796,7 @@ // Add this partial specialization to the set of variable template partial // specializations. The instantiation of the initializer is not necessary. - VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0); - + SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs, LateAttrs, Owner, StartingScope); @@ -3726,9 +3648,7 @@ VarTemplateSpecializationDecl *VarSpec = dyn_cast(Var); VarDecl *PatternDecl = 0, *Def = 0; - MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Var); - + MultiLevelTemplateArgumentList TemplateArgs; if (VarSpec) { // If this is a variable template specialization, make sure that it is // non-dependent, then find its instantiation pattern. @@ -3747,9 +3667,60 @@ llvm::PointerUnion PatternPtr = VarSpec->getSpecializedTemplateOrPartial(); - if (PatternPtr.is()) { + // 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*/); + + 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; + } + } + } + + if (NewPartialSpec || PatternPtr.is()) { VarTemplatePartialSpecializationDecl *Tmpl = - PatternPtr.get(); + NewPartialSpec + ? NewPartialSpec + : PatternPtr.get(); while (VarTemplatePartialSpecializationDecl *From = Tmpl->getInstantiatedFromMember()) { if (Tmpl->isMemberSpecialization()) @@ -3770,6 +3741,11 @@ 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 // it now. @@ -3839,6 +3815,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 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,826 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -emit-llvm-only %s +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fms-extensions %s -DMS_EXTENSIONS +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING + + + +namespace out_of_class_explicit_specialization_that_is_a_partial_spec_declaration { +template struct A { + template struct B {}; + template struct B : B { + template struct C; + template struct C { }; + }; +}; + +template<> template<> template +struct A::B::C { + typedef int type; +}; + +A::B::C::type abc; //expected-error {{no type}} +A::B::C::type use_out_of_class_partial_spec; + +} // end ns + +namespace test_if_explicit_partial_specializations_are_used { +template struct A { + template struct B {}; + template struct B : B { + template struct C { }; + }; +}; + +template<> template struct A::B { + typedef char type2; +}; + +template<> template struct A::B : B { + typedef int type3; +}; + + +A::B::type2 x1; +A::B::type3 x2; +A::B::type2 x3; + +A::B::type x4; //expected-error{{type}} +namespace swap_order_of_primary_and_partial { +template struct A { + template struct B {}; + template struct B : B { + template struct C { }; + }; +}; + + +template<> template struct A::B : B { + typedef int type3; +}; + +template<> template struct A::B { + typedef char type2; +}; + + +A::B::type2 x1; +A::B::type3 x2; +A::B::type2 x3; + +A::B::type x4; //expected-error{{type}} + +}// end ns + +} // end ns + + +namespace test_no_out_class_primary { +template struct A { + template struct B { int in_primary; }; + template struct B { + int in_partial3; + }; +}; + +template<> template struct A::B { + int out_int_partial1; +}; + +template<> template struct A::B { + int out_int_partial2; +}; + +template template struct A::B { + int out_partial4; +}; +//int x0 = A::B().out_int_primary; +int x0 = A::B().in_primary; +int x1 = A::B().out_int_partial1; +int x2 = A::B().out_int_partial2; +int x3 = A::B().in_partial3; +int x4 = A::B().out_partial4; +} + + +namespace test_out_class_primary_106_102 { +template struct A { + template struct B { int in_primary; }; + template struct B { + int in_partial3; + }; +}; + +template<> template struct A::B { + int out_int_primary; +}; +template<> template struct A::B { + int out_int_partial1; +}; + +template<> template struct A::B { + int out_int_partial2; +}; + +template template struct A::B { + int out_partial4; +}; +int x0 = A::B().out_int_primary; +int x1 = A::B().out_int_partial1; +int x2 = A::B().out_int_partial2; +int x3 = A::B().out_int_partial2; +int x4 = A::B().out_int_partial2; +namespace try_char_instead_of_int { +int x0 = A::B().in_primary; +int x1 = A::B().in_primary; +int x2 = A::B().in_primary; +int x3 = A::B().in_partial3; +int x4 = A::B().out_partial4; + +} //end inner ns +} + + +namespace test_out_class_primary_swap_order_106 { +template struct A { + template struct B { int in_primary; }; + template struct B { + int in_partial3; + }; +}; + +template<> template struct A::B { + int out_int_partial1; +}; + + +template<> template struct A::B { + int out_int_primary; +}; + +template<> template struct A::B { + int out_int_partial2; +}; + +template template struct A::B { + int out_partial4; +}; +int x0 = A::B().out_int_primary; +int x1 = A::B().out_int_partial1; +int x2 = A::B().out_int_partial2; +int x3 = A::B().out_int_partial2; +int x4 = A::B().out_int_partial2; + +namespace try_char_instead_of_int { +int x0 = A::B().in_primary; +int x1 = A::B().in_primary; +int x2 = A::B().in_primary; +int x3 = A::B().in_partial3; +int x4 = A::B().out_partial4; + +} //end inner ns +} + +namespace test_nested_member_partial_specs_3deep_180 { +template struct X { + template struct Y { + template struct Z { + int l; + }; + template struct Z { + int k; + }; + }; + }; + + template + template + template + struct X::Y::Z { + int j; + }; + + template<>template<> + template + struct X::Y::Z { + int i; + }; + + void a() + { + int x = X::Y::Z<0,int>().k; + x = X::Y::Z<0,int>().k; + x = X::Y::Z<0,char>().i; + x = X::Y::Z<0,char*>().j; + + } +} // end ns + + +namespace test_nested_member_partial_specs_3deep_180_swap_order1 { + template struct X { + template struct Y { + template struct Z { + int l; + }; + template struct Z { + int k; + }; + }; + }; + + template<>template<> + template + struct X::Y::Z { + int i; + }; + + template + template + template + struct X::Y::Z { + int j; + }; + + void a() + { + int x = X::Y::Z<0,int>().k; + x = X::Y::Z<0,int>().k; + x = X::Y::Z<0,char>().i; + x = X::Y::Z<0,char*>().j; + + } +} // end ns + +namespace test_no_instantiation_of_partial_specs_if_primary_is_specialized { + +template struct O { + template struct L; + //template struct L { int k; }; +}; + + +struct HasType { typedef HasType* type; }; +struct HasNoType { }; + +template template +struct O::L { int k; }; + + +template<> template +struct O::L { + int j; +}; + +int x0 = O::L().j; +int x1 = O::L().k; +} + + +namespace test_no_instantiation_of_partial_specs_if_primary_is_specialized_2 { + +template struct O { + template struct L; + template struct L { int k; }; +}; + + +struct HasType { typedef HasType* type; }; +struct HasNoType { }; + + +//template<> template +//struct O::L { int j; }; + +template template +struct O::L { int k; }; + +template<> template +struct O::L { + int l; +}; + +template<> template +struct O::L { + int j; +}; + + +//template +//template +//struct O::L { int k; }; + +//template<> template +//struct O::L { int j; }; + +int x0 = O::L().l; +int x1 = O::L().j; + +} + +namespace test_select_explicitly_specialized_partial_member_specs_if_ambiguous_317 { + +template struct O { + template struct L; + template struct L { int k; }; +}; + + +struct HasType { typedef HasType* type; }; +struct HasNoType { }; + + +template<> template +struct O::L { int j; }; + +template template +struct O::L { int k; }; + +template<> template +struct O::L { + int l; +}; + +template<> template +struct O::L { + int m; +}; + + +//template +//template +//struct O::L { int k; }; + +//template<> template +//struct O::L { int j; }; + +int x0 = O::L().j; +int x1 = O::L().m; + +} + + +namespace test_similar_partial_specs_if_but_use_explicit_specialized_359 { + +template struct O { + template struct L { int p; }; + template struct L { int k; }; +}; + + +struct HasType { typedef HasType* type; }; +struct HasNoType { }; + + +//template<> template +//struct O::L { int j; }; + +template template +struct O::L { int k2; }; + +template<> template +struct O::L { + int j; +}; + + +//template +//template +//struct O::L { int k; }; + +//template<> template +//struct O::L { int j; }; + +int x0 = O::L().j; +int x1 = O::L().p; +int x2 = O::L().p; +} + +namespace check_redefinitions { + +namespace ns1 { + +template struct O { + template struct L; + template struct L { int k; }; //expected-note{{previous definition}} +}; + +template template +struct O::L { //expected-error{{redefinition}} + int k; +}; + +} // end ns + + +namespace ns2 { + +template struct O { + template struct L; + template struct L { int k; }; +}; + +template<> +template +struct O::L { //expected-note{{previous}} + +}; +template<> +template +struct O::L { //expected-error{{redefinition}} + int k; +}; + +} // end ns + +} // end ns check_redefinitions + + +namespace TEST_PARTIAL_SPECS_434 { +template struct A { + template struct B { + U* u1; + }; + template struct C { + U1 *u1; + U2 *u2; + }; +}; + +template<> +template +struct A::B; +template<> +template +struct A::B { + U* u2; +}; +template<> +template +struct A::B; + +template +template +struct A::B; +template +template +struct A::B { + U* u3; +}; +template +template +struct A::B; + +template +template +struct A::B { + U* u4; +}; + +template<> +template +struct A::B { + U* u5; +}; +char *x1 = A::B{}.u5; +char *x2 = A::B{}.u2; +char *x3 = A::B{}.u4; + +template +template +struct A::C { + U1 *u3; +}; + +template +template +struct A::C { + U1 *u4; +}; + +char *x4 = A::C{}.u3; +struct HasType { + using type = int; +}; +char *x5 = A::C{}.u4; + +template template +struct A::B; + +template template +struct A::B { }; + +template<> template +struct A::B { + U* u510; +}; + +template<> template +struct A::B { + U* u515; +}; +char ***x6 = A::B{}.u515; + +} + + +namespace variable_template_tests { + +namespace ns1 { +template struct X { }; + +template +struct A { + template + static X u1; +}; + +template +template +X A::u1 = X{}; + +template +template +X A::u1 = X{}; + +template<> +template +X A::u1 = X{}; + +template<> +template +X A::u1 = X{}; + +template<> +template +X A::u1 = X{}; + +template +template +X A::u1 = X{}; + +X a1 = A::u1; +// choose the explicitly specialized partial specialization template +X a2 = A::u1; +X a479 = A::u1; +X a480 = A::u1; +X a481 = A::u1; +X a482 = A::u1; +X a483 = A::u1; +} + +namespace test_52_fv { +template struct X { }; + +template +struct A { + template + static constexpr X u1 = X{}; + auto f() { return u1; } +}; + +template<> template +constexpr X A::u1 = X{}; +template template +constexpr X A::u1 = X{}; + + +template<> template +constexpr X A::u1 = X{}; + + +X x65 = A::u1; +X x65_1 = A::u1; + +X x65_2 = A::u1; + + +X x67 = A::u1; + +X x70 = A{}.f(); +} + + +namespace test_explicit_spec_of_var_template { +template struct X { }; + +template +struct A { + template + static constexpr X u1 = X{}; + template + static constexpr X u1 = X{}; +}; + +template<> template +constexpr X A::u1 = X{}; + +template template +constexpr X A::u1; +template<> template +constexpr X A::u1 = X{}; + + +template template +constexpr X A::u1 = X{}; + + +template<> template +constexpr X A::u1 = X{}; + + +X x65 = A::u1; +X x65_1 = A::u1; + +X x65_2 = A::u1; +X x110 = A::u1; +X x116 = A::u1; +} + +namespace ns641_variable_templates { +template struct X { int n; X(int n) : n(n) { } }; + +template +struct A { + template + static X u1; + + using ptrtype = decltype(u1); //expected-note{{required here}} + + ptrtype foo() const { return u1; } +}; + +template<> template +X A::u1 = X{2}; //expected-error{{after instantiation}} + + +} + +} + +namespace vt_use_primary_template_before_explicit_specialization { +namespace ns1 { +template +struct A { + template + static constexpr int u1 = 1; + + int arr[u1]; //expected-note{{required here}} +}; + +template<> template +constexpr int A::u1 = 2; //expected-error{{after instantiation}} +} //end ns1 + +namespace ns2 { + +template +struct A { + template + static constexpr int u1 = 1; + template + static constexpr double u1 = 10; + + decltype(u1) member; //expected-note{{required here}} +}; + +template<> template +constexpr int A::u1 = 2; //expected-error{{after instantiation}} + +} + + +namespace ns3 { +template +struct A { + template + static constexpr int u1 = 1; + template + static constexpr int u1 = 10; + + //decltype(u1) member; + decltype(u1) member2; +}; + +template<> template +constexpr int A::u1 = 2; + +} + +namespace specialize_with_same_type { + +template +struct A { + template + static T u1; + + decltype(u1) member2; + +}; +template template +T A::u1 = 1; + +template<> template +short A::u1 = 2; // this is ok because same type +} + +namespace specialize_with_same_template_type { +template struct X { }; + +template +struct A { + template + static X u1; + decltype(u1) member2; +}; + +template template +X A::u1 = X{}; + +//template template +//X A::u1 = X{}; + + +template<> template +X A::u1 = X{}; // this is ok because same type +} +} + +namespace variable_templates_713 { +namespace auto_deduce_to_same_type { + +template +struct A { + template + static T u1; + + decltype(u1) member2; //expected-note{{required here}} + +}; +template template +T A::u1 = 1; + +template<> template +auto A::u1 = 2; + +template<> template +auto A::u1 = 2.0; //expected-error{{after instantiation}} + +} // end ns + +namespace auto_deduce_to_same_type2 { + + +template +struct A { + template + static constexpr auto u1 = 1; + + decltype(u1) member2; //expected-note{{required here}} + +}; + +template<> template +constexpr auto A::u1 = 3; + +template<> template +constexpr auto A::u1 = 3.0; //expected-error{{after instantiation}} + +namespace multiple_decls_and_lambda_as_member { + +template +struct A { + template + static int L; +}; + +template template +int A::L = 0; + +template template +auto A::L = [](T *, U *u) { return u; }; + +char *pc = A::L((int *)0, (char*)0); +} +} + +namespace cannot_define_partial_specs_twice { + +template +struct A { + template + static constexpr U u1 = 1; + template + static constexpr U u1 = 2; +}; + +template<> template +int A::u1; //expected-note{{previous definition}} + +template<> template +int A::u1 = 5; //expected-error{{redefinition}} + +} + +} \ No newline at end of file