Skip to content

Missed optimization: std::unique_ptr destructor emits check contradicting assume / unreachable #39236

@pwnall

Description

@pwnall
mannequin
Bugzilla Link 39889
Version trunk
OS All

Extended Description

I've been trying to find a way to tell Clang that a std::unique_ptr's pointer cannot be null, so the emitted destructor code does not contain an unnecessary check. GCC's optimizer seems to be able to figure this out. MSVC's optimizer misses this opportunity.

https://godbolt.org/z/rywaj3 has my code and the compilers I've used. I will also include the code at the end of the bug. In this example, the code generated for Handle::~Handle(), which contains an inlined unique_ptr::~unique_ptr(), should not contain a test/je sequence. The check contradicts the assumption that the unique_ptr is not null.

I tried expressing the assumption using the GCC-style _builtin_unreachable() as well as Clang's builtin_assume(). I tried to be more or less explicit in the predicate -- tried ptr, ptr.get(), ptr.get() != nullptr. I tried -O2, -O3 and -Ofast.

Here is the code in the godbolt link above. The code can be simplified by inlining the ASSUME(x) macro. I am submitting the current form so developers can easily compare output across Clang, GCC and MSVC.

#include
#include

#if defined(clang)
// #define ASSUME(x) __builtin_assume(static_cast(x))
#define ASSUME(x) if(!static_cast(x)) __builtin_unreachable()
#elif defined(GNUC)
#define ASSUME(x) if(!static_cast(x)) __builtin_unreachable()
#elif defined(_MSC_VER)
#define ASSUME(x) __assume(static_cast(x))
#else
#error "No ASSUME definition"
#endif

struct Resource {
~Resource() noexcept;
};

class HandleBase {
public:
HandleBase() noexcept = default;
virtual ~HandleBase();
};

class Handle : public HandleBase {
const std::unique_ptr ptr_;
public:
Handle();
~Handle() override;
};
Handle::Handle() : ptr_(std::make_unique()) {}
Handle::~Handle() {
ASSUME(ptr_.get() != nullptr);
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions