https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98646

--- Comment #12 from Martin Sebor <msebor at gcc dot gnu.org> ---
(In reply to Jakub Jelinek from comment #10)
> So, the problem is IMHO that the warning about passing NULL to this is
> misplaced, it shouldn't be done in the FEs, but later when there was at
> least some chance of dead code removal.

That would be a hack.  First, the this argument to a member function is just
like a plain argument to an ordinary nonnull function, so they all should be
treated the same.  Second, there already is code in tree-ssa-ccp.c to handle
-Wnonnull, so nothing needs to be moved.

The -Wnonnull code could be removed from the front end, but that would
considerably compromise the warning: passing null pointers to inline member
functions would cease to be diagnosed.  See for example the effect on the code
below.  In C++ that wouldn't be a good deal.

$ cat u.C && gcc -O2 -S -Wall -fdump-tree-optimized=/dev/stdout u.C
struct S {
  int i;
  void f () { i = 0; };
  void g ();
};

void f (void)
{
  S *p = 0;
  p->f ();   // missing warning
}

void g (void)
{
  S *p = 0;
  p->g ();   // -Wnonnull (good)
}

;; Function f (_Z1fv, funcdef_no=1, decl_uid=2357, cgraph_uid=2,
symbol_order=1) (executed once)

void f ()
{
  <bb 2> [local count: 1073741824]:
  MEM[(struct S *)0B].i ={v} 0;
  __builtin_trap ();

}


u.C: In function ‘void g()’:
u.C:16:8: warning: ‘this’ pointer null [-Wnonnull]
   16 |   p->g ();   // -Wnonnull (good)
      |   ~~~~~^~
u.C:4:8: note: in a call to non-static member function ‘void S::g()’
    4 |   void g ();
      |        ^

;; Function g (_Z1gv, funcdef_no=2, decl_uid=2360, cgraph_uid=3,
symbol_order=2)

void g ()
{
  <bb 2> [local count: 1073741824]:
  S::g (0B); [tail call]
  return;

}


Also, removing the -Wnonnull handling from the FE wouldn't actually solve the
reported problem.  It would just paper over it because the middle end warning
doesn't consider PHIs yet.  If/when it's enhanced to consider them the warning
would come back again as is plain to see in the dump for the test case from
comment #11:

$ cat pr98646.C && gcc -O2 -S -Wall -fdump-tree-optimized=/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 ();          // bogus -Wnonnull
}

;; Function f (_Z1fP1B, funcdef_no=0, decl_uid=2430, cgraph_uid=1,
symbol_order=0)

Removing basic block 5
void f (struct B * p)
{
  struct C * iftmp.0_1;
  struct B * _5;
  struct C * iftmp.0_6;

  <bb 2> [local count: 1073741824]:
  _5 = B::f (p_3(D));
  if (_5 != 0B)
    goto <bb 3>; [70.00%]
  else
    goto <bb 4>; [30.00%]

  <bb 3> [local count: 751619281]:
  iftmp.0_6 = _5 + 18446744073709551608;

  <bb 4> [local count: 1073741824]:
  # iftmp.0_1 = PHI <iftmp.0_6(3), _5(2)>
  C::g (iftmp.0_1); [tail call]     <<< should get a warning: pointer may be
null
  return;

}

We can see that already today by running the analyzer on the test case:

pr98646.C: In function ‘void f(B*)’:
pr98646.C:8:31: warning: use of NULL where non-null expected [CWE-476]
[-Wanalyzer-null-argument]
    8 |   static_cast<C*>(p->f ())->g ();          // bogus -Wnonnull
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
  ‘void f(B*)’: events 1-3
    |
    |
pr98646.C:4:38: note: argument 'this' of ‘void C::g() const’ must be non-null
    4 | struct C: A, B { virtual ~C (); void g () const; };
      |                                      ^

Which is why, if we want to avoid these warnings, we need the front end to
annotate the implicit COND_EXPR somehow.  It could be done by setting
TREE_NO_WARNING but I'd worry about it getting lost or unintentionally
suppressing important warnings.  Adding a special internal function instead and
expanding it after the first -Wnonnull handler would be better.

Reply via email to