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).

Reply via email to