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:
Replace
constevalwithconstexprReplace
constexprwithconstevalReplace
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;, withauto&& a = A{};or withA{};
Only exceptions:
Clang trunk with libstdc++ seems to fail compilation with the
std::allocatorversion 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::pointerMSVC rejects the
std::allocatorversion as long as there isconstevalon 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.
constructwill behave like the bare new expression.new Atonew A()makes GCC happy with the code.constevalfunction can appear anywhere (explicitly or implicitly), but independently of the context the call must by itself form a constant expression, assuming it does not appear inside anotherconstevalfunction. The question here is what it means for the implicit constructor call to form a constant expression and how that interacts with thenew-expression semantics. Coming back to this question I think the standard isn't specifying this properly, similar to how it doesn't specify the behavior ofconstexprvariables correctly.