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 <pola...@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. 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" } */ Marek