Fixed nested struct/union initialization.

Fixed bit-fields offsets in anonymous structs.
This commit is contained in:
acqn
2020-07-29 15:09:53 +08:00
committed by Oliver Schmidt
parent d6d667a688
commit 25d10d9d9a
7 changed files with 201 additions and 105 deletions

View File

@@ -61,6 +61,17 @@ static const char AnonTag[] = "$anon";
char* AnonFieldName (char* Buf, const char* Spec, int ANumber)
/* Get a name for an anonymous field of a struct or union. The given buffer is
** expected to be IDENTSIZE characters long. A pointer to the buffer is returned.
*/
{
xsprintf (Buf, IDENTSIZE, "%s-%s-%04X", AnonTag, Spec, ANumber);
return Buf;
}
char* AnonName (char* Buf, const char* Spec) char* AnonName (char* Buf, const char* Spec)
/* Get a name for an anonymous variable or type. The given buffer is expected /* Get a name for an anonymous variable or type. The given buffer is expected
** to be IDENTSIZE characters long. A pointer to the buffer is returned. ** to be IDENTSIZE characters long. A pointer to the buffer is returned.

View File

@@ -44,6 +44,11 @@
char* AnonFieldName (char* Buf, const char* Spec, int ANumber);
/* Get a name for an anonymous field of a struct or union. The given buffer is
** expected to be IDENTSIZE characters long. A pointer to the buffer is returned.
*/
char* AnonName (char* Buf, const char* Spec); char* AnonName (char* Buf, const char* Spec);
/* Get a name for an anonymous variable or type. The given buffer is expected /* Get a name for an anonymous variable or type. The given buffer is expected
** to be IDENTSIZE characters long. A pointer to the buffer is returned. ** to be IDENTSIZE characters long. A pointer to the buffer is returned.

View File

@@ -89,7 +89,7 @@ struct StructInitData {
static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers); static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers);
/* Parse a type specifier */ /* Parse a type specifier */
static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers); static unsigned ParseInitInternal (Type* T, int* Braces, int AllowFlexibleMembers);
/* Parse initialization of variables. Return the number of data bytes. */ /* Parse initialization of variables. Return the number of data bytes. */
@@ -717,24 +717,24 @@ static int ParseFieldWidth (Declaration* Decl)
static unsigned CopyAnonStructFields (const Declaration* Decl, int Offs) static unsigned AliasAnonStructFields (const Declaration* Decl, SymEntry* Anon)
/* Copy fields from an anon union/struct into the current lexical level. The /* Create alias fields from an anon union/struct in the current lexical level.
** function returns the size of the embedded struct/union. ** The function returns the count of created aliases.
*/ */
{ {
unsigned Count = 0;
SymEntry* Alias;
/* Get the pointer to the symbol table entry of the anon struct */ /* Get the pointer to the symbol table entry of the anon struct */
SymEntry* Entry = GetSymEntry (Decl->Type); SymEntry* Entry = GetSymEntry (Decl->Type);
/* Get the size of the anon struct */
unsigned Size = Entry->V.S.Size;
/* Get the symbol table containing the fields. If it is empty, there has /* Get the symbol table containing the fields. If it is empty, there has
** been an error before, so bail out. ** been an error before, so bail out.
*/ */
SymTable* Tab = Entry->V.S.SymTab; SymTable* Tab = Entry->V.S.SymTab;
if (Tab == 0) { if (Tab == 0) {
/* Incomplete definition - has been flagged before */ /* Incomplete definition - has been flagged before */
return Size; return 0;
} }
/* Get a pointer to the list of symbols. Then walk the list adding copies /* Get a pointer to the list of symbols. Then walk the list adding copies
@@ -743,10 +743,13 @@ static unsigned CopyAnonStructFields (const Declaration* Decl, int Offs)
Entry = Tab->SymHead; Entry = Tab->SymHead;
while (Entry) { while (Entry) {
/* Enter a copy of this symbol adjusting the offset. We will just /* Enter an alias of this symbol */
** reuse the type string here. if (!IsAnonName (Entry->Name)) {
*/ Alias = AddLocalSym (Entry->Name, Entry->Type, SC_STRUCTFIELD|SC_ALIAS, 0);
AddLocalSym (Entry->Name, Entry->Type, SC_STRUCTFIELD, Offs + Entry->V.Offs); Alias->V.A.Field = Entry;
Alias->V.A.Offs = Anon->V.Offs + Entry->V.Offs;
++Count;
}
/* Currently, there can not be any attributes, but if there will be /* Currently, there can not be any attributes, but if there will be
** some in the future, we want to know this. ** some in the future, we want to know this.
@@ -757,8 +760,8 @@ static unsigned CopyAnonStructFields (const Declaration* Decl, int Offs)
Entry = Entry->NextSym; Entry = Entry->NextSym;
} }
/* Return the size of the embedded struct */ /* Return the count of created aliases */
return Size; return Count;
} }
@@ -771,6 +774,8 @@ static SymEntry* ParseUnionDecl (const char* Name)
unsigned FieldSize; unsigned FieldSize;
int FieldWidth; /* Width in bits, -1 if not a bit-field */ int FieldWidth; /* Width in bits, -1 if not a bit-field */
SymTable* FieldTab; SymTable* FieldTab;
SymEntry* StructTypeEntry;
SymEntry* Entry;
if (CurTok.Tok != TOK_LCURLY) { if (CurTok.Tok != TOK_LCURLY) {
@@ -779,7 +784,9 @@ static SymEntry* ParseUnionDecl (const char* Name)
} }
/* Add a forward declaration for the struct in the current lexical level */ /* Add a forward declaration for the struct in the current lexical level */
AddStructSym (Name, SC_UNION, 0, 0); StructTypeEntry = AddStructSym (Name, SC_UNION, 0, 0);
StructTypeEntry->V.S.ACount = 0;
/* Skip the curly brace */ /* Skip the curly brace */
NextToken (); NextToken ();
@@ -821,16 +828,11 @@ static SymEntry* ParseUnionDecl (const char* Name)
/* This is an anonymous struct or union. Copy the fields /* This is an anonymous struct or union. Copy the fields
** into the current level. ** into the current level.
*/ */
FieldSize = CopyAnonStructFields (&Decl, 0); AnonFieldName (Decl.Ident, "field", StructTypeEntry->V.S.ACount);
if (FieldSize > UnionSize) {
UnionSize = FieldSize;
}
} else { } else {
/* A non bit-field without a name is legal but useless */ /* A non bit-field without a name is legal but useless */
Warning ("Declaration does not declare anything"); Warning ("Declaration does not declare anything");
} }
goto NextMember;
} }
/* Handle sizes */ /* Handle sizes */
@@ -842,9 +844,15 @@ static SymEntry* ParseUnionDecl (const char* Name)
/* Add a field entry to the table. */ /* Add a field entry to the table. */
if (FieldWidth > 0) { if (FieldWidth > 0) {
AddBitField (Decl.Ident, 0, 0, FieldWidth); AddBitField (Decl.Ident, 0, 0, FieldWidth);
} else {
if (IsAnonName (Decl.Ident)) {
Entry = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
Entry->V.A.ANumber = StructTypeEntry->V.S.ACount++;
AliasAnonStructFields (&Decl, Entry);
} else { } else {
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0); AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
} }
}
NextMember: if (CurTok.Tok != TOK_COMMA) { NextMember: if (CurTok.Tok != TOK_COMMA) {
break; break;
@@ -876,6 +884,8 @@ static SymEntry* ParseStructDecl (const char* Name)
unsigned BitOffs; /* Bit offset for bit-fields */ unsigned BitOffs; /* Bit offset for bit-fields */
int FieldWidth; /* Width in bits, -1 if not a bit-field */ int FieldWidth; /* Width in bits, -1 if not a bit-field */
SymTable* FieldTab; SymTable* FieldTab;
SymEntry* StructTypeEntry;
SymEntry* Entry;
if (CurTok.Tok != TOK_LCURLY) { if (CurTok.Tok != TOK_LCURLY) {
@@ -884,7 +894,9 @@ static SymEntry* ParseStructDecl (const char* Name)
} }
/* Add a forward declaration for the struct in the current lexical level */ /* Add a forward declaration for the struct in the current lexical level */
AddStructSym (Name, SC_STRUCT, 0, 0); StructTypeEntry = AddStructSym (Name, SC_STRUCT, 0, 0);
StructTypeEntry->V.S.ACount = 0;
/* Skip the curly brace */ /* Skip the curly brace */
NextToken (); NextToken ();
@@ -981,13 +993,11 @@ static SymEntry* ParseStructDecl (const char* Name)
/* This is an anonymous struct or union. Copy the /* This is an anonymous struct or union. Copy the
** fields into the current level. ** fields into the current level.
*/ */
StructSize += CopyAnonStructFields (&Decl, StructSize); AnonFieldName (Decl.Ident, "field", StructTypeEntry->V.S.ACount);
} else { } else {
/* A non bit-field without a name is legal but useless */ /* A non bit-field without a name is legal but useless */
Warning ("Declaration does not declare anything"); Warning ("Declaration does not declare anything");
} }
goto NextMember;
} else { } else {
/* A bit-field without a name will get an anonymous one */ /* A bit-field without a name will get an anonymous one */
AnonName (Decl.Ident, "bit-field"); AnonName (Decl.Ident, "bit-field");
@@ -1008,8 +1018,14 @@ static SymEntry* ParseStructDecl (const char* Name)
/* Add any full bytes to the struct size. */ /* Add any full bytes to the struct size. */
StructSize += BitOffs / CHAR_BITS; StructSize += BitOffs / CHAR_BITS;
BitOffs %= CHAR_BITS; BitOffs %= CHAR_BITS;
} else {
if (IsAnonName (Decl.Ident)) {
Entry = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
Entry->V.A.ANumber = StructTypeEntry->V.S.ACount++;
AliasAnonStructFields (&Decl, Entry);
} else { } else {
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize); AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
}
if (!FlexibleMember) { if (!FlexibleMember) {
StructSize += CheckedSizeOf (Decl.Type); StructSize += CheckedSizeOf (Decl.Type);
} }
@@ -1874,19 +1890,21 @@ void CheckEmptyDecl (const DeclSpec* D)
static void SkipInitializer (unsigned BracesExpected) static void SkipInitializer (int BracesExpected)
/* Skip the remainder of an initializer in case of errors. Try to be somewhat /* Skip the remainder of an initializer in case of errors. Try to be somewhat
** smart so we don't have too many following errors. ** smart so we don't have too many following errors.
*/ */
{ {
while (CurTok.Tok != TOK_CEOF && CurTok.Tok != TOK_SEMI && BracesExpected > 0) { while (CurTok.Tok != TOK_CEOF && CurTok.Tok != TOK_SEMI && BracesExpected >= 0) {
switch (CurTok.Tok) { switch (CurTok.Tok) {
case TOK_RCURLY: --BracesExpected; break; case TOK_RCURLY: --BracesExpected; break;
case TOK_LCURLY: ++BracesExpected; break; case TOK_LCURLY: ++BracesExpected; break;
default: break; default: break;
} }
if (BracesExpected >= 0) {
NextToken (); NextToken ();
} }
}
} }
@@ -1917,6 +1935,7 @@ static void ClosingCurlyBraces (unsigned BracesExpected)
*/ */
{ {
while (BracesExpected) { while (BracesExpected) {
/* TODO: Skip all excess initializers until next closing curly brace */
if (CurTok.Tok == TOK_RCURLY) { if (CurTok.Tok == TOK_RCURLY) {
NextToken (); NextToken ();
} else if (CurTok.Tok == TOK_COMMA && NextTok.Tok == TOK_RCURLY) { } else if (CurTok.Tok == TOK_COMMA && NextTok.Tok == TOK_RCURLY) {
@@ -2069,7 +2088,7 @@ static unsigned ParsePointerInit (Type* T)
static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers) static unsigned ParseArrayInit (Type* T, int* Braces, int AllowFlexibleMembers)
/* Parse initializaton for arrays. Return the number of data bytes. */ /* Parse initializaton for arrays. Return the number of data bytes. */
{ {
int Count; int Count;
@@ -2135,7 +2154,7 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
** an array (because the size of each element may differ ** an array (because the size of each element may differ
** otherwise). ** otherwise).
*/ */
ParseInitInternal (ElementType, 0); ParseInitInternal (ElementType, Braces, 0);
++Count; ++Count;
if (CurTok.Tok != TOK_COMMA) if (CurTok.Tok != TOK_COMMA)
break; break;
@@ -2158,23 +2177,29 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
} else if (Count < ElementCount) { } else if (Count < ElementCount) {
g_zerobytes ((ElementCount - Count) * ElementSize); g_zerobytes ((ElementCount - Count) * ElementSize);
} else if (Count > ElementCount) { } else if (Count > ElementCount) {
Error ("Too many initializers"); Error ("Excess elements in array initializer");
} }
return ElementCount * ElementSize; return ElementCount * ElementSize;
} }
static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers) static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
/* Parse initialization of a struct or union. Return the number of data bytes. */ /* Parse initialization of a struct or union. Return the number of data bytes. */
{ {
SymEntry* Entry; SymEntry* Entry;
SymTable* Tab; SymTable* Tab;
StructInitData SI; StructInitData SI;
int HasCurly = 0;
int SkipComma = 0;
/* Fields can be initialized without a pair of curly braces */
if (*Braces == 0 || CurTok.Tok == TOK_LCURLY) {
/* Consume the opening curly brace */ /* Consume the opening curly brace */
ConsumeLCurly (); HasCurly = ConsumeLCurly ();
*Braces += HasCurly;
}
/* Get a pointer to the struct entry from the type */ /* Get a pointer to the struct entry from the type */
Entry = GetSymEntry (T); Entry = GetSymEntry (T);
@@ -2189,7 +2214,7 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
if (Tab == 0) { if (Tab == 0) {
Error ("Cannot initialize variables with incomplete type"); Error ("Cannot initialize variables with incomplete type");
/* Try error recovery */ /* Try error recovery */
SkipInitializer (1); SkipInitializer (HasCurly);
/* Nothing initialized */ /* Nothing initialized */
return 0; return 0;
} }
@@ -2203,18 +2228,50 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
SI.ValBits = 0; SI.ValBits = 0;
while (CurTok.Tok != TOK_RCURLY) { while (CurTok.Tok != TOK_RCURLY) {
/* */ /* Check for excess elements */
if (Entry == 0) { if (Entry == 0) {
Error ("Too many initializers"); if (HasCurly) {
SkipInitializer (1); Error ("Excess elements in %s initializer", GetBasicTypeName (T));
SkipInitializer (HasCurly);
}
return SI.Offs; return SI.Offs;
} }
/* Check for special members that don't consume the initializer */
if ((Entry->Flags & SC_ALIAS) == SC_ALIAS) {
/* Just skip */
goto NextMember;
}
/* This may be an anonymous bit-field, in which case it doesn't
** have an initializer.
*/
if (SymIsBitField (Entry) && (IsAnonName (Entry->Name))) {
/* Account for the data and output it if we have at least a full
** word. We may have more if there was storage unit overlap, for
** example two consecutive 10 bit fields. These will be packed
** into 3 bytes.
*/
SI.ValBits += Entry->V.B.BitWidth;
CHECK (SI.ValBits <= CHAR_BITS + INT_BITS - 2);
while (SI.ValBits >= CHAR_BITS) {
OutputBitFieldData (&SI);
}
/* Avoid consuming the comma if any */
goto NextMember;
}
/* Skip comma this round */
if (SkipComma) {
NextToken ();
SkipComma = 0;
}
if (SymIsBitField (Entry)) {
/* Parse initialization of one field. Bit-fields need a special /* Parse initialization of one field. Bit-fields need a special
** handling. ** handling.
*/ */
if (SymIsBitField (Entry)) {
ExprDesc ED; ExprDesc ED;
unsigned Val; unsigned Val;
unsigned Shift; unsigned Shift;
@@ -2226,25 +2283,7 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
CHECK (Entry->V.B.Offs * CHAR_BITS + Entry->V.B.BitOffs == CHECK (Entry->V.B.Offs * CHAR_BITS + Entry->V.B.BitOffs ==
SI.Offs * CHAR_BITS + SI.ValBits); SI.Offs * CHAR_BITS + SI.ValBits);
/* This may be an anonymous bit-field, in which case it doesn't /* Read the data, check for a constant integer, do a range check */
** have an initializer.
*/
if (IsAnonName (Entry->Name)) {
/* Account for the data and output it if we have at least a
** full word. We may have more if there was storage unit
** overlap, for example two consecutive 10 bit fields.
** These will be packed into 3 bytes.
*/
SI.ValBits += Entry->V.B.BitWidth;
CHECK (SI.ValBits <= CHAR_BITS + INT_BITS - 2);
while (SI.ValBits >= CHAR_BITS) {
OutputBitFieldData (&SI);
}
goto NextMember;
} else {
/* Read the data, check for a constant integer, do a range
** check.
*/
ParseScalarInitInternal (type_uint, &ED); ParseScalarInitInternal (type_uint, &ED);
if (!ED_IsConstAbsInt (&ED)) { if (!ED_IsConstAbsInt (&ED)) {
Error ("Constant initializer expected"); Error ("Constant initializer expected");
@@ -2255,7 +2294,6 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
ED.IVal &= (long) Mask; ED.IVal &= (long) Mask;
} }
Val = (unsigned) ED.IVal; Val = (unsigned) ED.IVal;
}
/* Add the value to the currently stored bit-field value */ /* Add the value to the currently stored bit-field value */
Shift = (Entry->V.B.Offs - SI.Offs) * CHAR_BITS + Entry->V.B.BitOffs; Shift = (Entry->V.B.Offs - SI.Offs) * CHAR_BITS + Entry->V.B.BitOffs;
@@ -2285,7 +2323,7 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
/* Flexible array members may only be initialized if they are /* Flexible array members may only be initialized if they are
** the last field (or part of the last struct field). ** the last field (or part of the last struct field).
*/ */
SI.Offs += ParseInitInternal (Entry->Type, AllowFlexibleMembers && Entry->NextSym == 0); SI.Offs += ParseInitInternal (Entry->Type, Braces, AllowFlexibleMembers && Entry->NextSym == 0);
} }
/* More initializers? */ /* More initializers? */
@@ -2293,8 +2331,8 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
break; break;
} }
/* Skip the comma */ /* Skip the comma next round */
NextToken (); SkipComma = 1;
NextMember: NextMember:
/* Next member. For unions, only the first one can be initialized */ /* Next member. For unions, only the first one can be initialized */
@@ -2307,8 +2345,10 @@ NextMember:
} }
} }
if (HasCurly) {
/* Consume the closing curly brace */ /* Consume the closing curly brace */
ConsumeRCurly (); ConsumeRCurly ();
}
/* If we have data from a bit-field left, output it now */ /* If we have data from a bit-field left, output it now */
CHECK (SI.ValBits < CHAR_BITS); CHECK (SI.ValBits < CHAR_BITS);
@@ -2405,7 +2445,7 @@ static unsigned ParseVoidInit (Type* T)
static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers) static unsigned ParseInitInternal (Type* T, int *Braces, int AllowFlexibleMembers)
/* Parse initialization of variables. Return the number of data bytes. */ /* Parse initialization of variables. Return the number of data bytes. */
{ {
switch (GetUnderlyingTypeCode (T)) { switch (GetUnderlyingTypeCode (T)) {
@@ -2426,11 +2466,11 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
return ParsePointerInit (T); return ParsePointerInit (T);
case T_ARRAY: case T_ARRAY:
return ParseArrayInit (T, AllowFlexibleMembers); return ParseArrayInit (T, Braces, AllowFlexibleMembers);
case T_STRUCT: case T_STRUCT:
case T_UNION: case T_UNION:
return ParseStructInit (T, AllowFlexibleMembers); return ParseStructInit (T, Braces, AllowFlexibleMembers);
case T_VOID: case T_VOID:
if (IS_Get (&Standard) == STD_CC65) { if (IS_Get (&Standard) == STD_CC65) {
@@ -2451,10 +2491,13 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
unsigned ParseInit (Type* T) unsigned ParseInit (Type* T)
/* Parse initialization of variables. Return the number of data bytes. */ /* Parse initialization of variables. Return the number of data bytes. */
{ {
/* Current curly braces layers */
int Braces = 0;
/* Parse the initialization. Flexible array members can only be initialized /* Parse the initialization. Flexible array members can only be initialized
** in cc65 mode. ** in cc65 mode.
*/ */
unsigned Size = ParseInitInternal (T, IS_Get (&Standard) == STD_CC65); unsigned Size = ParseInitInternal (T, &Braces, IS_Get (&Standard) == STD_CC65);
/* The initialization may not generate code on global level, because code /* The initialization may not generate code on global level, because code
** outside function scope will never get executed. ** outside function scope will never get executed.

View File

@@ -1201,7 +1201,6 @@ static void StructRef (ExprDesc* Expr)
/* Process struct/union field after . or ->. */ /* Process struct/union field after . or ->. */
{ {
ident Ident; ident Ident;
SymEntry* Field;
Type* FinalType; Type* FinalType;
TypeCode Q; TypeCode Q;
@@ -1217,8 +1216,8 @@ static void StructRef (ExprDesc* Expr)
/* Get the symbol table entry and check for a struct/union field */ /* Get the symbol table entry and check for a struct/union field */
strcpy (Ident, CurTok.Ident); strcpy (Ident, CurTok.Ident);
NextToken (); NextToken ();
Field = FindStructField (Expr->Type, Ident); const SymEntry Field = FindStructField (Expr->Type, Ident);
if (Field == 0) { if (Field.Type == 0) {
Error ("No field named '%s' found in %s", Ident, GetBasicTypeName (Expr->Type)); Error ("No field named '%s' found in %s", Ident, GetBasicTypeName (Expr->Type));
/* Make the expression an integer at address zero */ /* Make the expression an integer at address zero */
ED_MakeConstAbs (Expr, 0, type_int); ED_MakeConstAbs (Expr, 0, type_int);
@@ -1264,10 +1263,10 @@ static void StructRef (ExprDesc* Expr)
} else { } else {
Q = GetQualifier (Indirect (Expr->Type)); Q = GetQualifier (Indirect (Expr->Type));
} }
if (GetQualifier (Field->Type) == (GetQualifier (Field->Type) | Q)) { if (GetQualifier (Field.Type) == (GetQualifier (Field.Type) | Q)) {
FinalType = Field->Type; FinalType = Field.Type;
} else { } else {
FinalType = TypeDup (Field->Type); FinalType = TypeDup (Field.Type);
FinalType->C |= Q; FinalType->C |= Q;
} }
@@ -1278,10 +1277,10 @@ static void StructRef (ExprDesc* Expr)
/* Get the size of the type */ /* Get the size of the type */
unsigned StructSize = SizeOf (Expr->Type); unsigned StructSize = SizeOf (Expr->Type);
unsigned FieldSize = SizeOf (Field->Type); unsigned FieldSize = SizeOf (Field.Type);
/* Safety check */ /* Safety check */
CHECK (Field->V.Offs + FieldSize <= StructSize); CHECK (Field.V.Offs + FieldSize <= StructSize);
/* The type of the operation depends on the type of the struct/union */ /* The type of the operation depends on the type of the struct/union */
switch (StructSize) { switch (StructSize) {
@@ -1304,16 +1303,16 @@ static void StructRef (ExprDesc* Expr)
/* Generate a shift to get the field in the proper position in the /* Generate a shift to get the field in the proper position in the
** primary. For bit fields, mask the value. ** primary. For bit fields, mask the value.
*/ */
BitOffs = Field->V.Offs * CHAR_BITS; BitOffs = Field.V.Offs * CHAR_BITS;
if (SymIsBitField (Field)) { if (SymIsBitField (&Field)) {
BitOffs += Field->V.B.BitOffs; BitOffs += Field.V.B.BitOffs;
g_asr (Flags, BitOffs); g_asr (Flags, BitOffs);
/* Mask the value. This is unnecessary if the shift executed above /* Mask the value. This is unnecessary if the shift executed above
** moved only zeroes into the value. ** moved only zeroes into the value.
*/ */
if (BitOffs + Field->V.B.BitWidth != FieldSize * CHAR_BITS) { if (BitOffs + Field.V.B.BitWidth != FieldSize * CHAR_BITS) {
g_and (CF_INT | CF_UNSIGNED | CF_CONST, g_and (CF_INT | CF_UNSIGNED | CF_CONST,
(0x0001U << Field->V.B.BitWidth) - 1U); (0x0001U << Field.V.B.BitWidth) - 1U);
} }
} else { } else {
g_asr (Flags, BitOffs); g_asr (Flags, BitOffs);
@@ -1325,7 +1324,7 @@ static void StructRef (ExprDesc* Expr)
} else { } else {
/* Set the struct/union field offset */ /* Set the struct/union field offset */
Expr->IVal += Field->V.Offs; Expr->IVal += Field.V.Offs;
/* Use the new type */ /* Use the new type */
Expr->Type = FinalType; Expr->Type = FinalType;
@@ -1341,8 +1340,8 @@ static void StructRef (ExprDesc* Expr)
} }
/* Make the expression a bit field if necessary */ /* Make the expression a bit field if necessary */
if (SymIsBitField (Field)) { if (SymIsBitField (&Field)) {
ED_MakeBitField (Expr, Field->V.B.BitOffs, Field->V.B.BitWidth); ED_MakeBitField (Expr, Field.V.B.BitOffs, Field.V.B.BitWidth);
} }
} }

View File

@@ -105,6 +105,7 @@ struct CodeEntry;
#define SC_SPADJUSTMENT 0x400000U #define SC_SPADJUSTMENT 0x400000U
#define SC_GOTO_IND 0x800000U /* Indirect goto */ #define SC_GOTO_IND 0x800000U /* Indirect goto */
#define SC_ALIAS 0x01000000U /* Alias of anonymous field */
@@ -138,6 +139,14 @@ struct SymEntry {
/* Offset for locals or struct members */ /* Offset for locals or struct members */
int Offs; int Offs;
/* Data for anonymous struct or union members */
struct {
int Offs; /* Byte offset into struct */
unsigned ANumber; /* Numeric ID */
SymEntry* Field; /* The real field aliased */
} A;
/* Label name for static symbols */ /* Label name for static symbols */
struct { struct {
unsigned Label; unsigned Label;
@@ -163,6 +172,7 @@ struct SymEntry {
struct { struct {
struct SymTable* SymTab; /* Member symbol table */ struct SymTable* SymTab; /* Member symbol table */
unsigned Size; /* Size of the union/struct */ unsigned Size; /* Size of the union/struct */
unsigned ACount; /* Count of anonymous fields */
} S; } S;
/* Data for enums */ /* Data for enums */

View File

@@ -490,10 +490,15 @@ SymEntry* FindTagSym (const char* Name)
SymEntry* FindStructField (const Type* T, const char* Name) SymEntry FindStructField (const Type* T, const char* Name)
/* Find a struct/union field in the fields list */ /* Find a struct/union field in the fields list.
** Return the info about the found field symbol filled in an entry struct by
** value, or an empty entry struct if the field is not found.
*/
{ {
SymEntry* Field = 0; SymEntry* Entry = 0;
SymEntry Field;
int Offs = 0;
/* The given type may actually be a pointer to struct/union */ /* The given type may actually be a pointer to struct/union */
if (IsTypePtr (T)) { if (IsTypePtr (T)) {
@@ -511,8 +516,24 @@ SymEntry* FindStructField (const Type* T, const char* Name)
** not exist. ** not exist.
*/ */
if (Struct->V.S.SymTab) { if (Struct->V.S.SymTab) {
Field = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name)); Entry = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name));
if (Entry != 0) {
Offs = Entry->V.Offs;
} }
while (Entry != 0 && (Entry->Flags & SC_ALIAS) == SC_ALIAS) {
/* Get the real field */
Entry = Entry->V.A.Field;
}
}
}
if (Entry != 0) {
Field = *Entry;
Field.V.Offs = Offs;
} else {
memset (&Field, 0, sizeof(SymEntry));
} }
return Field; return Field;
@@ -1001,7 +1022,13 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
/* Set the symbol attributes */ /* Set the symbol attributes */
Entry->Type = TypeDup (T); Entry->Type = TypeDup (T);
if ((Flags & SC_AUTO) == SC_AUTO || (Flags & SC_TYPEMASK) == SC_TYPEDEF) {
if ((Flags & SC_STRUCTFIELD) == SC_STRUCTFIELD ||
(Flags & SC_TYPEDEF) == SC_TYPEDEF) {
if ((Flags & SC_ALIAS) != SC_ALIAS) {
Entry->V.Offs = Offs;
}
} else if ((Flags & SC_AUTO) == SC_AUTO) {
Entry->V.Offs = Offs; Entry->V.Offs = Offs;
} else if ((Flags & SC_REGISTER) == SC_REGISTER) { } else if ((Flags & SC_REGISTER) == SC_REGISTER) {
Entry->V.R.RegOffs = Offs; Entry->V.R.RegOffs = Offs;
@@ -1013,8 +1040,6 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
/* Generate the assembler name from the label number */ /* Generate the assembler name from the label number */
Entry->V.L.Label = Offs; Entry->V.L.Label = Offs;
Entry->AsmName = xstrdup (LocalLabelName (Entry->V.L.Label)); Entry->AsmName = xstrdup (LocalLabelName (Entry->V.L.Label));
} else if ((Flags & SC_STRUCTFIELD) == SC_STRUCTFIELD) {
Entry->V.Offs = Offs;
} else { } else {
Internal ("Invalid flags in AddLocalSym: %04X", Flags); Internal ("Invalid flags in AddLocalSym: %04X", Flags);
} }

View File

@@ -133,8 +133,11 @@ SymEntry* FindLocalSym (const char* Name);
SymEntry* FindTagSym (const char* Name); SymEntry* FindTagSym (const char* Name);
/* Find the symbol with the given name in the tag table */ /* Find the symbol with the given name in the tag table */
SymEntry* FindStructField (const Type* TypeArray, const char* Name); SymEntry FindStructField (const Type* TypeArray, const char* Name);
/* Find a struct/union field in the fields list */ /* Find a struct/union field in the fields list.
** Return the info about the found field symbol filled in an entry struct by
** value, or an empty entry struct if the field is not found.
*/
unsigned short FindSPAdjustment (const char* Name); unsigned short FindSPAdjustment (const char* Name);
/* Search for an entry in the table of SP adjustments */ /* Search for an entry in the table of SP adjustments */