mirror of
https://github.com/cc65/cc65.git
synced 2025-01-14 16:33:00 +00:00
Merge pull request #1905 from acqn/DeclFix
[cc65] Fixed some missing declaration features
This commit is contained in:
commit
53b62184e8
@ -123,7 +123,7 @@ static void Parse (void)
|
||||
}
|
||||
|
||||
/* Read variable defs and functions */
|
||||
ParseDeclSpec (&Spec, SC_EXTERN | SC_STATIC, T_INT);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_EXTERN | SC_STATIC);
|
||||
|
||||
/* Don't accept illegal storage classes */
|
||||
if ((Spec.StorageClass & SC_TYPEMASK) == 0) {
|
||||
|
@ -72,8 +72,7 @@
|
||||
|
||||
|
||||
|
||||
static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
||||
int* SignednessSpecified);
|
||||
static void ParseTypeSpec (DeclSpec* D, typespec_t TSFlags, int* SignednessSpecified);
|
||||
/* Parse a type specifier */
|
||||
|
||||
|
||||
@ -84,6 +83,75 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
||||
|
||||
|
||||
|
||||
static unsigned ParseOneStorageClass (void)
|
||||
/* Parse and return a storage class specifier */
|
||||
{
|
||||
unsigned StorageClass = 0;
|
||||
|
||||
/* Check the storage class given */
|
||||
switch (CurTok.Tok) {
|
||||
|
||||
case TOK_EXTERN:
|
||||
StorageClass = SC_EXTERN | SC_STATIC;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_STATIC:
|
||||
StorageClass = SC_STATIC;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_REGISTER:
|
||||
StorageClass = SC_REGISTER | SC_STATIC;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_AUTO:
|
||||
StorageClass = SC_AUTO;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_TYPEDEF:
|
||||
StorageClass = SC_TYPEDEF;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return StorageClass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int ParseStorageClass (DeclSpec* D)
|
||||
/* Parse storage class specifiers. Return true if a specifier is read even if
|
||||
** it was duplicated or disallowed. */
|
||||
{
|
||||
/* Check the storage class given */
|
||||
unsigned StorageClass = ParseOneStorageClass ();
|
||||
|
||||
if (StorageClass == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (StorageClass != 0) {
|
||||
if (D->StorageClass == 0) {
|
||||
D->StorageClass = StorageClass;
|
||||
} else if (D->StorageClass == StorageClass) {
|
||||
Warning ("Duplicate storage class specifier");
|
||||
} else {
|
||||
Error ("Conflicting storage class specifier");
|
||||
}
|
||||
StorageClass = ParseOneStorageClass ();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DuplicateQualifier (const char* Name)
|
||||
/* Print an error message */
|
||||
{
|
||||
@ -92,9 +160,9 @@ static void DuplicateQualifier (const char* Name)
|
||||
|
||||
|
||||
|
||||
static TypeCode OptionalQualifiers (TypeCode Allowed)
|
||||
static TypeCode OptionalQualifiers (TypeCode Qualifiers, TypeCode Allowed)
|
||||
/* Read type qualifiers if we have any. Allowed specifies the allowed
|
||||
** qualifiers.
|
||||
** qualifiers. Return any read qualifiers even if they caused errors.
|
||||
*/
|
||||
{
|
||||
/* We start without any qualifiers */
|
||||
@ -107,7 +175,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
||||
|
||||
case TOK_CONST:
|
||||
if (Allowed & T_QUAL_CONST) {
|
||||
if (Q & T_QUAL_CONST) {
|
||||
if (Qualifiers & T_QUAL_CONST) {
|
||||
DuplicateQualifier ("const");
|
||||
}
|
||||
Q |= T_QUAL_CONST;
|
||||
@ -118,7 +186,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
||||
|
||||
case TOK_VOLATILE:
|
||||
if (Allowed & T_QUAL_VOLATILE) {
|
||||
if (Q & T_QUAL_VOLATILE) {
|
||||
if (Qualifiers & T_QUAL_VOLATILE) {
|
||||
DuplicateQualifier ("volatile");
|
||||
}
|
||||
Q |= T_QUAL_VOLATILE;
|
||||
@ -129,7 +197,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
||||
|
||||
case TOK_RESTRICT:
|
||||
if (Allowed & T_QUAL_RESTRICT) {
|
||||
if (Q & T_QUAL_RESTRICT) {
|
||||
if (Qualifiers & T_QUAL_RESTRICT) {
|
||||
DuplicateQualifier ("restrict");
|
||||
}
|
||||
Q |= T_QUAL_RESTRICT;
|
||||
@ -140,7 +208,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
||||
|
||||
case TOK_NEAR:
|
||||
if (Allowed & T_QUAL_NEAR) {
|
||||
if (Q & T_QUAL_NEAR) {
|
||||
if (Qualifiers & T_QUAL_NEAR) {
|
||||
DuplicateQualifier ("near");
|
||||
}
|
||||
Q |= T_QUAL_NEAR;
|
||||
@ -151,7 +219,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
||||
|
||||
case TOK_FAR:
|
||||
if (Allowed & T_QUAL_FAR) {
|
||||
if (Q & T_QUAL_FAR) {
|
||||
if (Qualifiers & T_QUAL_FAR) {
|
||||
DuplicateQualifier ("far");
|
||||
}
|
||||
Q |= T_QUAL_FAR;
|
||||
@ -162,7 +230,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
||||
|
||||
case TOK_FASTCALL:
|
||||
if (Allowed & T_QUAL_FASTCALL) {
|
||||
if (Q & T_QUAL_FASTCALL) {
|
||||
if (Qualifiers & T_QUAL_FASTCALL) {
|
||||
DuplicateQualifier ("fastcall");
|
||||
}
|
||||
Q |= T_QUAL_FASTCALL;
|
||||
@ -173,7 +241,7 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
||||
|
||||
case TOK_CDECL:
|
||||
if (Allowed & T_QUAL_CDECL) {
|
||||
if (Q & T_QUAL_CDECL) {
|
||||
if (Qualifiers & T_QUAL_CDECL) {
|
||||
DuplicateQualifier ("cdecl");
|
||||
}
|
||||
Q |= T_QUAL_CDECL;
|
||||
@ -187,13 +255,16 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
|
||||
|
||||
}
|
||||
|
||||
/* Combine with newly read qualifiers */
|
||||
Qualifiers |= Q;
|
||||
|
||||
/* Skip the token */
|
||||
NextToken ();
|
||||
}
|
||||
|
||||
Done:
|
||||
/* We cannot have more than one address size far qualifier */
|
||||
switch (Q & T_QUAL_ADDRSIZE) {
|
||||
switch (Qualifiers & T_QUAL_ADDRSIZE) {
|
||||
|
||||
case T_QUAL_NONE:
|
||||
case T_QUAL_NEAR:
|
||||
@ -202,11 +273,11 @@ Done:
|
||||
|
||||
default:
|
||||
Error ("Cannot specify more than one address size qualifier");
|
||||
Q &= ~T_QUAL_ADDRSIZE;
|
||||
Qualifiers &= ~T_QUAL_ADDRSIZE;
|
||||
}
|
||||
|
||||
/* We cannot have more than one calling convention specifier */
|
||||
switch (Q & T_QUAL_CCONV) {
|
||||
switch (Qualifiers & T_QUAL_CCONV) {
|
||||
|
||||
case T_QUAL_NONE:
|
||||
case T_QUAL_FASTCALL:
|
||||
@ -215,15 +286,41 @@ Done:
|
||||
|
||||
default:
|
||||
Error ("Cannot specify more than one calling convention qualifier");
|
||||
Q &= ~T_QUAL_CCONV;
|
||||
Qualifiers &= ~T_QUAL_CCONV;
|
||||
}
|
||||
|
||||
/* Return the qualifiers read */
|
||||
/* Return any qualifiers just read */
|
||||
return Q;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void OptionalSpecifiers (DeclSpec* Spec, TypeCode* Qualifiers, typespec_t TSFlags)
|
||||
/* Read storage specifiers and/or type qualifiers if we have any. Storage class
|
||||
** specifiers require the corresponding typespec_t flag set to be allowed, and
|
||||
** only const and volatile type qualifiers are allowed under any circumstance.
|
||||
** Read storage class specifiers are output in *Spec and type qualifiers are
|
||||
** output in *Qualifiers with error checking.
|
||||
*/
|
||||
{
|
||||
TypeCode Q = T_QUAL_NONE;
|
||||
int Continue;
|
||||
|
||||
do {
|
||||
/* There may be type qualifiers *before* any storage class specifiers */
|
||||
Q = OptionalQualifiers (*Qualifiers, T_QUAL_CONST | T_QUAL_VOLATILE);
|
||||
*Qualifiers |= Q;
|
||||
|
||||
/* Parse storage class specifiers anyway then check */
|
||||
Continue = ParseStorageClass (Spec);
|
||||
if (Continue && (TSFlags & (TS_STORAGE_CLASS_SPEC | TS_FUNCTION_SPEC)) == 0) {
|
||||
Error ("Unexpected storage class specified");
|
||||
}
|
||||
} while (Continue || Q != T_QUAL_NONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void OptionalInt (void)
|
||||
/* Eat an optional "int" token */
|
||||
{
|
||||
@ -396,48 +493,6 @@ static void FixQualifiers (Type* DataType)
|
||||
|
||||
|
||||
|
||||
static unsigned ParseOneStorageClass (void)
|
||||
/* Parse and return a storage class */
|
||||
{
|
||||
unsigned StorageClass = 0;
|
||||
|
||||
/* Check the storage class given */
|
||||
switch (CurTok.Tok) {
|
||||
|
||||
case TOK_EXTERN:
|
||||
StorageClass = SC_EXTERN | SC_STATIC;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_STATIC:
|
||||
StorageClass = SC_STATIC;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_REGISTER:
|
||||
StorageClass = SC_REGISTER | SC_STATIC;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_AUTO:
|
||||
StorageClass = SC_AUTO;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
case TOK_TYPEDEF:
|
||||
StorageClass = SC_TYPEDEF;
|
||||
NextToken ();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return StorageClass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void CheckArrayElementType (Type* DataType)
|
||||
/* Check if data type consists of arrays of incomplete element types */
|
||||
{
|
||||
@ -469,33 +524,6 @@ static void CheckArrayElementType (Type* DataType)
|
||||
|
||||
|
||||
|
||||
static void ParseStorageClass (DeclSpec* D, unsigned DefStorage)
|
||||
/* Parse a storage class */
|
||||
{
|
||||
/* Assume we're using an explicit storage class */
|
||||
D->Flags &= ~DS_DEF_STORAGE;
|
||||
|
||||
/* Check the storage class given */
|
||||
D->StorageClass = ParseOneStorageClass ();
|
||||
if (D->StorageClass == 0) {
|
||||
/* No storage class given, use default */
|
||||
D->Flags |= DS_DEF_STORAGE;
|
||||
D->StorageClass = DefStorage;
|
||||
} else {
|
||||
unsigned StorageClass = ParseOneStorageClass ();
|
||||
while (StorageClass != 0) {
|
||||
if (D->StorageClass == StorageClass) {
|
||||
Warning ("Duplicate storage class specifier");
|
||||
} else {
|
||||
Error ("Conflicting storage class specifier");
|
||||
}
|
||||
StorageClass = ParseOneStorageClass ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static SymEntry* ESUForwardDecl (const char* Name, unsigned Flags, unsigned* DSFlags)
|
||||
/* Handle an enum, struct or union forward decl */
|
||||
{
|
||||
@ -882,14 +910,21 @@ static SymEntry* ParseUnionDecl (const char* Name, unsigned* DSFlags)
|
||||
EnterStructLevel ();
|
||||
|
||||
/* Parse union fields */
|
||||
UnionSize = 0;
|
||||
UnionSize = 0;
|
||||
while (CurTok.Tok != TOK_RCURLY) {
|
||||
|
||||
/* Get the type of the entry */
|
||||
DeclSpec Spec;
|
||||
int SignednessSpecified = 0;
|
||||
|
||||
/* Check for a _Static_assert */
|
||||
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||
ParseStaticAssert ();
|
||||
continue;
|
||||
}
|
||||
|
||||
InitDeclSpec (&Spec);
|
||||
ParseTypeSpec (&Spec, -1, T_QUAL_NONE, &SignednessSpecified);
|
||||
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE, &SignednessSpecified);
|
||||
|
||||
/* Read fields with this type */
|
||||
while (1) {
|
||||
@ -1030,6 +1065,7 @@ static SymEntry* ParseStructDecl (const char* Name, unsigned* DSFlags)
|
||||
|
||||
/* Get the type of the entry */
|
||||
DeclSpec Spec;
|
||||
int SignednessSpecified = 0;
|
||||
|
||||
/* Check for a _Static_assert */
|
||||
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||
@ -1037,9 +1073,8 @@ static SymEntry* ParseStructDecl (const char* Name, unsigned* DSFlags)
|
||||
continue;
|
||||
}
|
||||
|
||||
int SignednessSpecified = 0;
|
||||
InitDeclSpec (&Spec);
|
||||
ParseTypeSpec (&Spec, -1, T_QUAL_NONE, &SignednessSpecified);
|
||||
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE, &SignednessSpecified);
|
||||
|
||||
/* Read fields with this type */
|
||||
while (1) {
|
||||
@ -1205,8 +1240,7 @@ NextMember: if (CurTok.Tok != TOK_COMMA) {
|
||||
|
||||
|
||||
|
||||
static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
||||
int* SignednessSpecified)
|
||||
static void ParseTypeSpec (DeclSpec* D, typespec_t TSFlags, int* SignednessSpecified)
|
||||
/* Parse a type specifier. Store whether one of "signed" or "unsigned" was
|
||||
** specified, so bit-fields of unspecified signedness can be treated as
|
||||
** unsigned; without special handling, it would be treated as signed.
|
||||
@ -1214,6 +1248,7 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
||||
{
|
||||
ident Ident;
|
||||
SymEntry* TagEntry;
|
||||
TypeCode Qualifiers = T_QUAL_NONE;
|
||||
|
||||
if (SignednessSpecified != NULL) {
|
||||
*SignednessSpecified = 0;
|
||||
@ -1222,8 +1257,8 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
||||
/* Assume we have an explicit type */
|
||||
D->Flags &= ~DS_DEF_TYPE;
|
||||
|
||||
/* Read type qualifiers if we have any */
|
||||
Qualifiers |= OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE);
|
||||
/* Read storage specifiers and/or type qualifiers if we have any */
|
||||
OptionalSpecifiers (D, &Qualifiers, TSFlags);
|
||||
|
||||
/* Look at the data type */
|
||||
switch (CurTok.Tok) {
|
||||
@ -1470,20 +1505,21 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers,
|
||||
/* FALL THROUGH */
|
||||
|
||||
default:
|
||||
if (Default < 0) {
|
||||
if ((TSFlags & TS_MASK_DEFAULT_TYPE) != TS_DEFAULT_TYPE_INT) {
|
||||
Error ("Type expected");
|
||||
D->Type[0].C = T_INT;
|
||||
D->Type[1].C = T_END;
|
||||
} else {
|
||||
D->Flags |= DS_DEF_TYPE;
|
||||
D->Type[0].C = (TypeCode) Default;
|
||||
D->Type[0].C = T_INT;
|
||||
D->Type[1].C = T_END;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* There may also be qualifiers *after* the initial type */
|
||||
D->Type[0].C |= (Qualifiers | OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE));
|
||||
/* There may also be specifiers/qualifiers *after* the initial type */
|
||||
OptionalSpecifiers (D, &Qualifiers, TSFlags);
|
||||
D->Type[0].C |= Qualifiers;
|
||||
}
|
||||
|
||||
|
||||
@ -1563,7 +1599,7 @@ static void ParseOldStyleParamList (FuncDesc* F)
|
||||
DeclSpec Spec;
|
||||
|
||||
/* Read the declaration specifier */
|
||||
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO);
|
||||
|
||||
/* We accept only auto and register as storage class specifiers, but
|
||||
** we ignore all this, since we use auto anyway.
|
||||
@ -1642,7 +1678,7 @@ static void ParseAnsiParamList (FuncDesc* F)
|
||||
}
|
||||
|
||||
/* Read the declaration specifier */
|
||||
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_NONE, SC_AUTO);
|
||||
|
||||
/* We accept only auto and register as storage class specifiers */
|
||||
if ((Spec.StorageClass & SC_AUTO) == SC_AUTO) {
|
||||
@ -1790,7 +1826,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
||||
** qualifier later will be transfered to the function itself. If it's a
|
||||
** pointer to something else, it will be flagged as an error.
|
||||
*/
|
||||
TypeCode Qualifiers = OptionalQualifiers (T_QUAL_ADDRSIZE | T_QUAL_CCONV);
|
||||
TypeCode Qualifiers = OptionalQualifiers (T_QUAL_NONE, T_QUAL_ADDRSIZE | T_QUAL_CCONV);
|
||||
|
||||
/* Pointer to something */
|
||||
if (CurTok.Tok == TOK_STAR) {
|
||||
@ -1799,7 +1835,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
||||
NextToken ();
|
||||
|
||||
/* Allow const, restrict, and volatile qualifiers */
|
||||
Qualifiers |= OptionalQualifiers (T_QUAL_CVR);
|
||||
Qualifiers |= OptionalQualifiers (Qualifiers, T_QUAL_CVR);
|
||||
|
||||
/* Parse the type that the pointer points to */
|
||||
Declarator (Spec, D, Mode);
|
||||
@ -1944,7 +1980,7 @@ Type* ParseType (Type* T)
|
||||
|
||||
/* Get a type without a default */
|
||||
InitDeclSpec (&Spec);
|
||||
ParseTypeSpec (&Spec, -1, T_QUAL_NONE, NULL);
|
||||
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE, NULL);
|
||||
|
||||
/* Parse additional declarators */
|
||||
ParseDecl (&Spec, &Decl, DM_NO_IDENT);
|
||||
@ -2069,22 +2105,23 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
||||
|
||||
|
||||
|
||||
void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, long DefType)
|
||||
void ParseDeclSpec (DeclSpec* D, typespec_t TSFlags, unsigned DefStorage)
|
||||
/* Parse a declaration specification */
|
||||
{
|
||||
TypeCode Qualifiers;
|
||||
|
||||
/* Initialize the DeclSpec struct */
|
||||
InitDeclSpec (D);
|
||||
|
||||
/* There may be qualifiers *before* the storage class specifier */
|
||||
Qualifiers = OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE);
|
||||
/* Assume we're using an explicit storage class */
|
||||
D->Flags &= ~DS_DEF_STORAGE;
|
||||
|
||||
/* Now get the storage class specifier for this declaration */
|
||||
ParseStorageClass (D, DefStorage);
|
||||
/* Parse the type specifiers */
|
||||
ParseTypeSpec (D, TSFlags | TS_STORAGE_CLASS_SPEC | TS_FUNCTION_SPEC, NULL);
|
||||
|
||||
/* Parse the type specifiers passing any initial type qualifiers */
|
||||
ParseTypeSpec (D, DefType, Qualifiers, NULL);
|
||||
/* If no explicit storage class is given, use the default */
|
||||
if (D->StorageClass == 0) {
|
||||
D->Flags |= DS_DEF_STORAGE;
|
||||
D->StorageClass = DefStorage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -53,6 +53,22 @@
|
||||
|
||||
|
||||
|
||||
/* Type specifier parser flags */
|
||||
typedef enum typespec_t typespec_t;
|
||||
enum typespec_t {
|
||||
TS_NONE = 0x00,
|
||||
|
||||
/* Default type */
|
||||
TS_MASK_DEFAULT_TYPE = 0x03,
|
||||
TS_DEFAULT_TYPE_NONE = 0x00, /* No default type */
|
||||
TS_DEFAULT_TYPE_INT = 0x01, /* Good old int */
|
||||
TS_DEFAULT_TYPE_AUTO = 0x02, /* C23 type inference with auto */
|
||||
|
||||
/* Whether to allow certain kinds of specifiers */
|
||||
TS_STORAGE_CLASS_SPEC = 0x04, /* Allow storage storage class specifiers */
|
||||
TS_FUNCTION_SPEC = 0x08, /* Allow function specifiers */
|
||||
};
|
||||
|
||||
/* Masks for the Flags field in DeclSpec */
|
||||
#define DS_DEF_STORAGE 0x0001U /* Default storage class used */
|
||||
#define DS_DEF_TYPE 0x0002U /* Default type used */
|
||||
@ -105,7 +121,7 @@ Type* ParseType (Type* Type);
|
||||
void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode);
|
||||
/* Parse a variable, type or function declaration */
|
||||
|
||||
void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, long DefType);
|
||||
void ParseDeclSpec (DeclSpec* D, typespec_t TSFlags, unsigned DefStorage);
|
||||
/* Parse a declaration specification */
|
||||
|
||||
void CheckEmptyDecl (const DeclSpec* D);
|
||||
|
@ -1301,7 +1301,7 @@ static void Primary (ExprDesc* E)
|
||||
/* Let's see if this is a C99-style declaration */
|
||||
DeclSpec Spec;
|
||||
InitDeclSpec (&Spec);
|
||||
ParseDeclSpec (&Spec, -1, T_QUAL_NONE);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_AUTO);
|
||||
|
||||
if (Spec.Type->C != T_END) {
|
||||
|
||||
|
@ -568,7 +568,7 @@ void DeclareLocals (void)
|
||||
continue;
|
||||
}
|
||||
|
||||
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
|
||||
ParseDeclSpec (&Spec, TS_DEFAULT_TYPE_INT, SC_AUTO);
|
||||
if ((Spec.Flags & DS_DEF_STORAGE) != 0 && /* No storage spec */
|
||||
(Spec.Flags & DS_DEF_TYPE) != 0 && /* No type given */
|
||||
GetQualifier (Spec.Type) == T_QUAL_NONE) { /* No type qualifier */
|
||||
|
@ -1,10 +0,0 @@
|
||||
|
||||
/* bug #1888 - The compiler doesn't accept valid data declarations */
|
||||
|
||||
/* The following is a valid declaration but not accepted by the compiler */
|
||||
int static a;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
19
test/val/decl-mixed-specifiers.c
Normal file
19
test/val/decl-mixed-specifiers.c
Normal file
@ -0,0 +1,19 @@
|
||||
/* bug 1888 - cc65 fails with storage class specifiers after type specifiers */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int const typedef volatile x_type, * const volatile y_type;
|
||||
|
||||
int static failures = 0;
|
||||
|
||||
int extern main(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
volatile static x_type const x = 42, * const volatile y[] = { 1 ? &x : (y_type)0 };
|
||||
if (**y != 42) {
|
||||
++failures;
|
||||
printf("y = %d, Expected: 42\n", **y);
|
||||
}
|
||||
return failures;
|
||||
}
|
@ -65,6 +65,13 @@ struct S {
|
||||
int b;
|
||||
};
|
||||
|
||||
/* _Static_assert can also appear in unions. */
|
||||
union U {
|
||||
int a;
|
||||
_Static_assert (1, "1 should still be true.");
|
||||
int b;
|
||||
};
|
||||
|
||||
|
||||
int main (void)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user