https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91369

--- Comment #15 from Jonathan Wakely <redi at gcc dot gnu.org> ---
That's not valid, because operator new is not a constexpr function.

You have to use a new-expression (that resolves to one of the standard operator
new allocation functions), or std::allocator<T>::allocate, or
std::allocator_traits<std::allocator<T>>::allocate.

The result of std::allocator<T>::allocate can't be dereferenced until you've
constructed an object there (and attempting to do so in a constexpr function
should be ill-formed).

This should work:

constexpr int
bar ()
{
  auto a = new int; // obtain storage for an int and begin its lifetime
  *a = 1;
  *a = *a + 2;
  int r = *a;
  delete a; // end lifetime and release storage
  return r;
}

constexpr auto p = bar ();

And this:

constexpr int
baz ()
{
  auto a = std::allocator<int>::allocate(1); // obtain storage for an int
  std::construct_at(a);                      // begin lifetime of an int
  *a = 1;
  *a = *a + 2;
  int r = *a;
  std::destroy_at(a);                        // end lifetime
  std::allocator<int>::deallocate(a, 1);     // release storage
  return r;
}

constexpr auto q = baz ();

And the equivalent using std::allocator_traits:

constexpr int
baz2 ()
{
  std::allocator<int> alloc;
  using A = std::allocator_traits<std::allocator<int>>;
  auto a = A::allocate(alloc, 1);            // obtain storage for an int
  A::construct(a);                           // calls std::construct_at
  *a = 1;
  *a = *a + 2;
  int r = *a;
  A::destroy(alloc, a);                      // calls std::destroy_at
  A::deallocate(alloc, a, 1);                // release storage
  return r;
}

constexpr auto q = baz2 ();

Reply via email to