diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-05-21 23:18:07 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-05-21 23:18:07 +0000 |
commit | 1fd6d44d7ca97631497551bbf98866263143d706 (patch) | |
tree | d55684a3629ba44cddbe0b9d29897c19e6663f3f /lib/Parse/ParseExprCXX.cpp | |
parent | db3f847cb883fdb19d79c7223fa032e7266c0ee5 (diff) |
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
Diffstat (limited to 'lib/Parse/ParseExprCXX.cpp')
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 46 |
1 files changed, 41 insertions, 5 deletions
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index b7ccea53d5..1588b69bda 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -289,11 +289,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, 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 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, 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 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, 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) |