From 635020a50def2174b5b0dd3356f59cac53838f1f Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 19 May 2017 01:54:59 +0000 Subject: [PATCH] When a type-id is unexpectedly given a name, assume that the name is unrelated syntax unless we have a reason to think otherwise. This improves error recovery in a couple of cases. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@303398 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/DeclSpec.h | 35 --------------------------- lib/Parse/ParseDecl.cpp | 27 +++++++++++++++++---- test/Parser/cxx-template-argument.cpp | 2 +- test/Parser/cxx0x-decl.cpp | 3 +++ test/Sema/block-args.c | 2 +- 5 files changed, 27 insertions(+), 42 deletions(-) diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index df5e105036..bc817150ab 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -1999,41 +1999,6 @@ public: llvm_unreachable("unknown context kind!"); } - /// diagnoseIdentifier - Return true if the identifier is prohibited and - /// should be diagnosed (because it cannot be anything else). - bool diagnoseIdentifier() const { - switch (Context) { - case FileContext: - case KNRTypeListContext: - case MemberContext: - case BlockContext: - case ForContext: - case InitStmtContext: - case ConditionContext: - case PrototypeContext: - case LambdaExprParameterContext: - case TemplateParamContext: - case CXXCatchContext: - case ObjCCatchContext: - case TypeNameContext: - case FunctionalCastContext: - case ConversionIdContext: - case ObjCParameterContext: - case ObjCResultContext: - case BlockLiteralContext: - case CXXNewContext: - case LambdaExprContext: - return false; - - case AliasDeclContext: - case AliasTemplateContext: - case TemplateTypeArgContext: - case TrailingReturnContext: - return true; - } - llvm_unreachable("unknown context kind!"); - } - /// Return true if the context permits a C++17 decomposition declarator. bool mayHaveDecompositionDeclarator() const { switch (Context) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 69e1af0ed0..b785f5f7d2 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5542,11 +5542,28 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetRangeEnd(Tok.getLocation()); ConsumeToken(); goto PastIdentifier; - } else if (Tok.is(tok::identifier) && D.diagnoseIdentifier()) { - // A virt-specifier isn't treated as an identifier if it appears after a - // trailing-return-type. - if (D.getContext() != Declarator::TrailingReturnContext || - !isCXX11VirtSpecifier(Tok)) { + } else if (Tok.is(tok::identifier) && !D.mayHaveIdentifier()) { + // We're not allowed an identifier here, but we got one. Try to figure out + // if the user was trying to attach a name to the type, or whether the name + // is some unrelated trailing syntax. + bool DiagnoseIdentifier = false; + if (D.hasGroupingParens()) + // An identifier within parens is unlikely to be intended to be anything + // other than a name being "declared". + DiagnoseIdentifier = true; + else if (D.getContext() == Declarator::TemplateTypeArgContext) + // T is an accidental identifier; T'. + DiagnoseIdentifier = + NextToken().isOneOf(tok::comma, tok::greater, tok::greatergreater); + else if (D.getContext() == Declarator::AliasDeclContext || + D.getContext() == Declarator::AliasTemplateContext) + // The most likely error is that the ';' was forgotten. + DiagnoseIdentifier = NextToken().isOneOf(tok::comma, tok::semi); + else if (D.getContext() == Declarator::TrailingReturnContext && + !isCXX11VirtSpecifier(Tok)) + DiagnoseIdentifier = NextToken().isOneOf( + tok::comma, tok::semi, tok::equal, tok::l_brace, tok::kw_try); + if (DiagnoseIdentifier) { Diag(Tok.getLocation(), diag::err_unexpected_unqualified_id) << FixItHint::CreateRemoval(Tok.getLocation()); D.SetIdentifier(nullptr, Tok.getLocation()); diff --git a/test/Parser/cxx-template-argument.cpp b/test/Parser/cxx-template-argument.cpp index 9b8ca985dd..963356eaab 100644 --- a/test/Parser/cxx-template-argument.cpp +++ b/test/Parser/cxx-template-argument.cpp @@ -10,7 +10,7 @@ template struct A {}; // Check for template argument lists followed by junk // FIXME: The diagnostics here aren't great... A int x; // expected-error {{expected '>'}} expected-error {{expected unqualified-id}} -A'}} +A'}} // PR8912 template struct S {}; diff --git a/test/Parser/cxx0x-decl.cpp b/test/Parser/cxx0x-decl.cpp index ba322a5894..2b253c019c 100644 --- a/test/Parser/cxx0x-decl.cpp +++ b/test/Parser/cxx0x-decl.cpp @@ -137,6 +137,9 @@ namespace AliasDeclEndLocation { >\ > // expected-error {{expected ';' after alias declaration}} ; + using D = AliasDeclEndLocation::A // expected-error {{expected ';' after alias declaration}} + B something_else; } struct Base { virtual void f() = 0; virtual void g() = 0; virtual void h() = 0; }; diff --git a/test/Sema/block-args.c b/test/Sema/block-args.c index c6beead391..69cf047a9e 100644 --- a/test/Sema/block-args.c +++ b/test/Sema/block-args.c @@ -37,7 +37,7 @@ void f0() { // rdar://problem/8962770 void test4() { - int (^f)() = ^((x)) { }; // expected-error {{expected ')'}} expected-warning {{type specifier missing}} expected-note {{to match this}} + int (^f)() = ^((x)) { }; // expected-warning {{type specifier missing}} expected-error {{type-id cannot have a name}} } // rdar://problem/9170609 -- 2.40.0