103

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
  • 9
    I'm tempted to say this probably should've stayed on Stack Overflow, since it's kind of a question about tool usage, but we'll see how the community swings.
    – Adam Lear
    Commented Nov 30, 2011 at 21:32
  • Thanks for the comment : ) In a way, I agree with you, and that's why I originally posted this on StackOverflow (also because I'm not a regular user here, shame on me). Got a lot of views, upvotes, etc... But not a single answer... And as people suggested to move it... Well, let's see : )
    – Macmade
    Commented Nov 30, 2011 at 21:35
  • 1
    Well, I hope we can give you a good answer. Good luck. :)
    – Adam Lear
    Commented Nov 30, 2011 at 21:36
  • 1
    For C and gcc, -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 initializer struct whatever obj = {0};. Also I find that -Wconversion gives more "spam" than useful warnings :)
    – pmg
    Commented Dec 9, 2011 at 15:10
  • Not worthy of an answer but... I always enable -Wall (mind you I'm talking C). I find that unused parameter can be annoying (sometimes you only have to have it for e.g. a callback prototype or some such like signal handlers). Also I find the Clang warning that tells you that the function/variables haven't been declared previously unless you have them in a header file or declare them static - even when you're declaring/defining them there and before usage - annoying. There are a few others in there I don't like but worse of all is GCC's misleading indentation warning. Great question.
    – Pryftan
    Commented Jan 17, 2020 at 15:53

5 Answers 5

177
+100

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.

9
  • 9
    Outstanding 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
    Commented 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? Commented Jan 19, 2015 at 21:28
  • 1
    This 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. Commented 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 off warn_no_constructor_for_refconst makes it PITA to use Boost.ConceptCheck and alike: github.com/boostorg/concept_check/blob/…
    – mloskot
    Commented 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
    Commented Jan 17, 2020 at 15:26
3

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.

2
  • 2
    Thanks 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
    Commented 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
    Commented Jan 17, 2020 at 15:36
1

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.

1
  • 1
    Thanks 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
    Commented Nov 30, 2011 at 22:12
1

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
5
  • 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
    Commented 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
    Commented 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
    Commented Jan 17, 2020 at 15:40
  • That was most likely in a proprietary project at work. Commented 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
    Commented Feb 14, 2021 at 4:28
1

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

1
  • 2
    If 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
    Commented Dec 10, 2011 at 17:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.