mirror of
https://github.com/cc65/cc65.git
synced 2025-04-13 22:37:12 +00:00
Fixed const qualifiers on named structs/unions members that should prevent assignments to the whole structs/unions.
Added warning on ignored qualifiers on anonymous structs/unions.
This commit is contained in:
parent
d7d1d89698
commit
0eb38770bd
@ -44,6 +44,7 @@
|
||||
#include "scanner.h"
|
||||
#include "stackptr.h"
|
||||
#include "stdnames.h"
|
||||
#include "symentry.h"
|
||||
#include "typecmp.h"
|
||||
#include "typeconv.h"
|
||||
|
||||
@ -82,6 +83,8 @@ static void CopyStruct (ExprDesc* LExpr, ExprDesc* RExpr)
|
||||
if (TypeCmp (ltype, RExpr->Type).C < TC_STRICT_COMPATIBLE) {
|
||||
TypeCompatibilityDiagnostic (ltype, RExpr->Type, 1,
|
||||
"Incompatible types in assignment to '%s' from '%s'");
|
||||
} else if (SymHasConstMember (ltype->A.S)) {
|
||||
Error ("Assignment to read only variable");
|
||||
}
|
||||
|
||||
/* Do we copy the value directly using the primary? */
|
||||
@ -627,7 +630,7 @@ void OpAssign (const GenDesc* Gen, ExprDesc* Expr, const char* Op)
|
||||
}
|
||||
} else if (IsQualConst (ltype)) {
|
||||
/* Check for assignment to const */
|
||||
Error ("Assignment to const");
|
||||
Error ("Assignment to const variable");
|
||||
}
|
||||
}
|
||||
|
||||
@ -686,7 +689,7 @@ void OpAddSubAssign (const GenDesc* Gen, ExprDesc *Expr, const char* Op)
|
||||
Error ("Invalid lvalue in assignment");
|
||||
} else if (IsQualConst (Expr->Type)) {
|
||||
/* The left side must not be const qualified */
|
||||
Error ("Assignment to const");
|
||||
Error ("Assignment to const variable");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -994,10 +994,14 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
|
||||
** a union.
|
||||
*/
|
||||
if (IS_Get (&Standard) >= STD_CC65 && IsClassStruct (Decl.Type)) {
|
||||
/* This is an anonymous struct or union. Copy the fields
|
||||
** into the current level.
|
||||
*/
|
||||
AnonFieldName (Decl.Ident, "field", UnionTagEntry->V.S.ACount);
|
||||
/* This is an anonymous struct or union */
|
||||
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 {
|
||||
/* A non bit-field without a name is legal but useless */
|
||||
Warning ("Declaration does not declare anything");
|
||||
@ -1011,13 +1015,18 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
|
||||
GetFullTypeName (Decl.Type));
|
||||
}
|
||||
|
||||
/* Check for const types */
|
||||
if (IsQualConst (Decl.Type)) {
|
||||
Flags |= SC_HAVECONST;
|
||||
}
|
||||
|
||||
/* Handle sizes */
|
||||
FieldSize = SizeOf (Decl.Type);
|
||||
if (FieldSize > UnionSize) {
|
||||
UnionSize = FieldSize;
|
||||
}
|
||||
|
||||
/* Add a field entry to the table. */
|
||||
/* Add a field entry to the table */
|
||||
if (FieldWidth > 0) {
|
||||
/* For a union, allocate space for the type specified by the
|
||||
** bit-field.
|
||||
@ -1025,19 +1034,30 @@ static SymEntry* ParseUnionSpec (const char* Name, unsigned* DSFlags)
|
||||
AddBitField (Decl.Ident, Decl.Type, 0, 0, FieldWidth,
|
||||
SignednessSpecified);
|
||||
} else if (Decl.Ident[0] != '\0') {
|
||||
/* Add the new field to the table */
|
||||
Field = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
|
||||
if (IsAnonName (Decl.Ident)) {
|
||||
Field->V.A.ANumber = UnionTagEntry->V.S.ACount++;
|
||||
AliasAnonStructFields (&Decl, Field);
|
||||
}
|
||||
|
||||
/* Check if the field itself has a flexible array member */
|
||||
/* Check the new field for certain kinds of members */
|
||||
if (IsClassStruct (Decl.Type)) {
|
||||
SymEntry* TagEntry = GetESUTagSym (Decl.Type);
|
||||
|
||||
/* Alias the fields of the anonymous member on the current level */
|
||||
if (IsAnonName (Decl.Ident)) {
|
||||
Field->V.A.ANumber = UnionTagEntry->V.S.ACount++;
|
||||
AliasAnonStructFields (&Decl, Field);
|
||||
}
|
||||
|
||||
/* Check if the field itself has a flexible array member */
|
||||
if (TagEntry && SymHasFlexibleArrayMember (TagEntry)) {
|
||||
Field->Flags |= SC_HAVEFAM;
|
||||
Flags |= SC_HAVEFAM;
|
||||
}
|
||||
|
||||
/* Check if the field itself has a const member */
|
||||
if (TagEntry && SymHasConstMember (TagEntry)) {
|
||||
Field->Flags |= SC_HAVECONST;
|
||||
Flags |= SC_HAVECONST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1190,10 +1210,14 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
|
||||
*/
|
||||
if (IS_Get (&Standard) >= STD_CC65 && IsClassStruct (Decl.Type)) {
|
||||
|
||||
/* This is an anonymous struct or union. Copy the
|
||||
** fields into the current level.
|
||||
*/
|
||||
AnonFieldName (Decl.Ident, "field", StructTagEntry->V.S.ACount);
|
||||
/* This is an anonymous struct or union */
|
||||
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 {
|
||||
/* A non bit-field without a name is legal but useless */
|
||||
Warning ("Declaration does not declare anything");
|
||||
@ -1211,6 +1235,11 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
|
||||
GetFullTypeName (Decl.Type));
|
||||
}
|
||||
|
||||
/* Check for const types */
|
||||
if (IsQualConst (Decl.Type)) {
|
||||
Flags |= SC_HAVECONST;
|
||||
}
|
||||
|
||||
/* Add a field entry to the table */
|
||||
if (FieldWidth > 0) {
|
||||
/* Full bytes have already been added to the StructSize,
|
||||
@ -1223,24 +1252,35 @@ static SymEntry* ParseStructSpec (const char* Name, unsigned* DSFlags)
|
||||
FieldWidth, SignednessSpecified);
|
||||
BitOffs += FieldWidth;
|
||||
CHECK (BitOffs <= CHAR_BITS * SizeOf (Decl.Type));
|
||||
/* Add any full bytes to the struct size. */
|
||||
/* Add any full bytes to the struct size */
|
||||
StructSize += BitOffs / CHAR_BITS;
|
||||
BitOffs %= CHAR_BITS;
|
||||
} else if (Decl.Ident[0] != '\0') {
|
||||
/* Add the new field to the table */
|
||||
Field = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
|
||||
if (IsAnonName (Decl.Ident)) {
|
||||
Field->V.A.ANumber = StructTagEntry->V.S.ACount++;
|
||||
AliasAnonStructFields (&Decl, Field);
|
||||
}
|
||||
|
||||
/* Check if the field itself has a flexible array member */
|
||||
/* Check the new field for certain kinds of members */
|
||||
if (IsClassStruct (Decl.Type)) {
|
||||
SymEntry* TagEntry = GetESUTagSym (Decl.Type);
|
||||
|
||||
/* Alias the fields of the anonymous member on the current level */
|
||||
if (IsAnonName (Decl.Ident)) {
|
||||
Field->V.A.ANumber = StructTagEntry->V.S.ACount++;
|
||||
AliasAnonStructFields (&Decl, Field);
|
||||
}
|
||||
|
||||
/* Check if the field itself has a flexible array member */
|
||||
if (TagEntry && SymHasFlexibleArrayMember (TagEntry)) {
|
||||
Field->Flags |= SC_HAVEFAM;
|
||||
Flags |= SC_HAVEFAM;
|
||||
Error ("Invalid use of struct with flexible array member");
|
||||
}
|
||||
|
||||
/* Check if the field itself has a const member */
|
||||
if (TagEntry && SymHasConstMember (TagEntry)) {
|
||||
Field->Flags |= SC_HAVECONST;
|
||||
Flags |= SC_HAVECONST;
|
||||
}
|
||||
}
|
||||
|
||||
if (!FlexibleMember) {
|
||||
|
@ -108,6 +108,7 @@ struct CodeEntry;
|
||||
#define SC_ALIAS 0x01000000U /* Alias of global or anonymous field */
|
||||
#define SC_FICTITIOUS 0x02000000U /* Symbol is fictitious (for error recovery) */
|
||||
#define SC_HAVEFAM 0x04000000U /* Type has a Flexible Array Member */
|
||||
#define SC_HAVECONST 0x08000000U /* Type has a const member */
|
||||
|
||||
|
||||
|
||||
@ -275,6 +276,16 @@ INLINE int SymHasFlexibleArrayMember (const SymEntry* Sym)
|
||||
# define SymHasFlexibleArrayMember(Sym) (((Sym)->Flags & SC_HAVEFAM) == SC_HAVEFAM)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int SymHasConstMember (const SymEntry* Sym)
|
||||
/* Return true if the given entry has a const member */
|
||||
{
|
||||
return ((Sym->Flags & SC_HAVECONST) == SC_HAVECONST);
|
||||
}
|
||||
#else
|
||||
# define SymHasConstMember(Sym) (((Sym)->Flags & SC_HAVECONST) == SC_HAVECONST)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE const char* SymGetAsmName (const SymEntry* Sym)
|
||||
/* Return the assembler label name for the symbol (beware: may be NULL!) */
|
||||
@ -282,7 +293,7 @@ INLINE const char* SymGetAsmName (const SymEntry* Sym)
|
||||
return Sym->AsmName;
|
||||
}
|
||||
#else
|
||||
# define SymGetAsmName(Sym) ((Sym)->AsmName)
|
||||
# define SymGetAsmName(Sym) ((Sym)->AsmName)
|
||||
#endif
|
||||
|
||||
const DeclAttr* SymGetAttr (const SymEntry* Sym, DeclAttrType AttrType);
|
||||
|
25
test/err/bug2018.c
Normal file
25
test/err/bug2018.c
Normal file
@ -0,0 +1,25 @@
|
||||
/* Bug #2018 - Compiler has problems with const struct fields */
|
||||
|
||||
struct X {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
union {
|
||||
int a;
|
||||
const int b;
|
||||
} b;
|
||||
};
|
||||
|
||||
struct X f(void)
|
||||
{
|
||||
struct X x = { 42 };
|
||||
return x;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct X x = { 0 };
|
||||
x = f(); /* Error since X is read only */
|
||||
|
||||
return 0;
|
||||
}
|
61
test/val/bug2018-ok.c
Normal file
61
test/val/bug2018-ok.c
Normal file
@ -0,0 +1,61 @@
|
||||
/* Bug #2018 - Compiler has problems with const struct fields */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
unsigned failures;
|
||||
|
||||
struct X {
|
||||
const struct { /* Qualifier ignored in cc65 */
|
||||
int a;
|
||||
};
|
||||
const union { /* Qualifier ignored in cc65 */
|
||||
int b;
|
||||
};
|
||||
};
|
||||
|
||||
union Y {
|
||||
const struct { /* Qualifier ignored in cc65 */
|
||||
int a;
|
||||
};
|
||||
const union { /* Qualifier ignored in cc65 */
|
||||
int b;
|
||||
};
|
||||
};
|
||||
|
||||
struct X f(struct X a)
|
||||
{
|
||||
struct X x = { 42 };
|
||||
return --a.a ? a : x;
|
||||
}
|
||||
|
||||
union Y g(union Y a)
|
||||
{
|
||||
union Y y = { 42 };
|
||||
return --a.a ? a : y;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct X x = { 1 };
|
||||
union Y y = { 1 };
|
||||
|
||||
x = f(x); /* Allowed in cc65 since X is not read only */
|
||||
y = g(y); /* Allowed in cc65 since Y is not read only */
|
||||
|
||||
if (x.a != 42)
|
||||
{
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (y.a != 42)
|
||||
{
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (failures > 0)
|
||||
{
|
||||
printf("failures: %u\n", failures);
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user