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?

Fedor
  • 17,146
  • 13
  • 40
  • 131

1 Answers1

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,

YSC
  • 38,212
  • 9
  • 96
  • 149
  • 1
    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. – Nicol Bolas Jan 17 '22 at 16:14
  • 1
    @NicolBolas like so https://gcc.godbolt.org/z/8fY1bEj5E ? – YSC Jan 17 '22 at 16:23
  • @YSC 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. https://gcc.godbolt.org/z/azETn746h? – user17732522 Jan 17 '22 at 18:42
  • @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. – YSC Jan 17 '22 at 18:47
  • 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. – user17732522 Jan 17 '22 at 18:59