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.

llvm-svn: 46984
This commit is contained in:
Steve Naroff 2008-02-12 04:08:59 +00:00
parent 779593cd9d
commit ab468cb14b
4 changed files with 45 additions and 21 deletions

View File

@ -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;

View File

@ -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)) {

View File

@ -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;

View File

@ -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 '}'}}