forked from OSchip/llvm-project
Parse A::template B as an identifier rather than as a template-id with no
template arguments. This fixes some cases where we'd incorrectly accept "A::template B" when B is a kind of template that requires template arguments (in particular, a variable template or a concept). llvm-svn: 331013
This commit is contained in:
parent
93979f67f8
commit
c08b693e30
|
@ -633,6 +633,8 @@ def err_template_spec_syntax_non_template : Error<
|
||||||
"<unused>|refers to a variable template|<unused>}1">;
|
"<unused>|refers to a variable template|<unused>}1">;
|
||||||
def err_id_after_template_in_nested_name_spec : Error<
|
def err_id_after_template_in_nested_name_spec : Error<
|
||||||
"expected template name after 'template' keyword in nested name specifier">;
|
"expected template name after 'template' keyword in nested name specifier">;
|
||||||
|
def err_unexpected_template_in_unqualified_id : Error<
|
||||||
|
"'template' keyword not permitted here">;
|
||||||
def err_two_right_angle_brackets_need_space : Error<
|
def err_two_right_angle_brackets_need_space : Error<
|
||||||
"a space is required between consecutive right angle brackets (use '> >')">;
|
"a space is required between consecutive right angle brackets (use '> >')">;
|
||||||
def err_right_angle_bracket_equal_needs_space : Error<
|
def err_right_angle_bracket_equal_needs_space : Error<
|
||||||
|
|
|
@ -2544,12 +2544,11 @@ private:
|
||||||
struct UsingDeclarator {
|
struct UsingDeclarator {
|
||||||
SourceLocation TypenameLoc;
|
SourceLocation TypenameLoc;
|
||||||
CXXScopeSpec SS;
|
CXXScopeSpec SS;
|
||||||
SourceLocation TemplateKWLoc;
|
|
||||||
UnqualifiedId Name;
|
UnqualifiedId Name;
|
||||||
SourceLocation EllipsisLoc;
|
SourceLocation EllipsisLoc;
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
TypenameLoc = TemplateKWLoc = EllipsisLoc = SourceLocation();
|
TypenameLoc = EllipsisLoc = SourceLocation();
|
||||||
SS.clear();
|
SS.clear();
|
||||||
Name.clear();
|
Name.clear();
|
||||||
}
|
}
|
||||||
|
@ -2744,7 +2743,7 @@ public:
|
||||||
bool AllowConstructorName,
|
bool AllowConstructorName,
|
||||||
bool AllowDeductionGuide,
|
bool AllowDeductionGuide,
|
||||||
ParsedType ObjectType,
|
ParsedType ObjectType,
|
||||||
SourceLocation& TemplateKWLoc,
|
SourceLocation *TemplateKWLoc,
|
||||||
UnqualifiedId &Result);
|
UnqualifiedId &Result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -6074,7 +6074,7 @@ public:
|
||||||
TemplateNameKind isTemplateName(Scope *S,
|
TemplateNameKind isTemplateName(Scope *S,
|
||||||
CXXScopeSpec &SS,
|
CXXScopeSpec &SS,
|
||||||
bool hasTemplateKeyword,
|
bool hasTemplateKeyword,
|
||||||
UnqualifiedId &Name,
|
const UnqualifiedId &Name,
|
||||||
ParsedType ObjectType,
|
ParsedType ObjectType,
|
||||||
bool EnteringContext,
|
bool EnteringContext,
|
||||||
TemplateTy &Template,
|
TemplateTy &Template,
|
||||||
|
@ -6244,7 +6244,7 @@ public:
|
||||||
|
|
||||||
TemplateNameKind ActOnDependentTemplateName(
|
TemplateNameKind ActOnDependentTemplateName(
|
||||||
Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
|
Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
|
||||||
UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext,
|
const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext,
|
||||||
TemplateTy &Template, bool AllowInjectedClassName = false);
|
TemplateTy &Template, bool AllowInjectedClassName = false);
|
||||||
|
|
||||||
DeclResult
|
DeclResult
|
||||||
|
|
|
@ -5600,12 +5600,11 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
||||||
D.getContext() == DeclaratorContext::MemberContext);
|
D.getContext() == DeclaratorContext::MemberContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceLocation TemplateKWLoc;
|
|
||||||
bool HadScope = D.getCXXScopeSpec().isValid();
|
bool HadScope = D.getCXXScopeSpec().isValid();
|
||||||
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
|
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
|
||||||
/*EnteringContext=*/true,
|
/*EnteringContext=*/true,
|
||||||
/*AllowDestructorName=*/true, AllowConstructorName,
|
/*AllowDestructorName=*/true, AllowConstructorName,
|
||||||
AllowDeductionGuide, nullptr, TemplateKWLoc,
|
AllowDeductionGuide, nullptr, nullptr,
|
||||||
D.getName()) ||
|
D.getName()) ||
|
||||||
// Once we're past the identifier, if the scope was bad, mark the
|
// Once we're past the identifier, if the scope was bad, mark the
|
||||||
// whole declarator bad.
|
// whole declarator bad.
|
||||||
|
|
|
@ -602,7 +602,7 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
|
||||||
/*AllowConstructorName=*/!(Tok.is(tok::identifier) &&
|
/*AllowConstructorName=*/!(Tok.is(tok::identifier) &&
|
||||||
NextToken().is(tok::equal)),
|
NextToken().is(tok::equal)),
|
||||||
/*AllowDeductionGuide=*/false,
|
/*AllowDeductionGuide=*/false,
|
||||||
nullptr, D.TemplateKWLoc, D.Name))
|
nullptr, nullptr, D.Name))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2476,7 +2476,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||||
SourceLocation TemplateKWLoc;
|
SourceLocation TemplateKWLoc;
|
||||||
UnqualifiedId Name;
|
UnqualifiedId Name;
|
||||||
if (ParseUnqualifiedId(SS, false, true, true, false, nullptr,
|
if (ParseUnqualifiedId(SS, false, true, true, false, nullptr,
|
||||||
TemplateKWLoc, Name)) {
|
&TemplateKWLoc, Name)) {
|
||||||
SkipUntil(tok::semi);
|
SkipUntil(tok::semi);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2488,6 +2488,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: We should do something with the 'template' keyword here.
|
||||||
return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration(
|
return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration(
|
||||||
getCurScope(), AS, /*UsingLoc*/ SourceLocation(),
|
getCurScope(), AS, /*UsingLoc*/ SourceLocation(),
|
||||||
/*TypenameLoc*/ SourceLocation(), SS, Name,
|
/*TypenameLoc*/ SourceLocation(), SS, Name,
|
||||||
|
|
|
@ -1755,7 +1755,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||||
/*AllowConstructorName=*/
|
/*AllowConstructorName=*/
|
||||||
getLangOpts().MicrosoftExt,
|
getLangOpts().MicrosoftExt,
|
||||||
/*AllowDeductionGuide=*/false,
|
/*AllowDeductionGuide=*/false,
|
||||||
ObjectType, TemplateKWLoc, Name)) {
|
ObjectType, &TemplateKWLoc, Name)) {
|
||||||
(void)Actions.CorrectDelayedTyposInExpr(LHS);
|
(void)Actions.CorrectDelayedTyposInExpr(LHS);
|
||||||
LHS = ExprError();
|
LHS = ExprError();
|
||||||
}
|
}
|
||||||
|
|
|
@ -553,7 +553,7 @@ ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOpe
|
||||||
/*AllowDestructorName=*/false,
|
/*AllowDestructorName=*/false,
|
||||||
/*AllowConstructorName=*/false,
|
/*AllowConstructorName=*/false,
|
||||||
/*AllowDeductionGuide=*/false,
|
/*AllowDeductionGuide=*/false,
|
||||||
/*ObjectType=*/nullptr, TemplateKWLoc, Name))
|
/*ObjectType=*/nullptr, &TemplateKWLoc, Name))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
// This is only the direct operand of an & operator if it is not
|
// This is only the direct operand of an & operator if it is not
|
||||||
|
@ -2044,9 +2044,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
|
||||||
ParsedType ObjectType,
|
ParsedType ObjectType,
|
||||||
UnqualifiedId &Id,
|
UnqualifiedId &Id,
|
||||||
bool AssumeTemplateId) {
|
bool AssumeTemplateId) {
|
||||||
assert((AssumeTemplateId || Tok.is(tok::less)) &&
|
assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id");
|
||||||
"Expected '<' to finish parsing a template-id");
|
|
||||||
|
|
||||||
TemplateTy Template;
|
TemplateTy Template;
|
||||||
TemplateNameKind TNK = TNK_Non_template;
|
TemplateNameKind TNK = TNK_Non_template;
|
||||||
switch (Id.getKind()) {
|
switch (Id.getKind()) {
|
||||||
|
@ -2142,10 +2141,10 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
|
||||||
// Parse the enclosed template argument list.
|
// Parse the enclosed template argument list.
|
||||||
SourceLocation LAngleLoc, RAngleLoc;
|
SourceLocation LAngleLoc, RAngleLoc;
|
||||||
TemplateArgList TemplateArgs;
|
TemplateArgList TemplateArgs;
|
||||||
if (Tok.is(tok::less) && ParseTemplateIdAfterTemplateName(
|
if (ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs,
|
||||||
true, LAngleLoc, TemplateArgs, RAngleLoc))
|
RAngleLoc))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (Id.getKind() == UnqualifiedIdKind::IK_Identifier ||
|
if (Id.getKind() == UnqualifiedIdKind::IK_Identifier ||
|
||||||
Id.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId ||
|
Id.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId ||
|
||||||
Id.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId) {
|
Id.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId) {
|
||||||
|
@ -2465,16 +2464,23 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
bool AllowConstructorName,
|
bool AllowConstructorName,
|
||||||
bool AllowDeductionGuide,
|
bool AllowDeductionGuide,
|
||||||
ParsedType ObjectType,
|
ParsedType ObjectType,
|
||||||
SourceLocation& TemplateKWLoc,
|
SourceLocation *TemplateKWLoc,
|
||||||
UnqualifiedId &Result) {
|
UnqualifiedId &Result) {
|
||||||
|
if (TemplateKWLoc)
|
||||||
|
*TemplateKWLoc = SourceLocation();
|
||||||
|
|
||||||
// Handle 'A::template B'. This is for template-ids which have not
|
// Handle 'A::template B'. This is for template-ids which have not
|
||||||
// already been annotated by ParseOptionalCXXScopeSpecifier().
|
// already been annotated by ParseOptionalCXXScopeSpecifier().
|
||||||
bool TemplateSpecified = false;
|
bool TemplateSpecified = false;
|
||||||
if (getLangOpts().CPlusPlus && Tok.is(tok::kw_template) &&
|
if (Tok.is(tok::kw_template)) {
|
||||||
(ObjectType || SS.isSet())) {
|
if (TemplateKWLoc && (ObjectType || SS.isSet())) {
|
||||||
TemplateSpecified = true;
|
TemplateSpecified = true;
|
||||||
TemplateKWLoc = ConsumeToken();
|
*TemplateKWLoc = ConsumeToken();
|
||||||
|
} else {
|
||||||
|
SourceLocation TemplateLoc = ConsumeToken();
|
||||||
|
Diag(TemplateLoc, diag::err_unexpected_template_in_unqualified_id)
|
||||||
|
<< FixItHint::CreateRemoval(TemplateLoc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unqualified-id:
|
// unqualified-id:
|
||||||
|
@ -2513,11 +2519,18 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the next token is a '<', we may have a template.
|
// If the next token is a '<', we may have a template.
|
||||||
if (TemplateSpecified || Tok.is(tok::less))
|
TemplateTy Template;
|
||||||
return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, Id, IdLoc,
|
if (Tok.is(tok::less))
|
||||||
EnteringContext, ObjectType,
|
return ParseUnqualifiedIdTemplateId(
|
||||||
Result, TemplateSpecified);
|
SS, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), Id, IdLoc,
|
||||||
|
EnteringContext, ObjectType, Result, TemplateSpecified);
|
||||||
|
else if (TemplateSpecified &&
|
||||||
|
Actions.ActOnDependentTemplateName(
|
||||||
|
getCurScope(), SS, *TemplateKWLoc, Result, ObjectType,
|
||||||
|
EnteringContext, Template,
|
||||||
|
/*AllowInjectedClassName*/ true) == TNK_Non_template)
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2558,7 +2571,14 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
// We have already parsed a template-id; consume the annotation token as
|
// We have already parsed a template-id; consume the annotation token as
|
||||||
// our unqualified-id.
|
// our unqualified-id.
|
||||||
Result.setTemplateId(TemplateId);
|
Result.setTemplateId(TemplateId);
|
||||||
TemplateKWLoc = TemplateId->TemplateKWLoc;
|
SourceLocation TemplateLoc = TemplateId->TemplateKWLoc;
|
||||||
|
if (TemplateLoc.isValid()) {
|
||||||
|
if (TemplateKWLoc && (ObjectType || SS.isSet()))
|
||||||
|
*TemplateKWLoc = TemplateLoc;
|
||||||
|
else
|
||||||
|
Diag(TemplateLoc, diag::err_unexpected_template_in_unqualified_id)
|
||||||
|
<< FixItHint::CreateRemoval(TemplateLoc);
|
||||||
|
}
|
||||||
ConsumeAnnotationToken();
|
ConsumeAnnotationToken();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2575,13 +2595,20 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
//
|
//
|
||||||
// template-id:
|
// template-id:
|
||||||
// operator-function-id < template-argument-list[opt] >
|
// operator-function-id < template-argument-list[opt] >
|
||||||
|
TemplateTy Template;
|
||||||
if ((Result.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId ||
|
if ((Result.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId ||
|
||||||
Result.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId) &&
|
Result.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId) &&
|
||||||
(TemplateSpecified || Tok.is(tok::less)))
|
Tok.is(tok::less))
|
||||||
return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc,
|
return ParseUnqualifiedIdTemplateId(
|
||||||
nullptr, SourceLocation(),
|
SS, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), nullptr,
|
||||||
EnteringContext, ObjectType,
|
SourceLocation(), EnteringContext, ObjectType, Result,
|
||||||
Result, TemplateSpecified);
|
TemplateSpecified);
|
||||||
|
else if (TemplateSpecified &&
|
||||||
|
Actions.ActOnDependentTemplateName(
|
||||||
|
getCurScope(), SS, *TemplateKWLoc, Result, ObjectType,
|
||||||
|
EnteringContext, Template,
|
||||||
|
/*AllowInjectedClassName*/ true) == TNK_Non_template)
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2649,12 +2676,11 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
IdentifierInfo *ClassName = Tok.getIdentifierInfo();
|
IdentifierInfo *ClassName = Tok.getIdentifierInfo();
|
||||||
SourceLocation ClassNameLoc = ConsumeToken();
|
SourceLocation ClassNameLoc = ConsumeToken();
|
||||||
|
|
||||||
if (TemplateSpecified || Tok.is(tok::less)) {
|
if (Tok.is(tok::less)) {
|
||||||
Result.setDestructorName(TildeLoc, nullptr, ClassNameLoc);
|
Result.setDestructorName(TildeLoc, nullptr, ClassNameLoc);
|
||||||
return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc,
|
return ParseUnqualifiedIdTemplateId(
|
||||||
ClassName, ClassNameLoc,
|
SS, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), ClassName,
|
||||||
EnteringContext, ObjectType,
|
ClassNameLoc, EnteringContext, ObjectType, Result, TemplateSpecified);
|
||||||
Result, TemplateSpecified);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that this is a destructor name.
|
// Note that this is a destructor name.
|
||||||
|
|
|
@ -1154,7 +1154,6 @@ bool Parser::ParseOpenMPSimpleVarList(
|
||||||
// Read tokens while ')' or annot_pragma_openmp_end is not found.
|
// Read tokens while ')' or annot_pragma_openmp_end is not found.
|
||||||
while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {
|
while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {
|
||||||
CXXScopeSpec SS;
|
CXXScopeSpec SS;
|
||||||
SourceLocation TemplateKWLoc;
|
|
||||||
UnqualifiedId Name;
|
UnqualifiedId Name;
|
||||||
// Read var name.
|
// Read var name.
|
||||||
Token PrevTok = Tok;
|
Token PrevTok = Tok;
|
||||||
|
@ -1166,7 +1165,7 @@ bool Parser::ParseOpenMPSimpleVarList(
|
||||||
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||||
StopBeforeMatch);
|
StopBeforeMatch);
|
||||||
} else if (ParseUnqualifiedId(SS, false, false, false, false, nullptr,
|
} else if (ParseUnqualifiedId(SS, false, false, false, false, nullptr,
|
||||||
TemplateKWLoc, Name)) {
|
nullptr, Name)) {
|
||||||
IsCorrect = false;
|
IsCorrect = false;
|
||||||
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||||
StopBeforeMatch);
|
StopBeforeMatch);
|
||||||
|
@ -1648,7 +1647,6 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind,
|
||||||
|
|
||||||
static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
|
static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
|
||||||
UnqualifiedId &ReductionId) {
|
UnqualifiedId &ReductionId) {
|
||||||
SourceLocation TemplateKWLoc;
|
|
||||||
if (ReductionIdScopeSpec.isEmpty()) {
|
if (ReductionIdScopeSpec.isEmpty()) {
|
||||||
auto OOK = OO_None;
|
auto OOK = OO_None;
|
||||||
switch (P.getCurToken().getKind()) {
|
switch (P.getCurToken().getKind()) {
|
||||||
|
@ -1690,7 +1688,7 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
|
||||||
/*AllowDestructorName*/ false,
|
/*AllowDestructorName*/ false,
|
||||||
/*AllowConstructorName*/ false,
|
/*AllowConstructorName*/ false,
|
||||||
/*AllowDeductionGuide*/ false,
|
/*AllowDeductionGuide*/ false,
|
||||||
nullptr, TemplateKWLoc, ReductionId);
|
nullptr, nullptr, ReductionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses clauses with list.
|
/// Parses clauses with list.
|
||||||
|
|
|
@ -239,7 +239,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
|
||||||
/*AllowDestructorName=*/false,
|
/*AllowDestructorName=*/false,
|
||||||
/*AllowConstructorName=*/false,
|
/*AllowConstructorName=*/false,
|
||||||
/*AllowDeductionGuide=*/false,
|
/*AllowDeductionGuide=*/false,
|
||||||
/*ObjectType=*/nullptr, TemplateKWLoc, Id);
|
/*ObjectType=*/nullptr, &TemplateKWLoc, Id);
|
||||||
// Perform the lookup.
|
// Perform the lookup.
|
||||||
Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id,
|
Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id,
|
||||||
IsUnevaluatedContext);
|
IsUnevaluatedContext);
|
||||||
|
|
|
@ -2002,7 +2002,7 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) {
|
||||||
if (ParseUnqualifiedId(
|
if (ParseUnqualifiedId(
|
||||||
Result.SS, /*EnteringContext*/false, /*AllowDestructorName*/true,
|
Result.SS, /*EnteringContext*/false, /*AllowDestructorName*/true,
|
||||||
/*AllowConstructorName*/true, /*AllowDeductionGuide*/false, nullptr,
|
/*AllowConstructorName*/true, /*AllowDeductionGuide*/false, nullptr,
|
||||||
TemplateKWLoc, Result.Name)) {
|
&TemplateKWLoc, Result.Name)) {
|
||||||
T.skipToEnd();
|
T.skipToEnd();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2080,7 +2080,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
|
||||||
(Id.getKind() == UnqualifiedIdKind::IK_ImplicitSelfParam)
|
(Id.getKind() == UnqualifiedIdKind::IK_ImplicitSelfParam)
|
||||||
? LookupObjCImplicitSelfParam
|
? LookupObjCImplicitSelfParam
|
||||||
: LookupOrdinaryName);
|
: LookupOrdinaryName);
|
||||||
if (TemplateArgs) {
|
if (TemplateKWLoc.isValid() || TemplateArgs) {
|
||||||
// Lookup the template name again to correctly establish the context in
|
// Lookup the template name again to correctly establish the context in
|
||||||
// which it was found. This is really unfortunate as we already did the
|
// which it was found. This is really unfortunate as we already did the
|
||||||
// lookup to determine that it was a template name in the first place. If
|
// lookup to determine that it was a template name in the first place. If
|
||||||
|
@ -2089,7 +2089,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
|
||||||
bool MemberOfUnknownSpecialization;
|
bool MemberOfUnknownSpecialization;
|
||||||
LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
|
LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
|
||||||
MemberOfUnknownSpecialization);
|
MemberOfUnknownSpecialization);
|
||||||
|
|
||||||
if (MemberOfUnknownSpecialization ||
|
if (MemberOfUnknownSpecialization ||
|
||||||
(R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation))
|
(R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation))
|
||||||
return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
|
return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
|
||||||
|
@ -2155,6 +2155,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
|
||||||
if (SS.isValid())
|
if (SS.isValid())
|
||||||
CCC->setTypoNNS(SS.getScopeRep());
|
CCC->setTypoNNS(SS.getScopeRep());
|
||||||
}
|
}
|
||||||
|
// FIXME: DiagnoseEmptyLookup produces bad diagnostics if we're looking for
|
||||||
|
// a template name, but we happen to have always already looked up the name
|
||||||
|
// before we get here if it must be a template name.
|
||||||
if (DiagnoseEmptyLookup(S, SS, R,
|
if (DiagnoseEmptyLookup(S, SS, R,
|
||||||
CCC ? std::move(CCC) : std::move(DefaultValidator),
|
CCC ? std::move(CCC) : std::move(DefaultValidator),
|
||||||
nullptr, None, &TE)) {
|
nullptr, None, &TE)) {
|
||||||
|
|
|
@ -759,9 +759,9 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
|
||||||
TypoExpr *TE = nullptr;
|
TypoExpr *TE = nullptr;
|
||||||
QualType RecordTy = BaseType;
|
QualType RecordTy = BaseType;
|
||||||
if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
|
if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
|
||||||
if (LookupMemberExprInRecord(*this, R, nullptr,
|
if (LookupMemberExprInRecord(
|
||||||
RecordTy->getAs<RecordType>(), OpLoc, IsArrow,
|
*this, R, nullptr, RecordTy->getAs<RecordType>(), OpLoc, IsArrow,
|
||||||
SS, TemplateArgs != nullptr, TE))
|
SS, TemplateKWLoc.isValid() || TemplateArgs != nullptr, TE))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
if (TE)
|
if (TE)
|
||||||
return TE;
|
return TE;
|
||||||
|
@ -769,10 +769,10 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
|
||||||
// Explicit member accesses.
|
// Explicit member accesses.
|
||||||
} else {
|
} else {
|
||||||
ExprResult BaseResult = Base;
|
ExprResult BaseResult = Base;
|
||||||
ExprResult Result = LookupMemberExpr(
|
ExprResult Result =
|
||||||
*this, R, BaseResult, IsArrow, OpLoc, SS,
|
LookupMemberExpr(*this, R, BaseResult, IsArrow, OpLoc, SS,
|
||||||
ExtraArgs ? ExtraArgs->ObjCImpDecl : nullptr,
|
ExtraArgs ? ExtraArgs->ObjCImpDecl : nullptr,
|
||||||
TemplateArgs != nullptr);
|
TemplateKWLoc.isValid() || TemplateArgs != nullptr);
|
||||||
|
|
||||||
if (BaseResult.isInvalid())
|
if (BaseResult.isInvalid())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
|
@ -158,7 +158,7 @@ bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R,
|
||||||
TemplateNameKind Sema::isTemplateName(Scope *S,
|
TemplateNameKind Sema::isTemplateName(Scope *S,
|
||||||
CXXScopeSpec &SS,
|
CXXScopeSpec &SS,
|
||||||
bool hasTemplateKeyword,
|
bool hasTemplateKeyword,
|
||||||
UnqualifiedId &Name,
|
const UnqualifiedId &Name,
|
||||||
ParsedType ObjectTypePtr,
|
ParsedType ObjectTypePtr,
|
||||||
bool EnteringContext,
|
bool EnteringContext,
|
||||||
TemplateTy &TemplateResult,
|
TemplateTy &TemplateResult,
|
||||||
|
@ -4102,7 +4102,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
|
||||||
TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
|
TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
|
||||||
CXXScopeSpec &SS,
|
CXXScopeSpec &SS,
|
||||||
SourceLocation TemplateKWLoc,
|
SourceLocation TemplateKWLoc,
|
||||||
UnqualifiedId &Name,
|
const UnqualifiedId &Name,
|
||||||
ParsedType ObjectType,
|
ParsedType ObjectType,
|
||||||
bool EnteringContext,
|
bool EnteringContext,
|
||||||
TemplateTy &Result,
|
TemplateTy &Result,
|
||||||
|
|
|
@ -67,7 +67,10 @@ namespace dr108 { // dr108: yes
|
||||||
namespace dr109 { // dr109: yes
|
namespace dr109 { // dr109: yes
|
||||||
struct A { template<typename T> void f(T); };
|
struct A { template<typename T> void f(T); };
|
||||||
template<typename T> struct B : T {
|
template<typename T> struct B : T {
|
||||||
using T::template f; // expected-error {{using declaration cannot refer to a template}}
|
using T::template f; // expected-error {{'template' keyword not permitted here}}
|
||||||
|
using T::template f<int>; // expected-error {{'template' keyword not permitted here}} expected-error {{using declaration cannot refer to a template specialization}}
|
||||||
|
// FIXME: We shouldn't suggest using the 'template' keyword in a location where it's not valid.
|
||||||
|
using T::f<int>; // expected-error {{use 'template' keyword}} expected-error {{using declaration cannot refer to a template specialization}}
|
||||||
void g() { this->f<int>(123); } // expected-error {{use 'template'}}
|
void g() { this->f<int>(123); } // expected-error {{use 'template'}}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -318,8 +318,8 @@ namespace dr420 { // dr420: yes
|
||||||
q->~id<int>();
|
q->~id<int>();
|
||||||
p->id<int>::~id<int>();
|
p->id<int>::~id<int>();
|
||||||
q->id<int>::~id<int>();
|
q->id<int>::~id<int>();
|
||||||
p->template id<int>::~id<int>(); // expected-error {{expected unqualified-id}}
|
p->template id<int>::~id<int>(); // expected-error {{'template' keyword not permitted here}} expected-error {{base type 'int' is not a struct}}
|
||||||
q->template id<int>::~id<int>(); // expected-error {{expected unqualified-id}}
|
q->template id<int>::~id<int>(); // expected-error {{'template' keyword not permitted here}} expected-error {{base type 'int' is not a struct}}
|
||||||
p->A::template id<int>::~id<int>();
|
p->A::template id<int>::~id<int>();
|
||||||
q->A::template id<int>::~id<int>();
|
q->A::template id<int>::~id<int>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,5 +34,5 @@ template<typename T> template<typename U> struct A<T>::B {
|
||||||
// a type, and then complain about the rest of the tokens, and then complain
|
// a type, and then complain about the rest of the tokens, and then complain
|
||||||
// that we didn't get a function declaration.
|
// that we didn't get a function declaration.
|
||||||
friend A<U>::C<T> f7(); // expected-error {{use 'template' keyword to treat 'C' as a dependent template name}} expected-error 3{{}}
|
friend A<U>::C<T> f7(); // expected-error {{use 'template' keyword to treat 'C' as a dependent template name}} expected-error 3{{}}
|
||||||
friend A<U>::template C<T> f8(); // expected-error 3{{}}
|
friend A<U>::template C<T> f8(); // expected-error 4{{}}
|
||||||
};
|
};
|
||||||
|
|
|
@ -237,10 +237,11 @@ namespace PR5066 {
|
||||||
namespace PR17255 {
|
namespace PR17255 {
|
||||||
void foo() {
|
void foo() {
|
||||||
typename A::template B<>; // expected-error {{use of undeclared identifier 'A'}}
|
typename A::template B<>; // expected-error {{use of undeclared identifier 'A'}}
|
||||||
|
// expected-error@-1 {{'template' keyword not permitted here}}
|
||||||
#if __cplusplus <= 199711L
|
#if __cplusplus <= 199711L
|
||||||
// expected-error@-2 {{'template' keyword outside of a template}}
|
// expected-error@-3 {{'template' keyword outside of a template}}
|
||||||
#endif
|
#endif
|
||||||
// expected-error@-4 {{expected a qualified name after 'typename'}}
|
// expected-error@-5 {{expected a qualified name after 'typename'}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -382,16 +382,16 @@ int main() {
|
||||||
|
|
||||||
namespace dependent_static_var_template {
|
namespace dependent_static_var_template {
|
||||||
struct A {
|
struct A {
|
||||||
template<int = 0> static int n; // expected-note {{here}}
|
template<int = 0> static int n; // expected-note 2{{here}}
|
||||||
};
|
};
|
||||||
int &r = A::template n; // FIXME: ill-formed
|
int &r = A::template n; // expected-error {{use of variable template 'n' requires template arguments}}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
int &f() { return T::template n; } // expected-error {{use of variable template 'n' requires template arguments}}
|
int &f() { return T::template n; } // expected-error {{use of variable template 'n' requires template arguments}}
|
||||||
int &s = f<A>(); // expected-note {{instantiation of}}
|
int &s = f<A>(); // expected-note {{instantiation of}}
|
||||||
|
|
||||||
namespace B {
|
namespace B {
|
||||||
template<int = 0> static int n;
|
template<int = 0> static int n; // expected-note {{here}}
|
||||||
}
|
}
|
||||||
int &t = B::template n; // FIXME: ill-formed
|
int &t = B::template n; // expected-error {{use of variable template 'n' requires template arguments}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,52 @@ struct Y0 {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename U> void Y0
|
||||||
|
::template // expected-error {{expected unqualified-id}}
|
||||||
|
f1(U) {}
|
||||||
|
|
||||||
|
// FIXME: error recovery is awful without this.
|
||||||
|
;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Y1 {
|
||||||
|
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() {
|
||||||
|
Y1::template f1<U>(0);
|
||||||
|
Y1::template f1(0);
|
||||||
|
this->template f1(0);
|
||||||
|
|
||||||
|
Y1::template f2<U>(0);
|
||||||
|
Y1::template f2(0);
|
||||||
|
|
||||||
|
Y1::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
|
||||||
|
Y1::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
|
||||||
|
|
||||||
|
int x;
|
||||||
|
x = Y1::f4(0);
|
||||||
|
x = Y1::f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
|
||||||
|
x = Y1::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'}}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void use_Y1(Y1<int> y1) { y1.f<int>(); } // expected-note {{in instantiation of}}
|
||||||
|
|
||||||
struct A {
|
struct A {
|
||||||
template<int I>
|
template<int I>
|
||||||
struct B {
|
struct B {
|
||||||
|
|
Loading…
Reference in New Issue