forked from OSchip/llvm-project
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:
parent
86ed5b016a
commit
b22ee88652
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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'}}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue