From 0278e123b4606ea15dbfa717e9c5a76a5ef2bc7d Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 5 May 2010 05:58:24 +0000 Subject: [PATCH] Support for 'template' as a disambiguator (PR7030) ParseOptionalCXXScopeSpecifier() only annotates the subset of template-ids which are not subject to lexical ambiguity. Add support for the more general case in ParseUnqualifiedId() to handle cases such as A::template B(). Also improve some diagnostic locations. Fixes PR7030, from Alp Toker! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103081 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 3 +- lib/Parse/ParseExprCXX.cpp | 42 ++++++++++++++++++-------- lib/Sema/SemaTemplate.cpp | 6 ++-- test/SemaTemplate/template-id-expr.cpp | 38 +++++++++++++++++++++++ 4 files changed, 74 insertions(+), 15 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 42a41d6d30..0180419e04 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1403,7 +1403,8 @@ private: bool EnteringContext, TypeTy *ObjectType, UnqualifiedId &Id, - bool AssumeTemplateId = false); + bool AssumeTemplateId, + SourceLocation TemplateKWLoc); bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, TypeTy *ObjectType, UnqualifiedId &Result); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 146762b83a..9eb9506239 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -576,7 +576,8 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, // it as such. if (Tok.is(tok::less) && ParseUnqualifiedIdTemplateId(SS, Name, NameLoc, false, ObjectType, - SecondTypeName, /*AssumeTemplateName=*/true)) + SecondTypeName, /*AssumeTemplateName=*/true, + /*TemplateKWLoc*/SourceLocation())) return ExprError(); return Actions.ActOnPseudoDestructorExpr(CurScope, move(Base), OpLoc, OpKind, @@ -952,8 +953,10 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, bool EnteringContext, TypeTy *ObjectType, UnqualifiedId &Id, - bool AssumeTemplateId) { - assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id"); + bool AssumeTemplateId, + SourceLocation TemplateKWLoc) { + assert((AssumeTemplateId || Tok.is(tok::less)) && + "Expected '<' to finish parsing a template-id"); TemplateTy Template; TemplateNameKind TNK = TNK_Non_template; @@ -962,7 +965,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_LiteralOperatorId: if (AssumeTemplateId) { - Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS, + Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, Id, ObjectType, EnteringContext); TNK = TNK_Dependent_template_name; @@ -985,7 +988,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, UnqualifiedId TemplateName; TemplateName.setIdentifier(Name, NameLoc); if (ObjectType) { - Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS, + Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName, ObjectType, EnteringContext); TNK = TNK_Dependent_template_name; @@ -1014,7 +1017,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; - if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, + if (Tok.is(tok::less) && + ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, &SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) @@ -1293,6 +1297,17 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowConstructorName, TypeTy *ObjectType, UnqualifiedId &Result) { + + // Handle 'A::template B'. This is for template-ids which have not + // already been annotated by ParseOptionalCXXScopeSpecifier(). + bool TemplateSpecified = false; + SourceLocation TemplateKWLoc; + if (getLang().CPlusPlus && Tok.is(tok::kw_template) && + (ObjectType || SS.isSet())) { + TemplateSpecified = true; + TemplateKWLoc = ConsumeToken(); + } + // unqualified-id: // identifier // template-id (when it hasn't already been annotated) @@ -1320,9 +1335,10 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, } // If the next token is a '<', we may have a template. - if (Tok.is(tok::less)) + if (TemplateSpecified || Tok.is(tok::less)) return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext, - ObjectType, Result); + ObjectType, Result, + TemplateSpecified, TemplateKWLoc); return false; } @@ -1383,10 +1399,11 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // operator-function-id < template-argument-list[opt] > if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId || Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) && - Tok.is(tok::less)) + (TemplateSpecified || Tok.is(tok::less))) return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(), EnteringContext, ObjectType, - Result); + Result, + TemplateSpecified, TemplateKWLoc); return false; } @@ -1411,10 +1428,11 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, IdentifierInfo *ClassName = Tok.getIdentifierInfo(); SourceLocation ClassNameLoc = ConsumeToken(); - if (Tok.is(tok::less)) { + if (TemplateSpecified || Tok.is(tok::less)) { Result.setDestructorName(TildeLoc, 0, ClassNameLoc); return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc, - EnteringContext, ObjectType, Result); + EnteringContext, ObjectType, Result, + TemplateSpecified, TemplateKWLoc); } // Note that this is a destructor name. diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 694b21c839..050bbbd683 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1704,7 +1704,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name) - << Name.getSourceRange(); + << Name.getSourceRange() + << TemplateKWLoc; return TemplateTy(); } else { // We found something; return it. @@ -1734,7 +1735,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name) - << Name.getSourceRange(); + << Name.getSourceRange() + << TemplateKWLoc; return TemplateTy(); } diff --git a/test/SemaTemplate/template-id-expr.cpp b/test/SemaTemplate/template-id-expr.cpp index b3f41be7bf..de8d7f6c91 100644 --- a/test/SemaTemplate/template-id-expr.cpp +++ b/test/SemaTemplate/template-id-expr.cpp @@ -44,3 +44,41 @@ struct X { }; template struct X<3>; + +// 'template' as a disambiguator. +// PR7030 +struct Y0 { + template + void f1(U); + + template + static void f2(U); + + void f3(int); + + static int f4(int); + template + static void f4(U); + + template + void f() { + Y0::template f1(0); + Y0::template f1(0); + this->template f1(0); + + Y0::template f2(0); + Y0::template f2(0); + + Y0::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + Y0::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + + int x; + x = Y0::f4(0); + x = Y0::f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = Y0::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + + x = this->f4(0); + x = this->f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + } +}; -- 2.40.0