Fix several issues related to specializations and explicit instantiations.

Explicit instantiations following specializations are no-ops and hence have
no PointOfInstantiation. That was done correctly in most cases, but for a
specialization -> instantiation decl -> instantiation definition chain, the
definition didn't realize that it was a no-op. Fix that.

Also, when printing diagnostics for these no-ops, get the diag location from
the decl name location.

Add many test cases, one of them not yet passing (but it failed the same way
before this change). Fixes http://llvm.org/pr11558 and more.

llvm-svn: 147225
This commit is contained in:
Nico Weber 2011-12-23 20:58:04 +00:00
parent 9b6b2e5535
commit d3bdadf616
3 changed files with 155 additions and 5 deletions

View File

@ -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,

View File

@ -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.

View File

@ -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 <typename STRING_TYPE> class BasicStringPiece;
template <> class BasicStringPiece<int> { };
extern template class BasicStringPiece<int>;
template class BasicStringPiece<int>;
}
namespace SID {
template <typename STRING_TYPE> class BasicStringPiece;
template <> class BasicStringPiece<int> { };
template class BasicStringPiece<int>; // expected-note {{explicit instantiation definition is here}}
extern template class BasicStringPiece<int>; // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}}
}
namespace ISD {
template <typename STRING_TYPE> class BasicStringPiece; // expected-note {{template is declared here}}
template class BasicStringPiece<int>; // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::ISD::BasicStringPiece<int>'}}
template <> class BasicStringPiece<int> { };
extern template class BasicStringPiece<int>;
}
namespace IDS {
template <typename STRING_TYPE> class BasicStringPiece; // expected-note {{template is declared here}}
template class BasicStringPiece<int>; // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::IDS::BasicStringPiece<int>'}} // expected-note {{explicit instantiation definition is here}}
extern template class BasicStringPiece<int>; // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}}
template <> class BasicStringPiece<int> { };
}
namespace DIS {
template <typename STRING_TYPE> class BasicStringPiece; // expected-note {{template is declared here}}
extern template class BasicStringPiece<int>; // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::DIS::BasicStringPiece<int>'}}
template class BasicStringPiece<int>;
template <> class BasicStringPiece<int> { };
}
namespace DSI {
template <typename STRING_TYPE> class BasicStringPiece; // expected-note {{template is declared here}}
extern template class BasicStringPiece<int>; // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::DSI::BasicStringPiece<int>'}}
template <> class BasicStringPiece<int> { };
template class BasicStringPiece<int>;
}
// The same again, with a defined template class.
namespace SDI_WithDefinedTemplate {
template <typename STRING_TYPE> class BasicStringPiece {};
template <> class BasicStringPiece<int> { };
extern template class BasicStringPiece<int>;
template class BasicStringPiece<int>;
}
namespace SID_WithDefinedTemplate {
template <typename STRING_TYPE> class BasicStringPiece {};
template <> class BasicStringPiece<int> { };
template class BasicStringPiece<int>; // expected-note {{explicit instantiation definition is here}}
extern template class BasicStringPiece<int>; // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}}
}
namespace ISD_WithDefinedTemplate {
template <typename STRING_TYPE> class BasicStringPiece {};
template class BasicStringPiece<int>; // expected-note {{explicit instantiation first required here}}
template <> class BasicStringPiece<int> { }; // expected-error {{explicit specialization of 'spec_vs_expl_inst::ISD_WithDefinedTemplate::BasicStringPiece<int>' after instantiation}}
extern template class BasicStringPiece<int>;
}
namespace IDS_WithDefinedTemplate {
template <typename STRING_TYPE> class BasicStringPiece {};
template class BasicStringPiece<int>; // expected-note {{explicit instantiation definition is here}} expected-note {{previous definition is here}}
extern template class BasicStringPiece<int>; // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}}
template <> class BasicStringPiece<int> { }; // expected-error {{redefinition of 'spec_vs_expl_inst::IDS_WithDefinedTemplate::BasicStringPiece<int>'}}
}
namespace DIS_WithDefinedTemplate {
template <typename STRING_TYPE> class BasicStringPiece {};
extern template class BasicStringPiece<int>; // expected-note {{explicit instantiation first required here}}
template class BasicStringPiece<int>;
template <> class BasicStringPiece<int> { }; // expected-error {{explicit specialization of 'spec_vs_expl_inst::DIS_WithDefinedTemplate::BasicStringPiece<int>' after instantiation}}
}
namespace DSI_WithDefinedTemplate {
template <typename STRING_TYPE> class BasicStringPiece {};
extern template class BasicStringPiece<int>; // expected-note {{explicit instantiation first required here}}
template <> class BasicStringPiece<int> { }; // expected-error {{explicit specialization of 'spec_vs_expl_inst::DSI_WithDefinedTemplate::BasicStringPiece<int>' after instantiation}}
template class BasicStringPiece<int>;
}
// 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 <typename STRING_TYPE> class BasicStringPiece {};
// template <> class BasicStringPiece<int> { };
// template class BasicStringPiece<int>;
// template class BasicStringPiece<int>;
// }
namespace SIS {
template <typename STRING_TYPE> class BasicStringPiece;
template <> class BasicStringPiece<int> { }; // expected-note {{previous definition is here}}
template class BasicStringPiece<int>;
template <> class BasicStringPiece<int> { }; // expected-error {{redefinition of 'spec_vs_expl_inst::SIS::BasicStringPiece<int>'}}
}
namespace SDS {
template <typename STRING_TYPE> class BasicStringPiece;
template <> class BasicStringPiece<int> { }; // expected-note {{previous definition is here}}
extern template class BasicStringPiece<int>;
template <> class BasicStringPiece<int> { }; // expected-error {{redefinition of 'spec_vs_expl_inst::SDS::BasicStringPiece<int>'}}
}
namespace SDIS {
template <typename STRING_TYPE> class BasicStringPiece;
template <> class BasicStringPiece<int> { }; // expected-note {{previous definition is here}}
extern template class BasicStringPiece<int>;
template class BasicStringPiece<int>;
template <> class BasicStringPiece<int> { }; // expected-error {{redefinition of 'spec_vs_expl_inst::SDIS::BasicStringPiece<int>'}}
}
}