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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104406 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index b7ccea5..1588b69 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -289,11 +289,13 @@
TemplateTy Template;
UnqualifiedId TemplateName;
TemplateName.setIdentifier(&II, Tok.getLocation());
+ bool MemberOfUnknownSpecialization;
if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS,
TemplateName,
ObjectType,
EnteringContext,
- Template)) {
+ Template,
+ MemberOfUnknownSpecialization)) {
// We have found a template name, so annotate this this token
// with a template-id annotation. We do not permit the
// template-id to be translated into a type annotation,
@@ -990,21 +992,54 @@
TNK = TNK_Dependent_template_name;
if (!Template.get())
return true;
- } else
+ } else {
+ bool MemberOfUnknownSpecialization;
TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType,
- EnteringContext, Template);
+ EnteringContext, Template,
+ MemberOfUnknownSpecialization);
+
+ if (TNK == TNK_Non_template && MemberOfUnknownSpecialization &&
+ ObjectType && IsTemplateArgumentList()) {
+ // We have something like t->getAs<T>(), where getAs is a
+ // member of an unknown specialization. However, this will only
+ // parse correctly as a template, so suggest the keyword 'template'
+ // before 'getAs' and treat this as a dependent template name.
+ std::string Name;
+ if (Id.getKind() == UnqualifiedId::IK_Identifier)
+ Name = Id.Identifier->getName();
+ else {
+ Name = "operator ";
+ if (Id.getKind() == UnqualifiedId::IK_OperatorFunctionId)
+ Name += getOperatorSpelling(Id.OperatorFunctionId.Operator);
+ else
+ Name += Id.Identifier->getName();
+ }
+ Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword)
+ << Name
+ << FixItHint::CreateInsertion(Id.StartLocation, "template ");
+ Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS,
+ Id, ObjectType,
+ EnteringContext);
+ TNK = TNK_Dependent_template_name;
+ if (!Template.get())
+ return true;
+ }
+ }
break;
case UnqualifiedId::IK_ConstructorName: {
UnqualifiedId TemplateName;
+ bool MemberOfUnknownSpecialization;
TemplateName.setIdentifier(Name, NameLoc);
TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType,
- EnteringContext, Template);
+ EnteringContext, Template,
+ MemberOfUnknownSpecialization);
break;
}
case UnqualifiedId::IK_DestructorName: {
UnqualifiedId TemplateName;
+ bool MemberOfUnknownSpecialization;
TemplateName.setIdentifier(Name, NameLoc);
if (ObjectType) {
Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS,
@@ -1015,7 +1050,8 @@
return true;
} else {
TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType,
- EnteringContext, Template);
+ EnteringContext, Template,
+ MemberOfUnknownSpecialization);
if (TNK == TNK_Non_template && Id.DestructorName == 0) {
Diag(NameLoc, diag::err_destructor_template_id)