diff mbox

[C] Handle typedef name as a flexible array member (PR c/64768)

Message ID 20150213184540.GC23138@redhat.com
State New
Headers show

Commit Message

Marek Polacek Feb. 13, 2015, 6:45 p.m. UTC
As discussed in the PR, the problem with this test case:

typedef int A[];
struct S { int i; A a; };

is twofold.  Firstly, we ICE with checking on, and secondly, we reject the
testcase.  But there's nothing wrong with using typedef name as a flexible
array member.

Turned out the problem was that we weren't setting a TYPE_DOMAIN for array
types in FIELD context (in case of using a typedef name) - and finish_decl
then crashed trying to determine the size of the array from initialization.
Fixed by doing what we do for normal flexible array members - that is, set
the open-ended range.

Since we had no testing for such cases whatsoever, I took existing flexible
array member tests and duplicated them, only adjusted them to use a typedef
name, so that we test as many scenarios as possible - I think this ought to
give us a reasonable level of confidence that this works as expected now.

Bootstrapped/regtested on {ppc64,x86_64}-linux, ok for trunk?

2015-02-13  Marek Polacek  <polacek@redhat.com>

	PR c/64768
	* c-decl.c (grokdeclarator): Set the range of a flexible array member
	declared through a typedef name.

	* gcc.dg/array-11.c: New test.
	* gcc.dg/array-12.c: New test.
	* gcc.dg/array-13.c: New test.
	* gcc.dg/array-14.c: New test.
	* gcc.dg/c99-flex-array-typedef-1.c: New test.
	* gcc.dg/c99-flex-array-typedef-2.c: New test.
	* gcc.dg/c99-flex-array-typedef-3.c: New test.
	* gcc.dg/c99-flex-array-typedef-5.c: New test.
	* gcc.dg/c99-flex-array-typedef-7.c: New test.
	* gcc.dg/c99-flex-array-typedef-8.c: New test.


	Marek

Comments

Joseph Myers Feb. 13, 2015, 8:53 p.m. UTC | #1
On Fri, 13 Feb 2015, Marek Polacek wrote:

> Since we had no testing for such cases whatsoever, I took existing flexible
> array member tests and duplicated them, only adjusted them to use a typedef
> name, so that we test as many scenarios as possible - I think this ought to
> give us a reasonable level of confidence that this works as expected now.
> 
> Bootstrapped/regtested on {ppc64,x86_64}-linux, ok for trunk?

OK, though the use of

/* { dg-bogus "warning" "warning in place of error" } */

is a relic of when dg-error / dg-warning used not to verify that 
diagnostics were in fact errors / warnings; now they do check that, simply 
using dg-error (on the line with the diagnostic, so not needing { target 
*-*-* } and a line number) suffices rather than needing such a dg-bogus / 
dg-error pair.
Marek Polacek Feb. 14, 2015, 11:26 a.m. UTC | #2
On Fri, Feb 13, 2015 at 08:53:38PM +0000, Joseph Myers wrote:
> On Fri, 13 Feb 2015, Marek Polacek wrote:
> 
> > Since we had no testing for such cases whatsoever, I took existing flexible
> > array member tests and duplicated them, only adjusted them to use a typedef
> > name, so that we test as many scenarios as possible - I think this ought to
> > give us a reasonable level of confidence that this works as expected now.
> > 
> > Bootstrapped/regtested on {ppc64,x86_64}-linux, ok for trunk?
> 
> OK, though the use of
> 
> /* { dg-bogus "warning" "warning in place of error" } */
> 
> is a relic of when dg-error / dg-warning used not to verify that 
> diagnostics were in fact errors / warnings; now they do check that, simply 
> using dg-error (on the line with the diagnostic, so not needing { target 
> *-*-* } and a line number) suffices rather than needing such a dg-bogus / 
> dg-error pair.

Thanks, I've fixed that up and committed the patch.

	Marek
diff mbox

Patch

diff --git gcc/c/c-decl.c gcc/c/c-decl.c
index 48c2bcb..14cf168 100644
--- gcc/c/c-decl.c
+++ gcc/c/c-decl.c
@@ -6514,6 +6514,19 @@  grokdeclarator (const struct c_declarator *declarator,
 	      error_at (loc, "unnamed field has incomplete type");
 	    type = error_mark_node;
 	  }
+	else if (TREE_CODE (type) == ARRAY_TYPE
+		 && TYPE_DOMAIN (type) == NULL_TREE)
+	  {
+	    /* We have a flexible array member through a typedef.
+	       Set suitable range.  Whether this is a correct position
+	       for a flexible array member will be determined elsewhere.  */
+	    if (!in_system_header_at (input_location))
+	      pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not "
+			   "support flexible array members");
+	    type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
+	    TYPE_DOMAIN (type) = build_range_type (sizetype, size_zero_node,
+						   NULL_TREE);
+	  }
 	type = c_build_qualified_type (type, type_quals);
 	decl = build_decl (declarator->id_loc,
 			   FIELD_DECL, declarator->u.id, type);
diff --git gcc/testsuite/gcc.dg/array-11.c gcc/testsuite/gcc.dg/array-11.c
index e69de29..dbf38ae 100644
--- gcc/testsuite/gcc.dg/array-11.c
+++ gcc/testsuite/gcc.dg/array-11.c
@@ -0,0 +1,15 @@ 
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* Verify that we can't do things to get ourselves in trouble
+   with GCC's initialized flexible array member extension.  */
+
+typedef int T[];
+struct f { int w; T x; };
+struct g { struct f f; };
+struct g g1 = { { 0, { } } };
+struct g g2 = { { 0, { 1 } } }; /* { dg-error "nested context" "nested" } */
+				/* { dg-message "near init" "near" { target *-*-* } 11 } */
+struct h { int x[0]; int y; };
+struct h h1 = { { 0 }, 1 }; /* { dg-warning "excess elements" "excess" } */
+			    /* { dg-message "near init" "before end" { target *-*-* } 14 } */
diff --git gcc/testsuite/gcc.dg/array-12.c gcc/testsuite/gcc.dg/array-12.c
index e69de29..b3beed57 100644
--- gcc/testsuite/gcc.dg/array-12.c
+++ gcc/testsuite/gcc.dg/array-12.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* ISO C99 flexible array members don't have a size.  GCC's zero-length
+   array extension does.  */
+
+typedef int T0[0];
+typedef int T[];
+struct f { int w; T0 x; } f;
+struct g { int w; T x; } g;
+
+char test_gcc[sizeof (f.x) ? -1 : 1];
+char test_iso[sizeof (g.x) ? -1 : 1]; /* { dg-error "incomplete type" "iso" } */
diff --git gcc/testsuite/gcc.dg/array-13.c gcc/testsuite/gcc.dg/array-13.c
index e69de29..8335b7a 100644
--- gcc/testsuite/gcc.dg/array-13.c
+++ gcc/testsuite/gcc.dg/array-13.c
@@ -0,0 +1,28 @@ 
+/* { dg-do run } */
+/* { dg-options "" } */
+
+/* Verify that GCC's initialized flexible array member extension
+   works properly.  */
+
+extern void abort(void);
+extern void exit(int);
+
+typedef int T[];
+typedef int T0[0];
+
+struct f { int w; T x; };
+struct g { int w; T0 x; };
+
+static struct f f = { 4, { 0, 1, 2, 3 } };
+static int junk1[] = { -1, -1, -1, -1 };
+static struct g g = { 4, { 0, 1, 2, 3 } }; /* { dg-warning "(excess elements)|(near initialization)" "" } */
+static int junk2[] = { -1, -1, -1, -1 };
+
+int main()
+{
+  int i;
+  for (i = 0; i < f.w; ++i)
+    if (f.x[i] != i)
+      abort ();
+  exit(0);
+}
diff --git gcc/testsuite/gcc.dg/array-14.c gcc/testsuite/gcc.dg/array-14.c
index e69de29..cb2a347 100644
--- gcc/testsuite/gcc.dg/array-14.c
+++ gcc/testsuite/gcc.dg/array-14.c
@@ -0,0 +1,18 @@ 
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* Verify that GCC forbids non-static initialization of
+   flexible array members. */
+
+typedef char T[];
+struct str { int len; T s; };
+
+struct str a = { 2, "a" };
+
+void foo()
+{
+  static struct str b = { 2, "b" };
+  struct str c = { 2, "c" }; /* { dg-error "(non-static)|(near initialization)" } */
+  struct str d = (struct str) { 2, "d" }; /* { dg-error "(non-static)|(near initialization)" } */
+  struct str e = (struct str) { d.len, "e" }; /* { dg-error "(non-static)|(initialization)" } */
+}
diff --git gcc/testsuite/gcc.dg/c99-flex-array-typedef-1.c gcc/testsuite/gcc.dg/c99-flex-array-typedef-1.c
index e69de29..93f91f8 100644
--- gcc/testsuite/gcc.dg/c99-flex-array-typedef-1.c
+++ gcc/testsuite/gcc.dg/c99-flex-array-typedef-1.c
@@ -0,0 +1,9 @@ 
+/* Test for invalid uses of flexible array members.  */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+typedef int A[];
+struct s1 { A x; }; /* { dg-error "empty struct" "empty" } */
+struct s2 { int :1; A x; }; /* { dg-error "empty struct" "empty" } */
+struct s3 { A x; int y; }; /* { dg-error "not at end" "not at end" } */
+struct s4 { int x; A y; };
diff --git gcc/testsuite/gcc.dg/c99-flex-array-typedef-2.c gcc/testsuite/gcc.dg/c99-flex-array-typedef-2.c
index e69de29..f869f75 100644
--- gcc/testsuite/gcc.dg/c99-flex-array-typedef-2.c
+++ gcc/testsuite/gcc.dg/c99-flex-array-typedef-2.c
@@ -0,0 +1,17 @@ 
+/* Test for invalid uses of flexible array members.  */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+typedef char A[];
+
+struct S {
+   int n;
+   A a;
+};
+
+void
+foo (void)
+{
+  struct S s;
+  s.a = "abc";  /* { dg-error "invalid use of flexible array member" } */
+}
diff --git gcc/testsuite/gcc.dg/c99-flex-array-typedef-3.c gcc/testsuite/gcc.dg/c99-flex-array-typedef-3.c
index e69de29..5442b6a 100644
--- gcc/testsuite/gcc.dg/c99-flex-array-typedef-3.c
+++ gcc/testsuite/gcc.dg/c99-flex-array-typedef-3.c
@@ -0,0 +1,47 @@ 
+/* Test for flexible array members.  Test for where structures with
+   such members may not occur.  */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+typedef int T[];
+struct flex { int a; T b; };
+union rf1 { struct flex a; int b; };
+union rf2 { int a; struct flex b; };
+union rf3 { int a; union rf1 b; };
+union rf4 { union rf2 a; int b; };
+
+/* The above structure and unions may not be members of structures or
+   elements of arrays (6.7.2.1#2).  */
+
+struct t0 { struct flex a; }; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "struct in struct" { target *-*-* } 16 } */
+struct t1 { union rf1 a; }; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "union in struct" { target *-*-* } 18 } */
+struct t2 { union rf2 a; }; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "union in struct" { target *-*-* } 20 } */
+struct t3 { union rf3 a; }; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "recursive union in struct" { target *-*-* } 22 } */
+struct t4 { union rf4 a; }; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "recursive union in struct" { target *-*-* } 24 } */
+
+void f0 (struct flex[]); /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "struct in array" { target *-*-* } 27 } */
+void f1 (union rf1[]); /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "union in array" { target *-*-* } 29 } */
+void f2 (union rf2[]); /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "union in array" { target *-*-* } 31 } */
+void f3 (union rf3[]); /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "recursive union in array" { target *-*-* } 33 } */
+void f4 (union rf4[]); /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "recursive union in array" { target *-*-* } 35 } */
+
+struct flex a0[1]; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "struct in array" { target *-*-* } 38 } */
+union rf1 a1[1]; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "union in array" { target *-*-* } 40 } */
+union rf2 a2[1]; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "union in array" { target *-*-* } 42 } */
+union rf3 a3[1]; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "recursive union in array" { target *-*-* } 44 } */
+union rf4 a4[1]; /* { dg-bogus "warning" "warning in place of error" } */
+/* { dg-error "invalid use of structure" "recursive union in array" { target *-*-* } 46 } */
diff --git gcc/testsuite/gcc.dg/c99-flex-array-typedef-5.c gcc/testsuite/gcc.dg/c99-flex-array-typedef-5.c
index e69de29..2d1fbe1 100644
--- gcc/testsuite/gcc.dg/c99-flex-array-typedef-5.c
+++ gcc/testsuite/gcc.dg/c99-flex-array-typedef-5.c
@@ -0,0 +1,6 @@ 
+/* Test for flexible array members: not permitted in unions.  */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+typedef char T[];
+union u { int a; T b; }; /* { dg-error "flexible array member in union" } */
diff --git gcc/testsuite/gcc.dg/c99-flex-array-typedef-7.c gcc/testsuite/gcc.dg/c99-flex-array-typedef-7.c
index e69de29..8b954db 100644
--- gcc/testsuite/gcc.dg/c99-flex-array-typedef-7.c
+++ gcc/testsuite/gcc.dg/c99-flex-array-typedef-7.c
@@ -0,0 +1,18 @@ 
+/* Initialization of a flexible array member with a string constant
+   must be diagnosed.  PR 37481.  */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+typedef char T[];
+struct s { int a; T b; };
+
+struct s a = { 0, "" }; /* { dg-error "initialization of a flexible array member" } */
+/* { dg-message "near init" "near init" { target *-*-* } 9 } */
+struct s b = { 0, { 0 } }; /* { dg-error "initialization of a flexible array member" } */
+/* { dg-message "near init" "near init" { target *-*-* } 11 } */
+struct s c = { 0, { } }; /* { dg-error "ISO C forbids empty initializer braces" } */
+struct s d = { .b = "" }; /* { dg-error "initialization of a flexible array member" } */
+/* { dg-message "near init" "near init" { target *-*-* } 14 } */
+struct s e = { .b = { 0 } }; /* { dg-error "initialization of a flexible array member" } */
+/* { dg-message "near init" "near init" { target *-*-* } 16 } */
+struct s f = { .b = { } }; /* { dg-error "ISO C forbids empty initializer braces" } */
diff --git gcc/testsuite/gcc.dg/c99-flex-array-typedef-8.c gcc/testsuite/gcc.dg/c99-flex-array-typedef-8.c
index e69de29..26c4a23 100644
--- gcc/testsuite/gcc.dg/c99-flex-array-typedef-8.c
+++ gcc/testsuite/gcc.dg/c99-flex-array-typedef-8.c
@@ -0,0 +1,16 @@ 
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+typedef char T[];
+struct foo { int x; T y; };
+struct bar { struct foo f; };
+struct baz { struct bar b; };
+
+struct foo a1 = { 1, "abc" };
+struct foo a2 = { 1, { "abc" } };
+struct foo b1[] = { { 1, "abc" } }; /* { dg-error "initialization of flexible array member" } */
+struct foo b2[] = { { 1, { "abc" } } }; /* { dg-error "initialization of flexible array member" } */
+struct bar c1[] = { { { 1, "abc" } } }; /* { dg-error "initialization of flexible array member" } */
+struct bar c2[] = { { { 1, { "abc" } } } }; /* { dg-error "initialization of flexible array member" } */
+struct baz d1[] = { { { { 1, "abc" } } } }; /* { dg-error "initialization of flexible array member" } */
+struct baz d2[] = { { { { 1, { "abc" } } } } }; /* { dg-error "initialization of flexible array member" } */