aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog46
-rw-r--r--gcc/c-typeck.c772
-rw-r--r--gcc/extend.texi10
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20000801-3.x2
-rw-r--r--gcc/testsuite/gcc.dg/c90-init-1.c25
-rw-r--r--gcc/testsuite/gcc.dg/c99-init-1.c78
-rw-r--r--gcc/testsuite/gcc.dg/c99-init-2.c30
-rw-r--r--gcc/testsuite/gcc.dg/gnu99-init-1.c62
9 files changed, 843 insertions, 190 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7ae8ae9..6e89eab 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,49 @@
+2001-01-12 Jakub Jelinek <jakub@redhat.com>
+
+ * c-typeck.c (store_init_value): Don't require constant initializer
+ elements with -pedantic -std=c99.
+ (digest_init): Change error about non-constant initializer elements
+ into pedwarn.
+ (constructor_range_end): Remove.
+ (constructor_incremental, designator_depth,
+ designator_errorneous): New variables.
+ (struct constructor_stack): Remove range_end, add incremental.
+ (struct constructor_range_stack, constructor_range_stack): New.
+ (struct initializer_stack): Add constructor_range_stack.
+ (finish_init): Set it.
+ (start_init): Likewise. require_constant_elements for non-static
+ trees only if not flag_isoc99.
+ (really_start_incremental_init): Remove constructor_range_end, add
+ constructor_incremental.
+ (pop_init_level): Likewise.
+ (push_init_level): Likewise. If implicit and the subobject had some
+ value set already, preinitialize the level with it.
+ Warn about missing braces only if not pushing due to designators.
+ (set_designator, push_range_stack): New functions.
+ (set_init_label): Use them.
+ (set_init_index): Likewise. Remove constructor_range_end.
+ Error if designator index is outside of array bounds.
+ (add_pending_init): Compare values of purpose index trees, not the
+ trees themselves. Allow overwriting of already initialized element.
+ Issue a warning if it had side-effects.
+ (set_nonincremental_init, set_nonincremental_init_from_string): New
+ functions.
+ (pending_init_member): Rename to...
+ (find_init_member): ...this function. Call set_nonincremental_init
+ if necessary. Compare values of purpose index trees, not the trees
+ themselves. Return the actual value, not just non-zero if something
+ is found.
+ (output_init_element): Remove checks for duplicates.
+ If field has zero size, only check the initializer for correctness.
+ Call set_nonincremental_init if necessary. Push RECORD/ARRAY into AVL
+ if constructor_incremental is zero. Change error about initializers
+ not computable at load time into pedwarn.
+ (output_pending_init_elements): Compare bit positions, not
+ FIELD_DECLs to take into account zero-sized fields.
+ (process_init_element): Use constructor_range_stack to fill all
+ ranges in the designator lists from current level up.
+ * extend.texi: Update documentation for labeled elements.
+
2001-01-12 Alexandre Oliva <aoliva@redhat.com>
* calls.c (emit_library_call_value_1): Add USEs and CLOBBERs
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 2868496..9db269e 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -76,8 +76,12 @@ static void warning_init PARAMS ((const char *));
static tree digest_init PARAMS ((tree, tree, int, int));
static void output_init_element PARAMS ((tree, tree, tree, int));
static void output_pending_init_elements PARAMS ((int));
+static int set_designator PARAMS ((int));
+static void push_range_stack PARAMS ((tree));
static void add_pending_init PARAMS ((tree, tree));
-static int pending_init_member PARAMS ((tree));
+static void set_nonincremental_init PARAMS ((void));
+static void set_nonincremental_init_from_string PARAMS ((tree));
+static tree find_init_member PARAMS ((tree));
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.) */
@@ -4410,7 +4414,7 @@ store_init_value (decl, init)
/* Digest the specified initializer into an expression. */
value = digest_init (type, init, TREE_STATIC (decl),
- TREE_STATIC (decl) || pedantic);
+ TREE_STATIC (decl) || (pedantic && !flag_isoc99));
/* Store the expression if valid; else report error. */
@@ -4769,10 +4773,7 @@ digest_init (type, init, require_constant, constructor_constant)
}
else if (require_constant
&& initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0)
- {
- error_init ("initializer element is not computable at load time");
- inside_init = error_mark_node;
- }
+ pedwarn ("initializer element is not computable at load time");
return inside_init;
}
@@ -4868,11 +4869,6 @@ static tree constructor_fields;
at which to store the next element we get. */
static tree constructor_index;
-/* For an ARRAY_TYPE, this is the end index of the range
- to initialize with the next element, or NULL in the ordinary case
- where the element is used just once. */
-static tree constructor_range_end;
-
/* For an ARRAY_TYPE, this is the maximum index. */
static tree constructor_max_index;
@@ -4892,6 +4888,10 @@ static tree constructor_bit_index;
most recent first). */
static tree constructor_elements;
+/* 1 if constructor should be incrementally stored into a constructor chain,
+ 0 if all the elements should be kept in AVL tree. */
+static int constructor_incremental;
+
/* 1 if so far this constructor's elements are all compile-time constants. */
static int constructor_constant;
@@ -4943,6 +4943,12 @@ static const char *constructor_asmspec;
/* Nonzero if this is an initializer for a top-level decl. */
static int constructor_top_level;
+/* Nesting depth of designator list. */
+static int designator_depth;
+
+/* Nonzero if there were diagnosed errors in this designator list. */
+static int designator_errorneous;
+
/* This stack has a level for each implicit or explicit level of
structuring in the initializer, including the outermost one. It
@@ -4954,7 +4960,6 @@ struct constructor_stack
tree type;
tree fields;
tree index;
- tree range_end;
tree max_index;
tree unfilled_index;
tree unfilled_fields;
@@ -4971,10 +4976,26 @@ struct constructor_stack
char implicit;
char erroneous;
char outer;
+ char incremental;
};
struct constructor_stack *constructor_stack;
+/* This stack represents designators from some range designator up to
+ the last designator in the list. */
+
+struct constructor_range_stack
+{
+ struct constructor_range_stack *next, *prev;
+ struct constructor_stack *stack;
+ tree range_start;
+ tree index;
+ tree range_end;
+ tree fields;
+};
+
+struct constructor_range_stack *constructor_range_stack;
+
/* This stack records separate initializers that are nested.
Nested initializers can't happen in ANSI C, but GNU C allows them
in cases like { ... (struct foo) { ... } ... }. */
@@ -4985,6 +5006,7 @@ struct initializer_stack
tree decl;
const char *asmspec;
struct constructor_stack *constructor_stack;
+ struct constructor_range_stack *constructor_range_stack;
tree elements;
struct spelling *spelling;
struct spelling *spelling_base;
@@ -5018,6 +5040,7 @@ start_init (decl, asmspec_tree, top_level)
p->require_constant_value = require_constant_value;
p->require_constant_elements = require_constant_elements;
p->constructor_stack = constructor_stack;
+ p->constructor_range_stack = constructor_range_stack;
p->elements = constructor_elements;
p->spelling = spelling;
p->spelling_base = spelling_base;
@@ -5036,7 +5059,7 @@ start_init (decl, asmspec_tree, top_level)
{
require_constant_value = TREE_STATIC (decl);
require_constant_elements
- = ((TREE_STATIC (decl) || pedantic)
+ = ((TREE_STATIC (decl) || (pedantic && !flag_isoc99))
/* For a scalar, you can always use any value to initialize,
even within braces. */
&& (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
@@ -5053,6 +5076,7 @@ start_init (decl, asmspec_tree, top_level)
}
constructor_stack = 0;
+ constructor_range_stack = 0;
missing_braces_mentioned = 0;
@@ -5083,12 +5107,16 @@ finish_init ()
free (q);
}
+ if (constructor_range_stack)
+ abort ();
+
/* Pop back to the data of the outer initializer (if any). */
constructor_decl = p->decl;
constructor_asmspec = p->asmspec;
require_constant_value = p->require_constant_value;
require_constant_elements = p->require_constant_elements;
constructor_stack = p->constructor_stack;
+ constructor_range_stack = p->constructor_range_stack;
constructor_elements = p->elements;
spelling = p->spelling;
spelling_base = p->spelling_base;
@@ -5119,7 +5147,6 @@ really_start_incremental_init (type)
p->type = constructor_type;
p->fields = constructor_fields;
p->index = constructor_index;
- p->range_end = constructor_range_end;
p->max_index = constructor_max_index;
p->unfilled_index = constructor_unfilled_index;
p->unfilled_fields = constructor_unfilled_fields;
@@ -5133,6 +5160,7 @@ really_start_incremental_init (type)
p->replacement_value = 0;
p->implicit = 0;
p->outer = 0;
+ p->incremental = constructor_incremental;
p->next = 0;
constructor_stack = p;
@@ -5142,6 +5170,9 @@ really_start_incremental_init (type)
constructor_elements = 0;
constructor_pending_elts = 0;
constructor_type = type;
+ constructor_incremental = 1;
+ designator_depth = 0;
+ designator_errorneous = 0;
if (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
@@ -5157,7 +5188,6 @@ really_start_incremental_init (type)
}
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
{
- constructor_range_end = 0;
if (TYPE_DOMAIN (constructor_type))
{
constructor_max_index
@@ -5187,13 +5217,14 @@ really_start_incremental_init (type)
/* Push down into a subobject, for initialization.
If this is for an explicit set of braces, IMPLICIT is 0.
If it is because the next element belongs at a lower level,
- IMPLICIT is 1. */
+ IMPLICIT is 1 (or 2 if the push is because of designator list). */
void
push_init_level (implicit)
int implicit;
{
struct constructor_stack *p;
+ tree value = NULL_TREE;
/* If we've exhausted any levels that didn't have braces,
pop them now. */
@@ -5210,11 +5241,22 @@ push_init_level (implicit)
break;
}
+ /* Unless this is an explicit brace, we need to preserve previous
+ content if any. */
+ if (implicit)
+ {
+ if ((TREE_CODE (constructor_type) == RECORD_TYPE
+ || TREE_CODE (constructor_type) == UNION_TYPE)
+ && constructor_fields)
+ value = find_init_member (constructor_fields);
+ else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+ value = find_init_member (constructor_index);
+ }
+
p = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack));
p->type = constructor_type;
p->fields = constructor_fields;
p->index = constructor_index;
- p->range_end = constructor_range_end;
p->max_index = constructor_max_index;
p->unfilled_index = constructor_unfilled_index;
p->unfilled_fields = constructor_unfilled_fields;
@@ -5228,6 +5270,7 @@ push_init_level (implicit)
p->replacement_value = 0;
p->implicit = implicit;
p->outer = 0;
+ p->incremental = constructor_incremental;
p->next = constructor_stack;
constructor_stack = p;
@@ -5235,7 +5278,13 @@ push_init_level (implicit)
constructor_simple = 1;
constructor_depth = SPELLING_DEPTH ();
constructor_elements = 0;
+ constructor_incremental = 1;
constructor_pending_elts = 0;
+ if (!implicit)
+ {
+ designator_depth = 0;
+ designator_errorneous = 0;
+ }
/* Don't die if an entire brace-pair level is superfluous
in the containing level. */
@@ -5269,7 +5318,18 @@ push_init_level (implicit)
return;
}
- if (implicit && warn_missing_braces && !missing_braces_mentioned)
+ if (value && TREE_CODE (value) == CONSTRUCTOR)
+ {
+ constructor_constant = TREE_CONSTANT (value);
+ constructor_simple = TREE_STATIC (value);
+ constructor_elements = TREE_OPERAND (value, 1);
+ if (constructor_elements
+ && (TREE_CODE (constructor_type) == RECORD_TYPE
+ || TREE_CODE (constructor_type) == ARRAY_TYPE))
+ set_nonincremental_init ();
+ }
+
+ if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned)
{
missing_braces_mentioned = 1;
warning_init ("missing braces around initializer");
@@ -5289,7 +5349,6 @@ push_init_level (implicit)
}
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
{
- constructor_range_end = 0;
if (TYPE_DOMAIN (constructor_type))
{
constructor_max_index
@@ -5307,6 +5366,13 @@ push_init_level (implicit)
constructor_index = bitsize_zero_node;
constructor_unfilled_index = constructor_index;
+ if (value && TREE_CODE (value) == STRING_CST)
+ {
+ /* We need to split the char/wchar array into individual
+ characters, so that we don't have to special case it
+ everywhere. */
+ set_nonincremental_init_from_string (value);
+ }
}
else
{
@@ -5363,7 +5429,7 @@ pop_init_level (implicit)
else if (pedantic)
pedwarn_init ("initialization of a flexible array member");
- /* We have already issued an error message for the existance
+ /* We have already issued an error message for the existance
of a flexible array member not at the end of the structure.
Discard the initializer so that we do not abort later. */
if (TREE_CHAIN (constructor_fields) != NULL_TREE)
@@ -5373,7 +5439,7 @@ pop_init_level (implicit)
{
warning_init ("deprecated initialization of zero-length array");
- /* We must be initializing the last member of a top-level struct. */
+ /* We must be initializing the last member of a top-level struct. */
if (TREE_CHAIN (constructor_fields) != NULL_TREE)
{
error_init ("initialization of zero-length array before end of structure");
@@ -5391,21 +5457,22 @@ pop_init_level (implicit)
&& TREE_CODE (constructor_type) == RECORD_TYPE
&& constructor_unfilled_fields)
{
- /* Do not warn for flexible array members or zero-length arrays. */
- while (constructor_unfilled_fields
- && (! DECL_SIZE (constructor_unfilled_fields)
- || integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
- constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
+ /* Do not warn for flexible array members or zero-length arrays. */
+ while (constructor_unfilled_fields
+ && (! DECL_SIZE (constructor_unfilled_fields)
+ || integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
+ constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
- if (constructor_unfilled_fields)
- {
- push_member_name (constructor_unfilled_fields);
- warning_init ("missing initializer");
- RESTORE_SPELLING_DEPTH (constructor_depth);
- }
+ if (constructor_unfilled_fields)
+ {
+ push_member_name (constructor_unfilled_fields);
+ warning_init ("missing initializer");
+ RESTORE_SPELLING_DEPTH (constructor_depth);
+ }
}
/* Now output all pending elements. */
+ constructor_incremental = 1;
output_pending_init_elements (1);
/* Pad out the end of the structure. */
@@ -5423,7 +5490,8 @@ pop_init_level (implicit)
the element, after verifying there is just one. */
if (constructor_elements == 0)
{
- error_init ("empty scalar initializer");
+ if (!constructor_erroneous)
+ error_init ("empty scalar initializer");
constructor = error_mark_node;
}
else if (TREE_CHAIN (constructor_elements) != 0)
@@ -5452,7 +5520,6 @@ pop_init_level (implicit)
constructor_type = p->type;
constructor_fields = p->fields;
constructor_index = p->index;
- constructor_range_end = p->range_end;
constructor_max_index = p->max_index;
constructor_unfilled_index = p->unfilled_index;
constructor_unfilled_fields = p->unfilled_fields;
@@ -5461,6 +5528,7 @@ pop_init_level (implicit)
constructor_constant = p->constant;
constructor_simple = p->simple;
constructor_erroneous = p->erroneous;
+ constructor_incremental = p->incremental;
constructor_pending_elts = p->pending_elts;
constructor_depth = p->depth;
RESTORE_SPELLING_DEPTH (constructor_depth);
@@ -5477,6 +5545,97 @@ pop_init_level (implicit)
return constructor;
}
+/* Common handling for both array range and field name designators.
+ ARRAY argument is non-zero for array ranges. Returns zero for success. */
+
+static int
+set_designator (array)
+ int array;
+{
+ tree subtype;
+ enum tree_code subcode;
+
+ /* Don't die if an entire brace-pair level is superfluous
+ in the containing level. */
+ if (constructor_type == 0)
+ return 1;
+
+ /* If there were errors in this designator list already, bail out silently. */
+ if (designator_errorneous)
+ return 1;
+
+ if (!designator_depth)
+ {
+ if (constructor_range_stack)
+ abort ();
+
+ /* Designator list starts at the level of closest explicit
+ braces. */
+ while (constructor_stack->implicit)
+ process_init_element (pop_init_level (1));
+ return 0;
+ }
+
+ if (constructor_no_implicit)
+ {
+ error_init ("initialization designators may not nest");
+ return 1;
+ }
+
+ if (TREE_CODE (constructor_type) == RECORD_TYPE
+ || TREE_CODE (constructor_type) == UNION_TYPE)
+ {
+ subtype = TREE_TYPE (constructor_fields);
+ if (subtype != error_mark_node)
+ subtype = TYPE_MAIN_VARIANT (subtype);
+ }
+ else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+ {
+ subtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
+ }
+ else
+ abort ();
+
+ subcode = TREE_CODE (subtype);
+ if (array && subcode != ARRAY_TYPE)
+ {
+ error_init ("array index in non-array initializer");
+ return 1;
+ }
+ else if (!array && subcode != RECORD_TYPE && subcode != UNION_TYPE)
+ {
+ error_init ("field name not in record or union initializer");
+ return 1;
+ }
+
+ push_init_level (2);
+ return 0;
+}
+
+/* If there are range designators in designator list, push a new designator
+ to constructor_range_stack. RANGE_END is end of such stack range or
+ NULL_TREE if there is no range designator at this level. */
+
+static void
+push_range_stack (range_end)
+ tree range_end;
+{
+ struct constructor_range_stack *p;
+
+ p = (struct constructor_range_stack *)
+ ggc_alloc (sizeof (struct constructor_range_stack));
+ p->prev = constructor_range_stack;
+ p->next = 0;
+ p->fields = constructor_fields;
+ p->range_start = constructor_index;
+ p->index = constructor_index;
+ p->stack = constructor_stack;
+ p->range_end = range_end;
+ if (constructor_range_stack)
+ constructor_range_stack->next = p;
+ constructor_range_stack = p;
+}
+
/* Within an array initializer, specify the next index to be initialized.
FIRST is that index. If LAST is nonzero, then initialize a range
of indices, running from FIRST through LAST. */
@@ -5485,6 +5644,11 @@ void
set_init_index (first, last)
tree first, last;
{
+ if (set_designator (1))
+ return;
+
+ designator_errorneous = 1;
+
while ((TREE_CODE (first) == NOP_EXPR
|| TREE_CODE (first) == CONVERT_EXPR
|| TREE_CODE (first) == NON_LVALUE_EXPR)
@@ -5504,18 +5668,34 @@ set_init_index (first, last)
error_init ("nonconstant array index in initializer");
else if (last != 0 && TREE_CODE (last) != INTEGER_CST)
error_init ("nonconstant array index in initializer");
- else if (! constructor_unfilled_index)
+ else if (TREE_CODE (constructor_type) != ARRAY_TYPE)
error_init ("array index in non-array initializer");
- else if (tree_int_cst_lt (first, constructor_unfilled_index))
- error_init ("duplicate array index in initializer");
+ else if (constructor_max_index
+ && tree_int_cst_lt (constructor_max_index, first))
+ error_init ("array index in initializer exceeds array bounds");
else
{
constructor_index = convert (bitsizetype, first);
if (last != 0 && tree_int_cst_lt (last, first))
- error_init ("empty index range in initializer");
- else
- constructor_range_end = last ? convert (bitsizetype, last) : 0;
+ {
+ error_init ("empty index range in initializer");
+ last = 0;
+ }
+ else if (last)
+ {
+ last = convert (bitsizetype, last);
+ if (constructor_max_index != 0
+ && tree_int_cst_lt (constructor_max_index, last))
+ {
+ error_init ("array index range in initializer exceeds array bounds");
+ last = 0;
+ }
+ }
+ designator_depth++;
+ designator_errorneous = 0;
+ if (constructor_range_stack || last)
+ push_range_stack (last);
}
}
@@ -5526,18 +5706,22 @@ set_init_label (fieldname)
tree fieldname;
{
tree tail;
- int passed = 0;
- /* Don't die if an entire brace-pair level is superfluous
- in the containing level. */
- if (constructor_type == 0)
+ if (set_designator (0))
return;
+ designator_errorneous = 1;
+
+ if (TREE_CODE (constructor_type) != RECORD_TYPE
+ && TREE_CODE (constructor_type) != UNION_TYPE)
+ {
+ error_init ("field name not in record or union initializer");
+ return;
+ }
+
for (tail = TYPE_FIELDS (constructor_type); tail;
tail = TREE_CHAIN (tail))
{
- if (tail == constructor_unfilled_fields)
- passed = 1;
if (DECL_NAME (tail) == fieldname)
break;
}
@@ -5545,11 +5729,14 @@ set_init_label (fieldname)
if (tail == 0)
error ("unknown field `%s' specified in initializer",
IDENTIFIER_POINTER (fieldname));
- else if (!passed)
- error ("field `%s' already initialized",
- IDENTIFIER_POINTER (fieldname));
else
- constructor_fields = tail;
+ {
+ constructor_fields = tail;
+ designator_depth++;
+ designator_errorneous = 0;
+ if (constructor_range_stack)
+ push_range_stack (NULL_TREE);
+ }
}
/* Add a new initializer to the tree of pending initializers. PURPOSE
@@ -5572,24 +5759,36 @@ add_pending_init (purpose, value)
p = *q;
if (tree_int_cst_lt (purpose, p->purpose))
q = &p->left;
- else if (p->purpose != purpose)
+ else if (tree_int_cst_lt (p->purpose, purpose))
q = &p->right;
else
- abort ();
+ {
+ if (TREE_SIDE_EFFECTS (p->value))
+ warning_init ("initialized field with side-effects overwritten");
+ p->value = value;
+ return;
+ }
}
}
else
{
+ tree bitpos;
+
+ bitpos = bit_position (purpose);
while (*q != NULL)
{
p = *q;
- if (tree_int_cst_lt (bit_position (purpose),
- bit_position (p->purpose)))
+ if (tree_int_cst_lt (bitpos, bit_position (p->purpose)))
q = &p->left;
else if (p->purpose != purpose)
q = &p->right;
else
- abort ();
+ {
+ if (TREE_SIDE_EFFECTS (p->value))
+ warning_init ("initialized field with side-effects overwritten");
+ p->value = value;
+ return;
+ }
}
}
@@ -5758,41 +5957,178 @@ add_pending_init (purpose, value)
}
}
-/* Return nonzero if FIELD is equal to the index of a pending initializer. */
+/* Build AVL tree from a sorted chain. */
-static int
-pending_init_member (field)
+static void
+set_nonincremental_init ()
+{
+ tree chain;
+
+ if (TREE_CODE (constructor_type) != RECORD_TYPE
+ && TREE_CODE (constructor_type) != ARRAY_TYPE)
+ return;
+
+ for (chain = constructor_elements; chain; chain = TREE_CHAIN (chain))
+ add_pending_init (TREE_PURPOSE (chain), TREE_VALUE (chain));
+ constructor_elements = 0;
+ if (TREE_CODE (constructor_type) == RECORD_TYPE)
+ {
+ constructor_unfilled_fields = TYPE_FIELDS (constructor_type);
+ /* Skip any nameless bit fields at the beginning. */
+ while (constructor_unfilled_fields != 0
+ && DECL_C_BIT_FIELD (constructor_unfilled_fields)
+ && DECL_NAME (constructor_unfilled_fields) == 0)
+ constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
+
+ }
+ else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+ {
+ if (TYPE_DOMAIN (constructor_type))
+ constructor_unfilled_index
+ = convert (bitsizetype,
+ TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
+ else
+ constructor_unfilled_index = bitsize_zero_node;
+ }
+ constructor_incremental = 0;
+}
+
+/* Build AVL tree from a string constant. */
+
+static void
+set_nonincremental_init_from_string (str)
+ tree str;
+{
+ tree value, purpose, type;
+ HOST_WIDE_INT val[2];
+ const char *p, *end;
+ int byte, wchar_bytes, charwidth, bitpos;
+
+ if (TREE_CODE (constructor_type) != ARRAY_TYPE)
+ abort ();
+
+ if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
+ == TYPE_PRECISION (char_type_node))
+ wchar_bytes = 1;
+ else if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
+ == TYPE_PRECISION (wchar_type_node))
+ wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+ else
+ abort ();
+
+ charwidth = TYPE_PRECISION (char_type_node);
+ type = TREE_TYPE (constructor_type);
+ p = TREE_STRING_POINTER (str);
+ end = p + TREE_STRING_LENGTH (str);
+
+ for (purpose = bitsize_zero_node;
+ p < end && !tree_int_cst_lt (constructor_max_index, purpose);
+ purpose = size_binop (PLUS_EXPR, purpose, bitsize_one_node))
+ {
+ if (wchar_bytes == 1)
+ {
+ val[1] = (unsigned char) *p++;
+ val[0] = 0;
+ }
+ else
+ {
+ val[0] = 0;
+ val[1] = 0;
+ for (byte = 0; byte < wchar_bytes; byte++)
+ {
+ if (BYTES_BIG_ENDIAN)
+ bitpos = (wchar_bytes - byte - 1) * charwidth;
+ else
+ bitpos = byte * charwidth;
+ val[bitpos < HOST_BITS_PER_WIDE_INT]
+ |= ((unsigned HOST_WIDE_INT) ((unsigned char) *p++))
+ << (bitpos % HOST_BITS_PER_WIDE_INT);
+ }
+ }
+
+ if (!TREE_UNSIGNED (type))
+ {
+ bitpos = ((wchar_bytes - 1) * charwidth) + HOST_BITS_PER_CHAR;
+ if (bitpos < HOST_BITS_PER_WIDE_INT)
+ {
+ if (val[1] & (((HOST_WIDE_INT) 1) << (bitpos - 1)))
+ {
+ val[1] |= ((HOST_WIDE_INT) -1) << bitpos;
+ val[0] = -1;
+ }
+ }
+ else if (bitpos == HOST_BITS_PER_WIDE_INT)
+ {
+ if (val[1] < 0)
+ val[0] = -1;
+ }
+ else if (val[0] & (((HOST_WIDE_INT) 1)
+ << (bitpos - 1 - HOST_BITS_PER_WIDE_INT)))
+ val[0] |= ((HOST_WIDE_INT) -1)
+ << (bitpos - HOST_BITS_PER_WIDE_INT);
+ }
+
+ value = build_int_2 (val[1], val[0]);
+ TREE_TYPE (value) = type;
+ add_pending_init (purpose, value);
+ }
+
+ constructor_incremental = 0;
+}
+
+/* Return value of FIELD in pending initializer or zero if the field was
+ not initialized yet. */
+
+static tree
+find_init_member (field)
tree field;
{
struct init_node *p;
- p = constructor_pending_elts;
if (TREE_CODE (constructor_type) == ARRAY_TYPE)
{
+ if (constructor_incremental
+ && tree_int_cst_lt (field, constructor_unfilled_index))
+ set_nonincremental_init ();
+
+ p = constructor_pending_elts;
while (p)
{
- if (field == p->purpose)
- return 1;
- else if (tree_int_cst_lt (field, p->purpose))
+ if (tree_int_cst_lt (field, p->purpose))
p = p->left;
- else
+ else if (tree_int_cst_lt (p->purpose, field))
p = p->right;
+ else
+ return p->value;
}
}
- else
+ else if (TREE_CODE (constructor_type) == RECORD_TYPE)
{
+ tree bitpos = bit_position (field);
+
+ if (constructor_incremental
+ && (!constructor_unfilled_fields
+ || tree_int_cst_lt (bitpos,
+ bit_position (constructor_unfilled_fields))))
+ set_nonincremental_init ();
+
+ p = constructor_pending_elts;
while (p)
{
if (field == p->purpose)
- return 1;
- else if (tree_int_cst_lt (bit_position (field),
- bit_position (p->purpose)))
+ return p->value;
+ else if (tree_int_cst_lt (bitpos, bit_position (p->purpose)))
p = p->left;
else
p = p->right;
}
}
-
+ else if (TREE_CODE (constructor_type) == UNION_TYPE)
+ {
+ if (constructor_elements
+ && TREE_PURPOSE (constructor_elements) == field)
+ return TREE_VALUE (constructor_elements);
+ }
return 0;
}
@@ -5811,8 +6147,6 @@ output_init_element (value, type, field, pending)
tree value, type, field;
int pending;
{
- int duplicate = 0;
-
if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
|| (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
&& !(TREE_CODE (value) == STRING_CST
@@ -5840,90 +6174,111 @@ output_init_element (value, type, field, pending)
}
else if (require_constant_elements
&& initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
- {
- error_init ("initializer element is not computable at load time");
- value = error_mark_node;
- }
+ pedwarn ("initializer element is not computable at load time");
+
+ /* If this field is empty (and not at the end of structure),
+ don't do anything other than checking the initializer. */
+ if (field
+ && (TREE_TYPE (field) == error_mark_node
+ || (COMPLETE_TYPE_P (TREE_TYPE (field))
+ && integer_zerop (TYPE_SIZE (TREE_TYPE (field)))
+ && (TREE_CODE (constructor_type) == ARRAY_TYPE
+ || TREE_CHAIN (field)))))
+ return;
- /* If this element duplicates one on constructor_pending_elts,
- print a message and ignore it. Don't do this when we're
- processing elements taken off constructor_pending_elts,
- because we'd always get spurious errors. */
- if (pending)
+ if (value == error_mark_node)
{
- if (TREE_CODE (constructor_type) == RECORD_TYPE
- || TREE_CODE (constructor_type) == UNION_TYPE
- || TREE_CODE (constructor_type) == ARRAY_TYPE)
- {
- if (pending_init_member (field))
- {
- error_init ("duplicate initializer");
- duplicate = 1;
- }
- }
+ constructor_erroneous = 1;
+ return;
}
/* If this element doesn't come next in sequence,
put it on constructor_pending_elts. */
if (TREE_CODE (constructor_type) == ARRAY_TYPE
- && ! tree_int_cst_equal (field, constructor_unfilled_index))
+ && (!constructor_incremental
+ || !tree_int_cst_equal (field, constructor_unfilled_index)))
{
- if (! duplicate)
- add_pending_init (field,
- digest_init (type, value, require_constant_value,
- require_constant_elements));
+ if (constructor_incremental
+ && tree_int_cst_lt (field, constructor_unfilled_index))
+ set_nonincremental_init ();
+
+ add_pending_init (field,
+ digest_init (type, value, require_constant_value,
+ require_constant_elements));
+ return;
}
else if (TREE_CODE (constructor_type) == RECORD_TYPE
- && field != constructor_unfilled_fields)
+ && (!constructor_incremental
+ || field != constructor_unfilled_fields))
{
/* We do this for records but not for unions. In a union,
no matter which field is specified, it can be initialized
right away since it starts at the beginning of the union. */
- if (!duplicate)
- add_pending_init (field,
- digest_init (type, value, require_constant_value,
- require_constant_elements));
+ if (constructor_incremental)
+ {
+ if (!constructor_unfilled_fields)
+ set_nonincremental_init ();
+ else
+ {
+ tree bitpos, unfillpos;
+
+ bitpos = bit_position (field);
+ unfillpos = bit_position (constructor_unfilled_fields);
+
+ if (tree_int_cst_lt (bitpos, unfillpos))
+ set_nonincremental_init ();
+ }
+ }
+
+ add_pending_init (field,
+ digest_init (type, value, require_constant_value,
+ require_constant_elements));
+ return;
}
- else
+ else if (TREE_CODE (constructor_type) == UNION_TYPE
+ && constructor_elements)
{
- /* Otherwise, output this element either to
- constructor_elements or to the assembler file. */
+ if (TREE_SIDE_EFFECTS (TREE_VALUE (constructor_elements)))
+ warning_init ("initialized field with side-effects overwritten");
- if (!duplicate)
- {
- if (field && TREE_CODE (field) == INTEGER_CST)
- field = copy_node (field);
- constructor_elements
- = tree_cons (field, digest_init (type, value,
- require_constant_value,
- require_constant_elements),
- constructor_elements);
- }
+ /* We can have just one union field set. */
+ constructor_elements = 0;
+ }
- /* Advance the variable that indicates sequential elements output. */
- if (TREE_CODE (constructor_type) == ARRAY_TYPE)
- constructor_unfilled_index
- = size_binop (PLUS_EXPR, constructor_unfilled_index,
- bitsize_one_node);
- else if (TREE_CODE (constructor_type) == RECORD_TYPE)
- {
- constructor_unfilled_fields
- = TREE_CHAIN (constructor_unfilled_fields);
-
- /* Skip any nameless bit fields. */
- while (constructor_unfilled_fields != 0
- && DECL_C_BIT_FIELD (constructor_unfilled_fields)
- && DECL_NAME (constructor_unfilled_fields) == 0)
- constructor_unfilled_fields =
- TREE_CHAIN (constructor_unfilled_fields);
- }
- else if (TREE_CODE (constructor_type) == UNION_TYPE)
- constructor_unfilled_fields = 0;
+ /* Otherwise, output this element either to
+ constructor_elements or to the assembler file. */
+
+ if (field && TREE_CODE (field) == INTEGER_CST)
+ field = copy_node (field);
+ constructor_elements
+ = tree_cons (field, digest_init (type, value,
+ require_constant_value,
+ require_constant_elements),
+ constructor_elements);
+
+ /* Advance the variable that indicates sequential elements output. */
+ if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+ constructor_unfilled_index
+ = size_binop (PLUS_EXPR, constructor_unfilled_index,
+ bitsize_one_node);
+ else if (TREE_CODE (constructor_type) == RECORD_TYPE)
+ {
+ constructor_unfilled_fields
+ = TREE_CHAIN (constructor_unfilled_fields);
- /* Now output any pending elements which have become next. */
- if (pending)
- output_pending_init_elements (0);
+ /* Skip any nameless bit fields. */
+ while (constructor_unfilled_fields != 0
+ && DECL_C_BIT_FIELD (constructor_unfilled_fields)
+ && DECL_NAME (constructor_unfilled_fields) == 0)
+ constructor_unfilled_fields =
+ TREE_CHAIN (constructor_unfilled_fields);
}
+ else if (TREE_CODE (constructor_type) == UNION_TYPE)
+ constructor_unfilled_fields = 0;
+
+ /* Now output any pending elements which have become next. */
+ if (pending)
+ output_pending_init_elements (0);
}
/* Output any pending elements which have become next.
@@ -5999,18 +6354,23 @@ output_pending_init_elements (all)
else if (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
{
+ tree ctor_unfilled_bitpos, elt_bitpos;
+
/* If the current record is complete we are done. */
if (constructor_unfilled_fields == 0)
break;
- if (elt->purpose == constructor_unfilled_fields)
+
+ ctor_unfilled_bitpos = bit_position (constructor_unfilled_fields);
+ elt_bitpos = bit_position (elt->purpose);
+ /* We can't compare fields here because there might be empty
+ fields in between. */
+ if (tree_int_cst_equal (elt_bitpos, ctor_unfilled_bitpos))
{
- output_init_element (elt->value,
- TREE_TYPE (constructor_unfilled_fields),
- constructor_unfilled_fields,
- 0);
+ constructor_unfilled_fields = elt->purpose;
+ output_init_element (elt->value, TREE_TYPE (elt->purpose),
+ elt->purpose, 0);
}
- else if (tree_int_cst_lt (bit_position (constructor_unfilled_fields),
- bit_position (elt->purpose)))
+ else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos))
{
/* Advance to the next smaller node. */
if (elt->left)
@@ -6036,9 +6396,8 @@ output_pending_init_elements (all)
elt = elt->parent;
elt = elt->parent;
if (elt
- && (tree_int_cst_lt
- (bit_position (constructor_unfilled_fields),
- bit_position (elt->purpose))))
+ && (tree_int_cst_lt (ctor_unfilled_bitpos,
+ bit_position (elt->purpose))))
{
next = elt->purpose;
break;
@@ -6081,6 +6440,9 @@ process_init_element (value)
tree orig_value = value;
int string_flag = value != 0 && TREE_CODE (value) == STRING_CST;
+ designator_depth = 0;
+ designator_errorneous = 0;
+
/* Handle superfluous braces around string cst as in
char x[] = {"foo"}; */
if (string_flag
@@ -6123,6 +6485,10 @@ process_init_element (value)
break;
}
+ /* In the case of [LO ... HI] = VALUE, only evaluate VALUE once. */
+ if (constructor_range_stack)
+ value = save_expr (value);
+
while (1)
{
if (TREE_CODE (constructor_type) == RECORD_TYPE)
@@ -6191,9 +6557,8 @@ process_init_element (value)
&& DECL_C_BIT_FIELD (constructor_fields)
&& DECL_NAME (constructor_fields) == 0)
constructor_fields = TREE_CHAIN (constructor_fields);
- break;
}
- if (TREE_CODE (constructor_type) == UNION_TYPE)
+ else if (TREE_CODE (constructor_type) == UNION_TYPE)
{
tree fieldtype;
enum tree_code fieldcode;
@@ -6252,9 +6617,8 @@ process_init_element (value)
}
constructor_fields = 0;
- break;
}
- if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+ else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
{
tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
enum tree_code eltcode = TREE_CODE (elttype);
@@ -6285,61 +6649,93 @@ process_init_element (value)
break;
}
- /* In the case of [LO .. HI] = VALUE, only evaluate VALUE once. */
- if (constructor_range_end)
+ /* Now output the actual element. */
+ if (value)
{
- if (constructor_max_index != 0
- && tree_int_cst_lt (constructor_max_index,
- constructor_range_end))
- {
- pedwarn_init ("excess elements in array initializer");
- constructor_range_end = constructor_max_index;
- }
-
- value = save_expr (value);
+ push_array_bounds (tree_low_cst (constructor_index, 0));
+ output_init_element (value, elttype, constructor_index, 1);
+ RESTORE_SPELLING_DEPTH (constructor_depth);
}
- /* Now output the actual element.
- Ordinarily, output once.
- If there is a range, repeat it till we advance past the range. */
- do
- {
- if (value)
- {
- push_array_bounds (tree_low_cst (constructor_index, 0));
- output_init_element (value, elttype, constructor_index, 1);
- RESTORE_SPELLING_DEPTH (constructor_depth);
- }
-
- constructor_index
- = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
-
- if (! value)
- /* If we are doing the bookkeeping for an element that was
- directly output as a constructor, we must update
- constructor_unfilled_index. */
- constructor_unfilled_index = constructor_index;
- }
- while (! (constructor_range_end == 0
- || tree_int_cst_lt (constructor_range_end,
- constructor_index)));
+ constructor_index
+ = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
- break;
+ if (! value)
+ /* If we are doing the bookkeeping for an element that was
+ directly output as a constructor, we must update
+ constructor_unfilled_index. */
+ constructor_unfilled_index = constructor_index;
}
/* Handle the sole element allowed in a braced initializer
for a scalar variable. */
- if (constructor_fields == 0)
+ else if (constructor_fields == 0)
{
pedwarn_init ("excess elements in scalar initializer");
break;
}
+ else
+ {
+ if (value)
+ output_init_element (value, constructor_type, NULL_TREE, 1);
+ constructor_fields = 0;
+ }
+
+ /* Handle range initializers either at this level or anywhere higher
+ in the designator stack. */
+ if (constructor_range_stack)
+ {
+ struct constructor_range_stack *p, *range_stack;
+ int finish = 0;
+
+ range_stack = constructor_range_stack;
+ constructor_range_stack = 0;
+ while (constructor_stack != range_stack->stack)
+ {
+ if (!constructor_stack->implicit)
+ abort ();
+ process_init_element (pop_init_level (1));
+ }
+ for (p = range_stack;
+ !p->range_end || tree_int_cst_equal (p->index, p->range_end);
+ p = p->prev)
+ {
+ if (!constructor_stack->implicit)
+ abort ();
+ process_init_element (pop_init_level (1));
+ }
+
+ p->index = size_binop (PLUS_EXPR, p->index, bitsize_one_node);
+ if (tree_int_cst_equal (p->index, p->range_end) && !p->prev)
+ finish = 1;
+
+ while (1)
+ {
+ constructor_index = p->index;
+ constructor_fields = p->fields;
+ if (finish && p->range_end && p->index == p->range_start)
+ {
+ finish = 0;
+ p->prev = 0;
+ }
+ p = p->next;
+ if (!p)
+ break;
+ push_init_level (2);
+ p->stack = constructor_stack;
+ if (p->range_end && tree_int_cst_equal (p->index, p->range_end))
+ p->index = p->range_start;
+ }
+
+ if (!finish)
+ constructor_range_stack = range_stack;
+ continue;
+ }
- if (value)
- output_init_element (value, constructor_type, NULL_TREE, 1);
- constructor_fields = 0;
break;
}
+
+ constructor_range_stack = 0;
}
/* Build an asm-statement, whose components are a CV_QUALIFIER, a
diff --git a/gcc/extend.texi b/gcc/extend.texi
index 45dda7c..005bd7e 100644
--- a/gcc/extend.texi
+++ b/gcc/extend.texi
@@ -1261,6 +1261,10 @@ int widths[] = @{ [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 @};
@end example
@noindent
+If the value in it has side-effects, the side-effects will happen only once,
+not for each initialized field by the range initializer.
+
+@noindent
Note that the length of the array is the highest value specified
plus one.
@@ -1345,6 +1349,12 @@ example, with the @samp{struct point} declaration above:
struct point ptarray[10] = @{ [2].y = yv2, [2].x = xv2, [0].x = xv0 @};
@end example
+@noindent
+If the same field is initialized multiple times, it will have value from
+the last initialization. If any such overridden initialization has
+side-effect, it is unspecified whether the side-effect happens or not.
+Currently, gcc will discard them and issue a warning.
+
@node Case Ranges
@section Case Ranges
@cindex case ranges
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 52c7aed..f34c384 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2001-01-12 Jakub Jelinek <jakub@redhat.com>
+
+ * gcc.c-torture/execute/20000801-3.x: Remove.
+ * gcc.dg/c90-init-1.c: New test.
+ * gcc.dg/c99-init-1.c: New test.
+ * gcc.dg/c99-init-2.c: New test.
+ * gcc.dg/gnu99-init-1.c: New test.
+
2001-01-12 Richard Earnshaw <rearnsha@arm.com>
* lib/f-torture.exp (f_torture_compile): Prune the warnings before
diff --git a/gcc/testsuite/gcc.c-torture/execute/20000801-3.x b/gcc/testsuite/gcc.c-torture/execute/20000801-3.x
deleted file mode 100644
index 2f397b9..0000000
--- a/gcc/testsuite/gcc.c-torture/execute/20000801-3.x
+++ /dev/null
@@ -1,2 +0,0 @@
-set torture_execute_xfail "*-*-*"
-return 0
diff --git a/gcc/testsuite/gcc.dg/c90-init-1.c b/gcc/testsuite/gcc.dg/c90-init-1.c
new file mode 100644
index 0000000..1ea0bdb4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c90-init-1.c
@@ -0,0 +1,25 @@
+/* Test for C99 designated initializers */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+struct A {
+ int B;
+ short C[2];
+};
+int a[10] = { 10, [4] = 15 }; /* { dg-error "ISO C89 forbids specifying subobject to initialize" } */
+struct A b = { .B = 2 }; /* { dg-error "ISO C89 forbids specifying subobject to initialize" } */
+struct A c[] = { [3].C[1] = 1 }; /* { dg-error "ISO C89 forbids specifying subobject to initialize" } */
+struct A d[] = { [4 ... 6].C[0 ... 1] = 2 }; /* { dg-error "(forbids specifying range of elements to initialize)|(ISO C89 forbids specifying subobject to initialize)" } */
+int e[] = { [2] 2 }; /* { dg-error "use of designated initializer without" } */
+struct A f = { C: { 0, 1 } }; /* { dg-error "use of designated initializer with " } */
+int g;
+
+void foo (int *);
+
+void bar (void)
+{
+ int x[] = { g++, 2 }; /* { dg-error "is not computable at load time" } */
+
+ foo (x);
+}
diff --git a/gcc/testsuite/gcc.dg/c99-init-1.c b/gcc/testsuite/gcc.dg/c99-init-1.c
new file mode 100644
index 0000000..95803c2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-init-1.c
@@ -0,0 +1,78 @@
+/* Test for C99 designated initializers */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do run } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+typedef __SIZE_TYPE__ size_t;
+typedef __WCHAR_TYPE__ wchar_t;
+extern int memcmp (const void *, const void *, size_t);
+extern void abort (void);
+extern void exit (int);
+
+int a[10] = { 10, 0, 12, 13, 14, 0, 0, 17, 0, 0 };
+int b[10] = { 10, [4] = 15, [2] = 12, [4] = 14, [7] = 17 };
+int c[10] = { 10, [4] = 15, [2] = 12, [3] = 13, 14, [7] = 17 };
+struct A {
+ int B;
+ short C[2];
+};
+struct A d[] = { { 0, { 1, 2 } }, { 0, { 0, 0 } }, { 10, { 11, 12 } } };
+struct A e[] = { 0, 1, 2, [2] = 10, 11, 12 };
+struct A f[] = { 0, 1, 2, [2].C = 11, 12, 13 };
+struct A g[] = { 0, 1, 2, [2].C[1] = 12, 13, 14 };
+struct A h[] = { 0, 1, 2, [2] = { .C[1] = 12 }, 13, 14 };
+struct A i[] = { 0, 1, 2, [2] = { .C = { [1] = 12 } }, 13, 14 };
+union D {
+ int E;
+ double F;
+ struct A G;
+};
+union D j[] = { [4] = 1, [4].F = 1.0, [1].G.C[1] = 4 };
+struct H {
+ char I[6];
+ int J;
+} k[] = { { { "foo" }, 1 }, [0].I[0] = 'b' };
+struct K {
+ wchar_t L[6];
+ int M;
+} l[] = { { { L"foo" }, 1 }, [0].L[2] = L'x', [0].L[4] = L'y' };
+struct H m[] = { { { "foo" }, 1 }, [0] = { .I[0] = 'b' } };
+struct H n[] = { { { "foo" }, 1 }, [0].I = { "a" }, [0].J = 2 };
+int o = { 22 };
+
+int main (void)
+{
+ if (b[3])
+ abort ();
+ b[3] = 13;
+ if (memcmp (a, b, sizeof (a)) || memcmp (a, c, sizeof (a)))
+ abort ();
+ if (memcmp (d, e, sizeof (d)) || sizeof (d) != sizeof (e))
+ abort ();
+ if (f[2].B != 0 || g[2].B != 0 || g[2].C[0] != 0)
+ abort ();
+ if (memcmp (g, h, sizeof (g)) || memcmp (g, i, sizeof (g)))
+ abort ();
+ f[2].B = 10;
+ g[2].B = 10;
+ g[2].C[0] = 11;
+ if (memcmp (d, f, sizeof (d)) || memcmp (d, g, sizeof (d)))
+ abort ();
+ if (f[3].B != 13 || g[3].B != 13 || g[3].C[0] != 14)
+ abort ();
+ if (j[0].E || j[1].G.B || j[1].G.C[0] || j[1].G.C[1] != 4)
+ abort ();
+ if (j[2].E || j[3].E || j[4].F != 1.0)
+ abort ();
+ if (memcmp (k[0].I, "boo\0\0", 6) || k[0].J != 1)
+ abort ();
+ if (memcmp (l[0].L, L"fox\0y", 6 * sizeof(wchar_t)) || l[0].M != 1)
+ abort ();
+ if (memcmp (m[0].I, "b\0\0\0\0", 6) || m[0].J)
+ abort ();
+ if (memcmp (n[0].I, "a\0\0\0\0", 6) || n[0].J != 2)
+ abort ();
+ if (o != 22)
+ abort ();
+ exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/c99-init-2.c b/gcc/testsuite/gcc.dg/c99-init-2.c
new file mode 100644
index 0000000..d3a331f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-init-2.c
@@ -0,0 +1,30 @@
+/* Test for C99 designated initializer warnings and errors */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -Wall -pedantic-errors" } */
+
+typedef struct {
+ int B;
+ short C[2];
+} A;
+A a = { [2] = 1 }; /* { dg-error "(array index in non-array)|(near initialization)" } */
+int b[] = { .B = 1 }; /* { dg-error "(field name not in record)|(near initialization)" } */
+A c[] = { [0].D = 1 }; /* { dg-error "unknown field" } */
+int d;
+int e = { d++ }; /* { dg-error "(is not constant)|(near initialization)" } */
+A f[2] = { [0].C[0] = 1, [2] = { 2, { 1, 2 } } };/* { dg-error "(array index in initializer exceeds array bounds)|(near initialization)" } */
+int g[4] = { [1] = 1, 2, [6] = 5 }; /* { dg-error "(array index in initializer exceeds array bounds)|(near initialization)" } */
+int h[] = { [0 ... 3] = 5 }; /* { dg-error "forbids specifying range of elements" } */
+int i[] = { [2] 4 }; /* { dg-error "use of designated initializer without" } */
+A j = { B: 2 }; /* { dg-error "use of designated initializer with " } */
+
+void foo (int *, A *);
+
+void bar (void)
+{
+ int a[] = { d++, [0] = 1 }; /* { dg-warning "(initialized field with side-effects overwritten)|(near initialization)" } */
+ A b = { 1, { d++, 2 }, .C[0] = 3 };/* { dg-warning "(initialized field with side-effects overwritten)|(near initialization)" } */
+ A c = { d++, { 2, 3 }, .B = 4 }; /* { dg-warning "(initialized field with side-effects overwritten)|(near initialization)" } */
+
+ foo (a, d ? &b : &c);
+}
diff --git a/gcc/testsuite/gcc.dg/gnu99-init-1.c b/gcc/testsuite/gcc.dg/gnu99-init-1.c
new file mode 100644
index 0000000..c78f1764
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu99-init-1.c
@@ -0,0 +1,62 @@
+/* Test for GNU extensions to C99 designated initializers */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" } */
+
+typedef __SIZE_TYPE__ size_t;
+extern int memcmp (const void *, const void *, size_t);
+extern void abort (void);
+extern void exit (int);
+
+int a[][2][4] = { [2 ... 4][0 ... 1][2 ... 3] = 1, [2] = 2, [2][0][2] = 3 };
+struct E {};
+struct F { struct E H; };
+struct G { int I; struct E J; int K; };
+struct H { int I; struct F J; int K; };
+struct G k = { .J = {}, 1 };
+struct H l = { .J.H = {}, 2 };
+struct H m = { .J = {}, 3 };
+struct I { int J; int K[3]; int L; };
+struct M { int N; struct I O[3]; int P; };
+struct M n[] = { [0 ... 5].O[1 ... 2].K[0 ... 1] = 4, 5, 6, 7 };
+
+int main (void)
+{
+ int x, y, z;
+
+ if (a[2][0][0] != 2 || a[2][0][2] != 3)
+ abort ();
+ a[2][0][0] = 0;
+ a[2][0][2] = 1;
+ for (x = 0; x <= 4; x++)
+ for (y = 0; y <= 1; y++)
+ for (z = 0; z <= 3; z++)
+ if (a[x][y][z] != (x >= 2 && z >= 2))
+ abort ();
+ if (k.I || l.I || m.I || k.K != 1 || l.K != 2 || m.K != 3)
+ abort ();
+ for (x = 0; x <= 5; x++)
+ {
+ if (n[x].N || n[x].O[0].J || n[x].O[0].L)
+ abort ();
+ for (y = 0; y <= 2; y++)
+ if (n[x].O[0].K[y])
+ abort ();
+ for (y = 1; y <= 2; y++)
+ {
+ if (n[x].O[y].J)
+ abort ();
+ if (n[x].O[y].K[0] != 4)
+ abort ();
+ if (n[x].O[y].K[1] != 4)
+ abort ();
+ if ((x < 5 || y < 2) && (n[x].O[y].K[2] || n[x].O[y].L))
+ abort ();
+ }
+ if (x < 5 && n[x].P)
+ abort ();
+ }
+ if (n[5].O[2].K[2] != 5 || n[5].O[2].L != 6 || n[5].P != 7)
+ abort ();
+ exit (0);
+}