mirror of
https://github.com/cc65/cc65.git
synced 2024-12-23 19:29:37 +00:00
Fixed a problem reported by Greg King. structs returned from functions in the
primary register are actually rvalues and need special treatment. git-svn-id: svn://svn.cc65.org/cc65/trunk@5413 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
66f1f82943
commit
cbefb85d47
@ -1105,6 +1105,7 @@ static void StructRef (ExprDesc* Expr)
|
||||
{
|
||||
ident Ident;
|
||||
SymEntry* Field;
|
||||
Type* FinalType;
|
||||
TypeCode Q;
|
||||
|
||||
/* Skip the token and check for an identifier */
|
||||
@ -1139,9 +1140,6 @@ static void StructRef (ExprDesc* Expr)
|
||||
ED_MakeLValExpr (Expr);
|
||||
}
|
||||
|
||||
/* Set the struct field offset */
|
||||
Expr->IVal += Field->V.Offs;
|
||||
|
||||
/* The type is the type of the field plus any qualifiers from the struct */
|
||||
if (IsClassStruct (Expr->Type)) {
|
||||
Q = GetQualifier (Expr->Type);
|
||||
@ -1149,27 +1147,81 @@ static void StructRef (ExprDesc* Expr)
|
||||
Q = GetQualifier (Indirect (Expr->Type));
|
||||
}
|
||||
if (GetQualifier (Field->Type) == (GetQualifier (Field->Type) | Q)) {
|
||||
Expr->Type = Field->Type;
|
||||
FinalType = Field->Type;
|
||||
} else {
|
||||
Expr->Type = TypeDup (Field->Type);
|
||||
Expr->Type->C |= Q;
|
||||
FinalType = TypeDup (Field->Type);
|
||||
FinalType->C |= Q;
|
||||
}
|
||||
|
||||
/* An struct member is actually a variable. So the rules for variables
|
||||
* with respect to the reference type apply: If it's an array, it is
|
||||
* a rvalue, otherwise it's an lvalue. (A function would also be a rvalue,
|
||||
* but a struct field cannot be a function).
|
||||
/* A struct is usually an lvalue. If not, it is a struct in the primary
|
||||
* register.
|
||||
*/
|
||||
if (IsTypeArray (Expr->Type)) {
|
||||
ED_MakeRVal (Expr);
|
||||
if (ED_IsRVal (Expr) && ED_IsLocExpr (Expr) && !IsTypePtr (Expr->Type)) {
|
||||
|
||||
unsigned Flags = 0;
|
||||
unsigned BitOffs;
|
||||
|
||||
/* Get the size of the type */
|
||||
unsigned Size = SizeOf (Expr->Type);
|
||||
|
||||
/* Safety check */
|
||||
CHECK (Field->V.Offs + Size <= SIZEOF_LONG);
|
||||
|
||||
/* The type of the operation depends on the type of the struct */
|
||||
switch (Size) {
|
||||
case 1: Flags = CF_CHAR | CF_UNSIGNED | CF_CONST; break;
|
||||
case 2: Flags = CF_INT | CF_UNSIGNED | CF_CONST; break;
|
||||
case 3: /* FALLTHROUGH */
|
||||
case 4: Flags = CF_LONG | CF_UNSIGNED | CF_CONST; break;
|
||||
default: Internal ("Invalid struct size: %u", Size); break;
|
||||
}
|
||||
|
||||
/* Generate a shift to get the field in the proper position in the
|
||||
* primary. For bit fields, mask the value.
|
||||
*/
|
||||
BitOffs = Field->V.Offs * CHAR_BITS;
|
||||
if (SymIsBitField (Field)) {
|
||||
BitOffs += Field->V.B.BitOffs;
|
||||
g_asr (Flags, BitOffs);
|
||||
/* Mask the value. This is unnecessary if the shift executed above
|
||||
* moved only zeroes into the value.
|
||||
*/
|
||||
if (BitOffs + Field->V.B.BitWidth != Size * CHAR_BITS) {
|
||||
g_and (CF_INT | CF_UNSIGNED | CF_CONST,
|
||||
(0x0001U << Field->V.B.BitWidth) - 1U);
|
||||
}
|
||||
} else {
|
||||
g_asr (Flags, BitOffs);
|
||||
}
|
||||
|
||||
/* Use the new type */
|
||||
Expr->Type = FinalType;
|
||||
|
||||
} else {
|
||||
ED_MakeLVal (Expr);
|
||||
|
||||
/* Set the struct field offset */
|
||||
Expr->IVal += Field->V.Offs;
|
||||
|
||||
/* Use the new type */
|
||||
Expr->Type = FinalType;
|
||||
|
||||
/* An struct member is actually a variable. So the rules for variables
|
||||
* with respect to the reference type apply: If it's an array, it is
|
||||
* a rvalue, otherwise it's an lvalue. (A function would also be a rvalue,
|
||||
* but a struct field cannot be a function).
|
||||
*/
|
||||
if (IsTypeArray (Expr->Type)) {
|
||||
ED_MakeRVal (Expr);
|
||||
} else {
|
||||
ED_MakeLVal (Expr);
|
||||
}
|
||||
|
||||
/* Make the expression a bit field if necessary */
|
||||
if (SymIsBitField (Field)) {
|
||||
ED_MakeBitField (Expr, Field->V.B.BitOffs, Field->V.B.BitWidth);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make the expression a bit field if necessary */
|
||||
if (SymIsBitField (Field)) {
|
||||
ED_MakeBitField (Expr, Field->V.B.BitOffs, Field->V.B.BitWidth);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2077,7 +2129,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
||||
|
||||
/* Comparing a char against a constant may have a constant
|
||||
* result. Please note: It is not possible to remove the code
|
||||
* for the compare alltogether, because it may have side
|
||||
* for the compare alltogether, because it may have side
|
||||
* effects.
|
||||
*/
|
||||
switch (Tok) {
|
||||
|
@ -688,7 +688,7 @@ static void MacroCall (StrBuf* Target, Macro* M)
|
||||
static void ExpandMacro (StrBuf* Target, Macro* M)
|
||||
/* Expand a macro into Target */
|
||||
{
|
||||
#if 0
|
||||
#if 1
|
||||
static unsigned V = 0;
|
||||
printf ("Expanding %s(%u)\n", M->Name, ++V);
|
||||
#endif
|
||||
@ -727,7 +727,7 @@ static void ExpandMacro (StrBuf* Target, Macro* M)
|
||||
DoneMacroExp (&E);
|
||||
|
||||
}
|
||||
#if 0
|
||||
#if 1
|
||||
printf ("Done with %s(%u)\n", M->Name, V--);
|
||||
#endif
|
||||
}
|
||||
@ -845,7 +845,7 @@ static void DefineMacro (void)
|
||||
while (IsSpace (SB_LookAtLast (&M->Replacement))) {
|
||||
SB_Drop (&M->Replacement, 1);
|
||||
}
|
||||
#if 0
|
||||
#if 1
|
||||
printf ("%s: <%.*s>\n", M->Name, SB_GetLen (&M->Replacement), SB_GetConstBuf (&M->Replacement));
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user