diff options
author | Richard Smith <richard@metafoo.co.uk> | 2020-03-27 17:08:26 -0700 |
---|---|---|
committer | Richard Smith <richard@metafoo.co.uk> | 2020-03-27 17:11:04 -0700 |
commit | b3f6e3d6d64d77a9c840b8407b7e3c49b62b46dd (patch) | |
tree | e895b196f86f66c63f133bf648951ee78f75fec8 /clang/lib/Parse/ParseDecl.cpp | |
parent | 569e4f9bc99a755cc30f0102b29b1eefd4fa33b4 (diff) | |
download | llvm-b3f6e3d6d64d77a9c840b8407b7e3c49b62b46dd.zip llvm-b3f6e3d6d64d77a9c840b8407b7e3c49b62b46dd.tar.gz llvm-b3f6e3d6d64d77a9c840b8407b7e3c49b62b46dd.tar.bz2 |
Improve recovery from invalid template-ids.
Instead of bailing out of parsing when we encounter an invalid
template-name or template arguments in a template-id, produce an
annotation token describing the invalid construct.
This avoids duplicate errors and generally allows us to recover better.
In principle we should be able to extend this to store some kinds of
invalid template-id in the AST for tooling use, but that isn't handled
as part of this change.
Diffstat (limited to 'clang/lib/Parse/ParseDecl.cpp')
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index e3c784c..95706fb 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3162,9 +3162,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // We are looking for a qualified typename. Token Next = NextToken(); - if (Next.is(tok::annot_template_id) && - static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()) - ->Kind == TNK_Type_template) { + + TemplateIdAnnotation *TemplateId = Next.is(tok::annot_template_id) + ? takeTemplateIdAnnotation(Next) + : nullptr; + if (TemplateId && TemplateId->hasInvalidName()) { + // We found something like 'T::U<Args> x', but U is not a template. + // Assume it was supposed to be a type. + DS.SetTypeSpecError(); + ConsumeAnnotationToken(); + break; + } + + if (TemplateId && TemplateId->Kind == TNK_Type_template) { // We have a qualified template-id, e.g., N::A<int> // If this would be a valid constructor declaration with template @@ -3174,7 +3184,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // // To improve diagnostics for this case, parse the declaration as a // constructor (and reject the extra template arguments later). - TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); if ((DSContext == DeclSpecContext::DSC_top_level || DSContext == DeclSpecContext::DSC_class) && TemplateId->Name && @@ -3195,9 +3204,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; } - if (Next.is(tok::annot_template_id) && - static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()) - ->Kind == TNK_Concept_template && + if (TemplateId && TemplateId->Kind == TNK_Concept_template && GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype)) { DS.getTypeSpecScope() = SS; // This is a qualified placeholder-specifier, e.g., ::C<int> auto ... @@ -3459,7 +3466,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // type-name or placeholder-specifier case tok::annot_template_id: { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + + if (TemplateId->hasInvalidName()) { + DS.SetTypeSpecError(); + break; + } + if (TemplateId->Kind == TNK_Concept_template) { + // If we've already diagnosed that this type-constraint has invalid + // arguemnts, drop it and just form 'auto' or 'decltype(auto)'. + if (TemplateId->hasInvalidArgs()) + TemplateId = nullptr; + if (NextToken().is(tok::identifier)) { Diag(Loc, diag::err_placeholder_expected_auto_or_decltype_auto) << FixItHint::CreateInsertion(NextToken().getLocation(), "auto"); @@ -5197,14 +5215,30 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { // placeholder-type-specifier case tok::annot_template_id: { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->hasInvalidName()) + return true; + // FIXME: What about type templates that have only been annotated as + // annot_template_id, not as annot_typename? return isTypeConstraintAnnotation() && - (NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype)); + (NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype)); } - case tok::annot_cxxscope: + + case tok::annot_cxxscope: { + TemplateIdAnnotation *TemplateId = + NextToken().is(tok::annot_template_id) + ? takeTemplateIdAnnotation(NextToken()) + : nullptr; + if (TemplateId && TemplateId->hasInvalidName()) + return true; + // FIXME: What about type templates that have only been annotated as + // annot_template_id, not as annot_typename? if (NextToken().is(tok::identifier) && TryAnnotateTypeConstraint()) return true; return isTypeConstraintAnnotation() && GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype); + } + case tok::kw___declspec: case tok::kw___cdecl: case tok::kw___stdcall: |