From 9ce302ed9c29be8f2e9d83f777d20513c3b22109 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 11 Jul 2013 05:10:21 +0000 Subject: [PATCH] PR5066: If a declarator cannot have an identifier, and cannot possibly be followed by an identifier, then diagnose an identifier as being a bogus part of the declarator instead of tripping over it. Improves diagnostics for cases like std::vector my_vec; llvm-svn: 186061 --- .../clang/Basic/DiagnosticParseKinds.td | 1 + clang/include/clang/Sema/DeclSpec.h | 32 +++++++++++++++++++ clang/lib/Parse/ParseDecl.cpp | 6 ++++ clang/test/FixIt/fixit.cpp | 5 +++ clang/test/Parser/cxx-decl.cpp | 7 ++++ clang/test/Parser/cxx-template-argument.cpp | 2 +- clang/test/Parser/cxx0x-decl.cpp | 7 ++++ 7 files changed, 59 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 26030775337f..d5982e9825d9 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -450,6 +450,7 @@ def err_invalid_operator_on_type : Error< "cannot use %select{dot|arrow}0 operator on a type">; def err_expected_unqualified_id : Error< "expected %select{identifier|unqualified-id}0">; +def err_unexpected_unqualified_id : Error<"type-id cannot have a name">; def err_func_def_no_params : Error< "function definition does not declare parameters">; def err_expected_lparen_after_type : Error< diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index ef74abe188b0..5924a15b7e4f 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1719,6 +1719,38 @@ 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 ConditionContext: + case PrototypeContext: + case TemplateParamContext: + case CXXCatchContext: + case ObjCCatchContext: + case TypeNameContext: + 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!"); + } + /// mayBeFollowedByCXXDirectInit - Return true if the declarator can be /// followed by a C++ direct initializer, e.g. "int x(1);". bool mayBeFollowedByCXXDirectInit() const { diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7559aa95965e..0b276d0b58f5 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -4696,6 +4696,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); goto PastIdentifier; + } else if (Tok.is(tok::identifier) && D.diagnoseIdentifier()) { + Diag(Tok.getLocation(), diag::err_unexpected_unqualified_id) + << FixItHint::CreateRemoval(Tok.getLocation()); + D.SetIdentifier(0, Tok.getLocation()); + ConsumeToken(); + goto PastIdentifier; } if (Tok.is(tok::l_paren)) { diff --git a/clang/test/FixIt/fixit.cpp b/clang/test/FixIt/fixit.cpp index 4e1900a346f8..22c1003e8c94 100644 --- a/clang/test/FixIt/fixit.cpp +++ b/clang/test/FixIt/fixit.cpp @@ -307,3 +307,8 @@ namespace dtor_fixit { // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:9}:"foo" }; } + +namespace PR5066 { + template struct X {}; + X x; // expected-error {{type-id cannot have a name}} +} diff --git a/clang/test/Parser/cxx-decl.cpp b/clang/test/Parser/cxx-decl.cpp index 41d305b17642..e3f3957d564c 100644 --- a/clang/test/Parser/cxx-decl.cpp +++ b/clang/test/Parser/cxx-decl.cpp @@ -187,6 +187,13 @@ namespace PR15017 { // Ensure we produce at least some diagnostic for attributes in C++98. [[]] struct S; // expected-error 2{{}} +namespace PR5066 { + template struct X {}; + X x; // expected-error {{type-id cannot have a name}} + + using T = int (*T)(); // expected-error {{type-id cannot have a name}} expected-warning {{C++11}} +} + // PR8380 extern "" // expected-error {{unknown linkage language}} test6a { ;// expected-error {{C++ requires a type specifier for all declarations}} \ diff --git a/clang/test/Parser/cxx-template-argument.cpp b/clang/test/Parser/cxx-template-argument.cpp index afe318df7a1a..a2c69be64630 100644 --- a/clang/test/Parser/cxx-template-argument.cpp +++ b/clang/test/Parser/cxx-template-argument.cpp @@ -5,7 +5,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/clang/test/Parser/cxx0x-decl.cpp b/clang/test/Parser/cxx0x-decl.cpp index e6cba726ab63..3d04bfe81608 100644 --- a/clang/test/Parser/cxx0x-decl.cpp +++ b/clang/test/Parser/cxx0x-decl.cpp @@ -73,3 +73,10 @@ enum E [[]] e; } + +namespace PR5066 { + using T = int (*f)(); // expected-error {{type-id cannot have a name}} + template using U = int (*f)(); // expected-error {{type-id cannot have a name}} + auto f() -> int (*f)(); // expected-error {{type-id cannot have a name}} + auto g = []() -> int (*f)() {}; // expected-error {{type-id cannot have a name}} +}