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

--- Comment #13 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Jakub Jelinek from comment #12)
> Well, not fully.  The paper has additions of constexpr keywords on the
> library side, but more importantly, we'll probably need some hacks in the
> compiler for the library side, but waiting for Jonathan with that.

Yes, I have the library parts coded up but not committed.

> My understanding is that right now (perhaps that might change) placement new
> should not be treated as constexpr function, but it needs to be in certain
> STL templates (at least std::construct_at, something else?)

The way EDG does it is not to allow placement new in constant expressions, but
to intercept calls to std::construct_at and std::destroy_at and replace them
with equivalent code that does the construction/destruction.

If allowing the body of std::construct_at to be valid is easier, that's fine
too.


> Also, I was afraid that in std::allocator<T>::allocate, the cast would be
> reinterpret_cast, but apparently it isn't:
> 
> template <typename T>
> constexpr T *
> foo ()
> {
>   return static_cast<T *> (::operator new (sizeof (T)));
> }
> 
> constexpr int
> bar ()
> {
>   auto a = foo <int> ();
>   ::operator delete (a);
>   return 0;
> }
> 
> constexpr auto p = bar ();
> 
> (this doesn't actually use placement new, because that does and should ATM
> fail).  So, maybe it is just the placement new that needs to be handled.
> But, if one can cast the global replaceable allocator function result to
> anything in constexpr and our implementation triggers on the cast rather
> than on some spot coming from the new operator, shouldn't we use some new
> C++ expression kind or say an internal function as an explicit cast in new
> expression (placement or not) rather than any cast of the pointer?

Again, instead of trying to allow whatever the body of std::allocator::allocate
does, EDG just intercepts call to std::allocator<T>::allocate and replaces it
with something else that works for the constexpr case.

That means it doesn't matter what the body of std::allocator<T>::allocate does,
and it doesn't matter whether operator new has been replaced by the program,
because that code is never evaluated in constant expressions.

> Note, clang++ rejects the above testcase with
> /tmp/6.C:16:16: error: constexpr variable 'p' must be initialized by a
> constant expression
> constexpr auto p = bar ();
>                ^   ~~~~~~
> /tmp/6.C:5:28: note: cannot allocate untyped memory in a constant
> expression; use 'std::allocator<T>::allocate' to allocate memory of type 'T'
>   return static_cast<T *> (::operator new (sizeof (T)));
>                            ^
> /tmp/6.C:11:12: note: in call to 'foo()'
>   auto a = foo <int> ();
>            ^
> /tmp/6.C:16:20: note: in call to 'bar()'
> constexpr auto p = bar ();
>                    ^
> 1 error generated.
> 
> Is it correct or not?  The allocation function itself is not constexpr, on
> the other side the wording says that the allocations should be elided in
> constexpr contexts.

I don't think Clang implements this feature yet, so I'd expect it to fail.

Reply via email to