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.