gcc's extended initializer lists warning - c++

gcc will warn about the following example code:
struct someStruct {
char c;
int i;
};
int main() {
someStruct s { 'a', 3 };
return 0;
}
warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x
I want to make my code compatible to older compilers having no C++11 support.
Now when I try to compile it with either -std=c++98 or even -ansi -pedantic it still issues the same warning and compiles.
Is this a compiler bug or am I missing something?

You're missing an =:
someStruct s = { 'a', 3 };

Related

Sequence point compiler warning only in gcc but not in clang

Consider the following code:
#include <tuple>
struct A {
template <typename... Types> operator std::tuple<Types...>() {
int i = 0;
return std::tuple<Types...>{Types(i++)...};
}
};
struct B {
B(int i){};
};
int main() {
A a;
std::tuple<B, B> t{a};
}
It produces the following warnings in gcc
$ g++-12 main.cpp -std=c++20 -Wall
main.cpp: In instantiation of ‘A::operator std::tuple<_UTypes ...>() [with Types = {B, B}]’:
main.cpp:18:23: required from here
main.cpp:7:46: warning: operation on ‘i’ may be undefined [-Wsequence-point]
7 | return std::tuple<Types...>{Types(i++)...};
| ^
main.cpp:7:46: warning: operation on ‘i’ may be undefined [-Wsequence-point]
but not in clang:
clang++-14 main.cpp -std=c++20 -Wall
main.cpp:18:20: warning: unused variable 't' [-Wunused-variable]
std::tuple<B, B> t{a};
^
1 warning generated.
Why?
This may be related but the referenced gcc bug is already fixed. I have gcc --version gcc (Debian 12.2.0-9) 12.2.0.
The order of evaluation of elements in a braced-init-list is strictly left-to-right, already since C++11, and regardless of the context in which the syntax is used. See https://timsong-cpp.github.io/cppwp/n3337/dcl.decl#dcl.init.list-4.
So the warning is bogus. #Artyer linked this bug report for a false positive warning under the question, which probably covers your example as well.
As mentioned in the other bug report you linked, GCC had actual wrong code generation for similar cases in earlier versions though, so you might want to be careful when relying on this order.

GCC and Clang differ in static_assert related to __builtin_constant_p

I happen to find that GCC and Clang differ in the compilation of the following code:
struct Foo
{
int mem = 42;
};
int main()
{
constexpr Foo foo;
static_assert(__builtin_constant_p(foo));
return 0;
}
I compile with g++ -std=c++17 and clang++ -std=c++17.
In particular,
g++ g++-9 (Homebrew GCC 9.3.0_1) 9.3.0 compiles, whereas
clang++ Apple clang version 11.0.3 (clang-1103.0.32.62) fails to compile, complaining that
error: static_assert failed due to requirement '__builtin_constant_p(foo)'
static_assert(__builtin_constant_p(foo));
^ ~~~~~~~~~~~~~~~~~~~~~~~~~
I didn't find any hint that there should be any difference regarding __builtin_constant_p.
For __builtin_constant_p
GCC says
You can use the built-in function __builtin_constant_p to determine if a value is known to be constant at compile time ...
Clang
says
Clang supports a number of builtin library functions with the same syntax as GCC, including things like __builtin_nan, __builtin_constant_p, __builtin_choose_expr, __builtin_types_compatible_p, __builtin_assume_aligned, __sync_fetch_and_add, etc.
Question: While I know __builtin_constant_p is a compiler extension, which one should be the correct one?
Both are poorly documented so I doubt there is a proper answer to your question.
If you need a workaround: it seems that clang gives up if the argument is not an int.
So this works:
struct Foo
{
int mem = 42;
};
int main()
{
constexpr Foo foo;
static_assert(__builtin_constant_p(foo.mem));
return 0;
}

what is the correct way to write this function, or is clang wrong? [duplicate]

Consider the following program:
#include <array>
int main()
{
std::array<int, 1> x = { 0 }; // warning!
x = { { 0 } }; // no warning
return 0;
}
The first initialization leads to warnings on gcc 4.7.2...
main.cpp:5:22: warning: unused variable ‘x’ [-Wunused-variable]
... and clang 3.1
main.cpp:5:28: warning: suggest braces around initialization of subobject [-Wmissing-braces]
std::array<int, 1> x = { 0 };
As far as the standard goes, there should be no difference between double or single curly braces, at least in this example.
There are two ways to deal with the warning:
Just turn it off
Fix the code, so the compiler is happy
What do you propose? IMHO, the double curly expression looks somewhat ugly. On the other hand, the warning might detect real problems in more complicated examples. Do you know an example where the warning would have helped you?
-Wmissing-braces will no longer be enabled in GCC's -Wall (for C++ mode), as of 4.8, for precisely the reason you describe. For current versions of GCC, either disable or ignore the warning, the code you have is written the way it should be.
The warning is probably meant to cover code such as
struct A { int a; int b; };
struct B { A a; int b; };
B b = {
1,
2 // initialises b.a.b, not b.b
};
However, IMHO, that is already handled well enough by -Wmissing-field-initializers, which does not warn about your original code.
I get the same warning in Xcode 6.1.1 (the current version as of March 9, 2015). When I add the extra braces around each subobject I get an error. When I add an extra set of braces around the entire initialization list then the warning goes away. According to the standard specification 14882:2011 23.3.2.1 [array.overview] subsection 2 explicitly states
array<T, N> a = { initializer-list };
where initializer-list is a comma-separated list of up to N elements
whose types are convertible to T
result of code in Xcode 6.1.1 (below)
array<int, 2> key1 = {1, 2}; // warning: suggest braces around initialization of subobject
array<int, 2> key2 = { {1}, {2} }; // error: no viable overload =
array<int, 2> key3 = array<int, 2> { {1}, {2} }; // error: excess elements in struct initializer
array<int, 2> key4 = { {1, 2} }; // no warning and no error
When we look at 14882:2011 8.5 [dcl.init] subsection 1 we see that an 'initializer-list' can optionally contain an 'initializer-clause', which itself can be a 'braced-init-list'. So either way should be correct. Though based on the spec I personally think single braces shouldn't output a compiler warning for a std::array initializer-list, and double braces is overkill.
Clang 6.0 suppresses the warning about missing braces. The svn log says:
Suppress -Wmissing-braces warning when aggregate-initializing a struct with a single field that is itself an aggregate. In C++, such initialization of std::array types is guaranteed to work by the standard, is completely idiomatic, and the "suggested" alternative from
Clang was technically invalid.
So I would omit the braces and disable -Wmissing-braces for Clang prior to 6.0 if it needs to be supported.
When ignoring the Clang warning with -Wno-missing-braces, I would recommend to enable -Wmissing-field-initializers (or use -Wextra, which also includes it). Otherwise, you miss a useful warning like in this example:
#include <cstdio>
struct A
{
int i;
int arr[2];
int j;
};
void print(const A& a)
{
printf("i=%d, arr={%d,%d}, j=%d\n", a.i, a.arr[0], a.arr[1], a.j);
}
int main() {
A a = {1, 2, 3}; // this is the critical line
print(a); // output: i=1, arr={2,3}, j=0
A b = {1, {2}, 3};
print(b); // output: i=1, arr={2,0}, j=3
A c = {1, {2,0}, 3};
print(c); // output: i=1, arr={2,0}, j=3
return 0;
}
$ clang++ -Wall example.cpp
example.cpp:16:13: warning: suggest braces around initialization of
subobject [-Wmissing-braces]
A a = {1, 2, 3};
^~~~
{ }
1 warning generated.
$ clang++ -Wall -Wno-missing-braces example.cpp
(no warnings)
$ clang++ -Wall -Wno-missing-braces -Wmissing-field-initializers example.cpp
example.cpp:16:17: warning: missing field 'j' initializer
[-Wmissing-field-initializers]
A a = {1, 2, 3};
^
1 warning generated.
$ clang++ --version
clang version 3.8.1 (tags/RELEASE_381/final)
For comparison, this is what GCC does:
$ g++ -Wall -Wextra example.cpp
(no warning)
$ g++ -Wall -Wmissing-field-initializers example.cpp
example.cpp: In function ‘int main()’
example.cpp:16:17: warning: missing initializer for member ‘A::j’ [-Wmissing-field-initializers]
A a = {1, 2, 3};
^
In summary:
For Clang, I would recommend -Wno-missing-braces -Wmissing-field-initializers to silence the warning without loosing other useful warnings
GCC does not complain in the original std::array<int, 1> x = { 0 }; example, so there is no need to disable any warnings. However, I would recommend to enable -Wmissing-field-initializers (or use -Wextra), as it is not enabled by -Wall.

default initialization of aggregates

For the following program, I do not get a warning that uoff.Reg and s.i is used without initialization. gcc (with -Wextra) and clang (with -Weverything) both do not warn, as I expected.
#include<stdint.h>
typedef union {
uint32_t Reg;
struct {
uint16_t Cx;
uint16_t sf;
};
} tf;
typedef struct {
uint16_t i;
uint16_t j;
} st;
int bar(tf, tf);
int foo(tf t0, int32_t offset) {
tf uoff;
st s;
t0.Reg = uoff.Reg + s.i + (uint32_t)offset;
t0.sf = uoff.sf;
return bar(t0, uoff);
}
I'm wondering why I'm not getting any warning. Does standard (C/C++) say that aggregates with automatic storage are initialized (by default) to zero, or is it a compiler limitation?
I checked gcc, : http://coliru.stacked-crooked.com/a/f1b25f7f369fbdbc, and warnings does get generated
here is how it gets compiled:
g++-4.8 -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
and output:
main.cpp:10:3: warning: ISO C++ prohibits anonymous structs [-Wpedantic]
};
^
main.cpp: In function 'int foo(tf, int32_t)':
main.cpp:23:21: warning: 'uoff.tf::Reg' is used uninitialized in this function -Wuninitialized]
t0.Reg = uoff.Reg + s.i + (uint32_t)offset;
^
main.cpp:23:21: warning: 's.st::i' is used uninitialized in this function -Wuninitialized]
/tmp/ccIy8fGt.o: In function `foo(tf, int)':
main.cpp:(.text+0xa): undefined reference to `bar(tf, tf)'
collect2: error: ld returned 1 exit status
In order to guarantee zero-initialization of POD aggregate data members, you need to value-initialize your instance. For example,
st s = st(); // C++03 and C++11
st s = {}; // C++03 and C++11
st s{}; // C++11
Compilers are not required to warn you about uninitializad variables. However, the minimal set of compilation flags needed to get a warning with g++ seem to be
-Wuninitialized -O2
In other words, it seems that without optimization, the warning disappears. It could be that in this case variables get zero initialized.
Does standard (C/C++) say that aggregates with automatic storage are
initialized (by default) to zero
No, it doesn't. Automatic variables are not initialized, their value is initially left undefined. Using them without initialization results in undefined behavior.
However, naturally, the standard doesn't require you to initialize variables, compilers are free to warn about this, but using an uninitialized variable is not a constraint violation, thus, implementations do not have to warn you.
No, the C-Standard does not require the compiler to generate code to initialise auto variables. Reading their value without prior initialisation provokes undefined behaviuor.
However, this code
int main(void)
{
int a;
int b = a;
b = b;
return 0;
}
compiled using gcc's option -Wall, gives:
main.c:4: warning: ‘a’ is used uninitialized in this function
[gcc (Debian 4.4.5-8) 4.4.5]

Is it wise to ignore gcc/clang's "-Wmissing-braces" warning?

Consider the following program:
#include <array>
int main()
{
std::array<int, 1> x = { 0 }; // warning!
x = { { 0 } }; // no warning
return 0;
}
The first initialization leads to warnings on gcc 4.7.2...
main.cpp:5:22: warning: unused variable ‘x’ [-Wunused-variable]
... and clang 3.1
main.cpp:5:28: warning: suggest braces around initialization of subobject [-Wmissing-braces]
std::array<int, 1> x = { 0 };
As far as the standard goes, there should be no difference between double or single curly braces, at least in this example.
There are two ways to deal with the warning:
Just turn it off
Fix the code, so the compiler is happy
What do you propose? IMHO, the double curly expression looks somewhat ugly. On the other hand, the warning might detect real problems in more complicated examples. Do you know an example where the warning would have helped you?
-Wmissing-braces will no longer be enabled in GCC's -Wall (for C++ mode), as of 4.8, for precisely the reason you describe. For current versions of GCC, either disable or ignore the warning, the code you have is written the way it should be.
The warning is probably meant to cover code such as
struct A { int a; int b; };
struct B { A a; int b; };
B b = {
1,
2 // initialises b.a.b, not b.b
};
However, IMHO, that is already handled well enough by -Wmissing-field-initializers, which does not warn about your original code.
I get the same warning in Xcode 6.1.1 (the current version as of March 9, 2015). When I add the extra braces around each subobject I get an error. When I add an extra set of braces around the entire initialization list then the warning goes away. According to the standard specification 14882:2011 23.3.2.1 [array.overview] subsection 2 explicitly states
array<T, N> a = { initializer-list };
where initializer-list is a comma-separated list of up to N elements
whose types are convertible to T
result of code in Xcode 6.1.1 (below)
array<int, 2> key1 = {1, 2}; // warning: suggest braces around initialization of subobject
array<int, 2> key2 = { {1}, {2} }; // error: no viable overload =
array<int, 2> key3 = array<int, 2> { {1}, {2} }; // error: excess elements in struct initializer
array<int, 2> key4 = { {1, 2} }; // no warning and no error
When we look at 14882:2011 8.5 [dcl.init] subsection 1 we see that an 'initializer-list' can optionally contain an 'initializer-clause', which itself can be a 'braced-init-list'. So either way should be correct. Though based on the spec I personally think single braces shouldn't output a compiler warning for a std::array initializer-list, and double braces is overkill.
Clang 6.0 suppresses the warning about missing braces. The svn log says:
Suppress -Wmissing-braces warning when aggregate-initializing a struct with a single field that is itself an aggregate. In C++, such initialization of std::array types is guaranteed to work by the standard, is completely idiomatic, and the "suggested" alternative from
Clang was technically invalid.
So I would omit the braces and disable -Wmissing-braces for Clang prior to 6.0 if it needs to be supported.
When ignoring the Clang warning with -Wno-missing-braces, I would recommend to enable -Wmissing-field-initializers (or use -Wextra, which also includes it). Otherwise, you miss a useful warning like in this example:
#include <cstdio>
struct A
{
int i;
int arr[2];
int j;
};
void print(const A& a)
{
printf("i=%d, arr={%d,%d}, j=%d\n", a.i, a.arr[0], a.arr[1], a.j);
}
int main() {
A a = {1, 2, 3}; // this is the critical line
print(a); // output: i=1, arr={2,3}, j=0
A b = {1, {2}, 3};
print(b); // output: i=1, arr={2,0}, j=3
A c = {1, {2,0}, 3};
print(c); // output: i=1, arr={2,0}, j=3
return 0;
}
$ clang++ -Wall example.cpp
example.cpp:16:13: warning: suggest braces around initialization of
subobject [-Wmissing-braces]
A a = {1, 2, 3};
^~~~
{ }
1 warning generated.
$ clang++ -Wall -Wno-missing-braces example.cpp
(no warnings)
$ clang++ -Wall -Wno-missing-braces -Wmissing-field-initializers example.cpp
example.cpp:16:17: warning: missing field 'j' initializer
[-Wmissing-field-initializers]
A a = {1, 2, 3};
^
1 warning generated.
$ clang++ --version
clang version 3.8.1 (tags/RELEASE_381/final)
For comparison, this is what GCC does:
$ g++ -Wall -Wextra example.cpp
(no warning)
$ g++ -Wall -Wmissing-field-initializers example.cpp
example.cpp: In function ‘int main()’
example.cpp:16:17: warning: missing initializer for member ‘A::j’ [-Wmissing-field-initializers]
A a = {1, 2, 3};
^
In summary:
For Clang, I would recommend -Wno-missing-braces -Wmissing-field-initializers to silence the warning without loosing other useful warnings
GCC does not complain in the original std::array<int, 1> x = { 0 }; example, so there is no need to disable any warnings. However, I would recommend to enable -Wmissing-field-initializers (or use -Wextra), as it is not enabled by -Wall.