As a C & Objective-C programmer, I'm a bit paranoid with the compiler warning flags.
I usually try to find a complete list of warning flags for the compiler I use, and turn most of them on, unless I have a really good reason not to turn it on.
I personally think this may actually improve coding skills, as well as potential code portability, prevent some issues, as it forces you to be aware of every little detail, potential implementation and architecture issues, and so on...
It's also in my opinion a good every day learning tool, even if you're an experienced programmer.
For the subjective part of this question, I'm interested in hearing other developers (mainly C, Objective-C and C++) about this topic.
Do you actually care about stuff like pedantic warnings, etc? And if yes or no, why?
Now about Objective-C, I recently completely switched to the LLVM toolchain (with Clang), instead of GCC.
On my production code, I usually set this warning flags (explicitly, even if some of them may be covered by -Wall):
- -Wall
- -Wbad-function-cast
- -Wcast-align
- -Wconversion
- -Wdeclaration-after-statement
- -Wdeprecated-implementations
- -Wextra
- -Wfloat-equal
- -Wformat=2
- -Wformat-nonliteral
- -Wfour-char-constants
- -Wimplicit-atomic-properties
- -Wmissing-braces
- -Wmissing-declarations
- -Wmissing-field-initializers
- -Wmissing-format-attribute
- -Wmissing-noreturn
- -Wmissing-prototypes
- -Wnested-externs
- -Wnewline-eof
- -Wold-style-definition
- -Woverlength-strings
- -Wparentheses
- -Wpointer-arith
- -Wredundant-decls
- -Wreturn-type
- -Wsequence-point
- -Wshadow
- -Wshorten-64-to-32
- -Wsign-compare
- -Wsign-conversion
- -Wstrict-prototypes
- -Wstrict-selector-match
- -Wswitch
- -Wswitch-default
- -Wswitch-enum
- -Wundeclared-selector
- -Wuninitialized
- -Wunknown-pragmas
- -Wunreachable-code
- -Wunused-function
- -Wunused-label
- -Wunused-parameter
- -Wunused-value
- -Wunused-variable
- -Wwrite-strings
I'm interested in hearing what other developers have to say about this.
For instance, do you think I missed a particular flag for Clang (Objective-C), and why?
Or do you think a particular flag is not useful (or not wanted at all), and why?
EDIT
To clarify the question, note that -Wall
only provides a few basic warnings.
They are actually a lot more warning flags, not covered by -Wall
, hence the question, and the list I provide.
5 Answers 5
For context, I'm a Clang developer working at Google. At Google, we've rolled Clang's diagnostics out to (essentially) all of our C++ developers, and we treat Clang's warnings as errors as well. As both a Clang developer and one of the larger users of Clang's diagnostics I'll try to shed some light on these flags and how they can be used. Note that everything I'm describing is generically applicable to Clang, and not specific to C, C++, or Objective-C.
TL;DR Version: Please use -Wall
and -Werror
at a minimum on any new code
you are developing. We (the compiler developers) add warnings here for good
reasons: they find bugs. If you find a warning that catches bugs for you, turn
it on as well. Try -Wextra
for a bunch of good candidates here. If one of
them is too noisy for you to use profitably, file a bug. If you write code that
contains an "obvious" bug but the compiler didn't warn about it, file a bug.
Now for the long version. First some background on warning flag groupings. There are a lot of "groupings" of warnings in Clang (and to a limited extent in GCC). Some that are relevant to this discussion:
- On-by-default: These warnings are always on unless you explicitly disable them.
-Wall
: These are warnings that the developers have high confidence in both their value and a low false-positive rate.-Wextra
: These are warnings that are believed to be valuable and sound (i.e., they aren't buggy), but they may have high false-positive rates or common philosophical objections.-Weverything
: This is an insane group that literally enables every warning in Clang. Don't use this on your code. It is intended strictly for Clang developers or for exploring what warnings exist.
There are two primary criteria mentioned above which guide where warnings go in Clang, and let's clarify what these really mean. The first is the potential value of a particular occurrence of the warning. This is the expected benefit to the user (developer) when the warning fires and correctly identifies an issue with the code.
The second criteria is the idea of false-positive reports. These are situations where the warning fires on code, but the potential problem being cited does not in fact occur due to the context or some other constraint of the program. The code warned about is actually behaving correctly. These are especially bad when the warning was never intended to fire on that code pattern. Instead, it is a deficiency in the warning's implementation that causes it to fire there.
For Clang warnings, the value is required to be in terms of correctness,
not in terms of style, taste, or coding conventions. This limits the set of
warnings available, precluding oft-requested warnings such as warning
whenever {}
s are not used around the body of an if
statement. Clang is also
very intolerant of false-positives. Unlike most other compilers it will use
an incredible variety of information sources to prune false positives including
the exact spelling of the construct, presence or absence of extra '()', casts,
or even preprocessor macros!
Now let's take some real-world example warnings from Clang, and look at how they are categorized. First, a default-on warning:
% nl x.cc
1 class C { const int x; };
% clang -fsyntax-only x.cc
x.cc:1:7: warning: class 'C' does not declare any constructor to initialize its non-modifiable members
class C { const int x; };
^
x.cc:1:21: note: const member 'x' will never be initialized
class C { const int x; };
^
1 warning generated.
Here no flag was required to get this warning. The rationale is that this is code is never really correct, giving the warning high value, and the warning only fires on code that Clang can prove falls into this bucket, giving it a zero false-positive rate.
% nl x2.cc
1 int f(int x_) {
2 int x = x;
3 return x;
4 }
% clang -fsyntax-only -Wall x2.cc
x2.cc:2:11: warning: variable 'x' is uninitialized when used within its own initialization [-Wuninitialized]
int x = x;
~ ^
1 warning generated.
Clang requires the -Wall
flag for this warning. The reason is that there is
a non-trivial amount of code out there which has used (for good or ill) the
code pattern we are warning about to intentionally produce an uninitialized
value. Philosophically, I see no point in this, but many others disagree and
the reality of this difference in opinion is what drives the warning under the
-Wall
flag. It still has very high value and a very low
false-positive rate, but on some codebases it is a non-starter.
% nl x3.cc
1 void g(int x);
2 void f(int arr[], unsigned int size) {
3 for (int i = 0; i < size; ++i)
4 g(arr[i]);
5 }
% clang -fsyntax-only -Wextra x3.cc
x3.cc:3:21: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
for (int i = 0; i < size; ++i)
~ ^ ~~~~
1 warning generated.
This warning requires the -Wextra
flag. The reason is that there are very
large codebases where mis-matched sign on comparisons is extremely common.
While this warning does find some bugs, the probability of the code being a bug
when the user writes it is fairly low on average. The result is an extremely
high false-positive rate. However, when there is a bug in a program due to
the strange promotion rules, it is often extremely subtle making this warning
when it flags a bug have relatively high value. As a consequence, Clang
provides it and exposes it under a flag.
Typically, warnings don't live long outside of the -Wextra
flag. Clang tries
very hard to not implement warnings which do not see regular use and testing.
The additional warnings turned on by -Weverything
are usually warnings under
active development or with active bugs. Either they will be fixed and placed
under appropriate flags, or they should be removed.
Now that we have an understanding of how these things work with Clang, let's try to get back to the original question: what warnings should you turn on for your development? The answer is, unfortunately, that it depends. Consider the following questions to help determine what warnings work best for your situation.
- Do you have control over all of your code, or is some of it external?
- What are your goals? Catching bugs, or writing better code?
- What is your false-positive tolerance? Are you willing to write extra code to silence warnings on a regular basis?
First and foremost, if you don't control the code, don't try turning extra warnings on there. Be prepared to turn some off. There is a lot of bad code in the world, and you may not be able to fix all of it. That is OK. Work to find a way to focus your efforts on the code you control.
Next, figure out what you want out of your warnings. This is different for
different people. Clang will try to warn without any options on egregious bugs,
or code patterns for which we have long historical precedent indicating the bug
rate is extremely high. By enabling -Wall
you're going to get a much more
aggressive set of warnings targeted at catching the most common mistakes that
Clang developers have observed in C++ code. But with both of these the
false-positive rate should remain quite low.
Finally, if you're perfectly willing to silence false-positives at every
turn, go for -Wextra
. File bugs if you notice warnings which are catching
a lot of real bugs, but which have silly or pointless false positives. We're
constantly working to find ways to bring more and more of the bug-finding logic
present in -Wextra
into -Wall
where we can avoid the false-positives.
Many will find that none of these options is just-right for them. At Google,
we've turned some warnings in -Wall
off due to a lot of existing code that
violated the warning. We've also turned some warnings on explicitly, even
though they aren't enabled by -Wall
, because they have a particularly high
value to us. Your mileage will vary, but will likely vary in similar ways. It
can often be much better to enable a few key warnings rather than all of
-Wextra
.
I would encourage everyone to turn on -Wall
for any non-legacy code. For
new code, the warnings here are almost always valuable, and really make the
experience of developing code better. Conversely, I would encourage everyone to
not enable flags beyond -Wextra
. If you find a Clang warning that -Wextra
doesn't include but which proves at all valuable to you, simply file a bug
and we can likely put it under -Wextra
. Whether you explicitly enable some
subset of the warnings in -Wextra
will depend heavily on your code, your
coding style, and whether maintaining that list is easier than fixing
everything uncovered by -Wextra
.
Of the OP's list of warnings (which included both -Wall
and -Wextra
) only
the following warnings are not covered by those two groups (or turned on by
default). The first group emphasize why over-reliance on explicit warning flags
can be bad: none of these are even implemented in Clang! They're accepted on
the command line only for GCC compatibility.
-Wbad-function-cast
-Wdeclaration-after-statement
-Wmissing-format-attribute
-Wmissing-noreturn
-Wnested-externs
-Wnewline-eof
-Wold-style-definition
-Wredundant-decls
-Wsequence-point
-Wstrict-prototypes
-Wswitch-default
The next bucket of unnecessary warnings in the original list are ones which are redundant with others in that list:
-Wformat-nonliteral
-- Subset of-Wformat=2
-Wshorten-64-to-32
-- Subset of-Wconversion
-Wsign-conversion
-- Subset of-Wconversion
There are also a selection of warnings which are more categorically different.
These deal with language dialect variants rather than with buggy or non-buggy
code. With the exception of -Wwrite-strings
, these all are warnings for
language extensions provided by Clang. Whether Clang warns about their use
depends on the prevalence of the extension. Clang aims for GCC compatibility,
and so in many cases it eases that with implicit language extensions that are
in wide use. -Wwrite-strings
, as commented on the OP, is a compatibility flag
from GCC that actually changes the program semantics. I deeply regret this
flag, but we have to support it due to the legacy it has now.
-Wfour-char-constants
-Wpointer-arith
-Wwrite-strings
The remaining options which are actually enabling potentially interesting warnings are these:
-Wcast-align
-Wconversion
-Wfloat-equal
-Wformat=2
-Wimplicit-atomic-properties
-Wmissing-declarations
-Wmissing-prototypes
-Woverlength-strings
-Wshadow
-Wstrict-selector-match
-Wundeclared-selector
-Wunreachable-code
The reason that these aren't in -Wall
or -Wextra
isn't always clear. For
many of these, they are actually based on GCC warnings (-Wconversion
,
-Wshadow
, etc.) and as such Clang tries to mimic GCC's behavior. We're
slowly breaking some of these down into more fine-grain and useful warnings.
Those then have a higher probability of making it into one of the top-level
warning groups. That said, to pick on one warning, -Wconversion
is so broad
that it will likely remain its own "top level" category for the foreseeable
future. Some other warnings which GCC has but which have low value and high
false-positive rates may be relegated to a similar no-man's-land.
Other reasons why these aren't in one of the larger buckets include simple bugs, very significant false-positive problems, and in-development warnings. I'm going to look into filing bugs for the ones I can identify. They should all eventually migrate into a proper large bucket flag or be removed from Clang.
I hope this clarifies the warning situation with Clang and provides some insight for those trying to pick a set of warnings for their use, or their company's use.
-
9Outstanding answer! Thanks a lot. I'll need to re-read it a few times, but I'll come back soon with some comments. Thanks again!Macmade– Macmade2011年12月12日 16:34:57 +00:00Commented Dec 12, 2011 at 16:34
-
2@Chandler Carruth: Great answer! But could you maybe update it, if anything has changed? I am using all your warnings on your last list, but maybe some are already moved to Wextra?gartenriese– gartenriese2015年01月19日 21:28:58 +00:00Commented Jan 19, 2015 at 21:28
-
1This is an excellent post. But finding new warnings is, I've found, an extremely good use for a flag, so I'm disappointed that you seem so negatively disposed towards the "everything" group, despite acknowledging that it's useful for this sort of exploration.Kyle Strand– Kyle Strand2015年09月15日 15:03:45 +00:00Commented Sep 15, 2015 at 15:03
-
@Chandler Carruth: I agree with the rationale behind warning about the "never really correct" code. It's just that having no
-Wno
to switch offwarn_no_constructor_for_refconst
makes it PITA to use Boost.ConceptCheck and alike: github.com/boostorg/concept_check/blob/…mloskot– mloskot2019年05月04日 21:08:22 +00:00Commented May 4, 2019 at 21:08 -
Please use -Wall and -Werror at a minimum on any new code you are developing. We (the compiler developers) add warnings here for good reasons: they find bugs. Cheers to that! That cannot be overstated! It's something I've 'preached' for a long time - decades worth of it. FWIW as an IOCCC participant (and a winner too) I can say from that perspective that really warnings are your best friends. The IOCCC judges applaud code that doesn't trigger warnings and they even say try to get a clean compile with Clang -Wall -Wextra -Weverything` - and I quite agree. (1/2)Pryftan– Pryftan2020年01月17日 15:26:13 +00:00Commented Jan 17, 2020 at 15:26
I don't use Clang, but I hope you won't mind having my opinion, too. I also go with the maximum warning level (I assume that's what -Wall means) and with treating warnings as errors (I assume that's what -Werror means) and I only disable those few warnings that don't make much sense. Actually, I am quite annoyed by the fact that certain very useful warnings are not issued by the C# compiler, and one has to run special code analysis tools to see them. I like warnings, because they help me catch little mistakes and bugs in my code. I like them so much, that when a warning is issued for a piece of code that I know is correct, I refactor that piece of code anyway, so that the warning will not be issued, rather than disable the warning, or --even worse-- allow it to appear and ignore it. I think warnings are awesome, and I wish there were more of them.
-
2Thanks for the answer. Unfortunately,
-Wall
provides only basic warnings. A lot of existing warning flags are not covered by-Wall
, hence the list in my question.Macmade– Macmade2011年12月10日 17:17:42 +00:00Commented Dec 10, 2011 at 17:17 -
@Macmade True but there's also
-Wextra
. Personally I find GCC warnings can be more frivolous than Clang's. But that's another matter entirely.Pryftan– Pryftan2020年01月17日 15:36:01 +00:00Commented Jan 17, 2020 at 15:36
I typically go with Xcode's default settings for a new project; it provides a good balance of helpful vs. annoying. Any specific list of warnings and other compiler options will be based largely on either personal preference or project requirements, so I don't think there's a lot of value in trying to go through your list and argue for or against specific warnings. If it works for you, great. If you find that you've made some error that the compiler should be able to detect and you'd like help with that in the future, look for a compiler option to warn about that and turn it on.
One thing that many programmers advocate is turning on the "Treat Warnings as Errors" (-Werror) option to prevent builds from completing with success if there are any warnings.
-
1Thanks for the answer! I agree with
-Werror
. Actually, as I'm using Clang, I set all of these warnings using pragmas (#pragma clang diagnostic), and they are set to fatal errors, so this is the same as-Werror
: )Macmade– Macmade2011年11月30日 22:12:03 +00:00Commented Nov 30, 2011 at 22:12
I think the best evidence that people care about warnings is the fact that they exist and are widely used. I am strongly of the opinion that the more errors caught during compile time, the better. If this wasn't a widely held belief, everyone would be using weak dynamically typed languages, because their compilers or interpreters give you a lot more leeway. To the contrary, even on scripting languages the use of strict
flags is popular. On static strongly typed languages not only do people use -Wall -Werror
frequently, but they often find warnings so valuable that they want even more, so they pay for static analysis tools like Coverity whose sole purpose is providing warnings.
That doesn't mean there aren't detractors. A lot of developers see warnings as working against them in the short term rather than working for them in the long term, and don't try to fix the underlying problem. Hence, you see lovely code like this snippet I came across yesterday:
node = node; // Shut up compiler warning
-
Thanks for your answer. The problem is I often see people working without
-Werror
, and actually ignoring the warnings issued by the compiler. Or if they do, they just usually stick to-Wall
. Most of the flags I provide in my question are not covered by-Wall
, and I personally think they are essential too. So am I just paranoid? ; )Macmade– Macmade2011年12月10日 17:21:49 +00:00Commented Dec 10, 2011 at 17:21 -
Odd... I didn't think they were widely used - even now. I suspect they aren't because humans are lazy and also don't seem to appreciate that there are some things that they might have missed or didn't think of. For some people it's because they refuse to believe they are imperfect/etc. But for others it might be that they don't understand the implications. @Macmade You're not - it's a good idea to enable warnings. Some will be a problem for some projects of course, some are frivolous, they're imperfect but warnings are your friends so you're absolutely right.Pryftan– Pryftan2020年01月17日 15:38:29 +00:00Commented Jan 17, 2020 at 15:38
-
And Karl that shutting up compiling warning right there is hilarious. Thanks for that. It's dangerous of course but it's a hilarious, cheeky way of shutting the compiler up. Do you remember where that was? As in which project? Thanks.Pryftan– Pryftan2020年01月17日 15:40:04 +00:00Commented Jan 17, 2020 at 15:40
-
That was most likely in a proprietary project at work.Karl Bielefeldt– Karl Bielefeldt2020年01月17日 16:42:55 +00:00Commented Jan 17, 2020 at 16:42
-
@Pryftan As a good example of why
-Wall -Werror
is currently obnoxious to me: I'm getting errors that prohibit me from compiling my code because I have a function that's currently unused. Gee, thanks. (Even worse, it's wrong lol.)Andrew– Andrew2021年02月14日 04:28:16 +00:00Commented Feb 14, 2021 at 4:28
Generally, I lean more toward -Wall, and definitely believe in also including -Werror. A module should never have expected warnings. You'll eventually get another warning and miss it. And that will be the one that is actually a problem.
It also depends on whether you are adding "-Wall -Werror" to a new or old project. If it's new, then go for it and demand perfection, otherwise you are probably in for days or weeks of edits and testing. I just did this on an older somewhat small project and I spent two or three days removing the warnings. I think the code is cleaner now.
In other words, try it and see.
Randy
-
2If you're only concerned by
-Wall
and-Werror
, I guess you should re-read the question. Lots of warning flags are not covered by-Wall
. Thanks for the answer, anyway.Macmade– Macmade2011年12月10日 17:16:30 +00:00Commented Dec 10, 2011 at 17:16
-Wwrite-strings
makes it a compiler of a language very similar but not exactly C. For that reason alone I don't use that option. Other than the ones you specify, I use-pedantic -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wlogical-op -Wstrict-aliasing=2
and-Wno-missing-braces -Wno-missing-field-initializers
for the perfectly reasonable initializerstruct whatever obj = {0};
. Also I find that-Wconversion
gives more "spam" than useful warnings :)