summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog19
-rw-r--r--gcc/c-common.c21
-rw-r--r--gcc/c-common.def6
-rw-r--r--gcc/c-common.h6
-rw-r--r--gcc/c-decl.c53
-rw-r--r--gcc/c-lang.c2
-rw-r--r--gcc/c-parse.in20
-rw-r--r--gcc/c-tree.h1
-rw-r--r--gcc/c-typeck.c9
-rw-r--r--gcc/doc/c-tree.texi10
-rw-r--r--gcc/doc/extend.texi25
-rw-r--r--gcc/objc/objc-lang.c2
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/init-3.c2
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20000722-1.x3
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20010123-1.x2
-rw-r--r--gcc/testsuite/gcc.dg/c90-complit-1.c20
-rw-r--r--gcc/testsuite/gcc.dg/c99-complit-1.c112
-rw-r--r--gcc/testsuite/gcc.dg/c99-complit-2.c68
19 files changed, 339 insertions, 50 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 22242e2274d..95ae31275af 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,24 @@
2001-12-04 Joseph S. Myers <jsm28@cam.ac.uk>
+ * c-common.def (COMPOUND_LITERAL_EXPR): New.
+ * c-common.c (c_expand_expr): Handle COMPOUND_LITERAL_EXPR.
+ (c_staticp): New function.
+ * c-common.h (COMPOUND_LITERAL_EXPR_DECL): New.
+ (c_staticp): Declare.
+ * c-typeck.c (default_function_array_conversion, build_unary_op):
+ Don't handle CONSTRUCTOR specially.
+ (lvalue_p, mark_addressable): Handle COMPOUND_LITERAL_EXPR.
+ * c-decl.c (build_compound_literal): New function.
+ * c-tree.h (build_compound_literal): Declare.
+ * c-parse.in (primary): Use build_compound_literal.
+ * c-lang.c (LANG_HOOKS_STATICP): Define.
+ * objc/objc-lang.c (LANG_HOOKS_STATICP): Likewise.
+ * doc/c-tree.texi: Document COMPOUND_LITERAL_EXPR.
+ * doc/extend.texi: Update documentation of compound literals.
+ Fixes PR c/4787.
+
+2001-12-04 Joseph S. Myers <jsm28@cam.ac.uk>
+
* langhooks.h (struct lang_hooks): Add staticp.
* langhooks-def.h (lhd_staticp, LANG_HOOKS_STATICP): New.
(LANG_HOOKS_INITIALIZER): Add LANG_HOOKS_STATICP.
diff --git a/gcc/c-common.c b/gcc/c-common.c
index a7d005b04ed..f5fc0d348f5 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -3432,6 +3432,15 @@ c_expand_expr (exp, target, tmode, modifier)
}
break;
+ case COMPOUND_LITERAL_EXPR:
+ {
+ /* Initialize the anonymous variable declared in the compound
+ literal, then return the variable. */
+ tree decl = COMPOUND_LITERAL_EXPR_DECL (exp);
+ emit_local_var (decl);
+ return expand_expr (decl, target, tmode, modifier);
+ }
+
default:
abort ();
}
@@ -3482,6 +3491,18 @@ c_unsafe_for_reeval (exp)
return -1;
}
+/* Hook used by staticp to handle language-specific tree codes. */
+
+int
+c_staticp (exp)
+ tree exp;
+{
+ if (TREE_CODE (exp) == COMPOUND_LITERAL_EXPR
+ && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp)))
+ return 1;
+ return 0;
+}
+
/* Tree code classes. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
diff --git a/gcc/c-common.def b/gcc/c-common.def
index 6ae0466f236..7840ce81610 100644
--- a/gcc/c-common.def
+++ b/gcc/c-common.def
@@ -101,3 +101,9 @@ DEFTREECODE (CASE_LABEL, "case_label", 'e', 3)
/* A STMT_EXPR represents a statement-expression. The
STMT_EXPR_STMT is the statement given by the expression. */
DEFTREECODE (STMT_EXPR, "stmt_expr", 'e', 1)
+
+/* A COMPOUND_LITERAL_EXPR represents a C99 compound literal. The
+ COMPOND_LITERAL_EXPR_DECL is the decl for the anonymous object
+ represented by the COMPOUND_LITERAL; the DECL_INITIAL of that
+ decl is the CONSTRUCTOR that initializes the compound literal. */
+DEFTREECODE (COMPOUND_LITERAL_EXPR, "compound_literal_expr", 'e', 1)
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 1ce21a1769f..4ab415c1f1e 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -630,6 +630,10 @@ extern tree strip_array_types PARAMS ((tree));
the given label statement. */
#define LABEL_STMT_LABEL(NODE) TREE_OPERAND (LABEL_STMT_CHECK (NODE), 0)
+/* COMPOUND_LITERAL_EXPR accessor. */
+#define COMPOUND_LITERAL_EXPR_DECL(NODE) \
+ TREE_OPERAND (COMPOUND_LITERAL_EXPR_CHECK (NODE), 0)
+
/* Nonzero if this SCOPE_STMT is for the beginning of a scope. */
#define SCOPE_BEGIN_P(NODE) \
(TREE_LANG_FLAG_0 (SCOPE_STMT_CHECK (NODE)))
@@ -813,6 +817,8 @@ extern rtx c_expand_expr PARAMS ((tree, rtx, enum machine_mode,
extern int c_safe_from_p PARAMS ((rtx, tree));
+extern int c_staticp PARAMS ((tree));
+
extern int c_unsafe_for_reeval PARAMS ((tree));
/* Information recorded about each file examined during compilation. */
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 34278546d97..b5597f98dad 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -3793,6 +3793,59 @@ clear_parm_order ()
current_binding_level->parm_order = NULL_TREE;
}
+/* Build a COMPOUND_LITERAL_EXPR. TYPE is the type given in the compound
+ literal, which may be an incomplete array type completed by the
+ initializer; INIT is a CONSTRUCTOR that initializes the compound
+ literal. */
+
+tree
+build_compound_literal (type, init)
+ tree type;
+ tree init;
+{
+ /* We do not use start_decl here because we have a type, not a declarator;
+ and do not use finish_decl because the decl should be stored inside
+ the COMPOUND_LITERAL_EXPR rather than added elsewhere as a DECL_STMT. */
+ tree decl = build_decl (VAR_DECL, NULL_TREE, type);
+ tree complit;
+ DECL_EXTERNAL (decl) = 0;
+ TREE_PUBLIC (decl) = 0;
+ TREE_STATIC (decl) = (current_binding_level == global_binding_level);
+ DECL_CONTEXT (decl) = current_function_decl;
+ TREE_USED (decl) = 1;
+ TREE_TYPE (decl) = type;
+ store_init_value (decl, init);
+
+ if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
+ {
+ int failure = complete_array_type (type, DECL_INITIAL (decl), 1);
+ if (failure)
+ abort ();
+ }
+
+ type = TREE_TYPE (decl);
+ if (type == error_mark_node || !COMPLETE_TYPE_P (type))
+ return error_mark_node;
+
+ complit = build1 (COMPOUND_LITERAL_EXPR, TREE_TYPE (decl), decl);
+ TREE_SIDE_EFFECTS (complit) = 1;
+
+ layout_decl (decl, 0);
+
+ if (TREE_STATIC (decl))
+ {
+ /* This decl needs a name for the assembler output. We also need
+ a unique suffix to be added to the name, for which DECL_CONTEXT
+ must be set. */
+ DECL_NAME (decl) = get_identifier ("__compound_literal");
+ DECL_CONTEXT (decl) = complit;
+ rest_of_decl_compilation (decl, NULL, 1, 0);
+ DECL_CONTEXT (decl) = NULL_TREE;
+ }
+
+ return complit;
+}
+
/* Make TYPE a complete type based on INITIAL_VALUE.
Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered,
2 if there was no information (in which case assume 1 if DO_DEFAULT). */
diff --git a/gcc/c-lang.c b/gcc/c-lang.c
index dceede52557..c2056c5b464 100644
--- a/gcc/c-lang.c
+++ b/gcc/c-lang.c
@@ -56,6 +56,8 @@ static void c_post_options PARAMS ((void));
#define LANG_HOOKS_GET_ALIAS_SET c_common_get_alias_set
#undef LANG_HOOKS_SAFE_FROM_P
#define LANG_HOOKS_SAFE_FROM_P c_safe_from_p
+#undef LANG_HOOKS_STATICP
+#define LANG_HOOKS_STATICP c_staticp
#undef LANG_HOOKS_PRINT_IDENTIFIER
#define LANG_HOOKS_PRINT_IDENTIFIER c_print_identifier
#undef LANG_HOOKS_SET_YYDEBUG
diff --git a/gcc/c-parse.in b/gcc/c-parse.in
index fe57047ec9c..e0457b2af67 100644
--- a/gcc/c-parse.in
+++ b/gcc/c-parse.in
@@ -627,29 +627,13 @@ primary:
$2 = groktypename ($2);
really_start_incremental_init ($2); }
initlist_maybe_comma '}' %prec UNARY
- { const char *name;
- tree result = pop_init_level (0);
+ { tree constructor = pop_init_level (0);
tree type = $2;
finish_init ();
if (pedantic && ! flag_isoc99)
pedwarn ("ISO C89 forbids compound literals");
- if (TYPE_NAME (type) != 0)
- {
- if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- name = IDENTIFIER_POINTER (TYPE_NAME (type));
- else
- name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
- }
- else
- name = "";
- $$ = result;
- if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
- {
- int failure = complete_array_type (type, $$, 1);
- if (failure)
- abort ();
- }
+ $$ = build_compound_literal (type, constructor);
}
| '(' expr ')'
{ char class = TREE_CODE_CLASS (TREE_CODE ($2));
diff --git a/gcc/c-tree.h b/gcc/c-tree.h
index e686ed4fd1b..a304b7ebff7 100644
--- a/gcc/c-tree.h
+++ b/gcc/c-tree.h
@@ -261,6 +261,7 @@ extern tree pop_init_level PARAMS ((int));
extern void set_init_index PARAMS ((tree, tree));
extern void set_init_label PARAMS ((tree));
extern void process_init_element PARAMS ((tree));
+extern tree build_compound_literal PARAMS ((tree, tree));
extern void pedwarn_c99 PARAMS ((const char *, ...))
ATTRIBUTE_PRINTF_1;
extern tree c_start_case PARAMS ((tree));
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index ff504dc1d05..297afad8ce8 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -910,8 +910,7 @@ default_function_array_conversion (exp)
}
lvalue_array_p = !not_lvalue && lvalue_p (exp);
- if (!flag_isoc99 && !lvalue_array_p
- && !(TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
+ if (!flag_isoc99 && !lvalue_array_p)
{
/* Before C99, non-lvalue arrays do not decay to pointers.
Normally, using such an array would be invalid; but it can
@@ -3141,10 +3140,6 @@ build_unary_op (code, xarg, flag)
}
#endif
- /* Allow the address of a constructor if all the elements
- are constant. */
- if (TREE_CODE (arg) == CONSTRUCTOR && TREE_CONSTANT (arg))
- ;
/* Anything not already handled and not a true memory reference
or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag
@@ -3256,6 +3251,7 @@ lvalue_p (ref)
case COMPONENT_REF:
return lvalue_p (TREE_OPERAND (ref, 0));
+ case COMPOUND_LITERAL_EXPR:
case STRING_CST:
return 1;
@@ -3411,6 +3407,7 @@ mark_addressable (exp)
x = TREE_OPERAND (x, 0);
break;
+ case COMPOUND_LITERAL_EXPR:
case CONSTRUCTOR:
TREE_ADDRESSABLE (x) = 1;
return 1;
diff --git a/gcc/doc/c-tree.texi b/gcc/doc/c-tree.texi
index dd21ae6285b..3db3d7f10ff 100644
--- a/gcc/doc/c-tree.texi
+++ b/gcc/doc/c-tree.texi
@@ -1738,6 +1738,7 @@ This macro returns the attributes on the type @var{type}.
@tindex COND_EXPR
@tindex CALL_EXPR
@tindex CONSTRUCTOR
+@tindex COMPOUND_LITERAL_EXPR
@tindex STMT_EXPR
@tindex BIND_EXPR
@tindex LOOP_EXPR
@@ -2201,6 +2202,15 @@ next available array element.
Conceptually, before any initialization is done, the entire area of
storage is initialized to zero.
+@item COMPOUND_LITERAL_EXPR
+@findex COMPOUND_LITERAL_EXPR_DECL
+These nodes represent ISO C99 compound literals. The
+@code{COMPOUND_LITERAL_EXPR_DECL} is an anonymous @code{VAR_DECL} for
+the unnamed object represented by the compound literal; the
+@code{DECL_INITIAL} of that @code{VAR_DECL} is a @code{CONSTRUCTOR}
+representing the brace-enclosed list of initializers in the compound
+literal.
+
@item SAVE_EXPR
A @code{SAVE_EXPR} represents an expression (possibly involving
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 781fa997add..cf275f1ecc9 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -1608,9 +1608,8 @@ foo (float f, float g)
ISO C99 supports compound literals. A compound literal looks like
a cast containing an initializer. Its value is an object of the
type specified in the cast, containing the elements specified in
-the initializer. (GCC does not yet implement the full ISO C99 semantics
-for compound literals.) As an extension, GCC supports compound literals
-in C89 mode and in C++.
+the initializer; it is an lvalue. As an extension, GCC supports
+compound literals in C89 mode and in C++.
Usually, the specified type is a structure. Assume that
@code{struct foo} and @code{structure} are declared as shown:
@@ -1638,28 +1637,14 @@ This is equivalent to writing the following:
You can also construct an array. If all the elements of the compound literal
are (made up of) simple constant expressions, suitable for use in
-initializers, then the compound literal is an lvalue and can be coerced to a
-pointer to its first element, as shown here:
+initializers of objects of static storage duration, then the compound
+literal can be coerced to a pointer to its first element and used in
+such an initializer, as shown here:
@example
char **foo = (char *[]) @{ "x", "y", "z" @};
@end example
-Array compound literals whose elements are not simple constants are
-not very useful, because the compound literal is not an lvalue; ISO C99
-specifies that it is, being a temporary object with automatic storage
-duration associated with the enclosing block, but GCC does not yet
-implement this. There are currently only two valid ways to use it with
-GCC: to subscript it, or initialize
-an array variable with it. The former is probably slower than a
-@code{switch} statement, while the latter does the same thing an
-ordinary C initializer would do. Here is an example of
-subscripting an array compound literal:
-
-@example
-output = ((int[]) @{ 2, x, 28 @}) [input];
-@end example
-
Compound literals for scalar types and union types are is
also allowed, but then the compound literal is equivalent
to a cast.
diff --git a/gcc/objc/objc-lang.c b/gcc/objc/objc-lang.c
index 33d2cde6ce3..7e2cae7bf00 100644
--- a/gcc/objc/objc-lang.c
+++ b/gcc/objc/objc-lang.c
@@ -44,6 +44,8 @@ static void objc_post_options PARAMS ((void));
#define LANG_HOOKS_DECODE_OPTION objc_decode_option
#undef LANG_HOOKS_POST_OPTIONS
#define LANG_HOOKS_POST_OPTIONS objc_post_options
+#undef LANG_HOOKS_STATICP
+#define LANG_HOOKS_STATICP c_staticp
#undef LANG_HOOKS_PRINT_IDENTIFIER
#define LANG_HOOKS_PRINT_IDENTIFIER c_print_identifier
#undef LANG_HOOKS_SET_YYDEBUG
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 795c502821b..d22c31dc4bb 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2001-12-04 Joseph S. Myers <jsm28@cam.ac.uk>
+
+ * gcc.c-torture/execute/20000722-1.x,
+ gcc.c-torture/execute/20010123-1.x: Remove.
+ * gcc.c-torture/compile/init-3.c: Don't use a compound literal.
+ * gcc.dg/c90-complit-1.c, gcc.dg/c99-complit-1.c,
+ gcc.dg/c99-complit-2.c: New tests.
+
2001-12-04 Nathan Sidwell <nathan@codesourcery.com>
* g++.dg/inherit/base1.C: New test.
diff --git a/gcc/testsuite/gcc.c-torture/compile/init-3.c b/gcc/testsuite/gcc.c-torture/compile/init-3.c
index d091168897b..be3d9b49679 100644
--- a/gcc/testsuite/gcc.c-torture/compile/init-3.c
+++ b/gcc/testsuite/gcc.c-torture/compile/init-3.c
@@ -6,6 +6,6 @@ struct something {
};
struct something X = {
- foo: (struct empty) { },
+ foo: { },
bar: 1,
};
diff --git a/gcc/testsuite/gcc.c-torture/execute/20000722-1.x b/gcc/testsuite/gcc.c-torture/execute/20000722-1.x
deleted file mode 100644
index bbad3bb394a..00000000000
--- a/gcc/testsuite/gcc.c-torture/execute/20000722-1.x
+++ /dev/null
@@ -1,3 +0,0 @@
-# Doesn't work. Hasn't worked ever, I think.
-set torture_execute_xfail "*-*-*"
-return 0
diff --git a/gcc/testsuite/gcc.c-torture/execute/20010123-1.x b/gcc/testsuite/gcc.c-torture/execute/20010123-1.x
deleted file mode 100644
index 2f397b96e51..00000000000
--- a/gcc/testsuite/gcc.c-torture/execute/20010123-1.x
+++ /dev/null
@@ -1,2 +0,0 @@
-set torture_execute_xfail "*-*-*"
-return 0
diff --git a/gcc/testsuite/gcc.dg/c90-complit-1.c b/gcc/testsuite/gcc.dg/c90-complit-1.c
new file mode 100644
index 00000000000..4cd910fa866
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c90-complit-1.c
@@ -0,0 +1,20 @@
+/* Test for compound literals: in C99 only. */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+struct s { int a; int b; };
+union u { int c; int d; };
+
+void
+foo (void)
+{
+ (int) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "compound literal" "scalar" { target *-*-* } 12 } */
+ (struct s) { 1, 2 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "compound literal" "struct" { target *-*-* } 14 } */
+ (union u) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "compound literal" "union" { target *-*-* } 16 } */
+ (int [1]) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "compound literal" "array" { target *-*-* } 18 } */
+}
diff --git a/gcc/testsuite/gcc.dg/c99-complit-1.c b/gcc/testsuite/gcc.dg/c99-complit-1.c
new file mode 100644
index 00000000000..94e15db6d2a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-complit-1.c
@@ -0,0 +1,112 @@
+/* Test for compound literals: in C99 only. Test for valid uses. */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do run } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+extern void abort (void);
+extern void exit (int);
+
+struct s { int a; int b; };
+union u { int c; int d; };
+
+int *i0a = &(int) { 0 };
+int *i0b = &(int) { 0 };
+int *i1a = &(int) { 1 };
+int *i1b = &(int) { 1 };
+const int *i0c = &(const int) { 0 };
+
+struct s *s0 = &(struct s) { 1, 2 };
+struct s *s1 = &(struct s) { 1, 2 };
+const struct s *s2 = &(const struct s) { 1, 2 };
+
+union u *u0 = &(union u) { 3 };
+union u *u1 = &(union u) { 3 };
+const union u *u2 = &(const union u) { 3 };
+
+int *a0 = (int []) { 1, 2, 3 };
+const int *a1 = (const int []) { 1, 2, 3 };
+
+char *p = (char []){ "foo" };
+
+int
+main (void)
+{
+ if (i0a == i0b || i0a == i0c || i0b == i0c)
+ abort ();
+ if (i1a == i1b)
+ abort ();
+ if (*i0a != 0 || *i0b != 0 || *i1a != 1 || *i1b != 1 || *i0c != 0)
+ abort ();
+ *i0a = 1;
+ *i1a = 0;
+ if (*i0a != 1 || *i0b != 0 || *i1a != 0 || *i1b != 1 || *i0c != 0)
+ abort ();
+ if (s0 == s1 || s1 == s2 || s2 == s0)
+ abort ();
+ if (s0->a != 1 || s0->b != 2 || s1->a != 1 || s1->b != 2
+ || s2->a != 1 || s2->b != 2)
+ abort ();
+ s0->a = 2;
+ s1->b = 1;
+ if (s0->a != 2 || s0->b != 2 || s1->a != 1 || s1->b != 1
+ || s2->a != 1 || s2->b != 2)
+ abort ();
+ if (u0 == u1 || u1 == u2 || u2 == u0)
+ abort ();
+ if (u0->c != 3 || u1->c != 3 || u2->c != 3)
+ abort ();
+ u0->d = 2;
+ if (u0->d != 2 || u1->c != 3 || u2->c != 3)
+ abort ();
+ if (a0 == a1)
+ abort ();
+ if (a0[0] != 1 || a0[1] != 2 || a0[2] != 3
+ || a1[0] != 1 || a1[1] != 2 || a1[2] != 3)
+ abort ();
+ a0[0] = 3;
+ if (a0[0] != 3 || a0[1] != 2 || a0[2] != 3
+ || a1[0] != 1 || a1[1] != 2 || a1[2] != 3)
+ abort ();
+ if (p[0] != 'f' || p[1] != 'o' || p[2] != 'o' || p[3] != 0)
+ abort ();
+ p[0] = 'g';
+ if (p[0] != 'g' || p[1] != 'o' || p[2] != 'o' || p[3] != 0)
+ abort ();
+ if (sizeof((int []) { 1, 2 ,3 }) != 3 * sizeof(int))
+ abort ();
+ if (sizeof((int []) { [3] = 4 }) != 4 * sizeof(int))
+ abort ();
+ struct s *y;
+ for (int i = 0; i < 3; i++) {
+ struct s *x = &(struct s) { 1, i };
+ if (x->a != 1 || x->b != i)
+ abort ();
+ x->a++;
+ x->b--;
+ if (x->a != 2 || x->b != i - 1)
+ abort ();
+ if (i && y != x)
+ abort ();
+ y = x;
+ }
+ int *z;
+ for (int i = 0; i < 4; i++) {
+ int *x = (int []){ 0, i, i + 2, i - 3 };
+ if (x[0] != 0 || x[1] != i || x[2] != i + 2 || x[3] != i - 3)
+ abort ();
+ x[0] = x[1];
+ x[1] *= x[2];
+ x[2] -= x[3];
+ x[3] += 7;
+ if (x[0] != i || x[1] != i * (i + 2) || x[2] != 5 || x[3] != i + 4)
+ abort ();
+ if (i && z != x)
+ abort ();
+ z = x;
+ }
+ (int) { 0 } = 1;
+ (struct s) { 0, 1 }.a = 3;
+ (union u) { 3 }.c = 4;
+ (int []){ 1, 2 }[0] = 0;
+ exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/c99-complit-2.c b/gcc/testsuite/gcc.dg/c99-complit-2.c
new file mode 100644
index 00000000000..faf44b2376e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-complit-2.c
@@ -0,0 +1,68 @@
+/* Test for compound literals: in C99 only. Test for invalid uses. */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+struct s { int a; int b; };
+union u { int c; int d; };
+
+struct si;
+union ui;
+
+void
+foo (int a)
+{
+ /* The type name must not be incomplete (apart from arrays of unknown
+ size), or a function type, or a VLA type. */
+ (void) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "init" "void type" { target *-*-* } 17 } */
+ &(struct si) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "init" "incomplete struct type" { target *-*-* } 19 } */
+ &(union ui) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "init" "incomplete union type" { target *-*-* } 21 } */
+ (void (void)) { 0 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "init" "function type" { target *-*-* } 23 } */
+ (int [a]) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "init|variable" "VLA type" { target *-*-* } 25 } */
+ /* Initializers must not attempt to initialize outside the object
+ declared. */
+ (int [1]) { [1] = 2 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "init" "value outside array" { target *-*-* } 29 } */
+ (int [1]) { [-1] = 2 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "init" "value outside array" { target *-*-* } 31 } */
+ (int [1]) { 0, 1 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "init" "value outside array" { target *-*-* } 33 } */
+}
+
+int z;
+
+/* Outside a function, initializers must be constant. */
+struct s *s0 = &(struct s) { 0, z }; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "init" "non-const" { target *-*-* } 40 } */
+int sz = sizeof((struct s) { 0, z }); /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "init" "non-const" { target *-*-* } 42 } */
+
+/* Compound literals aren't themselves constant expressions. */
+int x = (int) { 0 }; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "init" "non-const" { target *-*-* } 46 } */
+
+/* Nor are they suitable structure or union initializers
+ outside a function. */
+struct s s1 = (struct s) { 0, 1 }; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "init" "struct bad init" { target *-*-* } 51 } */
+union u u1 = (union u) { 0 }; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "init" "union bad init" { target *-*-* } 53 } */
+
+/* They aren't suitable for array initializers, either inside or outside
+ a function. */
+int y[2] = (int [2]) { 0, 1 }; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "init" "array bad init" { target *-*-* } 58 } */
+
+void
+bar (void)
+{
+ struct s s2 = (struct s) { 0, 1 };
+ union u u2 = (union u) { 0 };
+ int z[2] = (int [2]) { 0, 1 }; /* { dg-bogus "warning" "warning in place of error" } */
+ /* { dg-error "init" "array bad init" { target *-*-* } 66 } */
+}