Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3392,6 +3392,8 @@ def note_specialized_decl : Note<"attempt to specialize declaration here">; def err_specialization_after_instantiation : Error< "explicit specialization of %0 after instantiation">; +def err_part_specialization_after_instantiation : Error< + "partial specialization of %0 after instantiation">; def note_instantiation_required_here : Note< "%select{implicit|explicit}0 instantiation first required here">; def err_template_spec_friend : Error< Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -6217,6 +6217,39 @@ CanonType = Context.getTypeDeclType(Specialization); } + // C++ [temp.class.spec]p1: + // A partial specialization shall be declared before the first use of a class + // template specialization that would make use of partial specialization as + // the result of an implicit or explicit instantiation in every translation + // unit in which such a use occurs; no diagnostic is required. + if (isPartialSpecialization) { + auto *const ThisPartialSpec = + static_cast(Specialization); + for (auto S = ClassTemplate->spec_begin(), SEnd = ClassTemplate->spec_end(); + S != SEnd; ++S) { + TemplateDeductionInfo Info(KWLoc); + if (S->getSpecializationKind() != TSK_ExplicitSpecialization && + S->hasDefinition() && + !DeduceTemplateArguments(ThisPartialSpec, S->getTemplateArgs(), Info)) { + auto *const InstantiatedFrom = + S->getInstantiatedFrom() + .dyn_cast(); + if (!InstantiatedFrom || + getMoreSpecializedPartialSpecialization( + ThisPartialSpec, InstantiatedFrom, KWLoc) == ThisPartialSpec) { + SourceRange Range(TemplateNameLoc, RAngleLoc); + Diag(TemplateNameLoc, diag::err_part_specialization_after_instantiation) + << Context.getTypeDeclType(ThisPartialSpec) << Range; + + Diag(S->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << (S->getTemplateSpecializationKind() != + TSK_ImplicitInstantiation); + } + } + } + } + // C++ [temp.expl.spec]p6: // If a template, a member template or the member of a class template is // explicitly specialized then that specialization shall be declared