From a971d2410fabb093954c4119d2287ac24208ea8d Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 9 May 2012 20:55:26 +0000 Subject: [PATCH] Push the knowledge that we are parsing a type-id/type-name further into the parser, and use it to emit better diagnostics in cases where an identifer can't be looked up as a type name. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156508 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 2 +- lib/Parse/ParseDecl.cpp | 7 +++++-- test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp | 4 +--- test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp | 6 +++++- test/Parser/cxx-throw.cpp | 2 ++ test/Parser/cxx11-type-specifier.cpp | 7 +++++++ 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index e1d5b53dec..0ea592fd7e 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1531,7 +1531,7 @@ private: enum DeclSpecContext { DSC_normal, // normal context DSC_class, // class context, enables 'friend' - DSC_type_specifier, // C++ type-specifier-seq + DSC_type_specifier, // C++ type-specifier-seq or C specifier-qualifier-list DSC_trailing, // C++11 trailing-type-specifier in a trailing return type DSC_top_level // top-level/namespace declaration context }; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index e57db6ff9b..7ca9e280ca 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -38,6 +38,8 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, AccessSpecifier AS, Decl **OwnedType) { DeclSpecContext DSC = getDeclSpecContextFromDeclaratorContext(Context); + if (DSC == DSC_normal) + DSC = DSC_type_specifier; // Parse the common declaration-specifiers piece. DeclSpec DS(AttrFactory); @@ -1543,7 +1545,8 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, // Validate declspec for type-name. unsigned Specs = DS.getParsedSpecifiers(); - if (DSC == DSC_type_specifier && !DS.hasTypeSpecifier()) { + if ((DSC == DSC_type_specifier || DSC == DSC_trailing) && + !DS.hasTypeSpecifier()) { Diag(Tok, diag::err_expected_type); DS.SetTypeSpecError(); } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && @@ -1640,7 +1643,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // FIXME: Don't bail out here in languages with no implicit int (like // C++ with no -fms-extensions). This is much more likely to be an undeclared // type or typo than a use of implicit int. - if (DSC != DSC_type_specifier && + if (DSC != DSC_type_specifier && DSC != DSC_trailing && isValidAfterIdentifierInDeclarator(NextToken())) { // If this token is valid for implicit int, e.g. "static x = 4", then // we just avoid eating the identifier, so it will be parsed as the diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp index b06eb01a7f..89a28adcc6 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp @@ -124,9 +124,7 @@ namespace TagName { } namespace CWG1044 { - // FIXME: this diagnostic isn't ideal. one diagnostic is enough. - using T = T; // expected-error {{type name requires a specifier}} \ - expected-error {{expected ';' after alias declaration}} + using T = T; // expected-error {{unknown type name 'T'}} } namespace StdExample { diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp index 574a3e7a79..680e9124cb 100644 --- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp @@ -1,3 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -auto j() -> enum { e3 }; // expected-error{{unnamed enumeration must be a definition}} expected-error {{requires a specifier or qualifier}} expected-error {{without trailing return type}} +// FIXME: We should catch the case of tag with an incomplete type here (which +// will necessarily be ill-formed as a trailing return type for a function +// definition), and recover with a "type cannot be defined in a trailing return +// type" error. +auto j() -> enum { e3 }; // expected-error{{unnamed enumeration must be a definition}} expected-error {{expected a type}} expected-error {{without trailing return type}} diff --git a/test/Parser/cxx-throw.cpp b/test/Parser/cxx-throw.cpp index d63b6d4cae..a1be710fb5 100644 --- a/test/Parser/cxx-throw.cpp +++ b/test/Parser/cxx-throw.cpp @@ -13,3 +13,5 @@ void foo() { __extension__ throw 1; // expected-error {{expected expression}} (void)throw; // expected-error {{expected expression}} } + +void f() throw(static); // expected-error {{expected a type}} expected-error {{does not allow storage class}} diff --git a/test/Parser/cxx11-type-specifier.cpp b/test/Parser/cxx11-type-specifier.cpp index 2e629f3ab5..212ffb407b 100644 --- a/test/Parser/cxx11-type-specifier.cpp +++ b/test/Parser/cxx11-type-specifier.cpp @@ -18,3 +18,10 @@ void f() { (void) new struct S {}; // expected-error{{'S' can not be defined in a type specifier}} (void) new enum E { e }; // expected-error{{'E' can not be defined in a type specifier}} } + +// And for trailing-type-specifier-seq + +// FIXME: Don't treat an ill-formed trailing-return-type the same as no +// trailing-return-type, and avoid the second diagnostic. +auto f() -> unknown; // expected-error{{unknown type name 'unknown'}} \ + expected-error{{'auto' return without trailing return type}} -- 2.40.0