GCC vs Clang: Meaning of "-pedantic-errors" - c++

I'm using Clang v3.7.0 with Mingw-w64 5.1.0 and GCC 5.1.0, all 64-bit, on Windows 10. My goal is to use a set of Clang and GCC options that will give me the best chance of detecting potential C89 and C++98 language standards portability issues across many different compilers. For example, for C I have been using the following GCC command line with pretty good success:
gcc -c -x c -std=c89 -pedantic-errors -Wall -Wextra -Wno-comment -Wno-parentheses -Wno-format-zero-length test.c
However, I recently tried it with Clang and got a different result. Here is my sample test code:
int main(void)
{
int length = (int)strlen("Hello");
return 0;
}
With Clang I get the following error, whereas with GCC I get the same basic thing, but it flags it as a warning instead:
test.c:3:22: error: implicitly declaring library function 'strlen'
with type 'unsigned long long (const char *)'
int length = (int)strlen("Hello");
If I remove the -pedantic-errors option, or just change it to -pedantic, Clang then only flags it as a warning, which is what I actually want. However, according to the GCC documentation the -pedantic-errors option causes warnings that are considered language extensions to be flagged as errors, but not using a prototype for a function is not an extension in C89. So, I have three basic questions:
Has Clang changed the meaning of -pedantic-errors from the meaning used by GCC, or am I misinterpreting something?
What is the best set of options that will enforce adherence to the selected standard and will issue errors for all non-conforming code?
If I continue to use -pedantic-errors with Clang is there a way to get it to issue a warning instead of an error in specific cases? In another posting on this site an answer was given that said to use the following, where foo is the error:
-Wno-error=foo
If that is a correct approach, what do I actually use in place of foo for an error like I'm getting since there is no actual error number indicated? I can't believe it actually wants all of the following:
-Wno-error=implicitly declaring library function 'strlen'
with type 'unsigned long long (const char *)'

Your code is invalid, and the behavior is undefined, so the compiler can do anything also when compiling. The implicitly declared int strlen(char*) is not compatible with size_t strlen(const char *).
Has Clang changed the meaning of -pedantic-errors from the meaning used by GCC, or am I misinterpreting something?
As I read it, yes. From clang documentation:
-pedantic-errors
Error on language extensions.
In GCC:
-pedantic
Issue all the warnings demanded by strict ISO C and ISO C++ [...]
-pedantic-errors
Give an error whenever the base standard (see -Wpedantic) requires a diagnostic, in some cases where there is undefined behavior at compile-time and in some other cases that do not prevent compilation of programs that are valid according to the standard.
Clang errors on extensions.
GCC errors when standard explicitly requires it and in other "some cases".
This is a different, it is a different set of errors. Standard may not require a diagnostic, but it's still an extension - GCC will be silent, Clang will error.
What is the best set of options that will enforce adherence to the selected standard and will issue errors for all non-conforming code?
The first answer that comes to mind is: "none". Compiler inherently use "implementation-defined behavior" and extension, because they are meant to compile the code in the first place, not meant to not compile non-conforming code. There are cases where the code is conforming, but still the behavior differs between compilers - you can explore such a case here.
Anyway, keep using -pedantic-errors, as it seems to work in detection of non-conforming code. Your code is invalid, the behavior is undefined, so your code is non-conforming, so clang properly detects it. Also use linters and sanitizers to detect other cases of undefined behavior.
If I continue to use -pedantic-errors with Clang is there a way to get it to issue a warning instead of an error in specific cases?
Use -fno-builtin.

Related

warning: 'auto' type specifier is a C++11 extension

I have a very simple C++ code statement auto a = 12;.
When I am compiling it with g++ in Linux using -std=c++98 option I am getting an error as expected
error: ‘a’ does not name a type
But when I am compiling the same code with the same option in MacOS I am getting just a warning, but the code get's compiled fine.
warning: 'auto' type specifier is a C++11 extension [-Wc++11-extensions]
But wasn't the whole point of -std=c++98 to compile the code following C++ 98 standards? So the warning tells even though auto is a C++11 extension I am going to compile it for you?
Is there any option to force using c++98 (or other standard)?
g++ --version prints
Apple clang version 12.0.0 (clang-1200.0.32.29)
which is another weird thing by the way. So it is clang actually.
It's like asking firefox --version and getting chrome 87.0.4280.163
On MacOS, you're using clang, not gcc. (If I recall correctly, MacOS provides "gcc" and "g++" as symlinks to "clang" and "clang++", respectively, so that scripts that assume gcc don't break.)
The two compilers just treat this case differently.
Yes, a compiler that conforms to the 1998 ISO C standard, as both gcc and clang attempt to do with -std=c++98, must diagnose that line.
As far as the standard is concerned, a non-fatal warning is a valid diagnostic. The standard doesn't require an invalid program to be rejected (unless it contains a #error directive).
If you want to strictly enforce C++98 rules and reject code that violates them, use -std=c++98 -pedantic-errors (with either gcc or clang).
You may be looking for -pedantic or -pedantic-errors, quoting man g++:
-pedantic
Issue all the warnings demanded by strict ISO C and ISO C ++ ; reject all programs that use forbidden extensions, and some other
programs that do not follow ISO C and ISO C ++ . For ISO C, follows
the version of the ISO C standard specified by any -std option used.
Note: this is not meant as a feature to check strict standards conformance (see the rest of the description in the man page)

What does the clang compiler's `-Weverything` option include and where is it documented?

clang, but NOT gcc, has a -Weverything option which appears to include things such as -Wpedantic. You can test it here: https://godbolt.org/z/qcYKd1. See the top-right of the window for where I have typed in -Weverything as an explicit compiler option.
Notice the -Wvla-extension warning we get since we are relying on a C99 extension in C++ in this case, and we have -Weverything set. We get the same warning if we just use -Wpedantic, as shown here: https://godbolt.org/z/M9ahE4, indicating that -Weverything does in fact include -Wpedantic.
We get no warning if we have neither of those flags set: https://godbolt.org/z/j8sfsY.
Despite -Weverything existing and working in clang, however, I can find no documentation whatsoever on its existence, neither in the clang man pages nor in the online manual here: https://clang.llvm.org/docs/DiagnosticsReference.html. Maybe I'm looking in the wrong place? I'm not super familiar with clang's manual.
So, what does -Weverything include and where is it documented?
It seems logical to do something like -Wall -Werror -Weverything, but I don't know how that differs from just -Wall -Werror.
Dope! I just found it.
The bottom of the main clang documentation index page: https://clang.llvm.org/docs/index.html, under the "Indices and tables" section at the very bottom, has a "Search Page" link. Using that link, here is my search for "-Weverything": https://clang.llvm.org/docs/search.html?q=-Weverything, which brings me to the official documentation here!: https://clang.llvm.org/docs/UsersManual.html?highlight=weverything#cmdoption-weverything. Done! There it is!
See also: https://clang.llvm.org/docs/UsersManual.html?highlight=weverything#diagnostics-enable-everything
And the parts I really care about (emphasis added):
Since -Weverything enables every diagnostic, we generally don’t recommend using it. -Wall -Wextra are a better choice for most projects. Using -Weverything means that updating your compiler is more difficult because you’re exposed to experimental diagnostics which might be of lower quality than the default ones. If you do use -Weverything then we advise that you address all new compiler diagnostics as they get added to Clang, either by fixing everything they find or explicitly disabling that diagnostic with its corresponding Wno- option.
So, my final recommendation is to use -Wall -Wextra for warnings, but NOT -Weverything, and personally, not -Wpedantic (or -pedantic--same thing) either since I frequently rely on gcc compiler extensions for low-level embedded work and hardware-centric programming, especially on microcontrollers.
I also strongly recommend forcing all warnings into errors with -Werror. This is particularly important for safety-critical code and/or embedded firmware that needs to run forever, because it forces you to fix all warnings to get the code to fully compile. So, my final recommendation is this, as I describe further in my github repo below:
# Apply "all" and "extra" warnings, and convert them all to errors
# to force you to actually abide by them!
-Wall -Wextra -Werror
You can read my more-thorough opinion and research on this topic in my GitHub repo here: https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world#build-notes.
Extra notes: -Wpedantic == -pedantic:
In gcc, they are the same:
Both are listed together.
-Wpedantic
-pedantic
Issue all the warnings demanded by strict ISO C and ISO C++...
In clang, they appear to be the same too, in testing and documentation. Clang also strives to be gcc-compatible in their syntax and usage: "End-User Features:"..."GCC compatibility".
-pedantic
-Wpedantic
Related:
Why should I always enable compiler warnings?

Clang and GCC different diagnostics behaviour for function invocation before definition?

Let's analyze the following code example:
int main() {
return func();
}
int func() {
return 1;
}
Clang will report error:
/private/tmp/src.cpp:2,9 - Error - use of undeclared identifier 'func'
But i can find lot's of such errors in wide used examples, f.e. some arduino sources:
https://github.com/firmata/arduino/blob/master/examples/StandardFirmata/StandardFirmata.ino
line 235 : disableI2CPins(); // invocation (before definition, no declaration before)
...
line 651 : void disableI2CPins() { .. } // definition
Though function is used before defined that code can be compiled with GCC successfully. How that can be? Is it different Clang and GCC behavior? Are there any flags to allow this for Clang?
PS. Here is successful command line to compile the code used by Arduino IDE:
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-g++
-c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10600 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR -I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/cores/arduino
-I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/variants/mega
-I/Applications/Arduino.app/Contents/Resources/Java/libraries/Servo/src
-I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/libraries/Wire
-I/Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata/src
/var/folders/64/fwfkm1k51zbd4_c5lwpsbljh0000gn/T/build8049651108713091801.tmp/StandardFirmata.cpp
-o /var/folders/64/fwfkm1k51zbd4_c5lwpsbljh0000gn/T/build8049651108713091801.tmp/StandardFirmata.cpp.o
This is actually not to do with the compiler, but the Arduino IDE. The IDE has a preprocessing step which forward-declares all the defined functions so that you don't need to worry about function placement in the file.
My strong recommendation would be to just follow the language rules and forward-declare your functions or define them before their use. Your code will be more portable and understandable for it.
No, you don't want clang to behave like gcc in this regard. In fact, use -Wall and -W (or -Wextra) in order to get gcc and clang both to give you even more warnings.
But i can find lot's of such errors in wide used examples
Sadly, getting C and C++ right is so hard that widely used examples are not good enough.
Your example includes a bug that arguably has no real effect on this program. EDIT: it appears that the IDE is clever enough to workaround language features. Refer to #TartanLlama's answer for details. Perhaps the author could make the claim that it's by design. But it's so rarely the case that clang thankfully saves you from yourself.
C89 §3.3.2.2, "Function calls" includes:
If the expression that precedes the parenthesized argument list in a
function call consists solely of an identifier, and if no declaration
is visible for this identifier, the identifier is implicitly declared
exactly as if, in the innermost block containing the function call,
the declaration
extern int identifier();
appeared
When I first learned that, I thought to myself, "OMG that's not what I wanted at all!" And, so it went with so many other folks that this "feature" was changed in C99.
Clang is per default in GNU C11 mode which is uses C99 semantics. In C99 the implicit function declaration is not allowed anymore.
you can put clang into c89 mode with clang --std=c89 or clang --std=gnu89 which should allow that behavior,
See: Are prototypes required for all functions in C89, C90 or C99?

how can I check a particular gcc feature in configure.ac

For example, gcc 4.7 has a new feature -Wnarrowing. In configure.ac, how can I test where a feature is supported by the current gcc or not?
There's a file in gnulibc, but doesn't make much sense to me.
Both gcc and clang support -W[no-]narrowing and -W[no-]error=narrowing options.
With -std=c++11, gcc emits a warning by default, and clang emits an error by default. Even though you only mention gcc, I think you could extend the functionality check to compilers like clang that attempt to provide the same options and extensions. That might include Intel's icc too.
Let's assume you've selected the C++ compiler with AC_PROG_CXX, and have ensured that it's using the C++11 standard.
ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS -Werror -Wno-error=narrowing"
AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
[[int i {1.0}; (void) i;]])],
[ac_cxx_warn_narrowing=1], [ac_cxx_warn_narrowing=0])
AS_IF([test $ac_cxx_warn_narrowing -ne 0],
[AC_MSG_RESULT(['$CXX' supports -Wnarrowing])])
AC_LANG_POP([C++])
CXXFLAGS="$ac_save_CXXFLAGS"
Compilation will only succeed if: 1) the compiler supports -Wnarrowing related options, which implies it supports -Werror, and: 2) recognizes C++11 initialization syntax.
Normally, configure.ac scripts and flags passed to configure should avoid -Werror, as it breaks too many internal tests. In this context, we ensure there are no other warnings besides the narrowing, which is why (void) i; is needed to prevent a warning about unused variables.
The logic behind this should probably be:
Create a correct file that should get a warning with -Wnarrowing. Verify that it gets compiled correctly. This is a sanity check.
Then compile that same file with -Wnarrowing, and verify that it still gets compiled correctly. This makes sure you detect compilers that don't support -Wnarrowing as an option, and don't attempt to pass bogus options to them.
Finally, compile that same file with -Werror=narrowing, and verify that it now does not get compiled correctly. If it now fails, you can be fairly certain that the compiler does indeed support -Wnarrowing. This last check is useful to detect compilers that do accept -Wnarrowing/-Werror=narrowing, but spit out a warning "ignoring unknown option -Wnarrowing". In that case, you shouldn't be passing -Wnarrowing.
Optionally, you may also want to compile a file that shouldn't get a warning with -Wnarrowing with -Werror=narrowing, in case you find a compiler where -Wnarrowing is useless and -Werror=narrowing is a hard error. I cannot think of a compiler where this would be required, though.
Translating this to a configure check should be trivial.
See http://code.google.com/p/opendoom/source/browse/trunk/VisualC8/autotools/ac_c_compile_flags.m4 for an example test of this sort - this tries to compile a trivial program with the given compiler flag, and adds it to CFLAGS if it works.

gcc detecting "subindex out of bound" error

Surprisingly I found gcc can find this error when it compiles C. I simplified the code which still triggers the warning. I post the question for making clear the details of the techniques it uses. Below is my code of file a.c
int main(){
int a[1]={0};
return(a[1]);
}
My gcc version is gcc (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3. When using gcc a.c -Wall, there is no warning; when using gcc -O1 a.c -Wall, there is a warning:
warning: ‘a[1]’ is used uninitialized in this function [-Wuninitialized]
and when using gcc -O2 a.c -Wall (or -O3), there is another warning:
warning: array subscript is above array bounds [-Warray-bounds]
The most surprising thing is that, when I give a[1] a value, then none of the above compiling options gives any warning. There is no warning even when I change the index to a huge number (of course the compiled file offends the operating system and will be kicked out),
int main(){
int a[1]={0};
a[2147483648]=0;
return(a[2147483648]);
}
I think the above phenomenon is more of a function than a bug. I hope someone help me figure out what happens, and/or why the compiler is designed so. Many thanks!
Accessing memory past the end of the array results in undefined behaviour.
gcc is nice enough to go out of its way to detect, and warn you about, some of these errors. However, it is under no obligation to do so, and certainly cannot be expected to catch all such errors.
The compiler is not required to provide diagnostic for this kind of error, but gcc is often able to help; notice that these warnings often arise in part as a byproduct of the static analysis passes done for optimization purposes, which means that, as you noticed, such warnings often depend from the specified optimization level.