Fix speculative parsing of dependent template names in
nested-name-specifiers so that they don't gobble the template name (or
operator-function-id) unless there is also a
template-argument-list. For example, given
T::template apply
we would previously consume both "template" and "apply" as part of
parsing the nested-name-specifier, then error when we see that there
is no "<" starting a template argument list. Now, we parse such
constructs tentatively, and back off if the "<" is not present. This
allows us to parse dependent template names as one would use them for,
e.g., template template parameters:
template<typename T, template<class> class X = T::template apply>
struct MetaSomething;
Also, test default arguments for template template parameters.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86841 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index a7e7648..b2ecc9e 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -109,52 +109,43 @@
if (!HasScopeSpecifier && !ObjectType)
break;
+ TentativeParsingAction TPA(*this);
SourceLocation TemplateKWLoc = ConsumeToken();
UnqualifiedId TemplateName;
if (Tok.is(tok::identifier)) {
- TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
-
- // If the next token is not '<', we may have a stray 'template' keyword.
- // Complain and suggest removing the template keyword, but otherwise
- // allow parsing to continue.
- if (NextToken().isNot(tok::less)) {
- Diag(NextToken().getLocation(),
- diag::err_less_after_template_name_in_nested_name_spec)
- << Tok.getIdentifierInfo()->getName()
- << CodeModificationHint::CreateRemoval(SourceRange(TemplateKWLoc));
- break;
- }
-
// Consume the identifier.
+ TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken();
} else if (Tok.is(tok::kw_operator)) {
if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType,
- TemplateName))
+ TemplateName)) {
+ TPA.Commit();
break;
+ }
if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId) {
Diag(TemplateName.getSourceRange().getBegin(),
diag::err_id_after_template_in_nested_name_spec)
<< TemplateName.getSourceRange();
- break;
- } else if (Tok.isNot(tok::less)) {
- std::string OperatorName = "operator ";
- OperatorName += getOperatorSpelling(
- TemplateName.OperatorFunctionId.Operator);
- Diag(Tok.getLocation(),
- diag::err_less_after_template_name_in_nested_name_spec)
- << OperatorName
- << TemplateName.getSourceRange();
+ TPA.Commit();
break;
}
} else {
- Diag(Tok.getLocation(),
- diag::err_id_after_template_in_nested_name_spec)
- << SourceRange(TemplateKWLoc);
+ TPA.Revert();
break;
}
+ // If the next token is not '<', we have a qualified-id that refers
+ // to a template name, such as T::template apply, but is not a
+ // template-id.
+ if (Tok.isNot(tok::less)) {
+ TPA.Revert();
+ break;
+ }
+
+ // Commit to parsing the template-id.
+ TPA.Commit();
TemplateTy Template
= Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName,
ObjectType);