From dc0a11cf52cf34ffae941255df60a086e44d1a71 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 26 Feb 2010 06:03:23 +0000 Subject: [PATCH] An explicit specialization is allowed following an explicit instantiation so long as that explicit specialization was declared previously. Fixes PR6160. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97210 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaTemplate.cpp | 48 ++++++++++++++++--- test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp | 7 +++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index c98f88f86a..c10b12b2da 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3242,6 +3242,23 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( return false; } +/// \brief Retrieve the previous declaration of the given declaration. +static NamedDecl *getPreviousDecl(NamedDecl *ND) { + if (VarDecl *VD = dyn_cast(ND)) + return VD->getPreviousDeclaration(); + if (FunctionDecl *FD = dyn_cast(ND)) + return FD->getPreviousDeclaration(); + if (TagDecl *TD = dyn_cast(ND)) + return TD->getPreviousDeclaration(); + if (TypedefDecl *TD = dyn_cast(ND)) + return TD->getPreviousDeclaration(); + if (FunctionTemplateDecl *FTD = dyn_cast(ND)) + return FTD->getPreviousDeclaration(); + if (ClassTemplateDecl *CTD = dyn_cast(ND)) + return CTD->getPreviousDeclaration(); + return 0; +} + Sema::DeclResult Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, @@ -3547,15 +3564,26 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) { - SourceRange Range(TemplateNameLoc, RAngleLoc); - Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) - << Context.getTypeDeclType(Specialization) << Range; + bool Okay = false; + for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) { + // Is there any previous explicit specialization declaration? + if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) { + Okay = true; + break; + } + } + + if (!Okay) { + SourceRange Range(TemplateNameLoc, RAngleLoc); + Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) + << Context.getTypeDeclType(Specialization) << Range; - Diag(PrevDecl->getPointOfInstantiation(), - diag::note_instantiation_required_here) - << (PrevDecl->getTemplateSpecializationKind() + Diag(PrevDecl->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << (PrevDecl->getTemplateSpecializationKind() != TSK_ImplicitInstantiation); - return true; + return true; + } } // If this is not a friend, note that this is an explicit specialization. @@ -3728,6 +3756,12 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, // before the first use of that specialization that would cause an // implicit instantiation to take place, in every translation unit in // which such a use occurs; no diagnostic is required. + for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) { + // Is there any previous explicit specialization declaration? + if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) + return false; + } + Diag(NewLoc, diag::err_specialization_after_instantiation) << PrevDecl; Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp index 34c3710e04..f539471396 100644 --- a/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp @@ -54,3 +54,10 @@ void f(Array& v) { template<> void sort(Array& v); // // expected-error{{after instantiation}} template<> void sort<>(Array& v); // OK: sort not yet used + +namespace PR6160 { + template void f(T); + template<> void f(int); + extern template void f(int); + template<> void f(int) { } +} -- 2.40.0