From e9bd9330c0b09f646a52e36c6cbf198015887d2f Mon Sep 17 00:00:00 2001 From: acqn Date: Mon, 15 Jan 2024 23:56:42 +0800 Subject: [PATCH] Added warning on some code patterns of faulty attempt to declare anonymous structs/unions. Removed unnecessary warning on tagless enum/struct/unions that would be invisible out of a function declaration. --- src/cc65/datatype.c | 18 ++++++++++++ src/cc65/datatype.h | 6 ++++ src/cc65/declare.c | 68 ++++++++++++++++++++------------------------- 3 files changed, 54 insertions(+), 38 deletions(-) diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c index 9c82e6773..4d6cb25a5 100644 --- a/src/cc65/datatype.c +++ b/src/cc65/datatype.c @@ -989,6 +989,24 @@ int IsIncompleteESUType (const Type* T) +int IsAnonESUType (const Type* T) +/* Return true if this is an anonymous ESU type */ +{ + SymEntry* TagSym = GetESUTagSym (T); + + return TagSym != 0 && SymHasAnonName (TagSym); +} + + + +int IsAnonStructClass (const Type* T) +/* Return true if this is an anonymous struct or union type */ +{ + return IsClassStruct (T) && IsAnonESUType (T); +} + + + int IsPassByRefType (const Type* T) /* Return true if this is a large struct/union type that doesn't fit in the ** primary. This returns false for the void value extension type since it is diff --git a/src/cc65/datatype.h b/src/cc65/datatype.h index dbe0eedaa..8446fb914 100644 --- a/src/cc65/datatype.h +++ b/src/cc65/datatype.h @@ -792,6 +792,12 @@ int IsESUType (const Type* T); int IsIncompleteESUType (const Type* T); /* Return true if this is an incomplete ESU type */ +int IsAnonESUType (const Type* T); +/* Return true if this is an anonymous ESU type */ + +int IsAnonStructClass (const Type* T); +/* Return true if this is an anonymous struct or union type */ + int IsPassByRefType (const Type* T); /* Return true if this is a large struct/union type that doesn't fit in the ** primary. This returns false for the void value extension type since it is diff --git a/src/cc65/declare.c b/src/cc65/declare.c index c3c1160a6..20e2e6879 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -1020,7 +1020,8 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags) ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE); /* Check if this is only a type declaration */ - if (CurTok.Tok == TOK_SEMI && (Spec.Flags & DS_EXTRA_TYPE) == 0) { + if (CurTok.Tok == TOK_SEMI && + !(IS_Get (&Standard) >= STD_CC65 && IsAnonStructClass (Spec.Type))) { CheckEmptyDecl (&Spec); NextToken (); continue; @@ -1061,22 +1062,12 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags) /* In cc65 mode, we allow anonymous structs/unions within ** a union. */ - SymEntry* TagEntry; - if (IS_Get (&Standard) >= STD_CC65 && - IsClassStruct (Decl.Type) && - (TagEntry = GetESUTagSym (Decl.Type)) && - SymHasAnonName (TagEntry)) { - /* This is an anonymous struct or union */ - AnonFieldName (Decl.Ident, GetBasicTypeName (Decl.Type), UnionTagEntry->V.S.ACount); + AnonFieldName (Decl.Ident, GetBasicTypeName (Decl.Type), UnionTagEntry->V.S.ACount); - /* Ignore CVR qualifiers */ - if (IsQualConst (Decl.Type) || IsQualVolatile (Decl.Type) || IsQualRestrict (Decl.Type)) { - Warning ("Anonymous %s qualifiers are ignored", GetBasicTypeName (Decl.Type)); - Decl.Type[0].C &= ~T_QUAL_CVR; - } - } else { - /* Invalid member */ - goto NextMember; + /* Ignore CVR qualifiers */ + if (IsQualConst (Decl.Type) || IsQualVolatile (Decl.Type) || IsQualRestrict (Decl.Type)) { + Warning ("Anonymous %s qualifiers are ignored", GetBasicTypeName (Decl.Type)); + Decl.Type[0].C &= ~T_QUAL_CVR; } } else if (FieldWidth > 0) { /* A bit-field without a name will get an anonymous one */ @@ -1240,7 +1231,8 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags) ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE); /* Check if this is only a type declaration */ - if (CurTok.Tok == TOK_SEMI && (Spec.Flags & DS_EXTRA_TYPE) == 0) { + if (CurTok.Tok == TOK_SEMI && + !(IS_Get (&Standard) >= STD_CC65 && IsAnonStructClass (Spec.Type))) { CheckEmptyDecl (&Spec); NextToken (); continue; @@ -1308,22 +1300,12 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags) /* In cc65 mode, we allow anonymous structs/unions within ** a struct. */ - SymEntry* TagEntry; - if (IS_Get (&Standard) >= STD_CC65 && - IsClassStruct (Decl.Type) && - (TagEntry = GetESUTagSym (Decl.Type)) && - SymHasAnonName (TagEntry)) { - /* This is an anonymous struct or union */ - AnonFieldName (Decl.Ident, GetBasicTypeName (Decl.Type), StructTagEntry->V.S.ACount); + AnonFieldName (Decl.Ident, GetBasicTypeName (Decl.Type), StructTagEntry->V.S.ACount); - /* Ignore CVR qualifiers */ - if (IsQualConst (Decl.Type) || IsQualVolatile (Decl.Type) || IsQualRestrict (Decl.Type)) { - Warning ("Anonymous %s qualifiers are ignored", GetBasicTypeName (Decl.Type)); - Decl.Type[0].C &= ~T_QUAL_CVR; - } - } else { - /* Invalid member */ - goto NextMember; + /* Ignore CVR qualifiers */ + if (IsQualConst (Decl.Type) || IsQualVolatile (Decl.Type) || IsQualRestrict (Decl.Type)) { + Warning ("Anonymous %s qualifiers are ignored", GetBasicTypeName (Decl.Type)); + Decl.Type[0].C &= ~T_QUAL_CVR; } } else if (FieldWidth > 0) { /* A bit-field without a name will get an anonymous one */ @@ -1854,7 +1836,7 @@ static void ParseOldStyleParamDeclList (FuncDesc* F attribute ((unused))) } /* Warn about new local type declaration */ - if ((Spec.Flags & DS_NEW_TYPE_DECL) != 0) { + if ((Spec.Flags & DS_NEW_TYPE_DECL) != 0 && !IsAnonESUType (Spec.Type)) { Warning ("'%s' will be invisible out of this function", GetFullTypeName (Spec.Type)); } @@ -1957,7 +1939,7 @@ static void ParseAnsiParamList (FuncDesc* F) } /* Warn about new local type declaration */ - if ((Spec.Flags & DS_NEW_TYPE_DECL) != 0) { + if ((Spec.Flags & DS_NEW_TYPE_DECL) != 0 && !IsAnonESUType (Spec.Type)) { Warning ("'%s' will be invisible out of this function", GetFullTypeName (Spec.Type)); } @@ -2508,10 +2490,20 @@ void CheckEmptyDecl (const DeclSpec* Spec) if ((Spec->Flags & DS_TYPE_MASK) == DS_NONE) { /* No declaration at all */ } else if ((Spec->Flags & DS_EXTRA_TYPE) == 0) { - Warning ("Declaration does not declare anything"); - } else if (IsClassStruct (Spec->Type) && - !IsIncompleteESUType (Spec->Type) && - SymHasAnonName (GetESUTagSym (Spec->Type))) { + /* Empty declaration of basic types */ + Warning ("Useless declaration"); + } else if (IsAnonStructClass (Spec->Type)) { + /* This could be that the user made a wrong attempt to declare an + ** anonymous struct/union field outside a struct/union. + */ Warning ("Unnamed %s that defines no instances", GetBasicTypeName (Spec->Type)); + } else if (GetLexicalLevel () == LEX_LEVEL_STRUCT) { + /* This could be that the user made a wrong attempt to declare an + ** anonymous struct/union field inside a struct/union. Perhaps just + ** paranoid since it is not so uncommon to do forward declarations. + */ + if (!IsTypeEnum (Spec->Type) || ((Spec->Flags & DS_NEW_TYPE_DEF) == 0)) { + Warning ("Declaration defines no instances"); + } } }