r206444 - PR19340: If we see a declaration of a member of an unspecialized class template
Richard Smith
richard-llvm at metafoo.co.uk
Wed Apr 16 20:52:21 PDT 2014
Author: rsmith
Date: Wed Apr 16 22:52:20 2014
New Revision: 206444
URL: http://llvm.org/viewvc/llvm-project?rev=206444&view=rev
Log:
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).
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=206444&r1=206443&r2=206444&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Apr 16 22:52:20 2014
@@ -3267,8 +3267,8 @@ def err_template_qualified_declarator_no
"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<
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=206444&r1=206443&r2=206444&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Apr 16 22:52:20 2014
@@ -1721,6 +1721,38 @@ TemplateParameterList *Sema::MatchTempla
// 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::MatchTempla
// 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::MatchTempla
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::MatchTempla
// 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::MatchTempla
// 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();
Modified: cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp?rev=206444&r1=206443&r2=206444&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp (original)
+++ cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp Wed Apr 16 22:52:20 2014
@@ -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}}
+}
More information about the cfe-commits
mailing list