C++Guns – RoboBlog

06.01.2015

GNU compiler collection - Useful GCC warning/errors not enabled by Wall Wextra

Filed under: — Thomas @ 08:01

Check cache size cat /sys/devices/system/cpu/cpu0/cache/index3/size or lstopo

https://gcc.gnu.org/onlinedocs/gcc/
https://gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode.html

-Werror=padded
-Werror=shadow
-Werror=pedantic
-Werror=null-dereference
-Werror=exceptions
-Werror=catch-value

Hier die Zusammenfassung C&P in eure Projekt Datei. Mit GCC Version Test

{
GCC_VERSION = $$system($$QMAKE_CXX " -dumpversion")
VERSIONS = $$split(GCC_VERSION, .)
VERSION_MAJ = $$member(VERSIONS)

contains(VERSION_MAJ, 12) {
message( "g++ version 12.x found" )
CONFIG += g++12
}
contains(VERSION_MAJ, 11) {
message( "g++ version 11.x found" )
CONFIG += g++11
}
contains(VERSION_MAJ, 10) {
message( "g++ version 10.x found" )
CONFIG += g++10
}
contains(VERSION_MAJ, 9) {
message( "g++ version 9.x found" )
CONFIG += g++9
}
contains(VERSION_MAJ, 8) {
message( "g++ version 8.x found" )
CONFIG += g++8
}
contains(VERSION_MAJ, 7) {
message( "g++ version 7.x found" )
CONFIG += g++7
}
contains(VERSION_MAJ, 6) {
message( "g++ version 6.x found" )
CONFIG += g++6
}
contains(VERSION_MAJ, 5) {
message( "g++ version 5.x found" )
CONFIG += g++5
}
contains(VERSION_MAJ, 4) {
message( "g++ version 4.x found" )
CONFIG += g++4
}
}

g++8|g++9|g++10|g++11|g++12: QMAKE_CXXFLAGS += -Werror=class-memaccess
g++9|g++10|g++11|g++12: QMAKE_CXXFLAGS += -Werror=init-list-lifetime -Werror=redundant-move -Werror=pessimizing-move -Werror=class-conversion
g++10|g++11|g++12: QMAKE_CXXFLAGS += -Werror=comma-subscript
g++11|g++12: QMAKE_CXXFLAGS += -Werror=range-loop-construct -Werror=deprecated-enum-enum-conversion -Werror=deprecated-enum-float-conversion -Werror=mismatched-new-delete -Werror=vexing-parse
g++12: QMAKE_CXXFLAGS += -Werror=missing-requires -Werror=int-in-bool-context -Werror=bidi-chars=any -Werror=array-compare

QMAKE_CXXFLAGS_DEBUG += -D_GLIBCXX_DEBUG
QMAKE_CXXFLAGS += -Wpedantic -Werror=extra -Wno-error=sign-compare -Wno-error=unused-parameter
QMAKE_CXXFLAGS += -Wvector-operation-performance -Werror=div-by-zero -Werror=multichar -Werror=switch -Werror=switch-enum -Werror=switch-bool -Werror=switch-unreachable
QMAKE_CXXFLAGS += -Werror=pedantic -pedantic-errors -Werror=unused-value -Werror=overflow -Werror=address -Werror=tautological-compare
QMAKE_CXXFLAGS += -Werror=narrowing -Werror=return-type -Werror=misleading-indentation -Werror=strict-aliasing -Werror=sign-promo
QMAKE_CXXFLAGS += -Werror=parentheses -Werror=logical-not-parentheses -Werror=logical-op -Werror=bool-compare -Werror=uninitialized -Werror=maybe-uninitialized
QMAKE_CXXFLAGS += -Werror=unused-result -Werror=reorder -Werror=duplicated-cond -Werror=duplicated-branches -Werror=type-limits -Werror=missing-field-initializers
QMAKE_CXXFLAGS += -Werror=return-local-addr -Werror=sequence-point -Werror=dangling-else -Werror=conversion-null -Werror=empty-body -Werror=ignored-qualifiers -Werror=null-dereference
# lot of work
# QMAKE_CXXFLAGS += -Werror=conversion
# we love pain
# QMAKE_CXXFLAGS += -Werror=shadow

# The QT library is not free of warnings. If we enable e.g. -Wconversion we see a lot
# of warnings from Qt we cant fix nor care. Here is a simple way to disable warnings
# for external framwork. Just include library headers using -isystem instead of -I.
# This will make them "system headers" and GCC won't report warnings for them.
# This still trigger some warnings due to inline of code.
# If a standard system include directory, or a directory specified with -isystem, is also specified with -I, the -I option is ignored.
QMAKE_CXXFLAGS += -isystem[QT_INSTALL_HEADERS]/QtCore<br />
QMAKE_CXXFLAGS += -isystem[QT_INSTALL_HEADERS]/QtWidgets
QMAKE_CXXFLAGS += -isystem[QT_INSTALL_HEADERS]/QtGui<br />
QMAKE_CXXFLAGS += -isystem[QT_INSTALL_HEADERS]/QtNetwork
QMAKE_CXXFLAGS += -isystem[QT_INSTALL_HEADERS]/QtOpenGL<br />
QMAKE_CXXFLAGS += -isystem[QT_INSTALL_HEADERS]/QtScript
QMAKE_CXXFLAGS += -isystem$$[QT_INSTALL_HEADERS]/QtTest

Unabdingbar!!!

TODO -Werror=range-loop-construct -Werror=deprecated-enum-enum-conversion -Werror=deprecated-enum-float-conversion -Werror=mismatched-new-delete -Werror=vexing-parse
TODO GCC12 -Wno-missing-requires -Wint-in-bool-context -Wbidi-chars=[none|unpaired|any|ucn] -Warray-compare

-Werror=extra

struct A { };

struct B {
    B(A) {};
};

struct C {
    C(const A& a)
    : b(B(a)) // error: a temporary bound to 'C::b' only persists until the constructor exits
    {
    }

    const B& b; // Do not store references
};
}

-Werror=return-type

Eine vergessene return Anweisung für zu 99% zum segfault.

int func() {   
// error: no return statement in function returning non-void
}

-Werror=return-local-addr
Lokale Konstanten als const referenzen zurückgeben führt leider zum sefault;

const int& func() {
    return 0; // error: returning reference to temporary
}

-Werror=uninitialized
Error if an automatic variable is used without first being initialized.

auto func()  {
    double X;
    return X; // error: 'X' is used uninitialized in this function
}

-Werror=unused-value
Warn whenever a statement computes a result that is explicitly not used. This includes an expression-statement or the left-hand side of a comma expression that contains no side effects.

auto func(std::vector<int> v, int i, int j) {  
  return v[i,j];                               //  error: left operand of comma operator has no effect
} 

-Werror=comma-subscript
Warn about uses of a comma expression within a subscripting expression. This usage was deprecated in C++20. However

auto func(std::vector<int> v, int i, int j) {  
  return v[i,j];                               //  error: top-level comma expression in array subscript is deprecated
} 

-Werror=missing-field-initializers
Warn if a structure’s initializer has some fields missing.

struct X {    
  int a,b,c; 
};
X x{1, 2};    // error: missing initializer for member 'X::c'

-Werror=maybe-uninitialized
For an automatic (i.e. local) variable, if there exists a path from the function entry to a use of the variable that is initialized, but there exist some other paths for which the variable is not initialized, the compiler emits a warning if it cannot prove the uninitialized paths are not executed at run time.

    double T=0, dt;
    for (double t=0; t<T; t+=dt) { } // error: 'dt' may be used uninitialized in this function

-Werror=unused-result
Error if a caller of a function does not use its return value / if the return value is discarded.

[[nodiscard]] int bar(int);
auto foo() {
    bar(3); // error: ignoring return value of 'int bar(int)', declared with attribute nodiscard
}

-Werror=narrowing
When you try something not possible.

int func(double a) {
    return {a};    //  error: narrowing conversion of 'a' from 'double' to 'int' inside { } 
}

-Werror=address
Error about suspicious uses of memory addresses, e.g. comparisons against the memory address of a string literal.

if(g->name == "quad")   // error: comparison with string literal results in unspecified behavior

-Werror=misleading-indentation
Error when the indentation of the code does not reflect the block structure.

void a();
void b();
void func() {   
    for(int i=0; i < 10; ++i) //  error: this 'for' clause does not guard...
      a();
      b();                    // ...this statement, but the latter is misleadingly indented as if it were guarded by the 'for'
}

-Werror=strict-aliasing
Error about code that might break the strict aliasing rules that the compiler is using for optimization.

int i=0;
float f = *reinterpret_cast<float*>(&i); // error: dereferencing type-punned pointer will break strict-aliasing rule
i = *(int*)&f;                               // error: dereferencing type-punned pointer will break strict-aliasing rule

-Werror=sign-promo
Error when overload resolution chooses a promotion from unsigned or enumerated type to a signed type, over a conversion to an unsigned type of the same size.
A function with a signed parameter is called with a unsigned argument, instead of the function with an unsigned parameter.

void func(int32_t);
void func(uint32_t);
func(uint8_t()); // error: passing 'uint8_t' {aka 'unsigned char'} chooses 'int32_t' {aka 'int'} over 'uint32_t' {aka 'unsigned int'}
func(int8_t()); // ok
func(uint16_t()); // error: passing 'uint16_t' {aka 'short unsigned int'} chooses 'int32_t' {aka 'int'} over 'uint32_t' {aka 'unsigned int'}
enum noClassEnum { A };
func(e); // error: passing 'noClassEnum' chooses 'int32_t' {aka 'int'} over 'uint32_t' {aka 'unsigned int'}

-Werror=dangling-else
Error about constructions where there may be confusion to which if statement an else branch belongs.

if(true)       // error: suggest explicit braces to avoid ambiguous 'else'
  if(false)
    return 0;
  else
    return 1;  

-Werror=parentheses
Error if parentheses are omitted in certain contexts, such as when there is an assignment in a context where a truth value is expected, or when operators are nested whose precedence people often get confused about. ^

int (a);          // error: unnecessary parentheses in declaration of 'a'
if(a = 1)         // error: suggest parentheses around assignment used as truth value

-Werror=logical-not-parentheses
Error about logical not used on the left hand side operand of a comparison.

if(!a == 1)   // error: logical not is only applied to the left hand side of comparison
              // note: add parentheses around left hand side expression

-Werror=logical-op
Error about suspicious uses of logical operators in expressions. This includes using logical operators in contexts where a bit-wise operator is likely to be expected. Also warns when the operands of a logical operator are the same:

    if((a && 0b10) or (a && 0b10)) {} // error: logical 'and' applied to non-boolean constant
                                      // error: logical 'or' of equal expressions

-Werror=bool-compare
Error about boolean expression compared with an integer value different from true/false

 return (x > 0) == 2;    //   error: comparison of constant '2' with boolean expression is always false

-Werror=switch
Error whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration. (The presence of a default label prevents this warning.)

error: enumeration value 'unknown' not handled in switch

See next.

-Werror=switch-enum
The only difference between -Wswitch and this option is that this option gives a warning about an omitted enumeration code even if there is a default label.

-Werror=switch-bool
Warn whenever a switch statement has an index of boolean type and the case values are outside the range of a boolean type

auto func(int type) {
    switch (type==4) {  // error: switch condition has boolean value
        case 2:;
    }
}

-Werror=switch-unreachable
Warn whenever a switch statement contains statements between the controlling expression and the first case label, which will never be executed.

auto func(int type) {
    switch (type) {
        int i = 0;   // note:   crosses initialization of 'int i'
        case 2:;     // error: jump to case label
                     // error: statement will never be executed
    }
}

-Werror=implicit-fallthrough=3
Error when a switch case falls through.
C++17 provides a standard way to suppress error using [[fallthrough]]; attribute.

error: this statement may fall through

-Werror=reorder
Warn when the order of member initializers given in the code does not match the order in which they must be executed.

struct A {
  int i;
  int j;                 // error: 'A::j' will be initialized after 'int A::i'
  A(): j (0), i (1) { }  // error: when initialized here
};

-Werror=duplicated-cond
Warn about duplicated conditions in an if-else-if chain.

    if(a == 0) {          // note: previously used here
    } else if (a == 0) {  // error: duplicated 'if' condition
    }

-Werror=duplicated-branches
Warn about duplicated conditions in an if-else-if chain.

    if(a == 0) {     // error: this condition has identical branches
        return 1;
    } else  {
        return 1;
    }

-Werror=type-limits
Error if a comparison is always true or always false due to the limited range of the data type.

auto func(unsigned int x) {
  return x >= 0;    // error: comparison of unsigned expression >= 0 is always true
}

-Werror=tautological-compare
Error if a self-comparison always evaluates to true or false, or about bitwise comparisons that always evaluate to true or false.

auto func(int i) {
  return i >= i;  //  error: self-comparison always evaluates to true
}

-Werror=empty-body
Passiert...

if(1==2);  // error: suggest braces around empty body in an 'if' statement

-Werror=ignored-qualifiers

const int func() {  // error: type qualifiers ignored on function return type
    return 42;
}

-Werror=sequence-point
Error about code that may have undefined semantics because of violations of sequence point rules in the C and C++ standards. There is more to read in the GCC manual.

auto func(int i) {
  return i++ + ++i;  //  error: operation on 'i' may be undefined 
}

-Werror=div-by-zero
Error on compile-time integer division by zero. Floating-point division by zero is not warned about.

  while(pos_nextRecord /= 0) { // error: division by zero [-Werror=div-by-zero]

-Werror=multichar
Error if a multicharacter constant (‘'FOOF'’) is used.

  std::cout << ' kB\n';  // error: multi-character character constant

-Werror=class-conversion
Error about the case when a conversion function will never be called.

struct U {};

struct T : U { 
  operator T() { // error: converting 'T' to the same type will never use a type conversion operator
  }

  operator U() { // errro  converting 'T' to a base class 'U' will never use a type conversion operator
  }
  
  operator void() { // error: converting 'T' to 'void' will never use a type conversion operator
  }
};

-Werror=conversion-null
Offensichtlich

int func() {
    return NULL; // error converting to non-pointer type 'int' from NULL
}

-Werror=redundant-move
Error about redundant calls to std::move.

T fn(T t) {
  return std::move(t); // error: redundant move in return statement
}

-Werror=pessimizing-move
Error when a call to std::move prevents copy elision.

T fn() {
  T t;
  return std::move(t); // error: moving a local object in a return statement prevents copy elision
}

-Werror=init-list-lifetime
Error about uses of std::initializer_list that are likely to result in dangling pointers.

// initializer_list underlying array’s lifetime ends at the end of the return statement
auto func1() {
  std::initializer_list<int> li = { 1,2,3 }; 
  return li;  // error: returning local initializer_list variable 'li' does not extend the lifetime of the underlying array
}

// li's initial underlying array lives as long as li
// assignment changes li to point to a temporary array
auto func2() {
  std::initializer_list<int> li = { 1,2,3 };
  li = { 4, 5 }; // error: assignment from temporary initializer_list does not extend the lifetime of the underlying array
}

// When a list constructor stores the begin pointer from the initializer_list argument, this doesn’t extend the lifetime of the array. 
// so if a class variable is constructed from a temporary initializer_list,
// the pointer is left dangling by the end of the variable declaration statement. 
struct A {
  A(std::initializer_list<int> li) 
  : p(li.begin()) // error: initializing 'A::p' from 'std::initializer_list<int>::begin' does not extend the lifetime of the underlying array
  {
  }

  const int* p;
};

-Werror=class-memaccess
Warn when the destination of a call to a raw memory function such as memset or memcpy is an object of class type, and when writing into such an object might bypass the class non-trivial or deleted constructor or copy assignment, violate const-correctness or encapsulation, or corrupt virtual table pointers.

struct A {
    A() = default;
    A(A&) { };
};

static_assert( std::is_trivially_copyable<A>::value);  // error: static assertion failed

auto func() {
    A a, b;
    memcpy(&b, &a, sizeof(b)); // error: 'void* memcpy(void*, const void*, size_t)' writing to an object of non-trivially copyable type 'struct A'; use copy-assignment or copy-initialization instead
}

Don't implement constructors for data types. Use the compiler generated ones.

-Werror=padded

Warn if padding is included in a structure, either to align an element of the structure or to align the whole structure.

struct X {    // error: padding struct size to alignment boundary
  int i;  
  double d;   // error: padding struct to align 'X::d'
  float j;
};

auto func() {
    return X{1, 2.0, 3.0};
}
func():
        movq    .LC0(%rip), %rdx
        movq    %rdi, %rax
        movl    $1, (%rdi)
        movl    $0x40400000, 16(%rdi)
        movq    %rdx, 8(%rdi)
        ret

Swap the double with the float. It create less and hence faster ASM code too.

struct X {    
  int i;  
  float j;
  double d;  
};
func():
        movsd   .LC0(%rip), %xmm0
        movabsq $4611686018427387905, %rax
        ret

-Werror=shadow

Warn whenever a local variable or type declaration shadows another variable, parameter, type, class member, or whenever a built-in function is shadowed.
This IS a good thing. See C++ Guns: -Wshadow for constructor arguments

struct A{
    int i;         // note: shadowed declaration is here
    auto func() {
        int i;     // error: declaration of 'i' shadows a member of 'A'
    }
};

-Werror=pedantic -pedantic-errors

Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++

struct A {
};;         // error: extra ';'

Y0u als0 pay @tt3nti0n to t43 sp311ing rul3s. Do YOU?

-Werror=null-dereference

Warn if the compiler detects paths that trigger erroneous or undefined behavior due to dereferencing a null pointer.

-Werror=exceptions

Warn about the case when an exception handler is shadowed by another handler, which can point out a wrong ordering of exception handlers

int main() {
  try {
  }
  catch(std::exception& ex) {     // note: for type ‘std::exception’
  }
  catch(std::logic_error& ex) {   // error: exception of type ‘std::logic_error’ will be caught by earlier handler 
  }
}

-Werror=catch-value

https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Re-exception-ref

Warn about catch handlers that do not catch via reference.
With -Wcatch-value=1 (or -Wcatch-value for short) warn about polymorphic class types that are caught by value.
With -Wcatch-value=2 warn about all class types that are caught by value.
With -Wcatch-value=3 warn about all types that are not caught by reference. This might be overkill, because catching a "const char*" is then an error.

 try {
   ...
 }
 catch(std::system_error ex) { //  error: catching polymorphic type ‘class std::system_error’ by value
 }
 catch(std::error_code) { //  error: catching type ‘class std::error_code’ by value
 }
 catch(int) {  // error: catching non-reference type ‘int’
  }

Debug

Wenn du verzweifelst:
-fsignaling-nans -fsanitize-undefined-trap-on-error -fsanitize=undefined,address -fsanitize=float-divide-by-zero -ffpe-trap=invalid,zero,overflow

Some usefull compiler warnings which are not enabled by -Wall or -Wextra

-Werror=inline
Warn if a function that is declared as inline cannot be inlined.

-Wconversion
Warn for implicit conversions that may alter a value. This includes conversions between real and integer, like abs (x) when x is double; conversions between signed and unsigned, like unsigned ui = -1; and conversions to smaller types, like sqrtf (M_PI). also warn for confusing overload resolution for user-defined conversions

-Wvector-operation-performance
Warn if vector operation is not implemented via SIMD capabilities of the architecture. Mainly useful for the performance tuning. Vector operation can be implemented piecewise, which means that the scalar operation is performed on every vector element; in parallel, which means that the vector operation is implemented using scalars of wider type, which normally is more performance efficient; and as a single scalar, which means that vector fits into a scalar type.

-Weffc++ (C++ and Objective-C++ only)
Warn about violations of the following style guidelines from Scott Meyers' Effective C++ series of books:

Define a copy constructor and an assignment operator for classes with dynamically-allocated memory.
Prefer initialization to assignment in constructors.
Have operator= return a reference to *this.
Don't try to return a reference when you must return an object.
Distinguish between prefix and postfix forms of increment and decrement operators.
Never overload &&, ||, or ,.

This option also enables -Wnon-virtual-dtor, which is also one of the effective C++ recommendations. However, the check is extended to warn about the lack of virtual destructor in accessible non-polymorphic bases classes too.

When selecting this option, be aware that the standard library headers do not obey all of these guidelines; use ‘grep -v’ to filter out those warnings.

-Wdouble-promotion
Give a warning when a value of type float is implicitly promoted to double. CPUs with a 32-bit “single-precision” floating-point unit implement float in hardware, but emulate double in software. On such a machine, doing computations using double values is much more expensive because of the overhead required for software emulation.

-Wsuggest-attribute=pure
-Wsuggest-attribute=const
-Wsuggest-attribute=noreturn

Warn about functions that might be candidates for attributes pure, const or noreturn. The compiler only warns for functions visible in other compilation units or (in the case of pure and const) if it cannot prove that the function returns normally. A function returns normally if it doesn't contain an infinite loop or return abnormally by throwing, calling abort() or trapping. This analysis requires option -fipa-pure-const, which is enabled by default at -O and higher. Higher optimization levels improve the accuracy of the analysis.

Other Stuff
-fsplit-stack
Generate code to automatically split the stack before it overflows. The resulting program has a discontiguous stack which can only overflow if the program is unable to allocate any more memory. This is most useful when running threaded programs, as it is no longer necessary to calculate a good stack size to use for each thread. This is currently only implemented for the i386 and x86_64 back ends running GNU/Linux.

When code compiled with -fsplit-stack calls code compiled without -fsplit-stack, there may not be much stack space available for the latter code to run. If compiling all code, including library code, with -fsplit-stack is not an option, then the linker can fix up these calls so that the code compiled without -fsplit-stack always has a large stack. Support for this is implemented in the gold linker in GNU binutils release 2.21 and later.

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress