This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: Bug with compound literal initializer?
- From: Alexey Neyman <stilor at att dot net>
- To: Martin Sebor <msebor at redhat dot com>, gcc at gcc dot gnu dot org
- Date: Wed, 25 Mar 2015 11:19:11 -0700
- Subject: Re: Bug with compound literal initializer?
- Authentication-results: sourceware.org; auth=none
- References: <5511D668 dot 5060009 at att dot net> <5512EBB0 dot 4070601 at redhat dot com>
On 03/25/2015 10:09 AM, Martin Sebor wrote:
On 03/24/2015 03:26 PM, Alexey Neyman wrote:
Hi,
I am seeing a strange behavior when a compound initializer is used in a
structure initialization. A test case:
[[[
struct s {
int y;
unsigned long *x;
};
struct s foo = {
.y = 25,
.x = (unsigned long [SZ]){},
};
]]]
If SZ is zero, the initializer for .y (".y = 25") member is dropped as
well:
I'm having trouble finding support for any expectation in this
case. When SZ is zero, the source code above is invalid in C
not only because it attempts to create an array with zero
elements but also because it doesn't provide any initializers
for the initializer-list. Strictly speaking, it's required to
be diagnosed but at runtime it has undefined behavior.
This unit test is an excerpt from a bigger array where the compound
literal was a statically allocated bitmap. Some of the members of the
array may not need such a bitmap, depending on a configuration - and the
size of this bitmap was initialized to zero. I didn't expect to see
other structure members' initializers go away, though.
What's even worse that this bug not only deletes the .y initializer - it
also drops initializers in other array members. E.g., for:
[[[
struct s foo[] = {
{ .y = 25, .x = (unsigned long [0]){}, },
{ .y = 37, .x = (unsigned long [1]){}, },
};
]]]
GCC generates:
[[[
.type foo, @object
.size foo, 16
foo:
.zero 16
]]]
Regarding undefined behavior: this object has static storage, so I think
6.7.9-10 from C11 should apply:
"... If an object that has static or thread storage duration is not
initialized explicitly, then:
â if it has pointer type, it is initialized to a null pointer;
â if it has arithmetic type, it is initialized to (positive or unsigned)
zero;
â if it is an aggregate, every member is initialized (recursively)
according to these rules,
and any padding is initialized to zero bits;
â if it is a union, the first named member is initialized (recursively)
according to these
rules, and any padding is initialized to zero bits;"
It's unclear from the GCC manual (or from the apparent absence
of tests for this construct in the test suite) that the code
is intended to do something meaningful in GCC. The compiler
supports zero size arrays as an extension when declaring such
objects as the last members of structs. But in this case, the
code attempts to create an unnanmed temporary array of zero
elements which, IMO, makes no sense. At the same time, I
wouldn't expect gcc to simply omit the initialization for
foo.x. I suggest to open a gcc bug for it.
Point taken on zero-sized array being GCC extension, but I would argue
that since GCC permits zero-sized arrays, it should also permit empty
initializer-list as an initializer for such arrays. And indeed, with
-Wall it complains about neither zero-sized array nor empty
initializer-list, and with -Wpedantic it complains about them both.
Martin
PS This is the output what I get with gcc 5.0:
$ cat u.c && gcc -Wall -Wextra -Wpedantic -std=c11 -ansi u.c && ./a.out
[...snip...]
u.c:7:5: warning: ISO C90 forbids specifying subobject to initialize
[-Wpedantic]
u.c:8:5: warning: ISO C90 forbids specifying subobject to initialize
[-Wpedantic]
u.c:8:29: warning: ISO C90 forbids compound literals [-Wpedantic]
Isn't it strange that C90 warnings are emitted in presence of -std=c11?
I don't get these C90 warnings with 4.9.1 if I specify -std=c99 or -stc=c11.
Regards,
Alexey.