Improve parser recovery when we encounter a dependent template name
that is missing the 'template' keyword, e.g.,
t->getAs<T>()
where getAs is a member of an unknown specialization. C++ requires
that we treat "getAs" as a value, but that would fail to parse since T
is the name of a type. We would then fail at the '>', since a type
cannot be followed by a '>'.
This is a very common error for C++ programmers to make, especially
since GCC occasionally allows it when it shouldn't (as does Visual
C++). So, when we are in this case, we use tentative parsing to see if
the tokens starting at "<" can only be parsed as a template argument
list. If so, we produce a diagnostic with a fix-it that states that
the 'template' keyword is needed:
test/SemaTemplate/dependent-template-recover.cpp:5:8: error: 'template' keyword
is required to treat 'getAs' as a dependent template name
t->getAs<T>();
^
template
This is just a start of this patch; I'd like to apply the same
approach to everywhere that a template-id with dependent template name
can be parsed.
llvm-svn: 104406
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 0870431..1b61800 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -2800,14 +2800,16 @@
// C++ Templates [C++ 14]
//
void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
- QualType ObjectType, bool EnteringContext);
+ QualType ObjectType, bool EnteringContext,
+ bool &MemberOfUnknownSpecialization);
virtual TemplateNameKind isTemplateName(Scope *S,
CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext,
- TemplateTy &Template);
+ TemplateTy &Template,
+ bool &MemberOfUnknownSpecialization);
virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
SourceLocation IILoc,
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index b94f3d7..19e31da 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -287,8 +287,9 @@
Name.setIdentifier(&II, IILoc);
CXXScopeSpec EmptySS;
TemplateTy TemplateResult;
- if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult)
- == TNK_Type_template) {
+ bool MemberOfUnknownSpecialization;
+ if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult,
+ MemberOfUnknownSpecialization) == TNK_Type_template) {
TemplateName TplName = TemplateResult.getAsVal<TemplateName>();
Diag(IILoc, diag::err_template_missing_args) << TplName;
if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 933a696..8c854ab 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -1055,7 +1055,9 @@
// lookup to determine that it was a template name in the first place. If
// this becomes a performance hit, we can work harder to preserve those
// results until we get here but it's likely not worth it.
- LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false);
+ bool MemberOfUnknownSpecialization;
+ LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
+ MemberOfUnknownSpecialization);
} else {
bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl());
LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 6a4f347..b4f9c3d 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -100,10 +100,12 @@
UnqualifiedId &Name,
TypeTy *ObjectTypePtr,
bool EnteringContext,
- TemplateTy &TemplateResult) {
+ TemplateTy &TemplateResult,
+ bool &MemberOfUnknownSpecialization) {
assert(getLangOptions().CPlusPlus && "No template names in C!");
DeclarationName TName;
+ MemberOfUnknownSpecialization = false;
switch (Name.getKind()) {
case UnqualifiedId::IK_Identifier:
@@ -128,7 +130,8 @@
LookupResult R(*this, TName, Name.getSourceRange().getBegin(),
LookupOrdinaryName);
R.suppressDiagnostics();
- LookupTemplateName(R, S, SS, ObjectType, EnteringContext);
+ LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
+ MemberOfUnknownSpecialization);
if (R.empty() || R.isAmbiguous())
return TNK_Non_template;
@@ -191,8 +194,10 @@
void Sema::LookupTemplateName(LookupResult &Found,
Scope *S, CXXScopeSpec &SS,
QualType ObjectType,
- bool EnteringContext) {
+ bool EnteringContext,
+ bool &MemberOfUnknownSpecialization) {
// Determine where to perform name lookup
+ MemberOfUnknownSpecialization = false;
DeclContext *LookupCtx = 0;
bool isDependent = false;
if (!ObjectType.isNull()) {
@@ -241,6 +246,7 @@
} else if (isDependent) {
// We cannot look into a dependent object type or nested nme
// specifier.
+ MemberOfUnknownSpecialization = true;
return;
} else {
// Perform unqualified name lookup in the current scope.
@@ -1641,8 +1647,10 @@
RequireCompleteDeclContext(SS, DC))
return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs);
+ bool MemberOfUnknownSpecialization;
LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
- LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false);
+ LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false,
+ MemberOfUnknownSpecialization);
if (R.isAmbiguous())
return ExprError();
@@ -1699,8 +1707,10 @@
// "template" keyword is now permitted). We follow the C++0x
// rules, even in C++03 mode, retroactively applying the DR.
TemplateTy Template;
+ bool MemberOfUnknownSpecialization;
TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType,
- EnteringContext, Template);
+ EnteringContext, Template,
+ MemberOfUnknownSpecialization);
if (TNK == TNK_Non_template && LookupCtx->isDependentContext() &&
isa<CXXRecordDecl>(LookupCtx) &&
cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) {