Patch to make compound literals follow C99

Joseph S. Myers jsm28@cam.ac.uk
Tue Dec 4 14:57:00 GMT 2001


This patch makes GCC follow the C99 specification of compound literals
(as I understand it - there are some places it isn't perfectly clear)
for C.  I haven't touched C++, though it should probably do the same
when accepting compound literals as an extension, rather than using
CONSTRUCTOR nodes.

Bootstrapped with no regressions on i686-pc-linux-gnu.  Applied to
mainline.

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.

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

diff -rupN gcc.orig/c-common.c gcc/c-common.c
--- gcc.orig/c-common.c	Tue Nov 27 11:40:56 2001
+++ gcc/c-common.c	Mon Dec  3 14:48:21 2001
@@ -3432,6 +3432,15 @@ c_expand_expr (exp, target, tmode, modif
       }
       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 ();
     }
@@ -3480,6 +3489,18 @@ c_unsafe_for_reeval (exp)
 
   /* Walk all other expressions.  */
   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.  */
diff -rupN gcc.orig/c-common.def gcc/c-common.def
--- gcc.orig/c-common.def	Mon Oct 29 22:43:09 2001
+++ gcc/c-common.def	Sun Dec  2 00:53:40 2001
@@ -101,3 +101,9 @@ DEFTREECODE (CASE_LABEL, "case_label", '
 /* 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 -rupN gcc.orig/c-common.h gcc/c-common.h
--- gcc.orig/c-common.h	Wed Nov 28 11:17:56 2001
+++ gcc/c-common.h	Mon Dec  3 13:41:53 2001
@@ -630,6 +630,10 @@ extern tree strip_array_types           
    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)))
@@ -812,6 +816,8 @@ extern rtx c_expand_expr            PARA
 #endif
 
 extern int c_safe_from_p                        PARAMS ((rtx, tree));
+
+extern int c_staticp                            PARAMS ((tree));
 
 extern int c_unsafe_for_reeval			PARAMS ((tree));
 
diff -rupN gcc.orig/c-decl.c gcc/c-decl.c
--- gcc.orig/c-decl.c	Sun Dec  2 00:43:43 2001
+++ gcc/c-decl.c	Mon Dec  3 15:14:45 2001
@@ -3790,6 +3790,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 -rupN gcc.orig/c-lang.c gcc/c-lang.c
--- gcc.orig/c-lang.c	Wed Nov 28 11:17:56 2001
+++ gcc/c-lang.c	Mon Dec  3 13:40:48 2001
@@ -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 -rupN gcc.orig/c-parse.in gcc/c-parse.in
--- gcc.orig/c-parse.in	Sun Dec  2 00:43:43 2001
+++ gcc/c-parse.in	Sun Dec  2 16:11:13 2001
@@ -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 -rupN gcc.orig/c-tree.h gcc/c-tree.h
--- gcc.orig/c-tree.h	Wed Nov 28 11:17:56 2001
+++ gcc/c-tree.h	Mon Dec  3 00:11:42 2001
@@ -261,6 +261,7 @@ extern tree pop_init_level			PARAMS ((in
 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 -rupN gcc.orig/c-typeck.c gcc/c-typeck.c
--- gcc.orig/c-typeck.c	Thu Nov  8 02:11:40 2001
+++ gcc/c-typeck.c	Mon Dec  3 01:15:21 2001
@@ -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 -rupN gcc.orig/doc/c-tree.texi gcc/doc/c-tree.texi
--- gcc.orig/doc/c-tree.texi	Wed Nov 28 11:18:21 2001
+++ gcc/doc/c-tree.texi	Sun Dec  2 15:29:50 2001
@@ -1738,6 +1738,7 @@ This macro returns the attributes on the
 @tindex COND_EXPR
 @tindex CALL_EXPR
 @tindex CONSTRUCTOR
+@tindex COMPOUND_LITERAL_EXPR
 @tindex STMT_EXPR
 @tindex BIND_EXPR
 @tindex LOOP_EXPR
@@ -2200,6 +2201,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
 
diff -rupN gcc.orig/doc/extend.texi gcc/doc/extend.texi
--- gcc.orig/doc/extend.texi	Sun Nov 18 03:26:56 2001
+++ gcc/doc/extend.texi	Sun Dec  2 15:26:35 2001
@@ -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,26 +1637,12 @@ This is equivalent to writing the follow
 
 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
diff -rupN gcc.orig/objc/objc-lang.c gcc/objc/objc-lang.c
--- gcc.orig/objc/objc-lang.c	Sun Dec  2 16:46:38 2001
+++ gcc/objc/objc-lang.c	Mon Dec  3 13:41:16 2001
@@ -464,6 +464,8 @@ static int print_struct_values = 0;
 #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 -rupN gcc.orig/testsuite/gcc.c-torture/compile/init-3.c gcc/testsuite/gcc.c-torture/compile/init-3.c
--- gcc.orig/testsuite/gcc.c-torture/compile/init-3.c	Sun Feb 20 08:28:28 2000
+++ gcc/testsuite/gcc.c-torture/compile/init-3.c	Mon Dec  3 16:41:48 2001
@@ -6,6 +6,6 @@ struct something {
 };
 
 struct something X = {
-	foo: (struct empty) { },
+	foo: { },
 	bar: 1,
 };
diff -rupN gcc.orig/testsuite/gcc.c-torture/execute/20000722-1.x gcc/testsuite/gcc.c-torture/execute/20000722-1.x
--- gcc.orig/testsuite/gcc.c-torture/execute/20000722-1.x	Mon Jul 24 19:18:06 2000
+++ gcc/testsuite/gcc.c-torture/execute/20000722-1.x	Thu Jan  1 00:00:00 1970
@@ -1,3 +0,0 @@
-# Doesn't work.  Hasn't worked ever, I think.
-set torture_execute_xfail "*-*-*"
-return 0
diff -rupN gcc.orig/testsuite/gcc.c-torture/execute/20010123-1.x gcc/testsuite/gcc.c-torture/execute/20010123-1.x
--- gcc.orig/testsuite/gcc.c-torture/execute/20010123-1.x	Wed Mar  7 22:17:36 2001
+++ gcc/testsuite/gcc.c-torture/execute/20010123-1.x	Thu Jan  1 00:00:00 1970
@@ -1,2 +0,0 @@
-set torture_execute_xfail "*-*-*"
-return 0
diff -rupN gcc.orig/testsuite/gcc.dg/c90-complit-1.c gcc/testsuite/gcc.dg/c90-complit-1.c
--- gcc.orig/testsuite/gcc.dg/c90-complit-1.c	Thu Jan  1 00:00:00 1970
+++ gcc/testsuite/gcc.dg/c90-complit-1.c	Sun Dec  2 21:21:23 2001
@@ -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 -rupN gcc.orig/testsuite/gcc.dg/c99-complit-1.c gcc/testsuite/gcc.dg/c99-complit-1.c
--- gcc.orig/testsuite/gcc.dg/c99-complit-1.c	Thu Jan  1 00:00:00 1970
+++ gcc/testsuite/gcc.dg/c99-complit-1.c	Mon Dec  3 15:27:18 2001
@@ -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 -rupN gcc.orig/testsuite/gcc.dg/c99-complit-2.c gcc/testsuite/gcc.dg/c99-complit-2.c
--- gcc.orig/testsuite/gcc.dg/c99-complit-2.c	Thu Jan  1 00:00:00 1970
+++ gcc/testsuite/gcc.dg/c99-complit-2.c	Sun Dec  2 23:04:48 2001
@@ -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 } */
+}

-- 
Joseph S. Myers
jsm28@cam.ac.uk



More information about the Gcc-patches mailing list