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.