diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-04-17 03:52:20 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-04-17 03:52:20 +0000 |
| commit | 11a80dcb422ab40e8854a8de0715dce374c107e6 (patch) | |
| tree | 12efe515c960cc1119ed198959e77f18002b2507 | |
| parent | a56071c5fbe05b6fd8da3388fc60a959a6fc6464 (diff) | |
| download | bcm5719-llvm-11a80dcb422ab40e8854a8de0715dce374c107e6.tar.gz bcm5719-llvm-11a80dcb422ab40e8854a8de0715dce374c107e6.zip | |
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
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 85 | ||||
| -rw-r--r-- | clang/test/SemaTemplate/explicit-specialization-member.cpp | 18 |
3 files changed, 62 insertions, 45 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 180e088d39b..c13be0326ed 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 58742fc055e..2ef144f1587 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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(); diff --git a/clang/test/SemaTemplate/explicit-specialization-member.cpp b/clang/test/SemaTemplate/explicit-specialization-member.cpp index 07d73894468..e8dc4d219ac 100644 --- a/clang/test/SemaTemplate/explicit-specialization-member.cpp +++ b/clang/test/SemaTemplate/explicit-specialization-member.cpp @@ -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}} +} |

