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

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |diagnostic
                 CC|                            |rguenth at gcc dot gnu.org

--- Comment #2 from Richard Biener <rguenth at gcc dot gnu.org> ---
The diagnostic is confused about a PRE where we transform

  <bb 2> [local count: 1073741824]:
  _8 = MEM[(const struct shared_ptr &)sp_2(D)].ref_count;
  _9 = *_8;
  _20 = _9 + 1;
  *_8 = _20;
  if (_20 == 0)
    goto <bb 3>; [33.00%]
  else
    goto <bb 4>; [67.00%]

  <bb 3> [local count: 354334800]:
  free (_8);

  <bb 4> [local count: 1073741824]:
  _16 = *_8;
  _17 = _16 + 18446744073709551615;
  *_8 = _17;

to

  <bb 2> [local count: 1073741824]:
  _8 = MEM[(const struct shared_ptr &)sp_2(D)].ref_count;
  _9 = *_8;
  _20 = _9 + 1;
  *_8 = _20;
  if (_20 == 0)
    goto <bb 3>; [33.00%]
  else
    goto <bb 4>; [67.00%]

  <bb 3> [local count: 354334800]:
  free (_8);
  pretmp_5 = *_8;
  _25 = pretmp_5 + 18446744073709551615;

  <bb 4> [local count: 1073741824]:
  # prephitmp_10 = PHI <_9(2), _25(3)>
  *_8 = prephitmp_10;

I think this is both a missed diagnostic without PRE (the free () falls
through to a dereference to the freed pointer) and a missed optimization
where the

  _8 = MEM[(const struct shared_ptr &)sp_2(D)].ref_count;
  _9 = *_8;
  _20 = _9 + 1;
  *_8 = _20;
  if (_20 == 0)

test is not constant folded.  Note this is because your code is not
resilent against overflow of ref_count and also not resilent against
a ref_count of zero incoming into the copy ctor.  The latter is what
provokes the diagnostic in the end and also causes the missed
optimization.

changing the CTOR to sth like

    shared_ptr(const shared_ptr& other) : ref_count(other.ref_count) {
        if (*ref_count == 0)
          __builtin_unreachable ();
        (*ref_count)++;
    }

avoids the diagnostic and optimizes the example3 to an empty function
(since we never will need to free the reference count).

So what this bug shows is a missed diagnostic without PRE, but otherwise
it works as expected.

Reply via email to