https://gcc.gnu.org/g:27c985b774b2ccb0d2aa9eb72acf05f98b790296
commit r15-3615-g27c985b774b2ccb0d2aa9eb72acf05f98b790296 Author: Jonathan Wakely <jwak...@redhat.com> Date: Wed Sep 11 10:17:23 2024 +0100 libstdc++: Simplify std::launder definition A single static assert is a much simpler way to implement the compile-time preconditions on std::launder than an overload set of deleted functions and function templates. The only difficulty is that <new> doesn't include <type_traits> so we can't use std::is_function and std::is_void for the checks. That can be worked around though, by using the __is_same and __is_function built-ins. If the __is_function built-in isn't supported then the __builtin_launder built-in will give an error anyway, since the commit preceding this one. We can also remove the redundant __cplusplus >= 201703L check around the definitions of std::launder and the interference constants, which are already guarded by the appropriate feature test macros. libstdc++-v3/ChangeLog: * libsupc++/new (launder): Add static_assert and remove deleted overloads. * testsuite/18_support/launder/requirements_neg.cc: Adjust expected diagnostics. Diff: --- libstdc++-v3/libsupc++/new | 36 +++++++++------------- .../18_support/launder/requirements_neg.cc | 15 +++++---- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new index 2e2038e1a82c..af5c7690bb99 100644 --- a/libstdc++-v3/libsupc++/new +++ b/libstdc++-v3/libsupc++/new @@ -198,7 +198,6 @@ inline void operator delete[](void*, void*) _GLIBCXX_USE_NOEXCEPT { } //@} } // extern "C++" -#if __cplusplus >= 201703L namespace std { #ifdef __cpp_lib_launder // C++ >= 17 && HAVE_BUILTIN_LAUNDER @@ -206,33 +205,28 @@ namespace std template<typename _Tp> [[nodiscard]] constexpr _Tp* launder(_Tp* __p) noexcept - { return __builtin_launder(__p); } - - // The program is ill-formed if T is a function type or - // (possibly cv-qualified) void. - - template<typename _Ret, typename... _Args _GLIBCXX_NOEXCEPT_PARM> - void launder(_Ret (*)(_Args...) _GLIBCXX_NOEXCEPT_QUAL) = delete; - template<typename _Ret, typename... _Args _GLIBCXX_NOEXCEPT_PARM> - void launder(_Ret (*)(_Args......) _GLIBCXX_NOEXCEPT_QUAL) = delete; - - void launder(void*) = delete; - void launder(const void*) = delete; - void launder(volatile void*) = delete; - void launder(const volatile void*) = delete; + { + if constexpr (__is_same(const volatile _Tp, const volatile void)) + static_assert(!__is_same(const volatile _Tp, const volatile void), + "std::launder argument must not be a void pointer"); +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) + else if constexpr (__is_function(_Tp)) + static_assert(!__is_function(_Tp), + "std::launder argument must not be a function pointer"); +#endif + else + return __builtin_launder(__p); + return nullptr; + } #endif // __cpp_lib_launder #ifdef __cpp_lib_hardware_interference_size // C++ >= 17 && defined(gcc_dest_sz) inline constexpr size_t hardware_destructive_interference_size = __GCC_DESTRUCTIVE_SIZE; inline constexpr size_t hardware_constructive_interference_size = __GCC_CONSTRUCTIVE_SIZE; #endif // __cpp_lib_hardware_interference_size -} -#endif // C++17 // Emitted despite the FTM potentially being undefined. -#if __cplusplus > 201703L -namespace std -{ +#if __cplusplus >= 202002L /// Tag type used to declare a class-specific operator delete that can /// invoke the destructor before deallocating the memory. struct destroying_delete_t @@ -241,8 +235,8 @@ namespace std }; /// Tag variable of type destroying_delete_t. inline constexpr destroying_delete_t destroying_delete{}; -} #endif // C++20 +} #pragma GCC visibility pop diff --git a/libstdc++-v3/testsuite/18_support/launder/requirements_neg.cc b/libstdc++-v3/testsuite/18_support/launder/requirements_neg.cc index 2808ebf614dd..82ce0b35a8c6 100644 --- a/libstdc++-v3/testsuite/18_support/launder/requirements_neg.cc +++ b/libstdc++-v3/testsuite/18_support/launder/requirements_neg.cc @@ -25,14 +25,17 @@ int f2(const char*, ...); void test01() { - std::launder( &f1 ); // { dg-error "deleted function" } - std::launder( &f2 ); // { dg-error "deleted function" } + std::launder( &f1 ); // { dg-error "here" } + std::launder( &f2 ); // { dg-error "here" } void* p = nullptr; - std::launder( p ); // { dg-error "deleted function" } + std::launder( p ); // { dg-error "here" } const void* cp = nullptr; - std::launder( cp ); // { dg-error "deleted function" } + std::launder( cp ); // { dg-error "here" } volatile void* vp = nullptr; - std::launder( vp ); // { dg-error "deleted function" } + std::launder( vp ); // { dg-error "here" } const volatile void* cvp = nullptr; - std::launder( cvp ); // { dg-error "deleted function" } + std::launder( cvp ); // { dg-error "here" } } +// { dg-error "std::launder argument must not be a void pointer" "" { target *-*-* } 0 } +// { dg-error "std::launder argument must not be a function pointer" "" { target *-*-* } 0 } +// { dg-warning "ignoring return value" "nodiscard" { target *-*-* } 0 }