Date: Sat, 30 Nov 2024 20:29:47 -0600
On Sat, Nov 30, 2024 at 8:18 PM Arthur O'Dwyer via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> On Sat, Nov 30, 2024 at 6:42 PM James via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> Hi, I mean a specific valid runtime code should be able to run at compile
>> time. Nothing more. The following code is pretty much valid, but you can't
>> do it in compile time:
>> ```cpp
>> alignas(alignof(T)) std::byte data[sizeof(T)];
>> new(&data) T();
>> std::launder(reinterpret_cast<T*>(&data))->~T();
>> ```
>>
>> Compilers can detect overflow, memory leak, etc and don't allow it in
>> compile time. I'd like to see a similar approach. Allow both placement new
>> and reinterpret_cast, if usage is valid.
>>
>
> Read these two recent proposals, both already adopted for C++26:
> - P2747 constexpr placement new
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2747r2.html> (Revzin),
> adopted for C++26; feature-test macro is __cpp_lib_constexpr_new
> - P2738 constexpr cast from void*
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2738r1.pdf>
> (Jabot, Ledger), adopted for C++26: feature-test macro is (__cpp_constexpr
> == 202306L)
>
> The former seems to be exactly what you're asking for
> with constexpr `::new (p) T(...)`.
> The latter seems to be *almost* exactly what you're asking for with
> constexpr `reinterpret_cast<T*>(p)`, except that you are required to spell
> it `static_cast<T*>(static_cast<void*>(p))` instead of using the
> `reinterpret_cast` operator itself.
>
> My initial understanding was that these proposals would make this legal in
> C++26—
> https://godbolt.org/z/bbdGaMv4e
>
> template<class T>
> constexpr T f() {
> alignas(alignof(T)) char data[sizeof(T)];
> T *p = ::new (data) T();
> T t = *p;
> p->~T();
> return t;
> }
> static_assert(f<std::string>() == "");
>
> —but both Clang and GCC claim to have implemented them, and neither Clang
> nor GCC accepts this code.
>
Because the code is invalid.
>
> Both Clang and GCC accept this `union`-based code, though:
> https://godbolt.org/z/frhjh9nEx
>
> template<class T>
> constexpr T f() {
> union U {
> constexpr U() {}
> constexpr ~U() {}
> char c_;
> T t_;
> } data;
> T *p = ::new (&data.t_) T();
> T t = *p;
> p->~T();
> return t;
> }
> static_assert(f<std::string>() == "");
>
This is valid though.
>
> GCC (but not Clang) even accepts this:
> https://godbolt.org/z/fqxnfM6eo
>
> template<class T>
> constexpr T f() {
> union U {
> constexpr U() {}
> constexpr ~U() {}
> char c_;
> T t_;
> } data;
> T *p = ::new (&data) T();
> T t = *p;
> p->~T();
> return t;
> }
> static_assert(f<std::string>() == "");
>
This should also be valid (&data is pointer-interconvertible with &data.t_).
Barry
std-proposals_at_[hidden]> wrote:
> On Sat, Nov 30, 2024 at 6:42 PM James via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> Hi, I mean a specific valid runtime code should be able to run at compile
>> time. Nothing more. The following code is pretty much valid, but you can't
>> do it in compile time:
>> ```cpp
>> alignas(alignof(T)) std::byte data[sizeof(T)];
>> new(&data) T();
>> std::launder(reinterpret_cast<T*>(&data))->~T();
>> ```
>>
>> Compilers can detect overflow, memory leak, etc and don't allow it in
>> compile time. I'd like to see a similar approach. Allow both placement new
>> and reinterpret_cast, if usage is valid.
>>
>
> Read these two recent proposals, both already adopted for C++26:
> - P2747 constexpr placement new
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2747r2.html> (Revzin),
> adopted for C++26; feature-test macro is __cpp_lib_constexpr_new
> - P2738 constexpr cast from void*
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2738r1.pdf>
> (Jabot, Ledger), adopted for C++26: feature-test macro is (__cpp_constexpr
> == 202306L)
>
> The former seems to be exactly what you're asking for
> with constexpr `::new (p) T(...)`.
> The latter seems to be *almost* exactly what you're asking for with
> constexpr `reinterpret_cast<T*>(p)`, except that you are required to spell
> it `static_cast<T*>(static_cast<void*>(p))` instead of using the
> `reinterpret_cast` operator itself.
>
> My initial understanding was that these proposals would make this legal in
> C++26—
> https://godbolt.org/z/bbdGaMv4e
>
> template<class T>
> constexpr T f() {
> alignas(alignof(T)) char data[sizeof(T)];
> T *p = ::new (data) T();
> T t = *p;
> p->~T();
> return t;
> }
> static_assert(f<std::string>() == "");
>
> —but both Clang and GCC claim to have implemented them, and neither Clang
> nor GCC accepts this code.
>
Because the code is invalid.
>
> Both Clang and GCC accept this `union`-based code, though:
> https://godbolt.org/z/frhjh9nEx
>
> template<class T>
> constexpr T f() {
> union U {
> constexpr U() {}
> constexpr ~U() {}
> char c_;
> T t_;
> } data;
> T *p = ::new (&data.t_) T();
> T t = *p;
> p->~T();
> return t;
> }
> static_assert(f<std::string>() == "");
>
This is valid though.
>
> GCC (but not Clang) even accepts this:
> https://godbolt.org/z/fqxnfM6eo
>
> template<class T>
> constexpr T f() {
> union U {
> constexpr U() {}
> constexpr ~U() {}
> char c_;
> T t_;
> } data;
> T *p = ::new (&data) T();
> T t = *p;
> p->~T();
> return t;
> }
> static_assert(f<std::string>() == "");
>
This should also be valid (&data is pointer-interconvertible with &data.t_).
Barry
Received on 2024-12-01 02:30:02