]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c/4787 (Different anonymous variables declared but only one allocated when...
authorJoseph Myers <jsm28@cam.ac.uk>
Tue, 4 Dec 2001 22:55:40 +0000 (22:55 +0000)
committerJoseph Myers <jsm28@gcc.gnu.org>
Tue, 4 Dec 2001 22:55:40 +0000 (22:55 +0000)
* 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.

testsuite:
* 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.

From-SVN: r47629

19 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/c-common.def
gcc/c-common.h
gcc/c-decl.c
gcc/c-lang.c
gcc/c-parse.in
gcc/c-tree.h
gcc/c-typeck.c
gcc/doc/c-tree.texi
gcc/doc/extend.texi
gcc/objc/objc-lang.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/compile/init-3.c
gcc/testsuite/gcc.c-torture/execute/20000722-1.x [deleted file]
gcc/testsuite/gcc.c-torture/execute/20010123-1.x [deleted file]
gcc/testsuite/gcc.dg/c90-complit-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-complit-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-complit-2.c [new file with mode: 0644]

index 22242e2274d26105fc549ea9b370f73e7298c467..95ae31275afda63999567ecfdd8e249abe1fdbfc 100644 (file)
@@ -1,3 +1,22 @@
+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.
index a7d005b04ed4203656eafdbafd242addbb4709ca..f5fc0d348f5ded7b92610fa0a07bacb9e908bfbb 100644 (file)
@@ -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,
index 6ae0466f236e2e77d95ad265e01b1dc5430b311f..7840ce81610e9eed86f6d6dbedfa31efb16bd192 100644 (file)
@@ -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)
index 1ce21a1769f57f43fe6ad5a40d17606e935d4649..4ab415c1f1e922f55ab59683f53734c7803c98b3 100644 (file)
@@ -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.  */
index 34278546d979787e6d184a27f7e498607d333abf..b5597f98dadd222805e5f96567a06078b5066e60 100644 (file)
@@ -3793,6 +3793,59 @@ clear_parm_order ()
   current_binding_level->parm_order = NULL_TREE;
 }
 \f
+/* 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;
+}
+\f
 /* 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).  */
index dceede52557e7c3be2e2a349d3d80fae032516b5..c2056c5b46418b90dd72ba26a825570e70ff5845 100644 (file)
@@ -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
index fe57047ec9cd9e75463919bf5a658d3d01370f99..e0457b2af6751513f0bc97f96f5457660f956419 100644 (file)
@@ -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));
index e686ed4fd1ba043166d16c5b91be690b4600d8db..a304b7ebff79c1bedd47d698feb8c85533c82b7a 100644 (file)
@@ -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));
index ff504dc1d0520c2388ce9274bd5ad5ab2dd17f4e..297afad8ce8881b63668b5fb98ebeeeeac9d37f9 100644 (file)
@@ -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;
index dd21ae6285bbada30fde378a5da56a9df5986ef5..3db3d7f10ff794c936c36f0628a28b7a232a8854 100644 (file)
@@ -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
index 781fa997addc1a2dfa5af8186af783edf549eb80..cf275f1ecc9990a15916046c5387d75bc64b4069 100644 (file)
@@ -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.
index 33d2cde6ce35bea2e2d761025eb85ea89a43fb8b..7e2cae7bf008209da099bc71057e1796742eb393 100644 (file)
@@ -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
index 795c502821b67637fb447921868ddafa71ecaa53..d22c31dc4bb743d7a0b7dfe97c5140866229f9b7 100644 (file)
@@ -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.
index d091168897bb365d84964601c261c3cbbac32c1d..be3d9b49679a282b3b1aa35b603cad6a2db54039 100644 (file)
@@ -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 (file)
index bbad3bb..0000000
+++ /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 (file)
index 2f397b9..0000000
+++ /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 (file)
index 0000000..4cd910f
--- /dev/null
@@ -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 (file)
index 0000000..94e15db
--- /dev/null
@@ -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 (file)
index 0000000..faf44b2
--- /dev/null
@@ -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 } */
+}