mirror of
https://github.com/cc65/cc65.git
synced 2024-06-01 13:41:34 +00:00
Merge pull request #2354 from acqn/Diagnostics
[cc65] Improved diagnosis
This commit is contained in:
commit
bea2e86210
|
@ -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)
|
int IsPassByRefType (const Type* T)
|
||||||
/* Return true if this is a large struct/union type that doesn't fit in the
|
/* 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
|
** primary. This returns false for the void value extension type since it is
|
||||||
|
|
|
@ -792,6 +792,12 @@ int IsESUType (const Type* T);
|
||||||
int IsIncompleteESUType (const Type* T);
|
int IsIncompleteESUType (const Type* T);
|
||||||
/* Return true if this is an incomplete ESU type */
|
/* 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);
|
int IsPassByRefType (const Type* T);
|
||||||
/* Return true if this is a large struct/union type that doesn't fit in the
|
/* 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
|
** primary. This returns false for the void value extension type since it is
|
||||||
|
|
|
@ -1057,7 +1057,7 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
|
||||||
|
|
||||||
/* Parse union fields */
|
/* Parse union fields */
|
||||||
UnionSize = 0;
|
UnionSize = 0;
|
||||||
while (CurTok.Tok != TOK_RCURLY) {
|
while (CurTok.Tok != TOK_RCURLY && CurTok.Tok != TOK_CEOF) {
|
||||||
|
|
||||||
/* Get the type of the entry */
|
/* Get the type of the entry */
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
|
@ -1080,7 +1080,8 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
|
||||||
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE);
|
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE);
|
||||||
|
|
||||||
/* Check if this is only a type declaration */
|
/* 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);
|
CheckEmptyDecl (&Spec);
|
||||||
NextToken ();
|
NextToken ();
|
||||||
continue;
|
continue;
|
||||||
|
@ -1121,22 +1122,12 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
|
||||||
/* In cc65 mode, we allow anonymous structs/unions within
|
/* In cc65 mode, we allow anonymous structs/unions within
|
||||||
** a union.
|
** a union.
|
||||||
*/
|
*/
|
||||||
SymEntry* TagEntry;
|
AnonFieldName (Decl.Ident, GetBasicTypeName (Decl.Type), UnionTagEntry->V.S.ACount);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Ignore CVR qualifiers */
|
/* Ignore CVR qualifiers */
|
||||||
if (IsQualConst (Decl.Type) || IsQualVolatile (Decl.Type) || IsQualRestrict (Decl.Type)) {
|
if (IsQualConst (Decl.Type) || IsQualVolatile (Decl.Type) || IsQualRestrict (Decl.Type)) {
|
||||||
Warning ("Anonymous %s qualifiers are ignored", GetBasicTypeName (Decl.Type));
|
Warning ("Anonymous %s qualifiers are ignored", GetBasicTypeName (Decl.Type));
|
||||||
Decl.Type[0].C &= ~T_QUAL_CVR;
|
Decl.Type[0].C &= ~T_QUAL_CVR;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Invalid member */
|
|
||||||
goto NextMember;
|
|
||||||
}
|
}
|
||||||
} else if (FieldWidth > 0) {
|
} else if (FieldWidth > 0) {
|
||||||
/* A bit-field without a name will get an anonymous one */
|
/* 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;
|
FlexibleMember = 0;
|
||||||
StructSize = 0;
|
StructSize = 0;
|
||||||
BitOffs = 0;
|
BitOffs = 0;
|
||||||
while (CurTok.Tok != TOK_RCURLY) {
|
while (CurTok.Tok != TOK_RCURLY && CurTok.Tok != TOK_CEOF) {
|
||||||
|
|
||||||
/* Get the type of the entry */
|
/* Get the type of the entry */
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
|
@ -1300,7 +1291,8 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
|
||||||
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE);
|
ParseTypeSpec (&Spec, TS_DEFAULT_TYPE_NONE);
|
||||||
|
|
||||||
/* Check if this is only a type declaration */
|
/* 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);
|
CheckEmptyDecl (&Spec);
|
||||||
NextToken ();
|
NextToken ();
|
||||||
continue;
|
continue;
|
||||||
|
@ -1368,22 +1360,12 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
|
||||||
/* In cc65 mode, we allow anonymous structs/unions within
|
/* In cc65 mode, we allow anonymous structs/unions within
|
||||||
** a struct.
|
** a struct.
|
||||||
*/
|
*/
|
||||||
SymEntry* TagEntry;
|
AnonFieldName (Decl.Ident, GetBasicTypeName (Decl.Type), StructTagEntry->V.S.ACount);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Ignore CVR qualifiers */
|
/* Ignore CVR qualifiers */
|
||||||
if (IsQualConst (Decl.Type) || IsQualVolatile (Decl.Type) || IsQualRestrict (Decl.Type)) {
|
if (IsQualConst (Decl.Type) || IsQualVolatile (Decl.Type) || IsQualRestrict (Decl.Type)) {
|
||||||
Warning ("Anonymous %s qualifiers are ignored", GetBasicTypeName (Decl.Type));
|
Warning ("Anonymous %s qualifiers are ignored", GetBasicTypeName (Decl.Type));
|
||||||
Decl.Type[0].C &= ~T_QUAL_CVR;
|
Decl.Type[0].C &= ~T_QUAL_CVR;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Invalid member */
|
|
||||||
goto NextMember;
|
|
||||||
}
|
}
|
||||||
} else if (FieldWidth > 0) {
|
} else if (FieldWidth > 0) {
|
||||||
/* A bit-field without a name will get an anonymous one */
|
/* 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 */
|
/* An optional list of type specifications follows */
|
||||||
while (CurTok.Tok != TOK_LCURLY) {
|
while (CurTok.Tok != TOK_LCURLY && CurTok.Tok != TOK_CEOF) {
|
||||||
|
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
int NeedClean;
|
int NeedClean;
|
||||||
|
@ -1914,7 +1896,7 @@ static void ParseOldStyleParamDeclList (FuncDesc* F attribute ((unused)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Warn about new local type declaration */
|
/* 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",
|
Warning ("'%s' will be invisible out of this function",
|
||||||
GetFullTypeName (Spec.Type));
|
GetFullTypeName (Spec.Type));
|
||||||
}
|
}
|
||||||
|
@ -2017,7 +1999,7 @@ static void ParseAnsiParamList (FuncDesc* F)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Warn about new local type declaration */
|
/* 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",
|
Warning ("'%s' will be invisible out of this function",
|
||||||
GetFullTypeName (Spec.Type));
|
GetFullTypeName (Spec.Type));
|
||||||
}
|
}
|
||||||
|
@ -2456,16 +2438,26 @@ int ParseDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode)
|
||||||
GetFuncDesc (D->Type)->Flags |= FD_OLDSTYLE_INTRET;
|
GetFuncDesc (D->Type)->Flags |= FD_OLDSTYLE_INTRET;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For anything that is not a function or typedef, check for an implicit
|
/* For anything that is not a function, check for an implicit int
|
||||||
** int declaration.
|
** declaration.
|
||||||
*/
|
*/
|
||||||
if (!IsTypeFunc (D->Type) &&
|
if (!IsTypeFunc (D->Type) && IsRankInt (D->Type)) {
|
||||||
(D->StorageClass & SC_TYPEMASK) != SC_TYPEDEF) {
|
if ((D->StorageClass & SC_TYPEMASK) != SC_TYPEDEF) {
|
||||||
/* If the standard was not set explicitly to C89, print a warning
|
/* If the standard was not set explicitly to C89, print a warning
|
||||||
** for variables with implicit int type.
|
** for variables with implicit int type.
|
||||||
*/
|
*/
|
||||||
if (IS_Get (&Standard) >= STD_C99) {
|
if (IS_Get (&Standard) >= STD_C99) {
|
||||||
Warning ("Implicit 'int' is an obsolete feature");
|
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) {
|
} else if ((Spec->Flags & DS_TYPE_MASK) == DS_NONE) {
|
||||||
/* No declaration at all */
|
/* No declaration at all */
|
||||||
} else if ((Spec->Flags & DS_EXTRA_TYPE) == 0) {
|
} else if ((Spec->Flags & DS_EXTRA_TYPE) == 0) {
|
||||||
Warning ("Declaration does not declare anything");
|
/* Empty declaration of basic types */
|
||||||
} else if (IsClassStruct (Spec->Type) &&
|
Warning ("Useless declaration");
|
||||||
!IsIncompleteESUType (Spec->Type) &&
|
} else if (IsAnonStructClass (Spec->Type)) {
|
||||||
SymHasAnonName (GetESUTagSym (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));
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -551,7 +551,9 @@ void DeclareLocals (void)
|
||||||
/* A place to store info about potential initializations of auto variables */
|
/* A place to store info about potential initializations of auto variables */
|
||||||
CollAppend (&CurrentFunc->LocalsBlockStack, 0);
|
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) {
|
while (1) {
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
int NeedClean;
|
int NeedClean;
|
||||||
|
|
|
@ -170,7 +170,8 @@ static void CheckSymTable (SymTable* Tab)
|
||||||
if (SymIsDef (Entry) && !SymIsRef (Entry) &&
|
if (SymIsDef (Entry) && !SymIsRef (Entry) &&
|
||||||
!SymHasAttr (Entry, atUnused)) {
|
!SymHasAttr (Entry, atUnused)) {
|
||||||
if (Flags & SC_PARAM) {
|
if (Flags & SC_PARAM) {
|
||||||
if (IS_Get (&WarnUnusedParam)) {
|
if (IS_Get (&WarnUnusedParam) &&
|
||||||
|
!IsAnonName (Entry->Name)) {
|
||||||
Warning ("Parameter '%s' is never used", Entry->Name);
|
Warning ("Parameter '%s' is never used", Entry->Name);
|
||||||
}
|
}
|
||||||
} else if ((Flags & SC_TYPEMASK) == SC_FUNC) {
|
} else if ((Flags & SC_TYPEMASK) == SC_FUNC) {
|
||||||
|
@ -956,7 +957,13 @@ SymEntry* AddStructSym (const char* Name, unsigned Flags, unsigned Size, SymTabl
|
||||||
TagEntry = 0;
|
TagEntry = 0;
|
||||||
} else if (Size == 0) {
|
} else if (Size == 0) {
|
||||||
/* Empty struct is not supported now */
|
/* 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;
|
TagEntry = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user