Package: gcc-8 Version: 8.3.0-6 Severity: normal Tags: upstream Dear Maintainer, In a C program, when an enum's value is overridden by a variable with the same name, and it is compiled by gcc with -Wall, no warning is emitted even though it is questionable to override an enum. See the program below:
#include <stdio.h>
int main(void) {
enum {g, h, i} foo[3];
/* Set all elements of `foo' to `i' (2), or so you would think */
for (int i = 0; i < sizeof(foo) / sizeof(*foo); i++) {
foo[i] = i; /* <-- this doesn't do what you think */
}
/* Now print all the elements (note we use `iterator' instead of `i'
to avoid the situation above) */
for (int iterator = 0; iterator < sizeof(foo) / sizeof(*foo); iterator++) {
printf("foo[%d] is ", iterator);
switch (foo[iterator]) {
case g:
puts("g");
break;
case h:
puts("h");
break;
case i:
puts("i");
break;
default:
printf("something else: %d\n", foo[iterator]);
break;
}
}
return 0;
}
In line 8, "foo[i] = i;", foo[i] is indexed using the "i" which was
declared at the beginning of the loop ("int i = 0;"), as you would
expect. However, it is not clear what the second "i" (the one on the
right of the assignment) is referring to. It could be referring to the
value "2" (since that is the value `i' is assigned to in the enum), or
it could also be referring to the "i" which was declared at the
beginning of the loop. It is in fact referring to the loop `i' as you
can see if you compile and run the program.
$ gcc -Wall -o enum-test enum-test.c
$ ./enum-test
foo[0] is g
foo[1] is h
foo[2] is i
However, note that gcc succeeded with *no output* even though -Wall was
passed. Since overriding enum values is unclear and may not do what you
think, and it's easily avoidable (just change the variable or enum value
name), it should be warned against when -Wall is passed.
From the "(gcc) Warning Options" info node,
'-Wall'
This enables all the warnings about constructions that some users
consider questionable, and that are easy to avoid (or modify to
prevent the warning), even in conjunction with macros.
So I think this should definitely be warned against by -Wall.
Clang too, does not warn against this:
$ clang -Wall -o enum-test enum-test.c
$ ./enum-test
foo[0] is g
foo[1] is h
foo[2] is i
(As you can see, the runtime behavior of the program is the same as when
compiled with gcc, as you would expect.)
Curiously, both g++ and clang++ raise an error when an enum is
overridden (along with a few warnings since the program was not meant to
be compiled as C++).
$ g++ -Wall -o enum-test enum-test.c
enum-test.c: In function ‘int main()’:
enum-test.c:7:21: warning: comparison of integer expressions of different signedness: ‘int’ and ‘long unsigned int’ [-Wsign-compare]
for (int i = 0; i < sizeof(foo) / sizeof(*foo); i++) {
~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
enum-test.c:8:14: error: invalid conversion from ‘int’ to ‘main()::<unnamed enum>’ [-fpermissive]
foo[i] = i; /* <-- this doesn't do what you think */
^
enum-test.c:13:35: warning: comparison of integer expressions of different signedness: ‘int’ and ‘long unsigned int’ [-Wsign-compare]
for (int iterator = 0; iterator < sizeof(foo) / sizeof(*foo); iterator++) {
~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ clang++ -Wall -o enum-test enum-test.c
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]
enum-test.c:8:14: error: assigning to 'enum (anonymous enum at enum-test.c:4:3)' from incompatible type 'int'
foo[i] = i; /* <-- this doesn't do what you think */
^
1 error generated.
I haven't reported a bug against clang since you can only report a bug
against one package, but perhaps a bug should be reported against clang
referencing this one to alert the clang people about this too.
-- System Information:
Debian Release: 10.0
APT prefers testing
APT policy: (500, 'testing')
Architecture: amd64 (x86_64)
Kernel: Linux 4.19.0-5-amd64 (SMP w/2 CPU cores)
Kernel taint flags: TAINT_FIRMWARE_WORKAROUND
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
Versions of packages gcc-8 depends on:
ii binutils 2.31.1-16
ii cpp-8 8.3.0-6
ii gcc-8-base 8.3.0-6
ii libc6 2.28-10
ii libcc1-0 8.3.0-6
ii libgcc-8-dev 8.3.0-6
ii libgcc1 1:8.3.0-6
ii libgmp10 2:6.1.2+dfsg-4
ii libisl19 0.20-2
ii libmpc3 1.1.0-1
ii libmpfr6 4.0.2-1
ii libstdc++6 8.3.0-6
ii zlib1g 1:1.2.11.dfsg-1
Versions of packages gcc-8 recommends:
ii libc6-dev 2.28-10
Versions of packages gcc-8 suggests:
pn gcc-8-doc <none>
pn gcc-8-locales <none>
pn gcc-8-multilib <none>
pn libasan5-dbg <none>
pn libatomic1-dbg <none>
pn libgcc1-dbg <none>
pn libgomp1-dbg <none>
pn libitm1-dbg <none>
pn liblsan0-dbg <none>
pn libmpx2-dbg <none>
pn libquadmath0-dbg <none>
pn libtsan0-dbg <none>
pn libubsan1-dbg <none>
-- no debconf information
Attachment:
signature.asc
Description: PGP signature