https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98646
--- Comment #11 from Martin Sebor <msebor at gcc dot gnu.org> --- (In reply to Marek Polacek from comment #5) > A better one: > > // PR c++/98646 > // { dg-do compile } > // { dg-options "-Wnonnull" } > > struct B { > void foo(); > }; > > struct D : B { > void show(); > }; > > void > D::show() > { > constexpr void *p = nullptr; > if (p) > static_cast<D *>(p)->foo(); > } This test case isn't representative of the reported problem. It shows the general issue with the front-end part of -Wnonnull as well as with and most other flow-based front end warnings. An equivalent test case that shows the same issue with GCC 10 and prior is this: __attribute__ ((nonnull)) void f (void*); void g (void) { constexpr void *q = 0; if (q) f (q); // -Wnonnull } Because the front ends operate on one expression at a time they can't see past the expression boundary and so these kinds of examples will always trigger false positives in such warnings. The new problem reported in comment #0 that's unique in GCC 11 is due to the COND_EXPR that's implicitly added by the C++ front end for casts between related types. The following is the expression that triggers the warning in the attached test case, the this argument to virtual WId QXcbWindow::winId() const: SAVE_EXPR <QWindow::handle (NON_LVALUE_EXPR <VIEW_CONVERT_EXPR<const struct QWindow *>(tp)>)> != 0B ? (const struct QXcbWindow *) (SAVE_EXPR <QWindow::handle (NON_LVALUE_EXPR <VIEW_CONVERT_EXPR<const struct QWindow *>(tp)>)> + 18446744073709551600) : 0B The third operand of the COND_EXPR (i.e., the 0B) triggers the front end warning because check_function_arguments_recurse() is designed to look for it. The only bug I see here is not that the warning can be triggered in an if statement with an unreachable branch but that it can be triggered by the implicit literal null inserted by the front end that's not in the source code. A test case that more closely reflects the problem is this $ cat pr98646.C && gcc -S -Wall -fdump-tree-original=/dev/stdout pr98646.C struct A { virtual ~A (); }; struct B { virtual ~B (); B* f (); }; struct C: A, B { virtual ~C (); void g () const; }; void f (B *p) { static_cast<C*>(p->f ())->g (); // no warning } void g (B *p) { static_cast<const C*>(p->f ())->g (); // bogus -Wnonnull } ;; Function void f(B*) (null) ;; enabled by -tree-original <<cleanup_point <<< Unknown tree: expr_stmt C::g (SAVE_EXPR <B::f (NON_LVALUE_EXPR <p>)> != 0B ? (struct C *) (SAVE_EXPR <B::f (NON_LVALUE_EXPR <p>)> + 18446744073709551608) : 0B) >>>>>; pr98646.C: In function ‘void g(B*)’: pr98646.C:13:38: warning: ‘this’ pointer null [-Wnonnull] 13 | static_cast<const C*>(p->f ())->g (); // bogus -Wnonnull | ^ pr98646.C:4:38: note: in a call to non-static member function ‘void C::g() const’ 4 | struct C: A, B { virtual ~C (); void g () const; }; | ^ ;; Function void g(B*) (null) ;; enabled by -tree-original <<cleanup_point <<< Unknown tree: expr_stmt C::g (SAVE_EXPR <B::f (NON_LVALUE_EXPR <p>)> != 0B ? (const struct C *) (SAVE_EXPR <B::f (NON_LVALUE_EXPR <p>)> + 18446744073709551608) : 0B) >>>>>; But the problem isn't new to GCC 11. The same warning can be triggered in GCC 10 with a slightly modified test case: $ cat pr98646.C && /build/gcc-10-branch/gcc/xgcc -B /build/gcc-10-branch/gcc -S -Wall pr98646.C struct A { virtual ~A (); }; struct B { virtual ~B (); B* f (); }; struct C: A, B { virtual ~C (); }; __attribute__ ((nonnull)) void g (const void*); void f (B *p) { g (static_cast<C*>(p->f ())); // bogus -Wnonnull } void g (B *p) { g (static_cast<const C*>(p->f ())); // bogus -Wnonnull } pr98646.C: In function ‘void f(B*)’: pr98646.C:10:30: warning: null argument where non-null required (argument 1) [-Wnonnull] 10 | g (static_cast<C*>(p->f ())); // bogus -Wnonnull | ^ pr98646.C: In function ‘void g(B*)’: pr98646.C:15:36: warning: null argument where non-null required (argument 1) [-Wnonnull] 15 | g (static_cast<const C*>(p->f ())); // bogus -Wnonnull | ^ The only new aspect of it is that in GCC 11 it triggers for member functions.