From 9a94739d3924e083e69400b05a171c56517e6109 Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Sat, 3 Aug 2024 02:46:02 +0900 Subject: [PATCH] Add check for __builtin_addressof --- cmake/RunConfiguration.cmake | 2 + .../HaveConstexprBuiltinAddressof.cmake | 11 ++++ include/preview/__expected/expected.h | 24 +++---- include/preview/__memory/addressof.h | 63 ++++++++++++++----- include/preview/__optional/optional.h | 11 ++-- .../__ranges/views/basic_istream_view.h | 2 +- .../preview/__ranges/views/lazy_split_view.h | 6 +- .../preview/__ranges/views/take_while_view.h | 5 +- .../__ranges/views/zip_transform_view.h | 3 +- include/preview/cmake_config.h.in | 6 +- test/CMakeLists.txt | 1 - test/memory.cc | 37 ++++++++--- 12 files changed, 121 insertions(+), 50 deletions(-) create mode 100644 cmake/config/HaveConstexprBuiltinAddressof.cmake diff --git a/cmake/RunConfiguration.cmake b/cmake/RunConfiguration.cmake index 2cbaa0c..dfcac82 100644 --- a/cmake/RunConfiguration.cmake +++ b/cmake/RunConfiguration.cmake @@ -2,12 +2,14 @@ include(CheckCXXSourceCompiles) include(CheckCXXCompilerFlag) include(CheckCXXSymbolExists) +include(config/HaveConstexprBuiltinAddressof) include(config/HaveContiguousIteratorTag) include(config/HaveStringView) set(PREVIEW_CONFIG_INPUT_FILE "${PREVIEW_INCLUDE_DIR}/preview/cmake_config.h.in") function(RunConfiguration out_dir flags) + HaveConstexprBuiltinAddressof(PREVIEW_HAVE_CONSTEXPR_BUILTIN_ADDRESSOF ${flags}) HaveContiguousIteratorTag(PREVIEW_HAVE_CONTIGUOUS_ITERATOR_TAG ${flags}) HaveStringView(PREVIEW_HAVE_STRING_VIEW ${flags}) diff --git a/cmake/config/HaveConstexprBuiltinAddressof.cmake b/cmake/config/HaveConstexprBuiltinAddressof.cmake new file mode 100644 index 0000000..2ae780a --- /dev/null +++ b/cmake/config/HaveConstexprBuiltinAddressof.cmake @@ -0,0 +1,11 @@ +set(HaveConstexprBuiltinAddressof_Source " +constexpr int x = 0; +constexpr auto ptr = __builtin_addressof(x); +static_assert(ptr == &x, \"\"); +int main() { return 0; }") + +function(HaveConstexprBuiltinAddressof out) + set(CMAKE_REQUIRED_FLAGS ${ARGN}) + check_cxx_source_compiles("${HaveConstexprBuiltinAddressof_Source}" ${out}) + set(${out} ${${out}} PARENT_SCOPE) +endfunction() diff --git a/include/preview/__expected/expected.h b/include/preview/__expected/expected.h index 18a7ad9..1fccc15 100644 --- a/include/preview/__expected/expected.h +++ b/include/preview/__expected/expected.h @@ -1066,20 +1066,20 @@ class expected : private detail::expected_control_smf static PREVIEW_CONSTEXPR_AFTER_CXX17 void swap_value_with_error(expected& thiz, expected& other, std::true_type /* void */, Any) noexcept(error_nothrow_swappable::value) { - preview::construct_at(std::addressof(thiz.error()), std::move(other.error())); - preview::destroy_at(std::addressof(other.error())); + preview::construct_at(preview::addressof(thiz.error()), std::move(other.error())); + preview::destroy_at(preview::addressof(other.error())); } static PREVIEW_CONSTEXPR_AFTER_CXX23 void swap_value_with_error(expected& thiz, expected& other, std::false_type /* void */, std::true_type /* nothrow */) noexcept(nothrow_swappable::value) { E temp(std::move(other.error())); - preview::destroy_at(std::addressof(other.error())); + preview::destroy_at(preview::addressof(other.error())); try { - preview::construct_at(std::addressof(other.value()), std::move(thiz.value())); - preview::destroy_at(std::addressof(thiz.value())); - preview::construct_at(std::addressof(thiz.error()), std::move(temp)); + preview::construct_at(preview::addressof(other.value()), std::move(thiz.value())); + preview::destroy_at(preview::addressof(thiz.value())); + preview::construct_at(preview::addressof(thiz.error()), std::move(temp)); } catch (...) { - preview::construct_at(std::addressof(other.error()), std::move(temp)); + preview::construct_at(preview::addressof(other.error()), std::move(temp)); throw; } } @@ -1087,13 +1087,13 @@ class expected : private detail::expected_control_smf #include +#include "preview/core.h" +#include "preview/config.h" +#include "preview/__type_traits/void_t.h" + namespace preview { +namespace detail { + +PREVIEW_INLINE_VARIABLE constexpr int builtin_addressof_tester{}; + +template +struct have_builtin_addressof : std::false_type {}; + +template<> +struct have_builtin_addressof< + void_t< + decltype(std::integral_constant< + bool, + (&builtin_addressof_tester == __builtin_addressof(builtin_addressof_tester)) + >{}) + > +> : std::true_type {}; -# if __cplusplus < 201703L -# ifdef PREVIEW_CONSTEXPR_BUILTIN_ADDRESSOF_CXX14 template -constexpr T* addressof(T& t) noexcept { +constexpr T* addressof_object(T& t, std::true_type) noexcept { return __builtin_addressof(t); } -# else + template -std::enable_if_t::value, T*> -addressof(T& t) noexcept { - return - reinterpret_cast( +T* addressof_object(T& t, std::false_type) noexcept { + return reinterpret_cast( &const_cast( - reinterpret_cast(t) + reinterpret_cast(t) ) - ); + ); } + +template +constexpr T* addressof_impl(T& t, std::true_type /* is_object */) noexcept { + return preview::detail::addressof_object(t, have_builtin_addressof<>{}); +} + template -constexpr std::enable_if_t::value == false, T*> -addressof(T& t) noexcept { +constexpr T* addressof_impl(T& t, std::false_type /* is_object */) noexcept { return &t; } -# endif -# else + +} // namespace detail + +# if PREVIEW_CXX_VERSION >= 17 template constexpr T* addressof(T& t) noexcept { return std::addressof(t); } +# else +# if PREVIEW_HAVE_CONSTEXPR_BUILTIN_ADDRESSOF +template +constexpr T* addressof(T& t) noexcept { + return __builtin_addressof(t); +} +# else +template +constexpr T* addressof(T& t) noexcept { + return preview::detail::addressof_impl(t, std::is_object{}); +} +# endif # endif template diff --git a/include/preview/__optional/optional.h b/include/preview/__optional/optional.h index b8271ba..042e77e 100644 --- a/include/preview/__optional/optional.h +++ b/include/preview/__optional/optional.h @@ -14,6 +14,7 @@ # include "preview/__concepts/invocable.h" # include "preview/__concepts/move_constructible.h" # include "preview/__functional/invoke.h" +# include "preview/__memory/addressof.h" # include "preview/__memory/construct_at.h" # include "preview/__memory/destroy_at.h" # include "preview/__optional/bad_optional_access.h" @@ -84,13 +85,13 @@ struct optional_base { void reset() { if (storage_.has_value) { - preview::destroy_at(std::addressof(storage_.value)); + preview::destroy_at(preview::addressof(storage_.value)); storage_.has_value = false; } } - PREVIEW_CONSTEXPR_AFTER_CXX17 const value_type* operator->() const noexcept { return std::addressof(storage_.value); } - PREVIEW_CONSTEXPR_AFTER_CXX17 value_type* operator->() noexcept { return std::addressof(storage_.value); } + PREVIEW_CONSTEXPR_AFTER_CXX17 const value_type* operator->() const noexcept { return preview::addressof(storage_.value); } + PREVIEW_CONSTEXPR_AFTER_CXX17 value_type* operator->() noexcept { return preview::addressof(storage_.value); } constexpr const value_type& operator*() const& noexcept { return storage_.value; } constexpr value_type& operator*() & noexcept { return storage_.value; } @@ -168,13 +169,13 @@ struct optional_base { template void construct_with(Args&&... args) { - preview::construct_at(std::addressof(storage_.value), std::forward(args)...); + preview::construct_at(preview::addressof(storage_.value), std::forward(args)...); storage_.has_value = true; } void destruct() { if (has_value()) - preview::destroy_at(std::addressof(storage_.value)); + preview::destroy_at(preview::addressof(storage_.value)); } private: diff --git a/include/preview/__ranges/views/basic_istream_view.h b/include/preview/__ranges/views/basic_istream_view.h index 75f050f..2b62c06 100644 --- a/include/preview/__ranges/views/basic_istream_view.h +++ b/include/preview/__ranges/views/basic_istream_view.h @@ -107,7 +107,7 @@ class basic_istream_view : public view_interface& stream) - : stream_(std::addressof(stream)), value_() {} + : stream_(preview::addressof(stream)), value_() {} constexpr auto begin() { read(); diff --git a/include/preview/__ranges/views/lazy_split_view.h b/include/preview/__ranges/views/lazy_split_view.h index 08fc718..695f6ac 100644 --- a/include/preview/__ranges/views/lazy_split_view.h +++ b/include/preview/__ranges/views/lazy_split_view.h @@ -24,6 +24,7 @@ #include "preview/__iterator/iterator_tag.h" #include "preview/__iterator/iterator_traits.h" #include "preview/__iterator/detail/have_cxx20_iterator.h" +#include "preview/__memory/addressof.h" #include "preview/__ranges/begin.h" #include "preview/__ranges/end.h" #include "preview/__ranges/forward_range.h" @@ -31,7 +32,6 @@ #include "preview/__ranges/iterator_t.h" #include "preview/__ranges/non_propagating_cache.h" #include "preview/__ranges/range_difference_t.h" -//#include "preview/__ranges/range_reference_t.h" #include "preview/__ranges/range_value_t.h" #include "preview/__ranges/simple_view.h" #include "preview/__ranges/sized_range.h" @@ -136,13 +136,13 @@ class lazy_split_view negation> >::value, int> = 0> PREVIEW_CONSTEXPR_AFTER_CXX17 explicit outer_iterator(Parent& parent) - : parent_(std::addressof(parent)) {} + : parent_(preview::addressof(parent)) {} template, forward_range >::value, int> = 0> PREVIEW_CONSTEXPR_AFTER_CXX17 explicit outer_iterator(Parent& parent, iterator_t current) - : parent_(std::addressof(parent)) + : parent_(preview::addressof(parent)) , current_(std::move(current)) {} template> { negation> >::value, int> = 0> PREVIEW_CONSTEXPR_AFTER_CXX17 auto end() { - return sentinel{ranges::end(base_), std::addressof(*pred_)}; + return sentinel{ranges::end(base_), preview::addressof(*pred_)}; } template, @@ -165,7 +166,7 @@ class take_while_view : public view_interface> { indirect_unary_predicate> >::value, int> = 0> PREVIEW_CONSTEXPR_AFTER_CXX17 auto end() const { - return sentinel{ranges::end(base_), std::addressof(*pred_)}; + return sentinel{ranges::end(base_), preview::addressof(*pred_)}; } private: diff --git a/include/preview/__ranges/views/zip_transform_view.h b/include/preview/__ranges/views/zip_transform_view.h index 8ffcdb9..8560225 100644 --- a/include/preview/__ranges/views/zip_transform_view.h +++ b/include/preview/__ranges/views/zip_transform_view.h @@ -21,6 +21,7 @@ #include "preview/__iterator/iterator_tag.h" #include "preview/__iterator/iterator_traits.h" #include "preview/__iterator/sized_sentinel_for.h" +#include "preview/__memory/addressof.h" #include "preview/__ranges/bidirectional_range.h" #include "preview/__ranges/forward_range.h" #include "preview/__ranges/input_range.h" @@ -286,7 +287,7 @@ class zip_transform_view : public view_interface> { private: PREVIEW_CONSTEXPR_AFTER_CXX17 iterator(Parent& parent, ziperator inner) - : parent_(std::addressof(parent)), inner_(std::move(inner)) {} + : parent_(preview::addressof(parent)), inner_(std::move(inner)) {} Parent* parent_{}; ziperator inner_{}; diff --git a/include/preview/cmake_config.h.in b/include/preview/cmake_config.h.in index 5ed0fd3..30b7c98 100644 --- a/include/preview/cmake_config.h.in +++ b/include/preview/cmake_config.h.in @@ -5,6 +5,7 @@ #ifdef PREVIEW_CMAKE_CONFIG +#cmakedefine01 PREVIEW_HAVE_CONSTEXPR_BUILTIN_ADDRESSOF #cmakedefine01 PREVIEW_HAVE_STRING_VIEW #cmakedefine01 PREVIEW_HAVE_CONTIGUOUS_ITERATOR_TAG @@ -12,7 +13,8 @@ #include "preview/core.h" -#define PREVIEW_HAVE_STRING_VIEW (PREVIEW_CXX_VERSION >= 17) -#define PREVIEW_HAVE_CONTIGUOUS_ITERATOR_TAG (PREVIEW_CXX_VERSION >= 20) +#define PREVIEW_HAVE_CONSTEXPR_BUILTIN_ADDRESSOF (PREVIEW_CXX_VERSION >= 17) +#define PREVIEW_HAVE_CONTIGUOUS_ITERATOR_TAG (PREVIEW_CXX_VERSION >= 20) +#define PREVIEW_HAVE_STRING_VIEW (PREVIEW_CXX_VERSION >= 17) #endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7273129..460943e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -183,7 +183,6 @@ function(preview_add_multi_version_test name_prefix test_src) BUILD_COMMAND "" INSTALL_COMMAND "" BUILD_BYPRODUCTS - "/${PREVIEW_RELATIVE_GENERATED_INCLUDE_DIR}" "/${PREVIEW_RELATIVE_GENERATED_INCLUDE_DIR}/preview/cmake_config.h" ) add_dependencies(${target_name} preview-configure-${target_name}) diff --git a/test/memory.cc b/test/memory.cc index f962e7d..b98d358 100644 --- a/test/memory.cc +++ b/test/memory.cc @@ -1,6 +1,28 @@ #include "preview/memory.h" #include "gtest.h" +struct bizarre_object { + int operator&() const { + return 3; + } +}; + +constexpr int global_y = 4; +TEST(VERSIONED(Memory), addressof) { + + int x = 3; + EXPECT_EQ(&x, preview::addressof(x)); + + bizarre_object obj; + EXPECT_EQ_TYPE(int, decltype(&obj)); + EXPECT_EQ_TYPE(bizarre_object*, decltype(preview::addressof(obj))); + +#if PREVIEW_CXX_VERSION >= 17 + constexpr auto ptr = preview::addressof(global_y); + (void)ptr; +#endif +} + class S { int x_; @@ -18,13 +40,10 @@ class S }; TEST(VERSIONED(Memory), construct_at) { - - - - alignas(S) unsigned char storage[sizeof(S)]{}; - S uninitialized = std::bit_cast(storage); - std::destroy_at(&uninitialized); - S* ptr = std::construct_at(std::addressof(uninitialized), 42, 2.71f, 3.14); - const bool res{*ptr == S{42, 2.71f, 3.14}}; - std::destroy_at(ptr); +// alignas(S) unsigned char storage[sizeof(S)]{}; +// S uninitialized = std::bit_cast(storage); +// std::destroy_at(&uninitialized); +// S* ptr = std::construct_at(std::addressof(uninitialized), 42, 2.71f, 3.14); +// const bool res{*ptr == S{42, 2.71f, 3.14}}; +// std::destroy_at(ptr); }