New-expression with consteval constructor in constexpr context

Viewed 665
struct A {       
    consteval A() {};
};

constexpr bool g() {
    auto a = new A;
    delete a;
    return true;
}

int main() {
    static_assert(g());
}

https://godbolt.org/z/jsq35WxKs

GCC and MSVC reject the program, ICC and Clang accept it:

///MSVC: 
<source>(6): error C7595: 'A::A': call to immediate function is not a constant expression
Compiler returned: 2

//GCC:
<source>: In function 'constexpr bool g()':
<source>:6:18: error: the value of '<anonymous>' is not usable in a constant expression
    6 |     auto a = new A;
      |                  ^
<source>:6:18: note: '<anonymous>' was not declared 'constexpr'
<source>:7:12: error: type '<type error>' argument given to 'delete', expected pointer
    7 |     delete a;
      |            ^
Compiler returned: 1

Although, replacing new A by new A() results in GCC accepting the program as well (but not for new A{} either).


Making at least one of the following changes results in all four compilers accepting the program:

  1. Replace consteval with constexpr

  2. Replace constexpr with consteval

  3. Replace

    auto a = new A;
    delete a;
    

    with

    auto alloc = std::allocator<A>{};
    auto a = alloc.allocate(1);
    std::construct_at(a);
    std::destroy_at(a);
    alloc.deallocate(a, 1);
    

    with A a;, with auto&& a = A{}; or with A{};

Only exceptions:

  • Clang trunk with libstdc++ seems to fail compilation with the std::allocator version seemingly due to an unrelated bug. With Clang 13 or libc++ it is accepted as well.

    In file included from <source>:1:
    In file included from [...]/memory:78:
    [...]/shared_ptr_atomic.h:459:14: error: missing 'typename' prior to dependent type name '_Atomic_count::pointer'
      static _Atomic_count::pointer
    
  • MSVC rejects the std::allocator version as long as there is consteval on the constructor:

    error C7595: 'A::A': call to immediate function is not a constant expression
    <source>(10): note: see reference to function template instantiation '_Ty *std::construct_at<_Ty,,void>(_Ty *const ) noexcept(false)' being compiled
            with
            [
                _Ty=A
            ]
    

Replacing static_assert(g()); with g() or removing the call completely does not seem to have any impact on these results.


Which compilers are correct and if the original is ill-formed, why is only that particular combination of qualifiers and construction method disallowed?


Motivated by the comments under this answer.

0 Answers
Related