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!

llvm-svn: 103081
This commit is contained in:
Douglas Gregor 2010-05-05 05:58:24 +00:00
parent 86ed5b016a
commit b22ee88652
4 changed files with 74 additions and 15 deletions

View File

@ -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);

View File

@ -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.

View File

@ -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();
}

View File

@ -44,3 +44,41 @@ struct X {
};
template struct X<3>;
// 'template' as a disambiguator.
// PR7030
struct Y0 {
template<typename U>
void f1(U);
template<typename U>
static void f2(U);
void f3(int);
static int f4(int);
template<typename U>
static void f4(U);
template<typename U>
void f() {
Y0::template f1<U>(0);
Y0::template f1(0);
this->template f1(0);
Y0::template f2<U>(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<int>(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<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
}
};