Tested x86_64-linux. Pushed to trunk. -- >8 --
We can use if-constexpr and variable templates to simplify and optimize std::to_address. This should compile faster (and run faster for -O0) than dispatching to the pre-C++20 std::__to_address overloads. libstdc++-v3/ChangeLog: * include/bits/ptr_traits.h (to_address): Optimize. * testsuite/20_util/to_address/1_neg.cc: Adjust dg-error text. --- libstdc++-v3/include/bits/ptr_traits.h | 47 +++++++++++-------- .../testsuite/20_util/to_address/1_neg.cc | 2 +- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h index 6c65001cb74..ca67feecca3 100644 --- a/libstdc++-v3/include/bits/ptr_traits.h +++ b/libstdc++-v3/include/bits/ptr_traits.h @@ -200,36 +200,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Ptr, typename _Tp> using __ptr_rebind = typename pointer_traits<_Ptr>::template rebind<_Tp>; +#ifndef __glibcxx_to_address // C++ < 20 template<typename _Tp> + [[__gnu__::__always_inline__]] constexpr _Tp* __to_address(_Tp* __ptr) noexcept { - static_assert(!std::is_function<_Tp>::value, "not a function pointer"); + static_assert(!std::is_function<_Tp>::value, "std::to_address argument " + "must not be a function pointer"); return __ptr; } -#ifndef __glibcxx_to_address // C++ < 20 template<typename _Ptr> constexpr typename std::pointer_traits<_Ptr>::element_type* __to_address(const _Ptr& __ptr) { return std::__to_address(__ptr.operator->()); } #else - template<typename _Ptr> - constexpr auto - __to_address(const _Ptr& __ptr) noexcept - -> decltype(std::pointer_traits<_Ptr>::to_address(__ptr)) - { return std::pointer_traits<_Ptr>::to_address(__ptr); } - - template<typename _Ptr, typename... _None> - constexpr auto - __to_address(const _Ptr& __ptr, _None...) noexcept - { - if constexpr (is_base_of_v<__gnu_debug::_Safe_iterator_base, _Ptr>) - return std::__to_address(__ptr.base().operator->()); - else - return std::__to_address(__ptr.operator->()); - } - /** * @brief Obtain address referenced by a pointer to an object * @param __ptr A pointer to an object @@ -237,9 +223,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @ingroup pointer_abstractions */ template<typename _Tp> + [[__gnu__::__always_inline__]] constexpr _Tp* to_address(_Tp* __ptr) noexcept - { return std::__to_address(__ptr); } + { + static_assert(!is_function_v<_Tp>, "std::to_address argument " + "must not be a function pointer"); + return __ptr; + } /** * @brief Obtain address referenced by a pointer to an object @@ -251,7 +242,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Ptr> constexpr auto to_address(const _Ptr& __ptr) noexcept - { return std::__to_address(__ptr); } + { + if constexpr (requires { pointer_traits<_Ptr>::to_address(__ptr); }) + return pointer_traits<_Ptr>::to_address(__ptr); + else if constexpr (is_base_of_v<__gnu_debug::_Safe_iterator_base, _Ptr>) + return std::to_address(__ptr.base().operator->()); + else + return std::to_address(__ptr.operator->()); + } + + /// @cond undocumented + /// Compatibility for use in code that is also compiled as pre-C++20. + template<typename _Ptr> + [[__gnu__::__always_inline__]] + constexpr auto + __to_address(const _Ptr& __ptr) noexcept + { return std::to_address(__ptr); } + /// @endcond #endif // __glibcxx_to_address _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/testsuite/20_util/to_address/1_neg.cc b/libstdc++-v3/testsuite/20_util/to_address/1_neg.cc index 7385f0f335c..10e919757bb 100644 --- a/libstdc++-v3/testsuite/20_util/to_address/1_neg.cc +++ b/libstdc++-v3/testsuite/20_util/to_address/1_neg.cc @@ -16,7 +16,7 @@ // <http://www.gnu.org/licenses/>. // { dg-do compile { target c++20 } } -// { dg-error "not a function pointer" "" { target *-*-* } 0 } +// { dg-error "must not be a function pointer" "" { target *-*-* } 0 } #include <memory> -- 2.45.1