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,17 +1232,18 @@ // 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. @@ -1249,19 +1252,19 @@ TemplateParams->pop_back(); } else { TemplateParams = 0; - const_cast(TemplateInfo).Kind - = ParsedTemplateInfo::NonTemplate; + const_cast(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(TemplateInfo).Kind - = ParsedTemplateInfo::NonTemplate; - const_cast(TemplateInfo).TemplateLoc - = SourceLocation(); - const_cast(TemplateInfo).ExternLoc - = SourceLocation(); + const_cast(TemplateInfo).Kind = + ParsedTemplateInfo::NonTemplate; + const_cast(TemplateInfo).TemplateLoc = + SourceLocation(); + const_cast(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 + struct B { }; + + bool h = new struct B < 0; // expected-error{{expected '>'}} + bool i = new struct B < 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@-1{{allocation of incomplete type 'struct IDontExist'}} + // expected-note@-2{{forward declaration of 'PR18127::IDontExist'}} +}