Can a class with consteval constructor be created on heap in C++?
Asked Answered
K

1

11

In the following code struct A has immediate function default constructor, and an object of the struct is created in the dynamic memory be means of new A{}:

struct A {       
    consteval A() {}
};

int main() {
    new A{};
}

Only Clang accepts it.

GCC complains

error: the value of '<anonymous>' is not usable in a constant expression
    6 |     new A{};
      |           ^
note: '<anonymous>' was not declared 'constexpr'

And MSVC does as well:

error C7595: 'A::A': call to immediate function is not a constant expression

Demo: https://gcc.godbolt.org/z/6Px5WYGzd

Which compiler is right here?

Kraut answered 17/1, 2022 at 15:24 Comment(0)
R
8

Which compiler is right here?

Invoking a consteval constructor with new is ill-formed.
MSVC and GCC are right to reject it; clang is wrong as a diagnostic is required.


struct A { consteval A() {} };

consteval makes A::A() an immediate function1.

An immediate function can only be called from2,3:

  • another immediate function, or
  • a consteval if statement, or
  • a constant expression4.

new A{} is none of the above.


1) [dcl.constexpr]/2

A constexpr or consteval specifier used in the declaration of a function declares that function to be a constexpr function. A function or constructor declared with the consteval specifier is called an immediate function.

2) [expr.prim.id.general]/4

A potentially-evaluated id-expression that denotes an immediate function shall appear only
(4.1) as a subexpression of an immediate invocation, or
(4.2) in an immediate function context.

3) [expr.const]/13

An expression or conversion is in an immediate function context if it is potentially evaluated and either:
(13.1) its innermost enclosing non-block scope is a function parameter scope of an immediate function, or
(13.2) its enclosing statement is enclosed ([stmt.pre]) by the compound-statement of a consteval if statement ([stmt.if]).

An expression or conversion is an immediate invocation if it is a potentially-evaluated explicit or implicit invocation of an immediate function and is not in an immediate function context.
An immediate invocation shall be a constant expression.

4) [expr.const]/11.2

A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:
(11.2) if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object ([expr.add]), the address of a non-immediate function, or a null pointer value,

Roundtheclock answered 17/1, 2022 at 16:3 Comment(5)
Note that the code would be fine (in theory) within constant expression evaluation, since C++20 does let you allocate memory in constant evaluation... as long as you properly deallocate it. So A could be heap-allocated in a constant expression context.Azar
@NicolBolas like so gcc.godbolt.org/z/8fY1bEj5E ?Roundtheclock
@Roundtheclock The code in the link should still be ill-formed, because the new-expression is still not in an immediate function context and therefore an immediate invocation, which by itself needs to be a constant expression, right? And I think the same is true for e.g. gcc.godbolt.org/z/azETn746h?Waites
@user the key word is "potentially-evaluated" in expr.prim.id.general/4. I don't know the answer though. I need to get back on track regarding all the x-evaluated expressions.Roundtheclock
Not that I know for sure, but potentially-evaluated seems to only exclude contexts of unevaluated operands and I can't find mention of that term which would be relevant. It might be worth a new question. Maybe @NicolBolas would answer it.Waites

© 2022 - 2024 — McMap. All rights reserved.