PR19340: If we see a declaration of a member of an unspecialized class template

that looks like it might be an explicit specialization, don't recover as an
explicit specialization (bypassing the check that would reject that).

llvm-svn: 206444
This commit is contained in:
Richard Smith 2014-04-17 03:52:20 +00:00
parent a56071c5fb
commit 11a80dcb42
3 changed files with 62 additions and 45 deletions

View File

@ -3267,8 +3267,8 @@ def err_template_qualified_declarator_no_match : Error<
"nested name specifier '%0' for declaration does not refer into a class, "
"class template or class template partial specialization">;
def err_specialize_member_of_template : Error<
"cannot specialize (with 'template<>') a member of an unspecialized "
"template">;
"cannot specialize %select{|(with 'template<>') }0a member of an "
"unspecialized template">;
// C++ Class Template Partial Specialization
def err_default_arg_in_partial_spec : Error<

View File

@ -1721,6 +1721,38 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// template<> for each enclosing class template that is
// explicitly specialized.
bool SawNonEmptyTemplateParameterList = false;
auto CheckExplicitSpecialization = [&](SourceRange Range,
bool Recovery = false) {
if (SawNonEmptyTemplateParameterList) {
Diag(DeclLoc, diag::err_specialize_member_of_template)
<< !Recovery << Range;
Invalid = true;
IsExplicitSpecialization = false;
return true;
}
return false;
};
auto DiagnoseMissingExplicitSpecialization = [&] (SourceRange Range) {
// Check that we can have an explicit specialization here.
if (CheckExplicitSpecialization(Range, true))
return true;
// We don't have a template header, but we should.
SourceLocation ExpectedTemplateLoc;
if (!ParamLists.empty())
ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
else
ExpectedTemplateLoc = DeclStartLoc;
Diag(DeclLoc, diag::err_template_spec_needs_header)
<< Range
<< FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
return false;
};
unsigned ParamIdx = 0;
for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes;
++TypeIdx) {
@ -1791,13 +1823,8 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// are not explicitly specialized as well.
if (ParamIdx < ParamLists.size()) {
if (ParamLists[ParamIdx]->size() == 0) {
if (SawNonEmptyTemplateParameterList) {
Diag(DeclLoc, diag::err_specialize_member_of_template)
<< ParamLists[ParamIdx]->getSourceRange();
Invalid = true;
IsExplicitSpecialization = false;
if (CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange()))
return 0;
}
} else
SawNonEmptyTemplateParameterList = true;
}
@ -1820,29 +1847,20 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
Invalid = true;
return 0;
}
// Consume this template header.
++ParamIdx;
continue;
}
if (!IsFriend) {
// We don't have a template header, but we should.
SourceLocation ExpectedTemplateLoc;
if (!ParamLists.empty())
ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
else
ExpectedTemplateLoc = DeclStartLoc;
// FIXME: Don't recover this way if we SawNonEmptyTemplateParameterList.
Diag(DeclLoc, diag::err_template_spec_needs_header)
<< getRangeOfTypeInNestedNameSpecifier(Context, T, SS)
<< FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
}
if (!IsFriend)
if (DiagnoseMissingExplicitSpecialization(
getRangeOfTypeInNestedNameSpecifier(Context, T, SS)))
return 0;
continue;
}
if (NeedNonemptyTemplateHeader) {
// In friend declarations we can have template-ids which don't
// depend on the corresponding template parameter lists. But
@ -1886,18 +1904,11 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// the declaration itself.
if (ParamIdx >= ParamLists.size()) {
if (TemplateId && !IsFriend) {
// FIXME: Don't recover this way if we SawNonEmptyTemplateParameterList.
// We don't have a template header for the declaration itself, but we
// should.
SourceLocation ExpectedTemplateLoc;
if (!ParamLists.empty())
ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
else
ExpectedTemplateLoc = DeclStartLoc;
Diag(DeclLoc, diag::err_template_spec_needs_header)
<< SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
<< FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
IsExplicitSpecialization = true;
DiagnoseMissingExplicitSpecialization(SourceRange(TemplateId->LAngleLoc,
TemplateId->RAngleLoc));
// Fabricate an empty template parameter list for the invented header.
return TemplateParameterList::Create(Context, SourceLocation(),
@ -1947,14 +1958,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// unspecialized, except that the declaration shall not explicitly
// specialize a class member template if its en- closing class templates
// are not explicitly specialized as well.
if (ParamLists.back()->size() == 0 && SawNonEmptyTemplateParameterList) {
Diag(DeclLoc, diag::err_specialize_member_of_template)
<< ParamLists[ParamIdx]->getSourceRange();
Invalid = true;
IsExplicitSpecialization = false;
if (ParamLists.back()->size() == 0 &&
CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange()))
return 0;
}
// Return the last template parameter list, which corresponds to the
// entity being declared.
return ParamLists.back();

View File

@ -38,12 +38,22 @@ namespace PR18246 {
template<typename T>
template<int N>
void Baz<T>::bar() {
void Baz<T>::bar() { // expected-note {{couldn't infer template argument 'N'}}
}
// FIXME: Don't suggest the 'template<>' correction here, because this cannot
// be an explicit specialization.
// FIXME: We shouldn't try to match this against a prior declaration if
// template parameter matching failed.
template<typename T>
void Baz<T>::bar<0>() { // expected-error {{requires 'template<>'}}
void Baz<T>::bar<0>() { // expected-error {{cannot specialize a member of an unspecialized template}} \
// expected-error {{no function template matches}}
}
}
namespace PR19340 {
template<typename T> struct Helper {
template<int N> static void func(const T *m) {} // expected-note {{failed template argument deduction}}
};
template<typename T> void Helper<T>::func<2>() {} // expected-error {{cannot specialize a member}} \
// expected-error {{no function template matches}}
}