C, C++, x86/x64 assembly: The case of forgotten return
yurichev.com
yurichev.com
I've actually had some pieces of code where it was super useful to enable that padding warning as an error. Some complicated C++ types that needed to have identical memory layouts across compilers yet often weren't because of some really nasty shenanigans...
-Weverything is for people who really want to explicitly opt out of every warning they don't like.
Instead, do any of the following:
* Compile normally without -Werror, but have a test suite which compiles all your tests with -Werror. Make sure to only accept patches which don't break the test suite (probably using some CI system). If you don't want actual tests, a "test suite" which just makes sure `make clean && make CFLAGS=-Werror` doesn't fail would suffice.
* Use -Werror for regular builds, but enable only a fixed set of warnings, not -Wall or -Werror.
* Make your build system record warnings, and complain about them for every single build, not just the builds which happen to recompile the files which trigger warnings. This doesn't _guarantee_ that your project is warning-free like the other two do, but I imagine a lot of the reason projects end up with warnings is that people just see the warning once, and then never again until the file has to be recompiled.
I can't count the number of times I have wanted to use some project, but then had to dig through the project's Makefile or autotools m4/shell soup or gn files or meson files or cmake files or ad-hoc compile script or some other build configuration, just because my compiler is newer than the author's.
FTFY. It's fine to use them for development, but a major pain in the ass if you are distributing your code for others to compile (looking at you, google).
The three alternatives were meant as somthing easy one could do instead of blindly using using -Werror to achieve the same advantages, but there are of course more ways to do it.
I have also had the fortune of using Goole code. I have been meaning to write a blog post about the issues one encounters when using a Goole library without being a part of Google.
You could also use -Wno-error=unused-variable, but I find warnings as warnings almost completely pointless outside of extremely niche circumstances. I will lose them in a sea of other errors when a template goes awry, and after fixing that and building again the warning will disappear because the TU with said warning didn't need rebuilding.
It's not that it's usually _hard_ to figure out how to disable -Werror. In a correctly written Makefile, it's literally just `make CFLAGS=-Wno-error`. It's about having to figure it out at all. Don't make life annoying for every one of your users just because you're too lazy to set up your project such that builds used while developing (such as debug builds) use -Werror, while regular builds don't.
If you absolutely need every build to use -Werror, then please, just include your build system's version of `CFLAGS=-Wno-error` in your readme's compile instructions (even when using make; `CFLAGS=-Wno-error` works for _correctly written_ makefiles, which most makefiles are not.)
I absolutely don't understand what stockholm syndrome has to do with anything. I haven't advocated for any particular build system.
Assuming your answer to that is the same as mine. If you always have a build system where you can change flags easily, without thought very quickly, you do use Werror. We frequently (always?) don't have such a build system and we're used to that. We're prisoners of it. It sucks. C build systems are utterly terrible. We're captured by them. Whether it's autotools, cmake, scons, a bajillion make files used directly or whatever. I think acknowledging it is reasonable. I think claiming they are other than terrible is stockholm syndrome. (Note that they may not be capable of being improved, there may be nothing better, etc etc. - I make no claims about it).
Not using a flag because it makes life hard when the compiler is upgraded and the flag needs to be changed is a build system issue. Really.
100% disagree. If compilers add new warnings it's because they have new insights in your code, and old invalid but "working" code may not work at all in the newer version and eat your hard disk. So instead of risking your data, just accept that it won't work with this newer version of the language.
Unused variables, using `if (somevar = othervar)` instead of `if ((somevar = othervar))`, code which uses operators without parentheses where GCC has decided the operator precedence is unexpected and should have extra parentheses to be clearer, a switch which doesn't cover all the values of an enum, unnecessary parentheses in a variable declaration. Those are all warnings which absolutely don't mean that the code is broken. The author should absolutely fix new warnings like that, but that shouldn't be the responsibility of someone who just wants to use your open source project.
BTW, a few years ago we had a nasty bug (feature?), that might have been prevented when converted into error, but... "because we always have very large build logs I didn't notice the new warning." http://0x80.pl/notesen/2015-03-22-compiler-warnings.html
-Wall -Wextra -Werror=return-type
$ pbpaste | g++-8 -x c++ -
<stdin>: In function 'color* create_color(int, int, int)':
<stdin>:19:1: warning: no return statement in function returning non-void [-Wreturn-type]But you mentioned g++: not sure when this became invalid in c++ but for me g++ -std=17 warns by default (though we compile everything with maximum possible warnings already)
In the ISO C++ language, I vaguely seem to recall ("I could have sworn that") that failing to return a value from a function is a diagnosable semantic rule violation. And that it has been for a very long time.
So I fully sympathize with the "mind is blown" comment in grandparent.
Hey, g++ -pedantic catches some important semicolon trespasses, though:
noreturn.cc:19:2: warning: extra ‘;’ [-pedantic]
noreturn.cc:25:2: warning: extra ‘;’ [-pedantic]
:)GCC 5.4 is more than two years old; the current version is 8.2¹.
I know a company that paid a considerable amount of money to am outside team to get the current release of GCC running on their no longer supported version of RHEL.
A valid C program is not allowed to fall off the end of a non-void function without returning a value if the return value is used. This means that if the optimizer sees a function which will always do this, it "knows" that you never call it (as if you did, your program would be invalid). Since the function is never called, there's no point in emitting any code for the body of the function. It still needs to emit a small stub, as you could legally take the address of it.
As it so happens your program does call this function. This makes your program not a valid C program, and so the standard says nothing about how it should behave.
The C language itself does not prevent you from invoking these footguns. Why, I don't know for sure; I wasn't around for the genesis of C. I would guess that if C were designed today, most of the undefined behavior that can be detected statically would just be errors.
Of course, compilers are allowed to optimize assuming your code does not utilize undefined behavior. This is reasonable in my opinion. If the compiler were not allowed to optimize in ways that broke undefined behavior, it would be nearly impossible to write meaningful compiler optimizations. Most compiler optimizations change the semantics of the execution even though they keep the semantics of the program itself identical according to the rules of the C language. Where would you draw the line? If I monkey patch a function that my compiler decided to inline, would I have reason to complain?
In the face of C seeing your completely unused side-effects, it knows there is no possible way your program could ever actually touch those side-effects in the bounds of defined behavior. Therefore, it is free to throw them away. This may seem unreasonable, but in my opinion it's nearly the only reasonable choice.
To me the real solution is something like -Wall -Werror. For most statically detectable invocations of undefined behavior, this will save you, throwing an error in this case because "not all codepaths return a value." Then, you can sleep easy without sacrificing decent dead-code elimination.
I just wanted to point out that for me, C is more for embedded code, where modifying random parts of memory is a common task. So saying that a function that filled a pointer, used it to reset or set some parts of memory can be removed just because it does not have a return seems a bit extreme, but I agree that it is allowed.
I often see people pushing for -Wall and -Werror. In most professional projects I have been in, though, we have to use black boxes (or, currently, non-standard compilers) that prevent correcting many warnings. I wish we had a finer granularity there but well...
No, it's a compiler implementation detail, not a C/++ specification.
Given that no return is undefined behavior (6.6.3 c++ standard) this probably should just be treated as an error. (it would be nice if a manifested return was value/default init but it is not)
The reason why these are not errors in the compiler is for backwards compatibility.
In C reaching the end of a non-void function is not undefined behaviour though. It's equivalent to ending with a return; However attempting to use the return value of that function is undefined behaviour. It'd be fine to have that warning be an error when compiling for C++, but not for C.
C89 3.6.6.4 (http://port70.net/~nsz/c/c89/c89-draft.html#3.6.6.4): "If a return statement without an expression is executed, and the value of the function call is used by the caller, the behavior is undefined. Reaching the } that terminates a function is equivalent to executing a return statement without an expression."
From 6.9.1 - "If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined"
Though 6.8.6.4 also says "A return statement without an expression shall only appear in a function whose return type is void"
So it seems like a non-void function hitting the end of the block without a return statement is allowed (provided the value isn't used). But having a "return;" in that function would not be in C11.