Not -Werror considered harmful
rsalsamendi.github.io
rsalsamendi.github.io
If your primary product is a binary (even if you release code too for reference or to be open), by all means, use -Werror (and strictly set the supported compiler).
If your product is code (even if you release binaries too as a convenience), -Werror in the release is an impediment to your users because you've introduced a dependency on a specific compiler version. Think of what will happen when a user tries to use another source library using -Werror... but pinned to a different compiler or compiler version. You've created a problem with your project that your users will have to solve.
You could dictate the the build environment of your users, but that's simply a roundabout way to actually be in the business of releasing binaries.
For some projects, I think you can decide to dictate the use of -Werror (and compiler version) for certain code changes processes, but that's a judgement call, with pros and cons. A strength of open source is that the distinction between user and contributer can be blurry. E.g., imagine a user runs your library on a platform you have neither the time nor expertise to support, finds and fixes some issues and is willing to contribute those changes back... are you sure you want to put them in the position of addressing errors from a toolchain they don't know or understand? Maybe. But maybe not.
And the same exact critique applies to folks saying “-Werror is harmful”. That statement is false unless you also add the limiting principle: “-Werror is harmful in software shipped as source that users build themselves”.
This is a classic case of folks talking past each other. Kinda fun to watch actually.
Also: did anyone write an article titled "'consider harmful' is considered harmful" yet? I am considering writing something like this. I think this genre has a tendency to state an opinion as the final truth with a capital T, and because of that, it tends to provoke argument out of nothing.
No, if you get warnings, it means that your code is (and was already) wrong. And if you wrote wrong code you already have an implicit dependency on your compiler version, as more recent versions with more advanced static analysis may turn a semi-harmless unrecognized UB as a very harmful recognized one (and thus warn). I had this case a few times already, see a simple repro : https://gcc.godbolt.org/z/jY69sas8K
-Werror just makes this dependency explicit.
Further, the compilers are evolving entities written by mere mortals, with their own bugs, occasional poor decisions, and yes, chances to be corrected over time. If the compiler's authors decide a warning is too noisy and disable it in release X, but random linux distro still uses (X - 0.1), should you fix it for them...?
Sure, and I explicitly -Wno- them in that case.
> Further, the compilers are evolving entities written by mere mortals, with their own bugs, occasional poor decisions, and yes, chances to be corrected over time.
Yes, but it is still increasing the chances that someone makes a build of your software with code strongly broken due to UB - that is not a chance anyone should ever ever take
I get dozens of warnings for unused variables, signed unsigned conversions (where the value range is API enforced), etc. . Long ago we had thousands of warnings and went through our code base just to get rid of them, I would be surprised if we fixed even one bug while doing that, most was just adding some verbose construct to be explicit about what was already happening. Warnings can be helpful, which is why I still have them enabled, but not everyone is.
No, that's not right, otherwise they wouldn't be warnings. The whole point of them existing is the compiler trying to alert you of a suspicious construct, but it's not confident enough to be sure it's a bug. Sometimes I want to use assignment for its result–that's not a bug, it's just something that is often done accidentally.
In C and C++ there are a huge number of things that are legal, and thus must not cause an error diagnostic (out of the box) - and yet are obviously not what anybody should do (and so a warning diagnostic is appropriate if the compiler can successfully diagnose them).
You give the example of "sometimes I want to use assignment for its result". A better language outright forbids this. If you want the result, write that, if you want an assignment, write that, if you want both, write both so that it's clear what you intended, and let the optimiser turn your clear program into efficient machine code rather than trying to out-guess the machine.
Ideally warnings would not be red flags. If warnings are stuff like "This variable's name start with a capital letter when that's contrary to standard style guides." or "You keep saying 15 in this program, have you considered just defining a constant instead for whatever 15 is?" then you're in a better place, but unfortunately in C the warning is more likely to be "99.99% of the time this code is a buffer overflow, so, you probably don't mean that" or "It looks like this does X doesn't it? But, it actually does nothing at all, and for complicated reasons we can't make it do X, so, I really hope you didn't mean X."
In my experience it is more likely that 0.01% of the time this signed to unsigned conversion (the one in the if block checking value ranges) can cause issues, please explicitly cast it to silence the warning.
- new compiler versions regularly introduce new warnings, not a bad thing in general of course, but:
- even if your own code is warning-clean (which it really should be!), dependencies are usually full of warnings especially after upgrading compiler versions
- some compilers issue different warnings based on compile settings (e.g. optimization level)
- there's a threshold where picky warnings stop being all that useful. For instance hardly any C/C++ code I've encountered is -Wsign-compare clean, and some APIs are not designed with this sort of warning in mind, so you have the option of littering your code with explicit casts (which makes it less readable), or just ignore that warning and move on.
My own strategy is: enable -Werror for development and keep your own code warning free, while locally supressing warnings in dependencies. For release builds, don't use -Werror (because you can't know what compiler version your users are using).
There's also the theoretical feature that headers included with '#include <...>' don't generate warnings, but I haven't gotten this to work reliably across compilers.
I was already bitten in the backside by Werror. Allow me to tell you how.
I was working on a legacy C++ project and my employer uses an in-house build system that automatically builds the whole dependency tree if any dependency changes. A previous team was a staunch supporter of the "no Werror considered harmful" philosophy, and made it their point to even pass it to unit tests.
That's all fine and dandy, except compilers are upgraded and older compiler versions are deprecated out of our reach. Consequently, when I did a minor update to my project and launched a build job, the entire dependency tree started failing left and right, throwing a million error messages as a packed wall of text. The root cause? The current version of GCC was updated to throw warnings regarding some inane drivel involving white spaces, and with Werror passed everywhere those were upgraded to full blown errors.
The end result was a couple of weeks wasted going through the dependency tree to tackle warnings, because otherwise the build pipeline failed spectacularly.
Sorry but it really was. Passing Werror like confetti was the root cause of a problem that led to two weeks of downtime and added absolutely no value at all, and the solution consisted of addressing said warnings alone. And if there was any doubt, the upgrade was undoubtedly trivial, mainly due to the fact that the project still targeted C++11, and with exception of the Werror nonsense was absolutely flawless.
Alternative solutions which should not have taken two weeks would've included:
-Wno-inane-drivel-involving-white-spaces
-Wno-error=inane-drivel-involving-white-spaces
Just because you're using -Werror doesn't mean literally every single warning in the compiler ever should be a hard error. It means errors should be the default, allowing you to opt-out of stupid warnings-as-errors, rather than needing to opt-in to critical warnings-as-errors.The update after analysis and probably some retesting concluded as trivial, but before undertaking the change I think it has a risk of having the same impact as a change of software.
It’s not -Werror at the root of this general work (yes it turned that way in this specific case), but the analysis and recheck after was the core work from the compiler upgrade.
I suspect you wouldn't enjoy Python.
Also based on which platform they're run on.
> new compiler versions regularly introduce new warnings,
Much worse, IMO is older compiler versions which emit incorrect warnings. At least when a new version emits a new, correct, warning it's at least something you want to fix (or disabling a new unhelpful warning). The failure to compile may still be a practical problem but at least the direction it creates is a right one.
For older compiler versions, there may be no fix-- breaking the code or turning off the warning may be the only options if Werror is used.
Outside of heavily controlled environments, I think Werror is just plain toxic. Want to run it on your CI builds where you don't need to worry about the compiler being upgraded or downgraded without warning? Great! Everyone should do that. Being warning clean on your primary target toolchains(s) is an important move.
For code distributed to users the use of Werror use creates a pressure against introducing new and helpful warnings for compiler authors. Fortunately, it's such a nuisance for code distributed to others that no one survives enabling it for long and the worse damage it likely does is that the few projects that use it for publicly distributed code refrain from enabling many otherwise useful non-default warnings.
I don't see any reason to enable warnings for dependencies in your project's build system. I suggest building dependencies with (as much as possible, considering ABI compatibility) their own preferred compiler flags (and ideally, with their own build systems), and use your compiler's equivalent of `-isystem` to suppress warnings in their headers.
It means your code may fail to compile on future compilers using your provided build scripts. Since C doesn't have a method of enforcing a specific compiler version like newer languages, that's a use case you need to prepare for.
The most recent example I was bitten for with this was with the vendored version of ring used in the redox project. My system had GCC 11, which added a new warning for mixing array and pointer syntax between a function declaration and function definition.
1. This will take a couple weeks of back and forth before the person who filed it either updates to the latest version or admits that the error was in a modification they were working on.
I'd suggest using -Werror for CI builds, passed into CFLAGS or CXXFLAGS by the builder, instead of hardcoding it into the project. Then you get most of the assurances from the article without breaking random stuff downstream.
I think it's a good idea to have -Werror on your internal CI build but not on by default for released tarballs. Especially not if you enable -Weverything as well. That WILL break with almost every compiler update.
If someone wants to build the project with a different compiler, that's fine - they have to make the change and fix any resulting problems, just as if they were changing the version of a library.
In the open source world, the developer can not control which compiler their users will use to try and compile their program. (OK, the article advocates forcing users to use Docker, but that significantly restricts who will be able to use their software.)
This leads to a lot of interesting coding style practices. For a while, I needed to always declare variables at the beginning of my functions because FreeBSD users at the time would make a stink because their compiler back then could not handle variables declared mid-function.
-Werror was unthinkable. More like, -Wall and people would make a stink on the mailing list when they saw compiler warnings. Of course, I would minimize them, but new compiler warnings come up with every GCC update (CLANG makes a lot fewer warnings), and I can just imagine what my GitHub issues page would look like if I were foolish enough to actually use -Werror
The linked article is wrong. Do not, repeat, do not use -Werror in environments where end users will compile the code themselves. Feel free, however, to use -Werror for CI builds on a Docker container with a known version of GCC.
In any professional project I've ever worked on, the compiler version has been strictly controlled. The entire team must use the same version of Visual Studio, or Xcode, or the JDK, or the Android build tools or whatever. You don't just let your developers upgrade whenever they want. Upgrading the build tools is an involved process that must be coordinated with the release cycle. All new warnings need to be fixed, all CI nodes need to be upgraded at once, scripts and metadata need fixes to work with the new tools, etc.
You are only approaching this issue from the perspective of open source software. That is not most software. The parent is correct: the compiler version is a dependency of your project and, in any serious development team, should be fixed for the whole team.
There was a time my open source project was running on Solaris, MacOS X, Linux (multiple distros), and Windows. Making something run only on Docker is a little restrictive by comparison.
There is a difference between being a leaf and a node in a tree of producers and consumers.
As for compiler upgrades breaking things, everyone should be on the same compiler version to begin with. When a new Visual Studio version comes out you don't just let everyone upgrade right away, right? Someone installs it first and fixes up whatever issues arise with the new build tools. Then, at an appropriate point in the release cycle, they give the OK for everyone else to upgrade. Everyone upgrades at once including the CI nodes.
Why would GCC and Clang be any different? A serious project should have developers using a fixed version of GCC and other tools. Of course this doesn't help the random open source contributors who just use their system GCC but that's what --disable-werror is for.
If you have a rule that there must be 0 warnings it has to be on the assumption that compiler warnings are red flags that need to be looked at. So you need to keep that discipline: if a new version of the compiler add warnings and your code trigger them then it means you need to spend the time to look at each occurrence and to 'fix' it.
Which is an advantage. If the compiler issues a warning that triggers your -Werror then your code may contain bugs. A new version of the compiler may introduce a novel optimization step that causes code that takes advantage of some undefined behavior to crash. The way to detect this is to read the compiler warnings.
Essentially, you the developer have only have two choices. 1) Users complaining about random mysterious crashes. 2) Users complaining about not being able to compile your software. 2 is always preferable to 1.
Zero. None. Nada. Zilch.
Mind you, I did have reports of some other compiler (mostly MSVC, but Clang with -Weverything as well) complaining about various weird things, including stuff like using bitwise operations on signed integers, or negation on an unsigned integer. They never lead to the discovery of an actual bug.
On the other hand, one very important thing I did was using sanitizers extensively. ASan, MSan, UBSan, Valgrind, even the TIS interpreter (and now TIS CI), so I could weed out as much undefined behaviour as I could. And boy did those tools find actual bugs. Those, coupled with a proper test suite, will find all the bugs. The bugs I failed to find in time can all be traced with either not using the strictest runtime sanitiser, or a hole in the test suite.
That being said, I still try very hard to be warning-free for most compilers out there. And I mostly am. But this is not about bugs. This is about sparing my users the headache that comes with investigating some trivial warning they should not care about.
Monocypher does not need -Werror.
[1]: I'm joking, he actually didn't.
x25519.c:9:22: warning: '_0' defined but not used [-Wunused-const-variable=] 9 | static const uint8_t _0[16]; | ^~ ed25519.c:302:14: warning: argument 1 of type 'u8[64]' {aka 'unsigned char[64]'} with mismatched bound [-Warray-parameter=] 302 | void HASH(u8 hash[64], const u8 in, size_t inlen); | ~~~^~~~~~~~ In file included from ed25519.c:285: sha512.h:19:29: note: previously declared as 'uint8_t ' {aka 'unsigned char '} 19 | void crypto_sha512(uint8_t out,const uint8_t *input, size_t input_size);
Thus it appears to me that both the benefit and the cost of -Werror for your library is small.
You have to balance the inconvenience of false positives against the consequences of false negatives. If the false negatives are rare enough, compared to the false positives, it might be best not to be cautious.
Still, in practice I am fairly cautious, and tolerate zero warning. When someone reports a warning to me, I always try to fix it. So in practice, what I do is fairly close to -Werror, with one big difference: if some compiler comes up with some new warning, or if a set of compilers are impossible to please at the same time, my users aren't blocked. Which is important, because new warnings are now overwhelmingly likely to be false positives.
That mismatch bound you just showed however does set off my alarm bells. I'll need to make sure I actually got rid of it.
-Werror is just a stop gap desperate measure for when devs are pressured to write crap as quickly as possible. What's exceptional about Monocypher is not really that it's a cryptographic library (though that helps, modern cryptographic code tends to have pathologically simple control flow), it's that I took the time to polish it.
That being said, I am not against static analysis. On the contrary, I am huge fan of strong static type systems, and for languages like C a static analyser can be a huge help. I also trust John Carmack when he says running a static analyser has found non-trivial bugs in real code. But then I want real static analysis, that can assess actual risks of making mistakes. Compilers need to be fast, so their warnings naturally tend to be crude. And if they start complaining about stuff like whitespace in a language where whitespace has no semantics, that may hurt more than it helps.
Yes, it is outrageous that anybody still writes programs in C or C++, which basically guarantee that you'll write oodles of subtle bugs. Yes, static analysis that finds problems that you can't train humans to find is more interesting. Yes, sanitizers and fuzzing should be mandatory for any serious project in C or C++.
But "hey, you've got a vacuously true branch predicate" is valuable in a large number of cases even if humans can catch that with tests, since most organizations are not able to successfully hire only excellent engineers and give them sufficient time to never be rushed.
Just a few weeks ago Google shipped a branch condition that included & rather than && that broke all Chromebook logins. I submit this as evidence that it it not possible to construct a large organization that is resistant to bad code without automation. Yes, a lot of other things needed to go wrong to enable this code to reach production but so many of those processes are either done by humans (and therefore error prone) or produce the same complaints when mandated by automation (e.g., 100% line coverage).
To be fair to C++, that's not the sort of issue that can really be blamed on the language, its unsafety, or its many footguns.
Did they skimp on testing?
But there is a lesson from other forms of engineering here. Almost no failure has a single cause. A variety of things need to go wrong. "Just test better" is not a strategy. Any honest view of large scale software engineering has to internalize that all of the human processes can fail and even the technical processes can fail and so you need layers of protection.
People should try to write correct code. Sometimes they will fail.
People should review code carefully. Sometimes they will fail.
People should test code thoroughly. Sometimes they will fail.
Tooling should automate issue detection with static analysis and fuzzing. Sometimes it will fail.
Tooling should automate issue detection with canaries and monitoring. Sometimes it will fail.
Maybe the team skimped on testing as a rule. Maybe the engineers who submitted and review the code were tired that day and didn't test it well. Maybe something in the the CI was flakey so they did a force push. I don't know.
But I do know that making it harder to do weird things like using bitwise-and in a branch predicate with something other than a constant mask adds an extra layer of defense.
Sure, and perhaps I was mistaken in saying this isn't due to C++'s footguns. The & / && operators do look similar. Ada uses and / and then, which is more distinctive.
Also the fix is simple: -Werror for development builds, but not release builds. This way users can still compile even if they upgraded to a new compiler versions but haven't yet or can't update dependencies.
Instead, if you have a post compile test suite which covers extensively all branches in the code you will catch things like miscompilation that warnings have little chance of catching. And well constructed the tests can have a zero rate of false positives-- which isn't something you'll get from warnings.
So another choice: take the time you'd spend on the sisyphean task of dealing with random failures due to Werror new/old/different toolchains and invest it on making better post compile tests and save the Werror for your CI where its time wastage is more proportional to the benefit it provides.
Even if the compiler doesn't issue a warning that triggers -Werror, your code may contain bugs. This is the root of the false dichotomy you present.
That's a question of the compiler you'd enforce rather than C itself. You could enforce compiling with a specific GCC version, for example-- but you don't want to do that. After all, eventually someone is going to want to run your code on RISC-V or something where the enforced compiler doesn't work.
Language compilation environments themselves are vulnerable to security vulnerabilities, like libraries... Practices previously considered acceptable may become harmful if they are revealed to create common correctness exploits in code. So if code that compiles under a previous version now fails to compile in -Werror on a subsequent version, that's a signal to the maintainer to either fix the code to be in compliance with best practices or manually disable that specific error with an explanation... A signal they'd miss if they didn't turn all the warnings on and stop compilation by default.
Seems fishy. Changing compilers sounds like a hypothetical. If you know you're going to use say GCC on Linux, LLVM on maxOS, and MSVC on Windows then set that up and work through the problems. Otherwise, what future compiler change? Also, once all the warnings have been cleaned up there won't be that many when you change compiler.
How? It’s happened many times before – in the 90s, most people used the platform compilers; then most projects switched to GCC for {price,stability,features}; Mac developers flirted with things like xlc towards the end of the PowerPC era; lots of people switched to LLVM — many projects have scar tissue from those past transitions still scattered around their code and build scripts!
Moreover, you will certainly be switching to newer versions of the same compiler. Your code might fine now but after the compiler team helpfully identifies additional areas for concern the same code will raise new warnings.
> there won't be that many when you change compiler.
When people build your software as a dependency, as in the parents example, any error you didn't cover yet is a problem.
When your project is a dependency for others, I think you've got even more responsibility to use these flags and fix the issues. If not, you're denying your end users the ability to use those options for building their project.
I'm looking at you GTK.
Also: new versions of the same compiler add new warnings, so you need to account for that anyway, unless you want to stick forever on an old compiler version (I've worked on projects where upgrading to a new compiler version was often delayed for exactly that reason).
People often claim that without promoting warnings to be errors and thus stopping compilation that you'll just get a lot of warnings. However in reality most of these warnings just get disabled in the code, and often in a way that disables them for the entire project, meaning that you're missing out on good diagnostic warnings.
The proper way to fix warnings is to keep them as warnings and have it on the team to make sure they don't get out of hand. By making sure when you implement a new feature or fix a bug that you don't introduce new warnings, and also have people investigate warnings and fix them in the correct and sustainable way. In some cases you would disable that warnings but in general they should be fixed by fixing the code. That way you get the benefit of having good diagnostics along with the flexibility of being able to investigate and fix it at a later date.
One final note is that having warnings show up during the compile is a good indicator of how much technical debt there is in the project. If you just end up disabling warnings you're really hiding how bad the code state is.
"Proper"... no, warnings just scroll by and are forgotten. Error stop the build and make you keep the number of them at zero.
If you allow any warnings, they will increase according to the tolerance of the most lax person on your team. And you will never spend the time on the technical debt to clean them. You are accepting an increasing number of things wrong with your codebase that you will never investigate nor regain control of.
Sounds like a bad team/management, not anything to do with werror.
Plenty of groups have no problems maintaining warning free code on a target toolchain without using Werror.
Disrupting what people are working one sometimes encourages "just make it go" fixes that introduce bugs to silence the warning.
If the simplest change that silenced the warning was always the right one the compiler could just do it for you and not warn. :)
Better to be visible and culled promptly than disabled in code and hidden away.
If you start your project with 0 warnings and enforce it in CI it is responsibility of developer who adds the code to make it warnings free and not disable the warning (that needs to be checked in code review).
This is making a lot of assumptions about team dynamics, and fails to account for the person who notices build warnings creep and aggressively sends in patches to fix them.
If you have a lot of warnings then you have a lot of issues with the code. Would you rather have them visible or disabled?
If there are individual warnings that have no meaning, turn them off.
Everything else, is help from the compiler, which is your only friend. Ignoring even one of those should not be tolerated at all. They must be analyzed and the code improved to remove them. And you enforce your team following that policy with -Werror.
At least if they are scrolling by then people can get fed up with that and take some initiative to fix those warnings. Or the new people joining your studio can come in and try to fix them.
It's much more difficult to get people to fix pragmas scattered throughout the code. Which ones were legit, which ones were put in at the last moment out of frustration, which ones were put in temporarily years ago?
I think a softer approach works better since people won't be so quick to work around the compiler by disabling the warnings.
The point is that people often disable them in ways which they shouldn't just so they can compile their code and get on with fixing their bug or implementing their feature. Mainly because warnings get treated like errors and prevent the build from succeeding.
With warnings as warnings we could take a more caretaker approach to dealing with them and we shouldn't have these situations created.
So out of sight and out of mind.
This, do you know people that look at warnings that don't break the code/compilation?
Those are usually ignored, that's why one can promote them to errors.
This way you can still use the compiler to stop you reliably from committing unwanted code constructs.
But other than that, it is a bad idea.
Compiler warnings are just another static analyzer, on equal footing with cppcheck, clang-tidy, etc... It is just convenient because it is built-in. So you can make a policy that in order to push something, it has to pass a variety of automatic checks including compiler warnings, static analysis, unit tests, documentation, coverage, etc... And -Werror can be used for that, though I think it would be better to let the compilation go though to make a complete report.
The big problem with -Werror is that what a compiler considers a warning depends on the version of the compiler. It means you will get new warnings as you upgrade the compiler, so you will be tempted to stay with the old compiler to silence the new warnings, because otherwise, your code stops compiling. Terrible idea.
Another con that is not mentioned is a typical problem when you have strict rules you can't ignore. People will do what it takes to make the warning disappear without actually solving the problem. For example, there is a warning if an enum value is not referenced in a switch/case with no default. It is a very useful warning, it tells you that some case is not implemented, and IMHO, you should leave the warning until it is properly done. But let's say you need to move forward and that annoying -Werror won't let you. You just need to add and empty default case, silencing the warning, not fixing the problem, forgetting it, and shipping buggy code. And maybe you won't do these ugly hacks (really?) but someone else will, I've seen such things done in certified code, the kind that flies airplanes...
[0] https://www.reddit.com/r/cpp/comments/bubg7b/msvc_compiler_w...
[1] https://developercommunity.visualstudio.com/t/c-include-file...
But I would not use -Werror when building existing releases, so you can still build old versions of your code using newer compilers.
This article seems to only consider the pull-request scenario when talking about -Werror being fine, while the open-source people opposing -Werror are mostly concerned with building existing releases.
For example rust's stability guarantees do not cover new warnings, so your code can stop building when upgrading the compiler if you use its -Werror equivalent.
One of the things we finally managed to do at a previous job was "master=live", where a build was automatically triggered that put the product ('just' a website, but still) live in production. While I'm not advocating this per se, you SHOULD put everything in place so that you could do that. (see also: continuous integration vs continuous deployment).
To silence warnings in C without vendor-specific pragmas, people fiddle with the code until the warning goes away. This can be messy, cause bugs, and isn't even guaranteed to work on any other compiler, including a newer version of the same compiler.
So lack of -Werror is harmful, and -Werror is harmful too. C needs to sort it out.
I feel (rather strongly) that the language's standpoint is pretty clear, and that warnings are a message of joy, the compiler is giving you an opportunity to fix a bug before it happens. Why is not "fixing the code" an option? If people don't understand the warning, and resort to "fiddling" to make it go away, that's a warning that there might be some training needed. :)
To "fix" such warnings people add a cast to void, self-assignment, or some other dummy code that makes compiler think it's "used", until you get a compiler with better data flow analysis that can see through the faux-use code.
__attribute__((unused)) solves this properly, but technically it's a GNU extension. And it's just for this warning, not a general solution for hundreds of other warnings you may get.
Other cases:
• Implicit conversion warnings. This can happen due to platform's headers using slightly different types (e.g. disagreeing on signedness). You add an explicit cast, but now there's a third type involved, and if it wasn't the right type, you're worse off.
• Tautological or side-effect-free expressions. Platform-specific code and macros can make them. You add more ifdefs, which is a hit on readability, and more opportunity to mess it up and break a platform you don't have CI for.
• Cast to a type with a higher alignment. It is a common pitfall, and could cause UB, so it's good to be warned about. But if you've done required pointer arithmetic or aligned allocs, you need to be able to say "I know what I'm doing". You can't, apart from trying to obfuscate the code to confuse the compiler (and human readers too probably).
For the first case and third cases, as far as I know casting to void is the offical, supported, language-proper way to say "this value is not being used" so no compiler improvement should break that.
The draft C18 standard says:
If a function call is evaluated as an expression statement for its side effects only, the discarding of its value can be made explicit by converting the expression to a void expression by means of a cast
and (in 6.3.2.2 Void):
If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)
So that sounds like the proper solution, at least for those problems.
Regarding the alignment, I haven't seen that warning I think. This SO answer [1] recommends casting via void *, but that might count as an "obfuscation"; I would count it as just that, a "I'm know what I'm doing"-statement. :)
[1] https://stackoverflow.com/questions/33218873/how-to-properly...
That doesn't have a date on the page but there's an HN link back at least to 2015 and I think it's older than that.
Edsger W. Dijkstra’s note in the March 1968 Communications of the ACM, “Go To Statement Considered Harmful,”
I personally tend to not read these pieces anymore. I'm over my "I have strong opinions, and that's my style. Get used to it" style of writing quota for quite some time.
Perhaps you mean we should disregard titles like that?
I think it's a fine title for a polemic. You can interpret and grant as much weight as you like based on the presented arguments and the author's bona fides. Just like any other essay.
"Everything you always wanted to know about X, but were afraid to ask"
"How I learnt to stop worrying and love X"
For me personally, at this point, I have seen so many articles and conference talks with one of those titles, it's starting to genuinely annoy me. Thankfully, the 2016 trend of "make X great again" didn't last that long.
For Con #3, "make I=0" flag is cute, but the final "make" doesn't actually work. Any files that had warnings but still compiled successfully will not get recompiled. The simplest workaround is to "make clean" first but this can be time consuming (ccache helps.) Another workaround is a script that touches any unclean or just-committed git files but this is error-prone. It's possible to have "make" rebuild any files that were built with I=0 but it adds a lot more Makefile complexity. And in any case all of these are manual workarounds that are easy to forget.
For Con #4, a docker image doesn't help you build for Windows or macOS. You need full VMs to test on them (and a macOS VM violates the license, so technically you need a full Mac somewhere you can SSH into.) This process can be optimized pretty well but it's still another manual step.
But "just build it using Docker" is a pretty awful solution. Doing stuff in Docker is just extra pain in general, and it doesn't even work on Mac or Windows.
I think a better option I've seen is just to have a config flag to disable `-Werror`.
Docker doesn’t work in any of the BSDs, it doesn’t work in Solaris, it doesn’t work in HaikuOS, and it doesn’t work in anything resembling an embedded space. Saying “you must use Docker to compile my software” severely limits where it can actually be used.
I say all this as someone who uses a Docker container for my CI testing step (once a day whenever my code is changed, I compile and test it in a Docker container).
That's no help if you're building software for Mac or Windows.
I wonder if they are working on a Mac solution.
Right. If everyone downstream of you replicates your exact environment, then they won't see anything out of -Werror that you don't see.
Proof by Docker; QED.
For the rest of us who build programs that have to work with a wide range of compiler and compiler versions, we don't want to create work for the downstream packagers.
I don't want some downstream packaging person to be wasting their time non-productively adding "compiler shut-up patches" over top of my program because their distro is on a newer compiler, and my package drew attention to itself by suddenly failing to build. Or worse: not satisfied with shut-up patches, but they start digging into the failing code, decide that there are real problems and start fixing things, without contacting upstream.
If you take care of your warnings as a matter of habit, then your program builds quietly. When new diagnostics appear in the compiler, they stand out very boldly against your previously quiet build.
Warnings don't break the build for your downstream users; they just render it noisy. When you upgrade your compiler (perhaps due to being tipped off by thoser users), you see the noise too, and you can do something about it. You can do something about it in an official way that is committed to your trunk. The downstream people pick that up, and things are quiet again on their end also.
-Werror can be useful if you inject it into your builds externally, without committing that into the build system that ships with the program, so that other consumers of the program outside of your CI environment aren't impacted by it. It just says that, "for us, in this shop, with the version of the compiler that we have currently installed on our farm, we are treating all warnings as errors (so that changes which introduce warnings cannot pass review)."
Lone FOSS developers working by themselves (or in collaboration with others via patches) don't need that; just the habit of keeping the build clean of all warnings. The commit gatekeeping person builds everything and if they notice warnings, they can push back on the patch; no need for -Werror since a human is involved rather that simple build robot that only goes by the exit status of the build without looking at the output.
How to deal with different toolchains having different approaches to what warnings are enabled? Assertively disable the handful of stupid warnings like -Wno-unused-parameter, and have your CI encompass most toolchains such that the union of their warnings is your target and break build if any blow warnings.
Then you will have something robust and portable.
Yes, new compilers are able to get new insight into what is broken with your code. You can either:
a) ignore that and let your users continue with the brokenness, since that is convenient at build-time (but the consequent failures in the field of whatever that code is integrated in may be extremely inconvenient for all downstream users)
b) learn about it, and fix your code upstream so all users can benefit from the fixes
If you ever decide on to do formal verification of your code, getting it into shape will probably take as much as the verification itself.
Being super-duper strict from day 1 of the project makes it so much easier.