Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/Changes
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ This is now fixed: When generating code targeting GCC, the C-generating back
end now preserves the __weak__ attribute and suppresses the __always_inline__
attribute instead.

10/7/26 [GH #238]
Clang C compatibility: Empty aggregate initializers

The changes for EDGcpfe/29042 (version 7.0) restricted empty initializers
in pre-C23 Clang C modes to Clang 17 and later. However, earlier versions
of Clang accept empty initializers for aggregate types as an extension.
This is now fixed. For example, the following was incorrectly rejected
when emulating Clang 16 and earlier:

struct A {
int i;
};

struct A a = {}; // Previously an error. Now okay.

10/5/26 [GH #195]
C++-generating back end: dependent multi-dimensional subscripts
Expand Down
4 changes: 2 additions & 2 deletions src/decl_inits.c
Original file line number Diff line number Diff line change
Expand Up @@ -2365,7 +2365,7 @@ for this array initialization). *is describes the initialization as a whole.
diag_pos = &icp->variant.braced.end_pos;
/* Unwrap the braced list for the processing that follows. */
icp = icp->variant.braced.list;
if (icp == NULL && C_mode() && !empty_c_initializer_allowed) {
if (icp == NULL && C_mode() && !empty_c_aggregate_initializer_allowed) {
/* Empty initializer lists are permitted only in the C modes that
offer them. */
pos_error(ec_exp_primary_expr, diag_pos);
Expand Down Expand Up @@ -3778,7 +3778,7 @@ issued if no more specific position is available.
/* Unwrap the braced list for the processing that follows. */
icp = icp->variant.braced.list;
top_icp = icp;
if (icp == NULL && C_mode() && !empty_c_initializer_allowed) {
if (icp == NULL && C_mode() && !empty_c_aggregate_initializer_allowed) {
/* Empty initializer lists are permitted only in the C modes that
offer them. */
pos_error(ec_exp_primary_expr, diag_pos);
Expand Down
9 changes: 9 additions & 0 deletions src/lang_feat.h
Original file line number Diff line number Diff line change
Expand Up @@ -1959,6 +1959,15 @@ by the C23 standard or later C standards.
*/
#define c23_mode (C_mode() && std_version >= 202311)

/*
Macro that is TRUE when an empty aggregate initializer is accepted in C
mode. Such initializers are standard in C23. They are also an extension in
the GNU C modes, and in the Clang C modes.
*/
#define empty_c_aggregate_initializer_allowed (c23_mode || \
gcc_version_is(any_version) || \
clangc_version_is(any_version))

/*
Macro that is TRUE when an empty initializer ("int i = {};") is accepted in C
mode. Such initializers are standard in C23. They are also an extension in
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=1 --c11 --clang_version 30800 Test_name.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
fe_only -DTEST_NUMBER=1 --c11 --clang_version 160000 Test_name.c
"Test_name.c", line 6: error: expected an expression
int scalar = {};
^

1 error detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fe_only -DTEST_NUMBER=1 --c11 --clang_version 170000 Test_name.c
"Test_name.c", line 18: warning: variable "vla" was declared but never referenced
int vla[n] = {};
^

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fe_only -DTEST_NUMBER=1 --c11 --clang_version 160000 Test_name.c
"Test_name.c", line 8: error: variable "vla" may not be initialized
int vla[n] = {};
^

"Test_name.c", line 8: warning: variable "vla" was declared but never referenced
int vla[n] = {};
^

1 error detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//type:fp
//options_all:--c11 --clang_version 30800
//
// Clang accepts empty initializers for aggregate types as an extension in
// pre-C23 C modes.

struct A {
int i;
};

union U {
int i;
double d;
};

struct B {
int i;
struct A a;
};

struct A a = {};
union U u = {};
int fixed_array[4] = {};
int unknown_bound_array[] = {};
struct B nested = { 1, {} };
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//type:fn
//options_all:--c11 --clang_version 160000
//
// Clang versions before 17 do not accept accept empty scalar initializers.

int scalar = {};

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//type:fp
//options_all:--c11 --clang_version 170000
//
// Beginning with Clang 17, empty initializers are accepted as an extension for
// scalar types and variable-length arrays as well as aggregates.

struct A {
int i;
};

struct A aggregate = {};
int scalar = {};
double floating = {};
void *pointer = {};
int compound_literal = (int){};

void f(int n) {
int vla[n] = {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//type:fn
//options_all:--c11 --clang_version 160000
//
// Clang versions before 17 do not accept empty initializers for variable-length
// arrays.

void f(int n) {
int vla[n] = {};
}