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

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.

Related

Compiler, library, or user error? Eigen::Array, GCC 12.1, "array subscript [...] is partly outside array bounds"

After updating to GCC 12.1, I got a array subscript ‘__m256d_u[0]’ is partly outside array bounds error (or rather warning with -Werror) in my project, so I tried isolating the problem.
Here's an MWE, which I also put on godbolt (vector type is __m512d_u instead, but otherwise it's the same error):
#include <Eigen/Dense>
#include <iostream>
using Eigen::Array;
Array<double, 3, 2> foo(){
Array<double, 2, 2> a;
a.setRandom();
Array<double, 3, 2> b;
b.col(0).tail(2) = a.col(1);
// b.col(0).template tail<2>() = a.col(1);
return b;
}
int main(){
std::cout << foo() << '\n';
return 0;
}
Relevant compile options are -Wall -Wextra -Werror -O3 -march=native, and the error message notes note: at offset [16, 24] into object ‘a’ of size 32.
The error does not occur under the following circumstances:
on GCC 11.3 or older,
when removing -march=native
when using -O1 or below
when replacing the line b.col(0).tail(2) = a.col(1); with b.col(0).template tail<2>() = a.col(1);
So it looks like GCC sees the 3x2 array and the 2x2 array, and doesn't realise that only two entries are accessed each.
My question now is: Who should this be reported to? GCC, Eigen? Or is it a user bug?
Bonus points for telling me what the 24 in the error note (offset [16, 24]) is. The 16 is the start, is the 24 the read size?
EDIT: Example can be further simplified by using Array3d and Array2d, see here.

Why different diagnostics by clang on similar issue?

Here is my code:
#include <vector>
int main()
{
std::vector<int> a = {1, 2.2};
}
As expected this does not compile because of the illegal narrowing conversion:
$ clang++ -std=c++11 foo.cpp
foo.cpp:5:30: error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
std::vector<int> a = {1, 2.2};
^~~
Why does this compile then with only a warning?
#include <complex>
int main()
{
std::complex<int> a = {1, 2.2};
}
Here is the warning:
$ clang++ -std=c++11 foo.cpp
foo.cpp:5:31: warning: implicit conversion from 'double' to 'std::__1::complex<int>::value_type' (aka 'int') changes value from 2.2 to 2 [-Wliteral-conversion]
std::complex<int> a = {1, 2.2};
~ ^~~
1 warning generated.
I understand the notion of diagnostics and that the C++ compiler is only required to issue a diagnostic either in the form of error or warning.
But I want to be sure that I am not misunderstanding any concept here. Especially, I want to know if there is any C++ concept that I need to know why in the first case the c++11-narrowing diagnostic was issued but in the second case literal-conversion diagnostic was issued.
Two different things are happening, which as you can see result in different diagnostics:
In the first case, you're using copy-list-initialization and finding a constructor of std::vector which takes an std::initializer_lsit.
In the second case, you're using copy-list-initialization on a LiteralType, which results in aggregate initialization.
They both should prevent narrowing conversions, but it seems that clang implements the diagnostics differently.

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]

gcc's extended initializer lists warning

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 };