Skip to content

Commit 6591149

Browse files
committed
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. llvm-svn: 89651
1 parent 1c3feb5 commit 6591149

File tree

3 files changed

+38
-4
lines changed

3 files changed

+38
-4
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,11 @@ def err_template_param_list_matches_nontemplate : Error<
10491049
def err_template_spec_extra_headers : Error<
10501050
"extraneous template parameter list in template specialization or "
10511051
"out-of-line template definition">;
1052+
def warn_template_spec_extra_headers : Warning<
1053+
"extraneous template parameter list in template specialization">;
1054+
def note_explicit_template_spec_does_not_need_header : Note<
1055+
"'template<>' header not required for explicitly-specialized class %0 "
1056+
"declared here">;
10521057
def err_template_qualified_declarator_no_match : Error<
10531058
"nested name specifier '%0' for declaration does not refer into a class, "
10541059
"class template or class template partial specialization">;

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
10481048
// template-ids will match up with the template parameter lists.
10491049
llvm::SmallVector<const TemplateSpecializationType *, 4>
10501050
TemplateIdsInSpecifier;
1051+
llvm::SmallVector<ClassTemplateSpecializationDecl *, 4>
1052+
ExplicitSpecializationsInSpecifier;
10511053
for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
10521054
NNS; NNS = NNS->getPrefix()) {
10531055
if (const TemplateSpecializationType *SpecType
@@ -1061,10 +1063,10 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
10611063
= cast<ClassTemplateSpecializationDecl>(Record->getDecl());
10621064
// If the nested name specifier refers to an explicit specialization,
10631065
// we don't need a template<> header.
1064-
// FIXME: revisit this approach once we cope with specializations
1065-
// properly.
1066-
if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization)
1066+
if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) {
1067+
ExplicitSpecializationsInSpecifier.push_back(SpecDecl);
10671068
continue;
1069+
}
10681070
}
10691071

10701072
TemplateIdsInSpecifier.push_back(SpecType);
@@ -1145,10 +1147,20 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
11451147
// If there were too many template parameter lists, complain about that now.
11461148
if (Idx != NumParamLists - 1) {
11471149
while (Idx < NumParamLists - 1) {
1150+
bool isExplicitSpecHeader = ParamLists[Idx]->size() == 0;
11481151
Diag(ParamLists[Idx]->getTemplateLoc(),
1149-
diag::err_template_spec_extra_headers)
1152+
isExplicitSpecHeader? diag::warn_template_spec_extra_headers
1153+
: diag::err_template_spec_extra_headers)
11501154
<< SourceRange(ParamLists[Idx]->getTemplateLoc(),
11511155
ParamLists[Idx]->getRAngleLoc());
1156+
1157+
if (isExplicitSpecHeader && !ExplicitSpecializationsInSpecifier.empty()) {
1158+
Diag(ExplicitSpecializationsInSpecifier.back()->getLocation(),
1159+
diag::note_explicit_template_spec_does_not_need_header)
1160+
<< ExplicitSpecializationsInSpecifier.back();
1161+
ExplicitSpecializationsInSpecifier.pop_back();
1162+
}
1163+
11521164
++Idx;
11531165
}
11541166
}

clang/test/SemaTemplate/temp_explicit.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,20 @@ struct X6 {
108108
};
109109

110110
template struct X6::Inner; // expected-error{{non-templated}}
111+
112+
// PR5559
113+
template <typename T>
114+
struct Foo;
115+
116+
template <>
117+
struct Foo<int> // expected-note{{header not required for explicitly-specialized}}
118+
{
119+
template <typename U>
120+
struct Bar
121+
{};
122+
};
123+
124+
template <> // expected-warning{{extraneous template parameter list}}
125+
template <>
126+
struct Foo<int>::Bar<void>
127+
{};

0 commit comments

Comments
 (0)