[PATCH] Don't parse non-template name as template name
Ismail Pazarbasi
ismail.pazarbasi at gmail.com
Thu Jan 30 14:39:10 PST 2014
Hi rsmith,
PR18127: misparse of 'new struct S < ...' where S is not a template-name
If clang sees '<' token after an elaborated-type-specifier, it assumes elaborated-type-specifier refers to a template name, and then issues diagnostics concerning missing '>'.
We try to find corresponding '>' for diagnostics location purpose, and perform name lookup. Parser knows that it is not parsing a template. If name lookup doesn't find a name, we will keep issuing `explicit instantiation/specialization of non-template class` error.
http://llvm-reviews.chandlerc.com/D2662
Files:
lib/Parse/ParseDeclCXX.cpp
test/Parser/cxx-template-argument.cpp
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -24,6 +24,8 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallString.h"
+#include "clang/Sema/Lookup.h"
+
using namespace clang;
/// ParseNamespace - We know that the current token is a namespace keyword. This
@@ -1230,38 +1232,39 @@
// a class (or template thereof).
TemplateArgList TemplateArgs;
SourceLocation LAngleLoc, RAngleLoc;
- if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, SS,
- true, LAngleLoc,
- TemplateArgs, 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)
- << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
- << TagTokKind << Name << SourceRange(LAngleLoc, RAngleLoc);
+ LAngleLoc = ConsumeToken();
+ if (SkipUntil(tok::greater, StopBeforeMatch | StopAtSemi))
+ RAngleLoc = ConsumeToken();
+ // If a name was not found, this might be an explicit instantiation or
+ // specialization attempt. If a name was found, that name does not refer
+ // to a template name.
+ LookupResult Result(Actions, Name, NameLoc, Sema::LookupTagName);
+ Actions.LookupName(Result, getCurScope());
+ if (Result.getResultKind() != LookupResult::Found)
+ Diag(NameLoc, diag::err_explicit_spec_non_template)
+ << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
+ << TagTokKind << Name << SourceRange(LAngleLoc, RAngleLoc);
// Strip off the last template parameter list if it was empty, since
// we've removed its template argument list.
if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) {
if (TemplateParams && TemplateParams->size() > 1) {
TemplateParams->pop_back();
} else {
TemplateParams = 0;
- const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
- = ParsedTemplateInfo::NonTemplate;
+ const_cast<ParsedTemplateInfo &>(TemplateInfo).Kind =
+ ParsedTemplateInfo::NonTemplate;
}
- } else if (TemplateInfo.Kind
- == ParsedTemplateInfo::ExplicitInstantiation) {
+ } else if (TemplateInfo.Kind ==
+ ParsedTemplateInfo::ExplicitInstantiation) {
// Pretend this is just a forward declaration.
TemplateParams = 0;
- const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
- = ParsedTemplateInfo::NonTemplate;
- const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc
- = SourceLocation();
- const_cast<ParsedTemplateInfo&>(TemplateInfo).ExternLoc
- = SourceLocation();
+ const_cast<ParsedTemplateInfo &>(TemplateInfo).Kind =
+ ParsedTemplateInfo::NonTemplate;
+ const_cast<ParsedTemplateInfo &>(TemplateInfo).TemplateLoc =
+ SourceLocation();
+ const_cast<ParsedTemplateInfo &>(TemplateInfo).ExternLoc =
+ SourceLocation();
}
}
} else if (Tok.is(tok::annot_template_id)) {
Index: test/Parser/cxx-template-argument.cpp
===================================================================
--- test/Parser/cxx-template-argument.cpp
+++ test/Parser/cxx-template-argument.cpp
@@ -106,3 +106,21 @@
{ };
}
+
+namespace PR18127 {
+ struct A {} *a;
+ bool f = new struct A < 0;
+ bool g = new struct A < a;
+
+ template<typename T>
+ struct B { };
+
+ bool h = new struct B < 0; // expected-error{{expected '>'}}
+ bool i = new struct B<int> < 0;
+ bool operator<(const struct O &, const struct O &);
+ struct O { } *p;
+ bool j = *(new struct O) < *p;
+ bool k = new struct IDontExist < 0; // expected-error{{explicit specialization of non-template struct 'IDontExist'}}
+ // expected-error at -1{{allocation of incomplete type 'struct IDontExist'}}
+ // expected-note at -2{{forward declaration of 'PR18127::IDontExist'}}
+}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D2662.1.patch
Type: text/x-patch
Size: 4356 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140130/9ec2ded2/attachment.bin>
More information about the cfe-commits
mailing list