From: Douglas Gregor Date: Fri, 30 Oct 2009 21:46:58 +0000 (+0000) Subject: Improve diagnostics when parsing something like X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2cc782f7932f1069d9fa8bb5c518165802aad68d;p=clang Improve diagnostics when parsing something like template<> struct foo { ... }; where "foo" does not refer to a template. Fixes PR3844. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85616 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index add979a199..48f58fb9a6 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -282,6 +282,8 @@ def err_typename_refers_to_non_type_template : Error< "typename specifier refers to a non-template">; def err_expected_type_name_after_typename : Error< "expected an identifier or template-id after '::'">; +def err_explicit_spec_non_template : Error< + "explicit specialization of non-template %select{class|struct|union}0 %1">; def err_variadic_templates : Error< "variadic templates are only allowed in C++0x">; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index d381e3e974..72c9f33cd8 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -589,6 +589,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) Diag(Tok, diag::err_expected_ident); + TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; + // Parse the (optional) class name or simple-template-id. IdentifierInfo *Name = 0; SourceLocation NameLoc; @@ -596,6 +598,42 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); + + if (Tok.is(tok::less)) { + // The name was supposed to refer to a template, but didn't. + // Eat the template argument list and try to continue parsing this as + // a class (or template thereof). + TemplateArgList TemplateArgs; + TemplateArgIsTypeList TemplateArgIsType; + TemplateArgLocationList TemplateArgLocations; + SourceLocation LAngleLoc, RAngleLoc; + if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS, + true, LAngleLoc, + TemplateArgs, TemplateArgIsType, + TemplateArgLocations, RAngleLoc)) { + // We couldn't parse the template argument list at all, so don't + // try to give any location information for the list. + LAngleLoc = RAngleLoc = SourceLocation(); + } + + Diag(NameLoc, diag::err_explicit_spec_non_template) + << (TagType == DeclSpec::TST_class? 0 + : TagType == DeclSpec::TST_struct? 1 + : 2) + << Name + << SourceRange(LAngleLoc, RAngleLoc); + + // If this is an explicit specialization, strip off the last template + // parameter list, since we've removed its template arguments. + if (TemplateParams && TemplateParams->size() > 1) { + TemplateParams->pop_back(); + } else { + TemplateParams = 0; + const_cast(TemplateInfo).Kind + = ParsedTemplateInfo::NonTemplate; + } + + } } else if (Tok.is(tok::annot_template_id)) { TemplateId = static_cast(Tok.getAnnotationValue()); NameLoc = ConsumeToken(); @@ -660,7 +698,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Create the tag portion of the class or class template. Action::DeclResult TagOrTempResult = true; // invalid Action::TypeResult TypeResult = true; // invalid - TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; // FIXME: When TUK == TUK_Reference and we have a template-id, we need // to turn that template-id into a type. diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp index 2bd1400fae..33fb93bacf 100644 --- a/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp @@ -4,8 +4,7 @@ namespace N { template class X; } -// FIXME: this diagnostic is terrible (PR3844). -template<> class X { /* ... */ }; // expected-error {{unqualified-id}} +template<> class X { /* ... */ }; // expected-error {{non-template class 'X'}} namespace N { diff --git a/test/CXX/temp/temp.spec/temp.explicit/p5.cpp b/test/CXX/temp/temp.spec/temp.explicit/p5.cpp index ee75602770..b85b62f262 100644 --- a/test/CXX/temp/temp.spec/temp.explicit/p5.cpp +++ b/test/CXX/temp/temp.spec/temp.explicit/p5.cpp @@ -6,8 +6,7 @@ namespace N { }; } -// FIXME: poor diagnostic -template class Z; // expected-error{{unqualified-id}} +template class Z; // expected-error{{non-template class 'Z'}} // FIXME: This example from the standard is wrong; note posted to CWG reflector // on 10/27/2009 diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp index 67f52b6a67..2b2d3de504 100644 --- a/test/Parser/cxx-template-decl.cpp +++ b/test/Parser/cxx-template-decl.cpp @@ -92,3 +92,7 @@ void f2() { int x; A< typeof(x>1) > a; } + + +// PR3844 +template <> struct S { }; // expected-error{{explicit specialization of non-template struct 'S'}}