Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase compiler warnings #528

Open
DanRStevens opened this issue Mar 18, 2020 · 11 comments
Open

Increase compiler warnings #528

DanRStevens opened this issue Mar 18, 2020 · 11 comments

Comments

@DanRStevens
Copy link
Collaborator

DanRStevens commented Mar 18, 2020

We should strive to increase compiler warning options.

In #510, there were links to some useful external resources for warning flags (GCC):

References:
GCC: 3.8 Options to Request or Suppress Warnings
StackOverflow: How to turn on (literally) ALL of GCC's warnings?
Best GCC warning flags for compiling C++

Edit: Diagnostic flags in Clang


As noted in the links, you very likely do not want to enable all possible warning flags, as some may not make sense for modern code, and some may even be contradictory. Nevertheless, it's hard to know what warnings are available, or applicable to your code, without some way to turn them on. Conveniently Clang provides the -Weverything flag for such a purpose.

I experimented with Clang by enabling the -Weverything option, and then trying to disable warnings until the project was able to build again without warnings or errors. For each warning seen, I disabled it by adding the no- prefix to the flag name. The resulting command that got the project compiling cleanly again was:

make CXXFLAGS_EXTRA="-Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-documentation -Wno-documentation-unknown-command -Wno-weak-vtables -Wno-comma -Wno-sign-conversion -Wno-double-promotion -Wno-ctad-maybe-unsupported -Wno-cast-qual -Wno-old-style-cast -Wno-padded -Wno-missing-variable-declarations -Wno-float-equal -Wno-exit-time-destructors -Wno-inconsistent-missing-destructor-override -Wno-global-constructors -Wno-date-time -Wno-newline-eof -Wno-unreachable-code-break -Wno-shadow-field"

Edit: The reverse set of flags, to turn on all the warnings that produce errors, the command is:

make CXXFLAGS_EXTRA="-Wc++98-compat -Wc++98-compat-pedantic -Wdocumentation -Wdocumentation-unknown-command -Wweak-vtables -Wcomma -Wsign-conversion -Wdouble-promotion -Wctad-maybe-unsupported -Wcast-qual -Wold-style-cast -Wpadded -Wmissing-variable-declarations -Wfloat-equal -Wexit-time-destructors -Winconsistent-missing-destructor-override -Wglobal-constructors -Wdate-time -Wnewline-eof -Wunreachable-code-break -Wshadow-field"

Some of those are not of interest. In particular, we explicitly use C++17 features, and so we don't care about code that breaks compatibility with C++98. Other flags however do seem to suggest there are things we could improve upon. In particular, unknown commands in Doxygen comments, abuse of the comma operator, unexpected conversions, missing override declarations, no newlines at end of file, unreachable code, and old style casts.


The last link recommended the following flags.
New:

-Wredundant-decls
-Wmissing-declarations
-Wmissing-prototypes
-Wmissing-include-dirs
-Wswitch-enum
-Wswitch-default
-Winvalid-pch
-Wmissing-format-attribute
-Wformat=2

Redundant:

-Wformat-nonliteral  (included in `-Wformat=2`)

Existing:

-Werror
-Wextra
-Wall
-Wcast-align

There was also mention of -Weffc++ (based on the book Effective C++), though with the suggestion that it wasn't very good, and was pretty noisy. There was also mention of -Wodr (One Definition Rule), which was recommended.

Another flag I encountered while paying around was -Wunused-function.

DanRStevens added a commit that referenced this issue Mar 18, 2020
Add a bunch of warning flags based on an article linked by issue #528.
From those, a couple of warning flags were omitted. The `-Wformat=2` was
omitted due to the `string_format` method, which generates warnings from
the unit tests (and is the only place the method is now called from).
Additionally the `-Wmissing-prototypes` flag was removed since it was
not understood by GCC-7 nor by GCC-8.
DanRStevens added a commit that referenced this issue Mar 18, 2020
Add a bunch of warning flags based on an article linked by issue #528.
From those, a few warning flags were omitted.

- `-Wformat=2` due to the `string_format` method, which generates
warnings from the unit tests (and is the only place the method is now
called from).
- `-Wmissing-prototypes` since it was not understood by GCC-7 nor by
GCC-8.
- `-Wredundant-decls` since this caused problems with Mingw-w64 and SDL.
This was referenced Mar 18, 2020
@cugone
Copy link
Contributor

cugone commented Mar 18, 2020

Here's another good list of compiler warnings to enable (and some not) for The Big Three by Jason Turner.

For reference:

Compilers

Use every available and reasonable set of warning options. Some warning options only work with optimizations enabled, or work better the higher the chosen level of optimization is, for example -Wnull-dereference with GCC.

You should use as many compilers as you can for your platform(s). Each compiler implements the standard slightly differently and supporting multiple will help ensure the most portable, most reliable code.

GCC / Clang

-Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic

  • -Wall -Wextra reasonable and standard
  • -Wshadow warn the user if a variable declaration shadows one from a parent context
  • -Wnon-virtual-dtor warn the user if a class with virtual functions has a non-virtual destructor. This helps catch hard to track down memory errors
  • -Wold-style-cast warn for c-style casts
  • -Wcast-align warn for potential performance problem casts
  • -Wunused warn on anything being unused
  • -Woverloaded-virtual warn if you overload (not override) a virtual function
  • -Wpedantic (all versions of GCC, Clang >= 3.2) warn if non-standard C++ is used
  • -Wconversion warn on type conversions that may lose data
  • -Wsign-conversion (Clang all versions, GCC >= 4.3) warn on sign conversions
  • -Wmisleading-indentation (only in GCC >= 6.0) warn if indentation implies blocks where blocks do not exist
  • -Wduplicated-cond (only in GCC >= 6.0) warn if if / else chain has duplicated conditions
  • -Wduplicated-branches (only in GCC >= 7.0) warn if if / else branches have duplicated code
  • -Wlogical-op (only in GCC) warn about logical operations being used where bitwise were probably wanted
  • -Wnull-dereference (only in GCC >= 6.0) warn if a null dereference is detected
  • -Wuseless-cast (only in GCC >= 4.8) warn if you perform a cast to the same type
  • -Wdouble-promotion (GCC >= 4.6, Clang >= 3.8) warn if float is implicit promoted to double
  • -Wformat=2 warn on security issues around functions that format output (ie printf)
  • -Wlifetime (only special branch of Clang currently) shows object lifetime issues

Consider using -Weverything and disabling the few warnings you need to on Clang

-Weffc++ warning mode can be too noisy, but if it works for your project, use it also.

MSVC

/permissive- - Enforces standards conformance.

/W4 /w14640 - use these and consider the following (see descriptions below)

  • /W4 All reasonable warnings
  • /w14242 'identfier': conversion from 'type1' to 'type1', possible loss of data
  • /w14254 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
  • /w14263 'function': member function does not override any base class virtual member function
  • /w14265 'classname': class has virtual functions, but destructor is not virtual instances of this class may not be destructed correctly
  • /w14287 'operator': unsigned/negative constant mismatch
  • /we4289 nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside the for-loop scope
  • /w14296 'operator': expression is always 'boolean_value'
  • /w14311 'variable': pointer truncation from 'type1' to 'type2'
  • /w14545 expression before comma evaluates to a function which is missing an argument list
  • /w14546 function call before comma missing argument list
  • /w14547 'operator': operator before comma has no effect; expected operator with side-effect
  • /w14549 'operator': operator before comma has no effect; did you intend 'operator'?
  • /w14555 expression has no effect; expected expression with side-effect
  • /w14619 pragma warning: there is no warning number 'number'
  • /w14640 Enable warning on thread un-safe static member initialization
  • /w14826 Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior.
  • /w14905 wide string literal cast to 'LPSTR'
  • /w14906 string literal cast to 'LPWSTR'
  • /w14928 illegal copy-initialization; more than one user-defined conversion has been implicitly applied

Not recommended

  • /Wall - Also warns on files included from the standard library, so it's not very useful and creates too many extra warnings.

General

Start with very strict warning settings from the beginning. Trying to raise the warning level after the project is underway can be painful.

Consider using the treat warnings as errors setting. /Wx with MSVC, -Werror with GCC / Clang

DanRStevens added a commit that referenced this issue Mar 20, 2020
Add a bunch of warning flags based on an article linked by issue #528.
From those, a few warning flags were omitted.

- `-Wformat=2` due to the `string_format` method, which generates
warnings from the unit tests (and is the only place the method is now
called from).
- `-Wmissing-prototypes` since it was not understood by GCC-7 nor by
GCC-8.
- `-Wredundant-decls` since this caused problems with Mingw-w64 and SDL.
@DanRStevens
Copy link
Collaborator Author

DanRStevens commented Mar 20, 2020

Bit of an update.

The bulk of the recommended flags from the link in the first post were enabled by #539, with a few exceptions:

  • -Wformat=2 - conflicts with string_format, used by unit tests, and downstream OPHD
  • -Wformat-nonliteral (included in -Wformat=2)`

Additionally, the following flags were partially enabled, with exceptions:

The following 3 enabled flags have exlusions:

  • -Wmissing-prototypes - Clang only (flag not supported by GCC)
  • -Wredundant-decls - Excluded for Mingw-w64, due to conflicts with builtins
  • -Wcast-function-type (enabled by -Wextra) - Excluded for GCC-8, due to warnings about casts used by Delegate code, which likely won't be fixed anytime soon.

The flag -Weffc++ was found to produce warnings with GCC. Some of them look like they should be fixed. Perhaps not all of them should be.


The following miscellaneous fix was made:


For the Clang -Weverything section, the following warning flags now have fixes merged:

Remaining flags that produce warnings are:

make CXXFLAGS_EXTRA="-Wc++98-compat -Wc++98-compat-pedantic -Wdocumentation -Wdocumentation-unknown-command -Wweak-vtables -Wcomma -Wsign-conversion -Wdouble-promotion -Wctad-maybe-unsupported -Wcast-qual -Wpadded -Wmissing-variable-declarations -Wfloat-equal -Wexit-time-destructors -Winconsistent-missing-destructor-override -Wglobal-constructors -Wdate-time"

The complement of that, which enables -Weverything, and then selectively disables warnings is:

make CXX=clang++-9 CXXFLAGS_EXTRA="-Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-documentation -Wno-documentation-unknown-command -Wno-weak-vtables -Wno-comma -Wno-sign-conversion -Wno-double-promotion -Wno-ctad-maybe-unsupported -Wno-cast-qual -Wno-padded -Wno-missing-variable-declarations -Wno-float-equal -Wno-exit-time-destructors -Wno-inconsistent-missing-destructor-override -Wno-global-constructors -Wno-date-time"

Updating to Clang-11 (instead of Clang-9), the following additional warning is detected:

  • -Wimplicit-int-float-conversion

@DanRStevens
Copy link
Collaborator Author

From the GCC Warning Options page, the -Wall flag enables the following:

-Waddress   
-Warray-bounds=1 (only with -O2)  
-Wbool-compare  
-Wbool-operation  
-Wc++11-compat  -Wc++14-compat  
-Wcatch-value (C++ and Objective-C++ only)  
-Wchar-subscripts  
-Wcomment  
-Wduplicate-decl-specifier (C and Objective-C only) 
-Wenum-compare (in C/ObjC; this is on by default in C++) 
-Wenum-conversion in C/ObjC; 
-Wformat   
-Wint-in-bool-context  
-Wimplicit (C and Objective-C only) 
-Wimplicit-int (C and Objective-C only) 
-Wimplicit-function-declaration (C and Objective-C only) 
-Winit-self (only for C++) 
-Wzero-length-bounds 
-Wlogical-not-parentheses 
-Wmain (only for C/ObjC and unless -ffreestanding)  
-Wmaybe-uninitialized 
-Wmemset-elt-size 
-Wmemset-transposed-args 
-Wmisleading-indentation (only for C/C++) 
-Wmissing-attributes 
-Wmissing-braces (only for C/ObjC) 
-Wmultistatement-macros  
-Wnarrowing (only for C++)  
-Wnonnull  
-Wnonnull-compare  
-Wopenmp-simd 
-Wparentheses  
-Wpessimizing-move (only for C++)  
-Wpointer-sign  
-Wreorder   
-Wrestrict   
-Wreturn-type  
-Wsequence-point  
-Wsign-compare (only in C++)  
-Wsizeof-pointer-div 
-Wsizeof-pointer-memaccess 
-Wstrict-aliasing  
-Wstrict-overflow=1  
-Wswitch  
-Wtautological-compare  
-Wtrigraphs  
-Wuninitialized  
-Wunknown-pragmas  
-Wunused-function  
-Wunused-label     
-Wunused-value     
-Wunused-variable  
-Wvolatile-register-var

The -Wextra flag enables the following:

-Wclobbered  
-Wcast-function-type  
-Wdeprecated-copy (C++ only) 
-Wempty-body  
-Wignored-qualifiers 
-Wimplicit-fallthrough=3 
-Wmissing-field-initializers  
-Wmissing-parameter-type (C only)  
-Wold-style-declaration (C only)  
-Woverride-init  
-Wsign-compare (C only) 
-Wstring-compare 
-Wredundant-move (only for C++)  
-Wtype-limits  
-Wuninitialized  
-Wshift-negative-value (in C++03 and in C99 and newer)  
-Wunused-parameter (only with -Wunused or -Wall) 
-Wunused-but-set-parameter (only with -Wunused or -Wall)

Note that -Wall implies -Wunused, which implies all the sub-flags for unused items.


Given that list, we may be specifying redundant warning flags, which are already enabled by another group flag.

@DanRStevens
Copy link
Collaborator Author

Going through the list of possible additional warnings in this thread, the following additional flags appear to be potentially useful:

-Wshadow
-Wnon-virtual-dtor
-Wold-style-cast
-Wcast-align
-Woverloaded-virtual
-Wconversion
-Wsign-conversion
-Wduplicated-cond
-Wduplicated-branches
-Wlogical-op
-Wnull-dereference
-Wuseless-cast
-Wdouble-promotion
-Wformat=2
-Wlifetime
-Weffc++

The following are already included by -Wall:

-Wmisleading-indentation
-Wunused
-Wunused-function

@DanRStevens
Copy link
Collaborator Author

Looking through remaining Clang warnings:

make CXXFLAGS_EXTRA="-Wc++98-compat -Wc++98-compat-pedantic -Wdocumentation -Wdocumentation-unknown-command -Wweak-vtables -Wcomma -Wsign-conversion -Wdouble-promotion -Wctad-maybe-unsupported -Wcast-qual -Wpadded -Wmissing-variable-declarations -Wfloat-equal -Wexit-time-destructors -Winconsistent-missing-destructor-override -Wglobal-constructors -Wdate-time"

Uninteresting:

  • -Wc++98-compat (targeting C++17)
  • -Wc++98-compat-pedantic

Largely uninteresting:

  • -Wpadded (Overall structure sizes are uninteresting. Padding for fields may be interesting)
  • -Wfloat-equal (Compare against 0 not interesting, template object compare not interesting)

Mildly interesting:

  • -Wdate-time (Can potentially tag builds with Git commit hashes or tags instead)
  • -Wexit-time-destructors (Libraries should avoid declaring many globals)
  • -Wglobal-constructors (Libraries should avoid declaring many globals)

Interesting:

  • -Wdocumentation (Some documentation is inconsistent with declared parameters)
  • -Wdocumentation-unknown-command (Unknown command \fixme)
  • -Wweak-vtables (Move virtual function implementation from header to source file)
  • -Wcomma (Comma operator abuse)
  • -Wsign-conversion (Implicit signed/unsigned conversions)
  • -Wdouble-promotion (Implicit conversions float to double)
  • -Wctad-maybe-unsupported (Point and Rectangle have no deduction guides)
  • -Wcast-qual (All warnings already fixed)
  • -Wmissing-variable-declarations (Declare or wrap in unnamed namespace)
  • -Winconsistent-missing-destructor-override (Use override keyword)

@DanRStevens
Copy link
Collaborator Author

I went through the list of recommended GCC warning flags. I was able to add:

-Wshadow
-Wnon-virtual-dtor
-Wold-style-cast
-Wcast-align
-Woverloaded-virtual
-Wnull-dereference
-Wdouble-promotion

For the Clang flags, the following had all warnings fixed:

-Wdocumentation (Some documentation is inconsistent with declared parameters)
-Wdocumentation-unknown-command (Unknown command \fixme)
-Wcomma (Comma operator abuse)
-Wdouble-promotion (Implicit conversions float to double)
-Wcast-qual (All warnings already fixed)
-Winconsistent-missing-destructor-override (Use override keyword)

Some of the flags listed for Clang also worked with GCC:

-Wdouble-promotion (Implicit conversions float to double)
-Wcast-qual (All warnings already fixed)

Remaining GCC flags that have not been enabled:

-Wconversion
-Wsign-conversion
-Wduplicated-cond
-Wduplicated-branches
-Wlogical-op
-Wuseless-cast
-Wlifetime
-Wformat=2
-Weffc++

Remaining Clang flags that still produce warnings:

-Wweak-vtables (Move virtual function implementation from header to source file)
-Wsign-conversion (Implicit signed/unsigned conversions)
-Wctad-maybe-unsupported (Point and Rectangle have no deduction guides)
-Wmissing-variable-declarations (Declare or wrap in unnamed namespace)

@DanRStevens
Copy link
Collaborator Author

I did a Clang build using -Weverything and then turned off warnings that were still generated. The following list of flags was used to get back to a clean compile:

make CXXFLAGS_WARN="-Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-weak-vtables -Wno-date-time -Wno-global-constructors -Wno-exit-time-destructors -Wno-float-equal -Wno-implicit-int-float-conversion -Wno-sign-conversion -Wno-missing-variable-declarations -Wno-tautological-type-limit-compare"

Here's the inverted list that enables all flags that still generate warnings:

make CXXFLAGS_WARN="-Wc++98-compat -Wc++98-compat-pedantic -Wpadded -Wweak-vtables -Wdate-time -Wglobal-constructors -Wexit-time-destructors -Wfloat-equal -Wimplicit-int-float-conversion -Wsign-conversion -Wmissing-variable-declarations -Wtautological-type-limit-compare"

The first few flags are of little to no interest. Removing those, the remaining flags are:

make CXXFLAGS_WARN="-Wdate-time -Wglobal-constructors -Wexit-time-destructors -Wfloat-equal -Wimplicit-int-float-conversion -Wsign-conversion -Wmissing-variable-declarations -Wtautological-type-limit-compare"

@DanRStevens
Copy link
Collaborator Author

Found this article that may be worth noting here:
https://devblogs.microsoft.com/cppblog/broken-warnings-theory/


Some official documentation on warning levels is here:
https://learn.microsoft.com/en-us/cpp/build/reference/compiler-option-warning-level?view=msvc-170

We currently use warning level 4 (/W4). The documentation shows that /Wall is higher than /W4. The documentation also mentions /WX, which means to treat warnings as errors, which we do on CI builds. The /WX flag can be used by both the compiler and the linker to treat warnings as errors.

Individual warnings (with code nnnn) can be suppressed, treated as errors, or warned about only once:

  • /wdnnnn (suppressed)
  • /wennnn (treated as error)
  • /wonnnn (report only once)

Some more documentation:
https://learn.microsoft.com/en-us/cpp/build/reference/external-external-headers-diagnostics?view=msvc-170

Under the section on "Limitations":

Code analysis warnings are also unaffected, since they don't have warning levels.

This would seem to imply that CAExcludePath may still be needed even when using setting ExternalWarningLevel to TurnOffAllWarnings, since CAExcludePath is specifically about Code Analysis warnings, which don't have a warning level.

That is relevant to the recently merged PR #1119. Though in that case it was removed from the NAS2D project, where it didn't seem to be needed. Meanwhile the unit test project may need such an exclusion to enable Code Analysis.

@DanRStevens
Copy link
Collaborator Author

It may also be helpful to check that we have Security Development Lifecycle (SDL) checks on:
https://learn.microsoft.com/en-us/cpp/build/reference/sdl-enable-additional-security-checks?view=msvc-170

@cugone
Copy link
Contributor

cugone commented May 28, 2023

I'll re-iterate that turning on /Wall in Visual Studio is not recommended as you get numerous warnings from the STL and Microsoft-provided code. They themselves strive for clean '/W4` code, that is, no warnings when compiling under Level 4 warnings. Warnings-as-errors enforces this as well.

@DanRStevens
Copy link
Collaborator Author

Out of interest, I thought I'd give /Wall a try anyway. Here's a build log showing 601 warnings:
https://github.com/lairworks/nas2d-core/actions/runs/5103617248/jobs/9173981405

Most of them don't look particularly interesting. Some are pretty much just informational. So yeah, doesn't really look to be worth enabling.


Mind you, we have config that should exclude external headers from error reporting, so the STL and Microsoft provided code are not really a concern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants