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