From: Douglas Gregor Date: Mon, 23 Nov 2009 12:11:45 +0000 (+0000) Subject: Tolerate extraneous "template<>" headers better, downgrading the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3ebd75399112dd9ad1c96ee5e7c59df580378cc8;p=clang Tolerate extraneous "template<>" headers better, downgrading the complaint to a warning and providing a helpful node in the case where the "template<>" header is redundant because the corresponding template-id refers to an explicit specialization. C++0x might still change this behavior, and existing practice is all over the place on the number of "template<>" headers actually needed. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89651 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7ca011986b..399cf37cca 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1049,6 +1049,11 @@ def err_template_param_list_matches_nontemplate : Error< def err_template_spec_extra_headers : Error< "extraneous template parameter list in template specialization or " "out-of-line template definition">; +def warn_template_spec_extra_headers : Warning< + "extraneous template parameter list in template specialization">; +def note_explicit_template_spec_does_not_need_header : Note< + "'template<>' header not required for explicitly-specialized class %0 " + "declared here">; 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">; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 096289fa35..bfdf17afae 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1048,6 +1048,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // template-ids will match up with the template parameter lists. llvm::SmallVector TemplateIdsInSpecifier; + llvm::SmallVector + ExplicitSpecializationsInSpecifier; for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); NNS; NNS = NNS->getPrefix()) { if (const TemplateSpecializationType *SpecType @@ -1061,10 +1063,10 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, = cast(Record->getDecl()); // If the nested name specifier refers to an explicit specialization, // we don't need a template<> header. - // FIXME: revisit this approach once we cope with specializations - // properly. - if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) + if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) { + ExplicitSpecializationsInSpecifier.push_back(SpecDecl); continue; + } } TemplateIdsInSpecifier.push_back(SpecType); @@ -1145,10 +1147,20 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // If there were too many template parameter lists, complain about that now. if (Idx != NumParamLists - 1) { while (Idx < NumParamLists - 1) { + bool isExplicitSpecHeader = ParamLists[Idx]->size() == 0; Diag(ParamLists[Idx]->getTemplateLoc(), - diag::err_template_spec_extra_headers) + isExplicitSpecHeader? diag::warn_template_spec_extra_headers + : diag::err_template_spec_extra_headers) << SourceRange(ParamLists[Idx]->getTemplateLoc(), ParamLists[Idx]->getRAngleLoc()); + + if (isExplicitSpecHeader && !ExplicitSpecializationsInSpecifier.empty()) { + Diag(ExplicitSpecializationsInSpecifier.back()->getLocation(), + diag::note_explicit_template_spec_does_not_need_header) + << ExplicitSpecializationsInSpecifier.back(); + ExplicitSpecializationsInSpecifier.pop_back(); + } + ++Idx; } } diff --git a/test/SemaTemplate/temp_explicit.cpp b/test/SemaTemplate/temp_explicit.cpp index 9c824d6f41..ae409aff66 100644 --- a/test/SemaTemplate/temp_explicit.cpp +++ b/test/SemaTemplate/temp_explicit.cpp @@ -108,3 +108,20 @@ struct X6 { }; template struct X6::Inner; // expected-error{{non-templated}} + +// PR5559 +template +struct Foo; + +template <> +struct Foo // expected-note{{header not required for explicitly-specialized}} +{ + template + struct Bar + {}; +}; + +template <> // expected-warning{{extraneous template parameter list}} +template <> +struct Foo::Bar +{};