From: Steve Naroff Date: Tue, 12 Feb 2008 04:08:59 +0000 (+0000) Subject: Allow the parser to detect invalid DeclSpec's. This fixes http://llvm.org/bugs/show_b... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9532414c45a7114d9e94a733121655a5b5d5b473;p=clang Allow the parser to detect invalid DeclSpec's. This fixes http://llvm.org/bugs/show_bug.cgi?id=1987. This commit only "guards" the call to ParseDeclarationSpecifiers() in ParseDeclarationOrFunctionDefinition(). We could consider guarding all calls, however this is a bit radical (since it effectively stops parsing the declaration once we have a bad declspec). Will discuss with Chris tomorrow. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46984 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Parse/DeclSpec.cpp b/Parse/DeclSpec.cpp index 15e291f46c..8f9a5fd791 100644 --- a/Parse/DeclSpec.cpp +++ b/Parse/DeclSpec.cpp @@ -47,36 +47,40 @@ const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { } } -static bool BadSpecifier(DeclSpec::SCS S, const char *&PrevSpec) { - PrevSpec = DeclSpec::getSpecifierName(S); +bool DeclSpec::BadSpecifier(SCS S, const char *&PrevSpec) { + Invalid = true; + PrevSpec = getSpecifierName(S); return true; } -static bool BadSpecifier(DeclSpec::TSW W, const char *&PrevSpec) { +bool DeclSpec::BadSpecifier(TSW W, const char *&PrevSpec) { + Invalid = true; switch (W) { - case DeclSpec::TSW_unspecified: PrevSpec = "unspecified"; break; - case DeclSpec::TSW_short: PrevSpec = "short"; break; - case DeclSpec::TSW_long: PrevSpec = "long"; break; - case DeclSpec::TSW_longlong: PrevSpec = "long long"; break; + case TSW_unspecified: PrevSpec = "unspecified"; break; + case TSW_short: PrevSpec = "short"; break; + case TSW_long: PrevSpec = "long"; break; + case TSW_longlong: PrevSpec = "long long"; break; } return true; } -static bool BadSpecifier(DeclSpec::TSC C, const char *&PrevSpec) { +bool DeclSpec::BadSpecifier(TSC C, const char *&PrevSpec) { + Invalid = true; switch (C) { - case DeclSpec::TSC_unspecified: PrevSpec = "unspecified"; break; - case DeclSpec::TSC_imaginary: PrevSpec = "imaginary"; break; - case DeclSpec::TSC_complex: PrevSpec = "complex"; break; + case TSC_unspecified: PrevSpec = "unspecified"; break; + case TSC_imaginary: PrevSpec = "imaginary"; break; + case TSC_complex: PrevSpec = "complex"; break; } return true; } -static bool BadSpecifier(DeclSpec::TSS S, const char *&PrevSpec) { +bool DeclSpec::BadSpecifier(TSS S, const char *&PrevSpec) { + Invalid = true; switch (S) { - case DeclSpec::TSS_unspecified: PrevSpec = "unspecified"; break; - case DeclSpec::TSS_signed: PrevSpec = "signed"; break; - case DeclSpec::TSS_unsigned: PrevSpec = "unsigned"; break; + case TSS_unspecified: PrevSpec = "unspecified"; break; + case TSS_signed: PrevSpec = "signed"; break; + case TSS_unsigned: PrevSpec = "unsigned"; break; } return true; } @@ -103,12 +107,14 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { } } -static bool BadSpecifier(DeclSpec::TST T, const char *&PrevSpec) { - PrevSpec = DeclSpec::getSpecifierName(T); +bool DeclSpec::BadSpecifier(TST T, const char *&PrevSpec) { + Invalid = true; + PrevSpec = getSpecifierName(T); return true; } -static bool BadSpecifier(DeclSpec::TQ T, const char *&PrevSpec) { +bool DeclSpec::BadSpecifier(TQ T, const char *&PrevSpec) { + Invalid = true; switch (T) { case DeclSpec::TQ_unspecified: PrevSpec = "unspecified"; break; case DeclSpec::TQ_const: PrevSpec = "const"; break; diff --git a/Parse/Parser.cpp b/Parse/Parser.cpp index e3208a0b3e..860a44f9e9 100644 --- a/Parse/Parser.cpp +++ b/Parse/Parser.cpp @@ -367,7 +367,10 @@ Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() { // Parse the common declaration-specifiers piece. DeclSpec DS; ParseDeclarationSpecifiers(DS); - + // If the decl specs are invalid, there is no need to continue. + if (DS.isInvalid()) + return 0; + // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index bb2773217e..e38f764af6 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -134,6 +134,15 @@ private: SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc; SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc; SourceLocation FS_inlineLoc; + + bool Invalid; + + bool BadSpecifier(TST T, const char *&PrevSpec); + bool BadSpecifier(TQ T, const char *&PrevSpec); + bool BadSpecifier(TSS T, const char *&PrevSpec); + bool BadSpecifier(TSC T, const char *&PrevSpec); + bool BadSpecifier(TSW T, const char *&PrevSpec); + bool BadSpecifier(SCS T, const char *&PrevSpec); public: DeclSpec() @@ -147,7 +156,8 @@ public: FS_inline_specified(false), TypeRep(0), AttrList(0), - ProtocolQualifiers(0) { + ProtocolQualifiers(0), + Invalid(false) { } ~DeclSpec() { delete AttrList; @@ -160,6 +170,7 @@ public: SourceLocation getStorageClassSpecLoc() const { return StorageClassSpecLoc; } SourceLocation getThreadSpecLoc() const { return SCS_threadLoc; } + bool isInvalid() { return Invalid; } void ClearStorageClassSpecs() { StorageClassSpec = DeclSpec::SCS_unspecified; diff --git a/test/Sema/declspec.c b/test/Sema/declspec.c index 05f492d67a..fd57540681 100644 --- a/test/Sema/declspec.c +++ b/test/Sema/declspec.c @@ -5,4 +5,8 @@ T foo(int n, int m) { } // expected-error {{cannot return array or function}} void foof(const char *, ...) __attribute__((__format__(__printf__, 1, 2))), barf (void); - +struct _zend_module_entry { } +typedef struct _zend_function_entry { } // expected-error {{cannot combine with previous 'struct' declaration specifier}} +static void buggy(int *x) { // expected-error {{cannot combine with previous 'typedef' declaration specifier}} \ + // expected-error {{cannot combine with previous 'struct' declaration specifier}} + // expected-error {{expected '}'}}