Merge pull request #2354 from acqn/Diagnostics

[cc65] Improved diagnosis
This commit is contained in:
Bob Andrews 2024-01-22 19:09:51 +01:00 committed by GitHub
commit bea2e86210
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 88 additions and 53 deletions

View File

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

View File

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

View File

@ -1057,7 +1057,7 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
/* Parse union fields */
UnionSize = 0;
while (CurTok.Tok != TOK_RCURLY) {
while (CurTok.Tok != TOK_RCURLY && CurTok.Tok != TOK_CEOF) {
/* Get the type of the entry */
DeclSpec Spec;
@ -1080,7 +1080,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;
@ -1121,22 +1122,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 */
@ -1277,7 +1268,7 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
FlexibleMember = 0;
StructSize = 0;
BitOffs = 0;
while (CurTok.Tok != TOK_RCURLY) {
while (CurTok.Tok != TOK_RCURLY && CurTok.Tok != TOK_CEOF) {
/* Get the type of the entry */
DeclSpec Spec;
@ -1300,7 +1291,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;
@ -1368,22 +1360,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 */
@ -1874,7 +1856,7 @@ static void ParseOldStyleParamDeclList (FuncDesc* F attribute ((unused)))
}
/* An optional list of type specifications follows */
while (CurTok.Tok != TOK_LCURLY) {
while (CurTok.Tok != TOK_LCURLY && CurTok.Tok != TOK_CEOF) {
DeclSpec Spec;
int NeedClean;
@ -1914,7 +1896,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));
}
@ -2017,7 +1999,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));
}
@ -2456,16 +2438,26 @@ int ParseDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode)
GetFuncDesc (D->Type)->Flags |= FD_OLDSTYLE_INTRET;
}
/* For anything that is not a function or typedef, check for an implicit
** int declaration.
/* For anything that is not a function, check for an implicit int
** declaration.
*/
if (!IsTypeFunc (D->Type) &&
(D->StorageClass & SC_TYPEMASK) != SC_TYPEDEF) {
/* If the standard was not set explicitly to C89, print a warning
** for variables with implicit int type.
*/
if (IS_Get (&Standard) >= STD_C99) {
Warning ("Implicit 'int' is an obsolete feature");
if (!IsTypeFunc (D->Type) && IsRankInt (D->Type)) {
if ((D->StorageClass & SC_TYPEMASK) != SC_TYPEDEF) {
/* If the standard was not set explicitly to C89, print a warning
** for variables with implicit int type.
*/
if (IS_Get (&Standard) >= STD_C99) {
Warning ("Implicit 'int' is an obsolete feature");
}
} else {
/* If the standard was not set explicitly to C89, print a warning
** for typedefs with implicit int type.
*/
if (IS_Get (&Standard) >= STD_C99) {
Warning ("Type defaults to 'int' in typedef of '%s'",
D->Ident);
Note ("Implicit 'int' is an obsolete feature");
}
}
}
}
@ -2568,10 +2560,20 @@ void CheckEmptyDecl (const DeclSpec* Spec)
} else 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");
}
}
}

View File

@ -551,7 +551,9 @@ void DeclareLocals (void)
/* A place to store info about potential initializations of auto variables */
CollAppend (&CurrentFunc->LocalsBlockStack, 0);
/* Loop until we don't find any more variables */
/* Loop until we don't find any more variables. EOF is handled in the loop
** as well.
*/
while (1) {
DeclSpec Spec;
int NeedClean;

View File

@ -170,7 +170,8 @@ static void CheckSymTable (SymTable* Tab)
if (SymIsDef (Entry) && !SymIsRef (Entry) &&
!SymHasAttr (Entry, atUnused)) {
if (Flags & SC_PARAM) {
if (IS_Get (&WarnUnusedParam)) {
if (IS_Get (&WarnUnusedParam) &&
!IsAnonName (Entry->Name)) {
Warning ("Parameter '%s' is never used", Entry->Name);
}
} else if ((Flags & SC_TYPEMASK) == SC_FUNC) {
@ -956,7 +957,13 @@ SymEntry* AddStructSym (const char* Name, unsigned Flags, unsigned Size, SymTabl
TagEntry = 0;
} else if (Size == 0) {
/* Empty struct is not supported now */
Error ("Empty %s type '%s' is not supported", SCType == SC_STRUCT ? "struct" : "union", Name);
if (!IsAnonName (Name)) {
Error ("Empty %s type '%s' is not supported",
SCType == SC_STRUCT ? "struct" : "union", Name);
} else {
Error ("Empty %s type is not supported",
SCType == SC_STRUCT ? "struct" : "union");
}
TagEntry = 0;
}
}