forked from OSchip/llvm-project
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:
parent
9b6b2e5535
commit
d3bdadf616
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>'}}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue