https://gcc.gnu.org/g:84b4687eb445555c22db5ee5a71cb665ec7110d7
commit r16-4277-g84b4687eb445555c22db5ee5a71cb665ec7110d7 Author: Joseph Myers <[email protected]> Date: Tue Oct 7 23:04:54 2025 +0000 c: Implement C2y handling of incomplete tentative definitions [PR26581] Before C2y, a tentative definition (file-scope, not extern, no initializer) with internal linkage and incomplete type was undefined behavior ("shall" outside Constraints violated). In C2y, this has changed to a constraint violation if the type has not been completed by the end of the translation unit, and is valid if the type has been completed by the end of the translation unit. This change originates from N3347 but the wording accepted into C2y was that from reflector message 26758. In GCC, the case of incomplete array types was a hard error with -pedantic, rather than a pedwarn, contrary to how -pedantic is supposed to behave; bug 26581 requested a change to allow this case with -pedantic (i.e. the change made in C2y). For incomplete structs and unions, GCC only diagnoses them if the type remains incomplete at the end of the translation unit; bug 88727 (*not* fixed here) requests the case where the type gets completed should also be diagnosed as a quality of implementation matter (and that bug is still applicable for pre-C2y langauge versions and -Wc23-c2y-compat). Change the handling of arrays following C2y; the previous error becomes a pedwarn_c23 while there is a new error at the end of the translation unit if the type remains incomplete there in C2y mode. There is an ambiguity in the wording in C2y for the case where the type gets completed only in an inner scope; I've raised that in reflector message 34118. Bootstrapped with no regressions for x86_64-pc-linux-gnu. PR c/26581 gcc/c/ * c-decl.cc (c_finish_incomplete_decl): Give error for tentative definition of incomplete array for C2y with internal linkage. (finish_decl): Do not set DO_DEFAULT based on -pedantic. Use pedwarn_c23 for missing array sizes for internal linkage. gcc/testsuite/ * gcc.dg/c23-incomplete-2.c, gcc.dg/c23-incomplete-3.c, gcc.dg/c23-incomplete-4.c, gcc.dg/c2y-incomplete-4.c, gcc.dg/c2y-incomplete-5.c: New tests. * gcc.dg/c23-thread-local-2.c, gcc.dg/c2y-incomplete-1.c: Update expected errors. Diff: --- gcc/c/c-decl.cc | 17 ++++++++++------- gcc/testsuite/gcc.dg/c23-incomplete-2.c | 31 +++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c23-incomplete-3.c | 31 +++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c23-incomplete-4.c | 30 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c23-thread-local-2.c | 1 + gcc/testsuite/gcc.dg/c2y-incomplete-1.c | 2 +- gcc/testsuite/gcc.dg/c2y-incomplete-4.c | 28 ++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c2y-incomplete-5.c | 29 +++++++++++++++++++++++++++++ 8 files changed, 161 insertions(+), 8 deletions(-) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 632bbf057a33..d0dc5eeda39b 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -908,8 +908,12 @@ c_finish_incomplete_decl (tree decl) && !DECL_EXTERNAL (decl) && TYPE_DOMAIN (type) == NULL_TREE) { - warning_at (DECL_SOURCE_LOCATION (decl), - 0, "array %q+D assumed to have one element", decl); + if (flag_isoc2y && !TREE_PUBLIC (decl)) + error_at (DECL_SOURCE_LOCATION (decl), + "array size missing in %q+D", decl); + else + warning_at (DECL_SOURCE_LOCATION (decl), + 0, "array %q+D assumed to have one element", decl); complete_array_type (&TREE_TYPE (decl), NULL_TREE, true); @@ -5984,11 +5988,7 @@ finish_decl (tree decl, location_t init_loc, tree init, && !(TREE_PUBLIC (decl) && current_scope != file_scope)) { bool do_default - = (TREE_STATIC (decl) - /* Even if pedantic, an external linkage array - may have incomplete type at first. */ - ? pedantic && !TREE_PUBLIC (decl) - : !DECL_EXTERNAL (decl)); + = !TREE_STATIC (decl) && !DECL_EXTERNAL (decl); int failure = complete_array_type (&TREE_TYPE (decl), DECL_INITIAL (decl), do_default); @@ -6005,6 +6005,9 @@ finish_decl (tree decl, location_t init_loc, tree init, case 2: if (do_default) error ("array size missing in %q+D", decl); + else if (!TREE_PUBLIC (decl)) + pedwarn_c23 (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic, + "array size missing in %q+D", decl); break; case 3: diff --git a/gcc/testsuite/gcc.dg/c23-incomplete-2.c b/gcc/testsuite/gcc.dg/c23-incomplete-2.c new file mode 100644 index 000000000000..3b435a14567e --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-incomplete-2.c @@ -0,0 +1,31 @@ +/* Test tentative definitions with incomplete type: OK in C2y with internal + linkage if completed by the end of the translation unit, but not allowed in + C23. Note that incomplete structs and unions are not diagnosed for C23 when + completed by the end of the translation unit (bug 88727). */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ + +struct s1; +struct s2; +union u1; +union u2; + +struct s1 v1; +struct s2 v2; /* { dg-error "storage size" } */ +int v3[]; +int v4[]; /* { dg-warning "assumed to have one element" } */ +union u1 v5; +union u2 v6; /* { dg-error "storage size" } */ + +static struct s1 sv1; +static struct s2 sv2; /* { dg-error "storage size" } */ +static int sv3[]; /* { dg-error "array size missing" } */ +static int sv4[]; /* { dg-error "array size missing" } */ +/* { dg-warning "assumed to have one element" "one element" { target *-*-* } .-1 } */ +static union u1 sv5; +static union u2 sv6; /* { dg-error "storage size" } */ + +struct s1 { int x; }; +union u1 { int y; }; +extern int v3[1]; +extern int sv3[1]; diff --git a/gcc/testsuite/gcc.dg/c23-incomplete-3.c b/gcc/testsuite/gcc.dg/c23-incomplete-3.c new file mode 100644 index 000000000000..ebb4cf93a833 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-incomplete-3.c @@ -0,0 +1,31 @@ +/* Test tentative definitions with incomplete type: OK in C2y with internal + linkage if completed by the end of the translation unit, but not allowed in + C23. Note that incomplete structs and unions are not diagnosed for C23 when + completed by the end of the translation unit (bug 88727). */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic" } */ + +struct s1; +struct s2; +union u1; +union u2; + +struct s1 v1; +struct s2 v2; /* { dg-error "storage size" } */ +int v3[]; +int v4[]; /* { dg-warning "assumed to have one element" } */ +union u1 v5; +union u2 v6; /* { dg-error "storage size" } */ + +static struct s1 sv1; +static struct s2 sv2; /* { dg-error "storage size" } */ +static int sv3[]; /* { dg-warning "array size missing" } */ +static int sv4[]; /* { dg-warning "array size missing" } */ +/* { dg-warning "assumed to have one element" "one element" { target *-*-* } .-1 } */ +static union u1 sv5; +static union u2 sv6; /* { dg-error "storage size" } */ + +struct s1 { int x; }; +union u1 { int y; }; +extern int v3[1]; +extern int sv3[1]; diff --git a/gcc/testsuite/gcc.dg/c23-incomplete-4.c b/gcc/testsuite/gcc.dg/c23-incomplete-4.c new file mode 100644 index 000000000000..6a8b6cc42305 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-incomplete-4.c @@ -0,0 +1,30 @@ +/* Test tentative definitions with incomplete type: OK in C2y with internal + linkage if completed by the end of the translation unit, but not allowed in + C23. Note that incomplete structs and unions are not diagnosed for C23 when + completed by the end of the translation unit (bug 88727). */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors -Wno-c23-c2y-compat" } */ + +struct s1; +struct s2; +union u1; +union u2; + +struct s1 v1; +struct s2 v2; /* { dg-error "storage size" } */ +int v3[]; +int v4[]; /* { dg-warning "assumed to have one element" } */ +union u1 v5; +union u2 v6; /* { dg-error "storage size" } */ + +static struct s1 sv1; +static struct s2 sv2; /* { dg-error "storage size" } */ +static int sv3[]; +static int sv4[]; /* { dg-warning "assumed to have one element" } */ +static union u1 sv5; +static union u2 sv6; /* { dg-error "storage size" } */ + +struct s1 { int x; }; +union u1 { int y; }; +extern int v3[1]; +extern int sv3[1]; diff --git a/gcc/testsuite/gcc.dg/c23-thread-local-2.c b/gcc/testsuite/gcc.dg/c23-thread-local-2.c index 1d063f05e424..8fb34af5eeb7 100644 --- a/gcc/testsuite/gcc.dg/c23-thread-local-2.c +++ b/gcc/testsuite/gcc.dg/c23-thread-local-2.c @@ -25,6 +25,7 @@ static thread_local int f; /* { dg-error "redefinition" } */ rather than defaulting to size 1. */ thread_local int g[]; /* { dg-error "storage size" } */ static thread_local int h[]; /* { dg-error "array size missing" } */ +/* { dg-error "storage size" "storage size" { target *-*-* } .-1 } */ extern thread_local int i[]; thread_local int j[] = { 0 }; diff --git a/gcc/testsuite/gcc.dg/c2y-incomplete-1.c b/gcc/testsuite/gcc.dg/c2y-incomplete-1.c index 2d7b1812ac2e..4c3133d934df 100644 --- a/gcc/testsuite/gcc.dg/c2y-incomplete-1.c +++ b/gcc/testsuite/gcc.dg/c2y-incomplete-1.c @@ -10,7 +10,7 @@ f () struct s1 a; /* { dg-error "storage size" } */ int b[]; /* { dg-error "array size missing" } */ static struct s1 c; /* { dg-error "storage size" } */ - static int d[]; /* { dg-error "array size missing" } */ + static int d[]; /* { dg-error "storage size" } */ struct s2; struct s2 e; /* { dg-error "storage size" } */ static struct s2 g; /* { dg-error "storage size" } */ diff --git a/gcc/testsuite/gcc.dg/c2y-incomplete-4.c b/gcc/testsuite/gcc.dg/c2y-incomplete-4.c new file mode 100644 index 000000000000..a2708965ca50 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-incomplete-4.c @@ -0,0 +1,28 @@ +/* Test tentative definitions with incomplete type: OK in C2y with internal + linkage if completed by the end of the translation unit. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2y -pedantic-errors" } */ + +struct s1; +struct s2; +union u1; +union u2; + +struct s1 v1; +struct s2 v2; /* { dg-error "storage size" } */ +int v3[]; +int v4[]; /* { dg-warning "assumed to have one element" } */ +union u1 v5; +union u2 v6; /* { dg-error "storage size" } */ + +static struct s1 sv1; +static struct s2 sv2; /* { dg-error "storage size" } */ +static int sv3[]; +static int sv4[]; /* { dg-error "array size missing" } */ +static union u1 sv5; +static union u2 sv6; /* { dg-error "storage size" } */ + +struct s1 { int x; }; +union u1 { int y; }; +extern int v3[1]; +extern int sv3[1]; diff --git a/gcc/testsuite/gcc.dg/c2y-incomplete-5.c b/gcc/testsuite/gcc.dg/c2y-incomplete-5.c new file mode 100644 index 000000000000..4051cc01c21b --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-incomplete-5.c @@ -0,0 +1,29 @@ +/* Test tentative definitions with incomplete type: OK in C2y with internal + linkage if completed by the end of the translation unit. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2y -pedantic-errors -Wc23-c2y-compat" } */ + +struct s1; +struct s2; +union u1; +union u2; + +struct s1 v1; +struct s2 v2; /* { dg-error "storage size" } */ +int v3[]; +int v4[]; /* { dg-warning "assumed to have one element" } */ +union u1 v5; +union u2 v6; /* { dg-error "storage size" } */ + +static struct s1 sv1; +static struct s2 sv2; /* { dg-error "storage size" } */ +static int sv3[]; /* { dg-warning "array size missing" } */ +static int sv4[]; /* { dg-error "array size missing" } */ +/* { dg-warning "array size missing" "warning" { target *-*-* } .-1 } */ +static union u1 sv5; +static union u2 sv6; /* { dg-error "storage size" } */ + +struct s1 { int x; }; +union u1 { int y; }; +extern int v3[1]; +extern int sv3[1];
