forked from OSchip/llvm-project
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:
parent
a56071c5fb
commit
11a80dcb42
|
@ -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<
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue