Skip to content

<system_error>: Can we add constexpr to the default constructor of error_category without ABI breakage? #3119

@frederick-vs-ja

Description

@frederick-vs-ja

Currently the default constructor of error_category lacks constexpr in MSVC STL, which is non-conforming and expected to be fixed in vNext (see #1116).

STL/stl/inc/system_error

Lines 70 to 72 in 2f03bdf

/* constexpr */ error_category() noexcept { // TRANSITION, ABI
_Addr = reinterpret_cast<uintptr_t>(this);
}

However, it seems that we can implement _Addr as a union so that it can be constant during constant evaluation like this:

class ErrorCategoryLike {
private:
    union AddrStorage {
    private:
        uintptr_t          num;
        ErrorCategoryLike* ptr;

    public:
        constexpr explicit AddrStorage(uintptr_t addr_num) noexcept : num(addr_num) {}
        constexpr explicit AddrStorage(ErrorCategoryLike* addr_ptr) noexcept : ptr(addr_ptr) {}
    };
    static_assert(sizeof(AddrStorage) == sizeof(uintptr_t) && alignof(AddrStorage) == alignof(uintptr_t),
        "Unsupported platform");

    AddrStorage addr;

protected:
    constexpr explicit ErrorCategoryLike(uintptr_t addr_num) noexcept : addr(addr_num) {}

public:
    constexpr ErrorCategoryLike() noexcept : addr(this) {}

    bool operator==(const ErrorCategoryLike& rhs) const noexcept {
        return _STD _Bit_cast<uintptr_t>(addr) == _STD _Bit_cast<uintptr_t>(rhs.addr);
    }

    virtual ~ErrorCategoryLike() = default;
};

See also the test on godbolt.

Such technique requires that

  • the union has the same size and alignment of uintptr_t, and
  • reinterpret_cast between uintptr_t and pointers is equivalent to bit_cast.

I think both conditions hold on Windows (at least for MSVC, clang-cl, etc.) although they are not guaranteed by the standard.

So I guess we can add the constexpr without ABI breakge. Is it right?


constexpr explicit error_category(const uintptr_t _Addr_) noexcept : _Addr(_Addr_) {}

BTW, this protected constructor is probably also non-conforming as it is probably observable by a conforming program (that defines a class derived from error_category and tests the non-existence of this constructor). Changing its access control or signature seemly breaks ABI.

Metadata

Metadata

Assignees

No one assigned

    Labels

    fixedSomething works now, yay!questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions