Is this code valid or not? GCC and Clang disagree - c++11

The following code gives me different results on GCC and Clang. Who's right?
union Foo {
struct {
int a;
int b;
};
};
struct Bar {
Bar(void) : test{.a = 1, .b = 2} { }
Foo test;
};
I get the following error with GCC (and it compiles fine with Clang):
arcanis#/tmp # g++ -std=c++11 x.cpp
x.cpp: In constructor ‘Bar::Bar()’:
x.cpp:9:36: error: too many initializers for ‘Foo’
Bar(void) : test{.a = 1, .b = 2} { }
^

Using GCC 4.9.1 and the following options:
-Wall -Wextra -std=c++11 -pedantic
this is what you get:
prog.cc:7:5: warning: ISO C++ prohibits anonymous structs [-Wpedantic]
};
^
prog.cc: In constructor 'Bar::Bar()':
prog.cc:11:21: warning: ISO C++ does not allow C99 designated initializers [-Wpedantic]
Bar(void) : test{.a = 1, .b = 2} { }
^
prog.cc:11:28: warning: ISO C++ does not allow C99 designated initializers [-Wpedantic]
Bar(void) : test{.a = 1, .b = 2} { }
^
prog.cc:11:36: error: too many initializers for 'Foo'
Bar(void) : test{.a = 1, .b = 2} { }
^
Using Clang 3.5.0 with the same options you get pretty much the same thing:
prog.cc:4:5: warning: anonymous structs are a GNU extension [-Wgnu-anonymous-struct]
struct {
^
prog.cc:11:22: warning: designated initializers are a C99 feature [-Wc99-extensions]
Bar(void) : test{.a = 1, .b = 2} { }
^~~~~~
prog.cc:11:30: warning: designated initializers are a C99 feature [-Wc99-extensions]
Bar(void) : test{.a = 1, .b = 2} { }
^~~~~~
In short, that's not valid C++11 code, for two reasons that are clearly indicated in the warning messages. Clang just happens to tolerate it and only issue the warnings, instead of an error. I'm not sure if it's worth debating 'who's right' in this case.

Related

Why there is unused-but-set variable-warning with pointers

I have the following code:
#include <iostream>
class Test
{
public:
Test(int i)
{
initialize(i);
}
void initialize(int i)
{
std::cout<<"i: "<<i<<std::endl;
}
};
int main()
{
Test* obj1(nullptr);
obj1 = new Test(2);
Test* obj2(nullptr);
obj2 = new Test(2);
obj2->initialize(3);
return 0;
}
When I compile as such (GCC v11.2.0):
g++ -Wall --std=c++11 main.cpp
I see the following warning:
main.cpp: In function ‘int main()’:
main.cpp:25:15: warning: variable ‘obj1’ set but not used [-Wunused-but-set-variable]
25 | Test* obj1(nullptr);
| ^~~~
My question is why is there a warning for obj1, but not obj2 when they do almost the same thing?
The key thing to realize here is that you actually have FOUR objects in your code -- two instances of the class Test and two pointers. The instances of Test don't have names (they're created with new), while the pointers do have names (obj1 and obj2).
The warning here is about the pointer object obj1 which is only ever assigned to and not used. The fact that the object it points at after the final assignment has had various side effects prior to that assignment is not relevant. You could remove the declaration an assignment (but not the new call in the assignment) without affecting the behavior or output of your program.
int main()
{
new Test(2);
Test* obj2(nullptr);
obj2 = new Test(2);
obj2->initialize(3);
return 0;
}

GCC, empty structs, and -Wunused-result

The following program causes gcc to emit -Wunused-result:
struct Empty { };
__attribute__((warn_unused_result))
static struct Empty func(void) {
return (struct Empty){};
}
int main(void) {
struct Empty res = func();
(void)res;
return 0;
}
Compiler output:
gcc -Wall -Wextra /tmp/test.c -c -o /tmp/test
/tmp/test.c: In function ‘main’:
/tmp/test.c:12:22: warning: ignoring return value of ‘func’, declared with attribute warn_unused_result [-Wunused-result]
struct Empty res = func();
^~~~~~
clang doesn't emit a warning.
Is this a bug or a feature?
(Empty struct as return value is useful in some code generation scenarios where a return value is always expected, but that is beside the question)
This does indeed appear to be a bug in GCC. I filed a bug report with them.
A workaround is to include a nameless bitfield in the "empty" structure:
struct Empty {char:1;};
extern void use_empty(struct Empty);
__attribute__((warn_unused_result))
extern struct Empty make_empty(void);
void should_warn(void)
{
make_empty();
}
void shouldnt_warn_1(void)
{
use_empty(make_empty());
}
void shouldnt_warn_2(void)
{
struct Empty e = make_empty();
use_empty(e);
}
warns only for 'should_warn'. This does mean that sizeof(struct Empty) is 1 rather than 0, and GCC generates an additional move instruction in both shouldnt_warn_1 and shouldnt_warn_2, but those are probably acceptable side-effects.
(Note that both a struct with no fields at all, and a struct with no named fields, are GNU extensions — in ISO C you must include at least one named field in every struct. Nameless bitfields, however, are standard, just obscure.)

Why gcc doesn't recognize initialization like "unsigned int()" for C++11?

int main()
{
auto k = int();//ok
auto i = unsigned int();//gcc error
return 0;
}
The line of "auto i" leads to gcc reporint an eror:
error: expected primary-expression before 'unsigned'
While VC doesn't have problem on my code. Why is this, is this a bug of gcc or, should it use some extra parences?
Thanks.

Initializing an `atomic_int` with a braced constant: Is this valid C code? If so why does it not compile in clang?

I'm porting some code from C11 to C++. The project compiles fine in gcc and g++ but clang refuses to compile it. The offending lines are shown below:
static atomic_int sem = {0};
src/testdir.c:27:25: error: illegal initializer type 'atomic_int'
(aka '_Atomic(int)')
and
struct container {
volatile atomic_ullong workerThreadCount;
struct cfgoptions *config;
repaircmd_t *cmd;
};
Container container = {{0}, s, NULL};
src/testdir.c:334:25: error: illegal initializer type 'volatile atomic_ullong'
(aka 'volatile _Atomic(unsigned long long)')
Clang:
clang version 3.7.0 (tags/RELEASE_370/final)
gcc:
gcc (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)
Operating system:
Fedora 23
Test code:
https://gist.github.com/clockley/eb42964003a2e4fe6de97d5b192d61d3
P.S i = {0} or i(0) are the only valid initializers in C++ as atomic ints are not primitive types of the two only the former is valid C.
I believe this is a bug in clang.
Here's a simple test case, with the result of compiling it with gcc and clang:
$ cat c.c
static _Atomic int x = ( 42 );
static _Atomic int y = { 42 };
$ gcc-6.1.0 -std=c11 -c c.c
$ clang-3.7 -std=c11 -c c.c
c.c:2:24: error: illegal initializer type '_Atomic(int)'
static _Atomic int y = { 42 };
^
1 error generated.
$
C explicitly permits the initializer for a scalar object to be enclosed in braces (N1570 6.7.9p11). I see nothing that forbids such an initializer for an atomic object.
Atomics are an optional feature in C11, but both gcc and clang support it (neither predefines __STDC_NO_ATOMICS__).
As a workaround, I suggest just dropping the braces. This:
static _Atomic int z = 42;
is valid and accepted by both compilers.
If you're need the code to compile both as C and as C++, then you might want to reconsider that requirement. But if it's really necessary, you can use the __cplusplus predefined macro to distinguish between C and C++ compilers:
static _Atomic int foo =
#ifdef __cplusplus
{ 42 };
#else
42;
#endif
or play some other tricks with macros.
(I'll note that C11's <stdatomic.h> header defines a macro ATOMIC_VAR_INIT that's intended to be used to initialize atomic objects, with an example:
atomic_int guide = ATOMIC_VAR_INIT(42);
It appears to be needed for atomic objects with automatic storage duration, which doesn't apply here.)
I must disagree strongly with Mad Physicist. The braces {} are used to initialize an aggregate. A single int is not an aggregate. You may put the initializer in () if you like, but {} are verboten. It would be an aggregate if you dimensioned it out to one entry, as in:
static atomic_int sem[ 1 ] = { 0 };
or even
static atomic_int sem[] = { 0 };
if you're too lazy to count one integer initializer!

How to enable the _Generic keyword

I have this test source:
#include <stdio.h>
int main()
{
int x;
printf("x=%d\n", _Generic('x', int: 1, default: 0));
return 0;
}
Compiling with c++ (from GCC 4.9.2) fails:
t.cpp: In function ‘int main()’:
t.cpp:7:33: error: expected primary-expression before ‘int’
printf("x=%d\n", _Generic('x', int: 1, default: 0));
^
t.cpp:7:41: error: expected primary-expression before ‘default’
printf("x=%d\n", _Generic('x', int: 1, default: 0));
^
t.cpp:7:51: error: ‘_Generic’ was not declared in this scope
printf("x=%d\n", _Generic('x', int: 1, default: 0));
The compiler arguments are:
c++ --std=c++11 t.cpp -o t
What am I doing wrong?
_Generic is a C11 feature. It is not present in C++ (any version at least up to C++14 - I don't really expect it to be added either).
If you want to use it, you'll need to write C code, and use a compiler that supports that standard (reasonably recent versions of gcc and clang do for example, using -std=c11).
If you want to write C++, use overloading or templates instead, for example:
#include <iostream>
int foo(int) { return 1; }
int foo(char) { return 0; }
int main()
{
std::cout << "x=" << foo('x') << std::endl;
}
This prints x=0 in C++, the foo(char) overload is the best match.
Note that there's difference between C and C++ that might trick you here too: 'x' is a char in C++. It's an int in C. So if _Generic had been implemented (maybe as an extension) by your compiler, chances are you'd get different output when compiling your example as C versus compiling as C++.
Here's the C++ form (forgive me for using the using directive, I know its bad form):
#include <iostream>
using namespace std;
template< typename T> T do_something(T argument) {
// Put here what you need
}
int main()
{
int x;
cout << "x" << (x = do_something(x));
return 0;
}
_Generic is C11, you're probably using a C++ compiler when you meant to use a C compiler.

Resources