static void ParseTypeSpec (DeclSpec* D, int Default);
/* Parse a type specificier */
+static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers);
+/* Parse initialization of variables. Return the number of data bytes. */
+
/*****************************************************************************/
}
FlexibleMember = 1;
/* Assume zero for size calculations */
- Encode (Decl.Type + 1, 0);
+ Encode (Decl.Type + 1, FLEXIBLE);
} else {
StructSize += CheckedSizeOf (Decl.Type);
}
case T_UINT:
case T_PTR:
case T_ARRAY:
- if ((lval.Flags & E_MCTYPE) == E_TCONST) {
- /* Make it word sized */
- lval.ConstVal &= 0xFFFF;
- }
- DefineData (&lval);
- Size += SIZEOF_INT;
+ if ((lval.Flags & E_MCTYPE) == E_TCONST) {
+ /* Make it word sized */
+ lval.ConstVal &= 0xFFFF;
+ }
+ DefineData (&lval);
+ Size += SIZEOF_INT;
break;
case T_LONG:
case T_ULONG:
- DefineData (&lval);
- Size += SIZEOF_LONG;
+ DefineData (&lval);
+ Size += SIZEOF_LONG;
break;
default:
- Error ("Illegal type in initialization");
+ Error ("Illegal type in initialization");
break;
}
-static unsigned ParseStructInit (type* Type)
+static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers)
/* Parse initialization of a struct or union. Return the number of data bytes. */
{
SymEntry* Entry;
Error ("Too many initializers");
return Size;
}
- Size += ParseInit (Entry->Type);
+ /* Parse initialization of one field. Flexible array members may
+ * only be initialized if they are the last field (or part of the
+ * last struct field).
+ */
+ Size += ParseInitInternal (Entry->Type, AllowFlexibleMembers && Entry->NextSym == 0);
Entry = Entry->NextSym;
if (CurTok.Tok != TOK_COMMA)
break;
/* If there are struct fields left, reserve additional storage */
if (Size < StructSize) {
g_zerobytes (StructSize - Size);
+ Size = StructSize;
}
- /* Return the number of bytes initialized */
- return StructSize;
+ /* Return the actual number of bytes initialized. This number may be
+ * larger than StructSize if flexible array members are present and were
+ * initialized (possible in non ANSI mode).
+ */
+ return Size;
}
-unsigned ParseInit (type* T)
+static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers)
/* Parse initialization of variables. Return the number of data bytes. */
{
ExprDesc lval;
- type* t;
const char* str;
int Count;
- long ElementCount;
+ type* ElementType;
unsigned ElementSize;
+ long ElementCount;
switch (UnqualifiedType (*T)) {
return SIZEOF_LONG;
case T_ARRAY:
+ ElementType = GetElementType (T);
+ ElementSize = CheckedSizeOf (ElementType);
ElementCount = GetElementCount (T);
- ElementSize = CheckedSizeOf (T + DECODE_SIZE + 1);
- t = T + DECODE_SIZE + 1;
- if (IsTypeChar (t) && CurTok.Tok == TOK_SCONST) {
+ if (IsTypeChar (ElementType) && CurTok.Tok == TOK_SCONST) {
+ /* Char array initialized by string constant */
str = GetLiteral (CurTok.IVal);
Count = GetLiteralPoolOffs () - CurTok.IVal;
- TranslateLiteralPool (CurTok.IVal); /* Translate into target charset */
+ /* Translate into target charset */
+ TranslateLiteralPool (CurTok.IVal);
g_defbytes (str, Count);
- ResetLiteralPoolOffs (CurTok.IVal); /* Remove string from pool */
+ /* Remove string from pool */
+ ResetLiteralPoolOffs (CurTok.IVal);
NextToken ();
} else {
ConsumeLCurly ();
Count = 0;
while (CurTok.Tok != TOK_RCURLY) {
- ParseInit (T + DECODE_SIZE + 1);
+ /* Flexible array members may not be initialized within
+ * an array (because the size of each element may differ
+ * otherwise).
+ */
+ ParseInitInternal (ElementType, 0);
++Count;
if (CurTok.Tok != TOK_COMMA)
break;
ConsumeRCurly ();
}
if (ElementCount == UNSPECIFIED) {
+ /* Number of elements determined by initializer */
Encode (T + 1, Count);
+ ElementCount = Count;
+ } else if (ElementCount == FLEXIBLE && AllowFlexibleMembers) {
+ /* In non ANSI mode, allow initialization of flexible array
+ * members.
+ */
+ ElementCount = Count;
} else if (Count < ElementCount) {
g_zerobytes ((ElementCount - Count) * ElementSize);
} else if (Count > ElementCount) {
case T_STRUCT:
case T_UNION:
- return ParseStructInit (T);
+ return ParseStructInit (T, AllowFlexibleMembers);
case T_VOID:
if (!ANSI) {
+unsigned ParseInit (type* T)
+/* Parse initialization of variables. Return the number of data bytes. */
+{
+ return ParseInitInternal (T, !ANSI);
+}
+
+
g_defdatalabel (InitLabel);
/* Parse the initialization generating a memory image of the
- * data in the RODATA segment.
+ * data in the RODATA segment. The function does return the size
+ * of the initialization data, which may be greater than the
+ * actual size of the type, if the type is a structure with a
+ * flexible array member that has been initialized. Since we must
+ * know the size of the data in advance for register variables,
+ * we cannot allow that here.
*/
- ParseInit (Decl->Type);
+ if (ParseInit (Decl->Type) != Size) {
+ Error ("Cannot initialize flexible array members of storage class `register'");
+ }
/* Generate code to copy this data into the variable space */
g_initregister (InitLabel, Reg, Size);
/* Special handling for compound types */
if (IsCompound) {
- /* First reserve space for the variable */
- SymData = F_ReserveLocalSpace (CurrentFunc, Size);
-
- /* Next, allocate the space on the stack. This means that the
- * variable is now located at offset 0 from the current sp.
- */
- F_AllocLocalSpace (CurrentFunc);
-
/* Switch to read only data */
g_userodata ();
g_defdatalabel (InitLabel);
/* Parse the initialization generating a memory image of the
- * data in the RODATA segment.
+ * data in the RODATA segment. The function will return the
+ * actual size of the initialization data, which may be
+ * greater than the size of the variable if it is a struct
+ * that contains a flexible array member and we're not in
+ * ANSI mode.
*/
- ParseInit (Decl->Type);
+ Size = ParseInit (Decl->Type);
- /* Generate code to copy this data into the variable space */
+ /* Now reserve space for the variable on the stack */
+ SymData = F_ReserveLocalSpace (CurrentFunc, Size);
+
+ /* Next, allocate the space on the stack. This means that the
+ * variable is now located at offset 0 from the current sp.
+ */
+ F_AllocLocalSpace (CurrentFunc);
+
+ /* Generate code to copy the initialization data into the
+ * variable space
+ */
g_initauto (InitLabel, Size);
} else {