https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102221
--- Comment #5 from Giuseppe D'Angelo <dangelog at gmail dot com> ---
Here's a further testcase that doesn't even use unique_ptr:
#include <utility>
#include <memory>
using ptr = int *;
using rawptr = int *;
#ifndef RESTRICT
#define RESTRICT
#endif
void swap(ptr & RESTRICT a, ptr & RESTRICT b)
{
if (std::addressof(a) == std::addressof(b))
__builtin_unreachable();
ptr tmp = a; a = nullptr; // ptr tmp = std::move(a)
// a = std::move(b)
#if ONE
{
// a.reset(b.release())
rawptr tmp = b; // b.release()
b = nullptr;
rawptr old = a; // a.reset(tmp)
a = tmp;
delete old;
}
#elif TWO
{
// move+swap
rawptr tmp = b; b = nullptr; // ptr tmp = std::move(b)
{ // a.swap(tmp)
rawptr tmp2 = a;
a = tmp;
tmp = tmp2;
}
// ~tmp
delete tmp;
}
#elif THREE
{
delete a; a = b; b = nullptr;
}
#else
#error
#endif
delete b; b = tmp; tmp = nullptr; // b = std::move(tmp)
delete tmp;
}
https://gcc.godbolt.org/z/bv1T64ndo
ONE and TWO don't elide the delete, unless the arguments are marked
__restrict__. THREE does elide it. Sounds like some escape analysis going
wrong, combined with unique_ptr's self-move-assignment safety (that "bans"
THREE's implementation).