Skip to content

Commit

Permalink
Add check for __builtin_addressof
Browse files Browse the repository at this point in the history
  • Loading branch information
lackhole committed Aug 2, 2024
1 parent 80383d1 commit 27aea9e
Show file tree
Hide file tree
Showing 12 changed files with 121 additions and 50 deletions.
2 changes: 2 additions & 0 deletions cmake/RunConfiguration.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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})

Expand Down
11 changes: 11 additions & 0 deletions cmake/config/HaveConstexprBuiltinAddressof.cmake
Original file line number Diff line number Diff line change
@@ -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()
24 changes: 12 additions & 12 deletions include/preview/__expected/expected.h
Original file line number Diff line number Diff line change
Expand Up @@ -1066,34 +1066,34 @@ class expected : private detail::expected_control_smf<detail::void_placdholder_o
template<typename Any>
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;
}
}

static PREVIEW_CONSTEXPR_AFTER_CXX23
void swap_value_with_error(expected& thiz, expected& other, std::false_type /* void */, std::false_type /* nothrow */) noexcept(nothrow_swappable::value) {
T temp(std::move(thiz.value()));
preview::destroy_at(std::addressof(thiz.value()));
preview::destroy_at(preview::addressof(thiz.value()));
try {
preview::construct_at(std::addressof(thiz.error()), std::move(other.error()));
preview::destroy_at(std::addressof(other.error()));
preview::construct_at(std::addressof(other.value()), std::move(temp));
preview::construct_at(preview::addressof(thiz.error()), std::move(other.error()));
preview::destroy_at(preview::addressof(other.error()));
preview::construct_at(preview::addressof(other.value()), std::move(temp));
} catch (...) {
preview::construct_at(std::addressof(thiz.value()), std::move(temp));
preview::construct_at(preview::addressof(thiz.value()), std::move(temp));
throw;
}
}
Expand Down
63 changes: 49 additions & 14 deletions include/preview/__memory/addressof.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,71 @@
#include <memory>
#include <type_traits>

#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<typename = void>
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<typename T>
constexpr T* addressof(T& t) noexcept {
constexpr T* addressof_object(T& t, std::true_type) noexcept {
return __builtin_addressof(t);
}
# else

template<typename T>
std::enable_if_t<std::is_object<T>::value, T*>
addressof(T& t) noexcept {
return
reinterpret_cast<T*>(
T* addressof_object(T& t, std::false_type) noexcept {
return reinterpret_cast<T*>(
&const_cast<char&>(
reinterpret_cast<const volatile char&>(t)
reinterpret_cast<const volatile char&>(t)
)
);
);
}

template<typename T>
constexpr T* addressof_impl(T& t, std::true_type /* is_object */) noexcept {
return preview::detail::addressof_object(t, have_builtin_addressof<>{});
}

template<typename T>
constexpr std::enable_if_t<std::is_object<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<typename T>
constexpr T* addressof(T& t) noexcept {
return std::addressof(t);
}
# else
# if PREVIEW_HAVE_CONSTEXPR_BUILTIN_ADDRESSOF
template<typename T>
constexpr T* addressof(T& t) noexcept {
return __builtin_addressof(t);
}
# else
template<typename T>
constexpr T* addressof(T& t) noexcept {
return preview::detail::addressof_impl(t, std::is_object<T>{});
}
# endif
# endif

template<typename T>
Expand Down
11 changes: 6 additions & 5 deletions include/preview/__optional/optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -168,13 +169,13 @@ struct optional_base {

template<typename ...Args>
void construct_with(Args&&... args) {
preview::construct_at(std::addressof(storage_.value), std::forward<Args>(args)...);
preview::construct_at(preview::addressof(storage_.value), std::forward<Args>(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:
Expand Down
2 changes: 1 addition & 1 deletion include/preview/__ranges/views/basic_istream_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class basic_istream_view : public view_interface<basic_istream_view<Val, CharT,


PREVIEW_CONSTEXPR_AFTER_CXX17 explicit basic_istream_view(std::basic_istream<CharT, Traits>& stream)
: stream_(std::addressof(stream)), value_() {}
: stream_(preview::addressof(stream)), value_() {}

constexpr auto begin() {
read();
Expand Down
6 changes: 3 additions & 3 deletions include/preview/__ranges/views/lazy_split_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
#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"
#include "preview/__ranges/input_range.h"
#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"
Expand Down Expand Up @@ -136,13 +136,13 @@ class lazy_split_view
negation<forward_range<Base>>
>::value, int> = 0>
PREVIEW_CONSTEXPR_AFTER_CXX17 explicit outer_iterator(Parent& parent)
: parent_(std::addressof(parent)) {}
: parent_(preview::addressof(parent)) {}

template<typename Dummy = void, std::enable_if_t<conjunction<std::is_void<Dummy>,
forward_range<Base>
>::value, int> = 0>
PREVIEW_CONSTEXPR_AFTER_CXX17 explicit outer_iterator(Parent& parent, iterator_t<Base> current)
: parent_(std::addressof(parent))
: parent_(preview::addressof(parent))
, current_(std::move(current)) {}

template<bool AntiConst, std::enable_if_t<conjunction<
Expand Down
5 changes: 3 additions & 2 deletions include/preview/__ranges/views/take_while_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "preview/__concepts/copy_constructible.h"
#include "preview/__functional/invoke.h"
#include "preview/__iterator/indirect_unary_predicate.h"
#include "preview/__memory/addressof.h"
#include "preview/__ranges/begin.h"
#include "preview/__ranges/input_range.h"
#include "preview/__ranges/iterator_t.h"
Expand Down Expand Up @@ -157,15 +158,15 @@ class take_while_view : public view_interface<take_while_view<V, Pred>> {
negation<simple_view<V>>
>::value, int> = 0>
PREVIEW_CONSTEXPR_AFTER_CXX17 auto end() {
return sentinel<false>{ranges::end(base_), std::addressof(*pred_)};
return sentinel<false>{ranges::end(base_), preview::addressof(*pred_)};
}

template<typename Dummy = void, std::enable_if_t<preview::conjunction<std::is_void<Dummy>,
range<const V>,
indirect_unary_predicate<const Pred, iterator_t<const V>>
>::value, int> = 0>
PREVIEW_CONSTEXPR_AFTER_CXX17 auto end() const {
return sentinel<true>{ranges::end(base_), std::addressof(*pred_)};
return sentinel<true>{ranges::end(base_), preview::addressof(*pred_)};
}

private:
Expand Down
3 changes: 2 additions & 1 deletion include/preview/__ranges/views/zip_transform_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -286,7 +287,7 @@ class zip_transform_view : public view_interface<zip_transform_view<Views...>> {

private:
PREVIEW_CONSTEXPR_AFTER_CXX17 iterator(Parent& parent, ziperator<Const> inner)
: parent_(std::addressof(parent)), inner_(std::move(inner)) {}
: parent_(preview::addressof(parent)), inner_(std::move(inner)) {}

Parent* parent_{};
ziperator<Const> inner_{};
Expand Down
6 changes: 4 additions & 2 deletions include/preview/cmake_config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@

#ifdef PREVIEW_CMAKE_CONFIG

#cmakedefine01 PREVIEW_HAVE_CONSTEXPR_BUILTIN_ADDRESSOF
#cmakedefine01 PREVIEW_HAVE_STRING_VIEW
#cmakedefine01 PREVIEW_HAVE_CONTIGUOUS_ITERATOR_TAG

#else

#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
1 change: 0 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,6 @@ function(preview_add_multi_version_test name_prefix test_src)
BUILD_COMMAND ""
INSTALL_COMMAND ""
BUILD_BYPRODUCTS
"<BINARY_DIR>/${PREVIEW_RELATIVE_GENERATED_INCLUDE_DIR}"
"<BINARY_DIR>/${PREVIEW_RELATIVE_GENERATED_INCLUDE_DIR}/preview/cmake_config.h"
)
add_dependencies(${target_name} preview-configure-${target_name})
Expand Down
37 changes: 28 additions & 9 deletions test/memory.cc
Original file line number Diff line number Diff line change
@@ -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_;
Expand All @@ -18,13 +40,10 @@ class S
};

TEST(VERSIONED(Memory), construct_at) {



alignas(S) unsigned char storage[sizeof(S)]{};
S uninitialized = std::bit_cast<S>(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<S>(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);
}

0 comments on commit 27aea9e

Please sign in to comment.