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/ParseTemplate.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/ParseTemplate.cpp')
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 93197816ce..8b9142ce9b 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -902,10 +902,12 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { ConsumeToken(); // the identifier if (isEndOfTemplateArgument(Tok)) { + bool MemberOfUnknownSpecialization; TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, Name, /*ObjectType=*/0, /*EnteringContext=*/false, - Template); + Template, + MemberOfUnknownSpecialization); if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { // We have an id-expression that refers to a class template or // (C++0x) template alias. @@ -966,6 +968,32 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { ExprArg.release(), Loc); } +/// \brief Determine whether the current tokens can only be parsed as a +/// template argument list (starting with the '<') and never as a '<' +/// expression. +bool Parser::IsTemplateArgumentList() { + struct AlwaysRevertAction : TentativeParsingAction { + AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { } + ~AlwaysRevertAction() { Revert(); } + } Tentative(*this); + + // '<' + if (!Tok.is(tok::less)) + return false; + ConsumeToken(); + + // An empty template argument list. + if (Tok.is(tok::greater)) + return true; + + // See whether we have declaration specifiers, which indicate a type. + while (isCXXDeclarationSpecifier() == TPResult::True()) + ConsumeToken(); + + // If we have a '>' or a ',' then this is a template argument list. + return Tok.is(tok::greater) || Tok.is(tok::comma); +} + /// ParseTemplateArgumentList - Parse a C++ template-argument-list /// (C++ [temp.names]). Returns true if there was an error. /// |