diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index f6bc41a640e8..fbf7b345acca 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1607,7 +1607,7 @@ class ClassTemplatePartialSpecializationDecl public: static ClassTemplatePartialSpecializationDecl * - Create(ASTContext &Context, TagKind TK,DeclContext *DC, + Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index d0c0f0bf2d12..b0006e6ac2a3 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -5344,9 +5344,17 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, // translation unit, the definition shall follow the declaration. Diag(NewLoc, diag::err_explicit_instantiation_declaration_after_definition); - Diag(PrevPointOfInstantiation, - diag::note_explicit_instantiation_definition_here); - assert(PrevPointOfInstantiation.isValid() && + + // Explicit instantiations following a specialization have no effect and + // hence no PrevPointOfInstantiation. In that case, walk decl backwards + // until a valid name loc is found. + SourceLocation PrevDiagLoc = PrevPointOfInstantiation; + for (NamedDecl *Prev = PrevDecl; Prev && !PrevDiagLoc.isValid(); + Prev = getPreviousDecl(Prev)) { + PrevDiagLoc = Prev->getLocation(); + } + Diag(PrevDiagLoc, diag::note_explicit_instantiation_definition_here); + assert(PrevDiagLoc.isValid() && "Explicit instantiation without point of instantiation?"); HasNoEffect = true; return false; @@ -5383,6 +5391,20 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, case TSK_ExplicitInstantiationDeclaration: // We're explicity instantiating a definition for something for which we // were previously asked to suppress instantiations. That's fine. + + // C++0x [temp.explicit]p4: + // For a given set of template parameters, if an explicit instantiation + // of a template appears after a declaration of an explicit + // specialization for that template, the explicit instantiation has no + // effect. + for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) { + // Is there any previous explicit specialization declaration? + if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) { + HasNoEffect = true; + break; + } + } + return false; case TSK_ExplicitInstantiationDefinition: @@ -5677,7 +5699,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { // C++ [temp.expl.spec]p6: // If a template, a member template or the member of a class template is - // explicitly specialized then that spe- cialization shall be declared + // explicitly specialized then that specialization shall be declared // 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. diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp index f04c544aa448..89f343869f29 100644 --- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp @@ -207,3 +207,131 @@ namespace template_class_spec_perClassDecl_nested static void foo(); }; } + + +namespace spec_vs_expl_inst { + + // Test all permutations of Specialization, + // explicit instantiation Declaration, and explicit instantiation defInition. + + namespace SDI { // PR11558 + template class BasicStringPiece; + template <> class BasicStringPiece { }; + extern template class BasicStringPiece; + template class BasicStringPiece; + } + + namespace SID { + template class BasicStringPiece; + template <> class BasicStringPiece { }; + template class BasicStringPiece; // expected-note {{explicit instantiation definition is here}} + extern template class BasicStringPiece; // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}} + } + + namespace ISD { + template class BasicStringPiece; // expected-note {{template is declared here}} + template class BasicStringPiece; // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::ISD::BasicStringPiece'}} + template <> class BasicStringPiece { }; + extern template class BasicStringPiece; + } + + namespace IDS { + template class BasicStringPiece; // expected-note {{template is declared here}} + template class BasicStringPiece; // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::IDS::BasicStringPiece'}} // expected-note {{explicit instantiation definition is here}} + extern template class BasicStringPiece; // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}} + template <> class BasicStringPiece { }; + } + + namespace DIS { + template class BasicStringPiece; // expected-note {{template is declared here}} + extern template class BasicStringPiece; // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::DIS::BasicStringPiece'}} + template class BasicStringPiece; + template <> class BasicStringPiece { }; + } + + namespace DSI { + template class BasicStringPiece; // expected-note {{template is declared here}} + extern template class BasicStringPiece; // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::DSI::BasicStringPiece'}} + template <> class BasicStringPiece { }; + template class BasicStringPiece; + } + + // The same again, with a defined template class. + + namespace SDI_WithDefinedTemplate { + template class BasicStringPiece {}; + template <> class BasicStringPiece { }; + extern template class BasicStringPiece; + template class BasicStringPiece; + } + + namespace SID_WithDefinedTemplate { + template class BasicStringPiece {}; + template <> class BasicStringPiece { }; + template class BasicStringPiece; // expected-note {{explicit instantiation definition is here}} + extern template class BasicStringPiece; // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}} + } + + namespace ISD_WithDefinedTemplate { + template class BasicStringPiece {}; + template class BasicStringPiece; // expected-note {{explicit instantiation first required here}} + template <> class BasicStringPiece { }; // expected-error {{explicit specialization of 'spec_vs_expl_inst::ISD_WithDefinedTemplate::BasicStringPiece' after instantiation}} + extern template class BasicStringPiece; + } + + namespace IDS_WithDefinedTemplate { + template class BasicStringPiece {}; + template class BasicStringPiece; // expected-note {{explicit instantiation definition is here}} expected-note {{previous definition is here}} + extern template class BasicStringPiece; // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}} + template <> class BasicStringPiece { }; // expected-error {{redefinition of 'spec_vs_expl_inst::IDS_WithDefinedTemplate::BasicStringPiece'}} + } + + namespace DIS_WithDefinedTemplate { + template class BasicStringPiece {}; + extern template class BasicStringPiece; // expected-note {{explicit instantiation first required here}} + template class BasicStringPiece; + template <> class BasicStringPiece { }; // expected-error {{explicit specialization of 'spec_vs_expl_inst::DIS_WithDefinedTemplate::BasicStringPiece' after instantiation}} + } + + namespace DSI_WithDefinedTemplate { + template class BasicStringPiece {}; + extern template class BasicStringPiece; // expected-note {{explicit instantiation first required here}} + template <> class BasicStringPiece { }; // expected-error {{explicit specialization of 'spec_vs_expl_inst::DSI_WithDefinedTemplate::BasicStringPiece' after instantiation}} + template class BasicStringPiece; + } + + // And some more random tests. + +// FIXME: Enable this test. The error is printed fine, but the note is at some +// weird source location that causes "previous explicit instantiation is here" +// without anything after it to be printed. That happened before this patch too. +// namespace SII_WithDefinedTemplate { +// template class BasicStringPiece {}; +// template <> class BasicStringPiece { }; +// template class BasicStringPiece; +// template class BasicStringPiece; +// } + + namespace SIS { + template class BasicStringPiece; + template <> class BasicStringPiece { }; // expected-note {{previous definition is here}} + template class BasicStringPiece; + template <> class BasicStringPiece { }; // expected-error {{redefinition of 'spec_vs_expl_inst::SIS::BasicStringPiece'}} + } + + namespace SDS { + template class BasicStringPiece; + template <> class BasicStringPiece { }; // expected-note {{previous definition is here}} + extern template class BasicStringPiece; + template <> class BasicStringPiece { }; // expected-error {{redefinition of 'spec_vs_expl_inst::SDS::BasicStringPiece'}} + } + + namespace SDIS { + template class BasicStringPiece; + template <> class BasicStringPiece { }; // expected-note {{previous definition is here}} + extern template class BasicStringPiece; + template class BasicStringPiece; + template <> class BasicStringPiece { }; // expected-error {{redefinition of 'spec_vs_expl_inst::SDIS::BasicStringPiece'}} + } + +}