Skip to content

Commit

Permalink
Bug fix: Function pointer can't be used to create a proxy (#50)
Browse files Browse the repository at this point in the history
* Bug fix: Function pointer can't be used to create a proxy

* Reduce warning
  • Loading branch information
mingxwa authored Dec 26, 2023
1 parent a6f65fe commit 30c87ef
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 9 deletions.
25 changes: 17 additions & 8 deletions proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,20 @@ consteval bool has_destructibility(constraint_level level) {

// As per std::to_address() wording in [pointer.conversion]
template <class P>
concept is_address_deducible =
(std::is_pointer_v<P> && !std::is_function_v<std::remove_pointer_t<P>>) ||
concept is_address_deducible = std::is_pointer_v<P> ||
requires(P p) { std::pointer_traits<P>::to_address(p); } ||
requires(P p) { p.operator->(); };

// Bypass function pointer restriction of std::to_address()
template <class P>
auto deduce_address(const P& p) {
if constexpr (std::is_pointer_v<P>) {
return p;
} else {
return std::to_address(p);
}
}

template <class T, class... Us> struct contains_traits : inapplicable_traits {};
template <class T, class... Us>
struct contains_traits<T, T, Us...> : applicable_traits {};
Expand Down Expand Up @@ -130,14 +139,14 @@ struct overload_traits<R(Args...)> : applicable_traits {

template <class D, class P>
static constexpr bool applicable_pointer = requires(const P& p, Args... args)
{ { D{}(*std::to_address(p), std::forward<Args>(args)...) }; };
{ D{}(*deduce_address(p), std::forward<Args>(args)...); };
template <class D, class P>
static R dispatcher(const char* erased, Args... args) {
const P& p = *reinterpret_cast<const P*>(erased);
if constexpr (std::is_void_v<R>) {
D{}(*std::to_address(p), std::forward<Args>(args)...);
D{}(*deduce_address(p), std::forward<Args>(args)...);
} else {
return D{}(*std::to_address(p), std::forward<Args>(args)...);
return D{}(*deduce_address(p), std::forward<Args>(args)...);
}
}
};
Expand Down Expand Up @@ -180,7 +189,7 @@ struct dispatch_traits_impl<D, std::tuple<Os...>> : applicable_traits,
template <class D> struct dispatch_traits : inapplicable_traits {};
template <class D> requires(requires {
typename D::overload_types;
{ D{} };
D{};
})
struct dispatch_traits<D>
: dispatch_traits_impl<D, typename D::overload_types> {};
Expand Down Expand Up @@ -603,7 +612,7 @@ struct facade_prototype {

#define PRO_DEF_MEMBER_DISPATCH(__NAME, ...) \
struct __NAME { \
using overload_types = std::tuple<__VA_ARGS__>;\
using overload_types = std::tuple<__VA_ARGS__>; \
template <class __T, class... __Args> \
decltype(auto) operator()(__T&& __self, __Args&&... __args) \
requires(requires{ std::forward<__T>(__self) \
Expand All @@ -614,7 +623,7 @@ struct facade_prototype {
}
#define PRO_DEF_FREE_DISPATCH(__NAME, __FUNC, ...) \
struct __NAME { \
using overload_types = std::tuple<__VA_ARGS__>;\
using overload_types = std::tuple<__VA_ARGS__>; \
template <class __T, class... __Args> \
decltype(auto) operator()(__T&& __self, __Args&&... __args) \
requires(requires{ __FUNC(std::forward<__T>(__self), \
Expand Down
8 changes: 7 additions & 1 deletion tests/proxy_invocation_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ struct Append {

} // namespace poly


template <class F, class D, class... Args>
concept InvocableWithDispatch = requires(pro::proxy<F> p, Args... args)
{ { p.template invoke<D>(std::forward<Args>(args)...) }; };
Expand Down Expand Up @@ -163,3 +162,10 @@ TEST(ProxyInvocationTests, TestOverloadResolution) {
ASSERT_EQ(side_effect, (GetTypeIndices<std::string, int>()));
ASSERT_FALSE((std::is_invocable_v<decltype(p), std::vector<int>>));
}

TEST(ProxyInvocationTests, TestFunctionPointer) {
struct TestFacade : poly::Callable<std::vector<std::type_index>()> {};
pro::proxy<TestFacade> p{ &GetTypeIndices<int, double> };
auto ret = p();
ASSERT_EQ(ret, (GetTypeIndices<int, double>()));
}
14 changes: 14 additions & 0 deletions tests/proxy_traits_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ using MockMovablePtr = MockPtr<true, false, false, sizeof(void*) * 2, alignof(vo
using MockCopyablePtr = MockPtr<true, true, false, sizeof(void*) * 2, alignof(void*)>;
using MockCopyableSmallPtr = MockPtr<true, true, false, sizeof(void*), alignof(void*)>;
using MockTrivialPtr = MockPtr<true, true, true, sizeof(void*), alignof(void*)>;
using MockFunctionPtr = void(*)();

PRO_DEF_FACADE(DefaultFacade);
static_assert(DefaultFacade::pointer_constraints.minimum_copyability == pro::constraint_level::none);
Expand All @@ -39,6 +40,7 @@ static_assert(std::is_nothrow_constructible_v<pro::proxy<DefaultFacade>, std::in
static_assert(std::is_nothrow_constructible_v<pro::proxy<DefaultFacade>, std::in_place_type_t<MockCopyablePtr>, int>);
static_assert(std::is_nothrow_constructible_v<pro::proxy<DefaultFacade>, std::in_place_type_t<MockCopyableSmallPtr>, int>);
static_assert(std::is_nothrow_constructible_v<pro::proxy<DefaultFacade>, std::in_place_type_t<MockTrivialPtr>, int>);
static_assert(std::is_nothrow_constructible_v<pro::proxy<DefaultFacade>, std::in_place_type_t<MockFunctionPtr>, MockFunctionPtr>);

PRO_DEF_FACADE(RelocatableFacade);
static_assert(!std::is_copy_constructible_v<pro::proxy<RelocatableFacade>>);
Expand All @@ -55,6 +57,7 @@ static_assert(pro::proxiable<MockMovablePtr, RelocatableFacade>);
static_assert(pro::proxiable<MockCopyablePtr, RelocatableFacade>);
static_assert(pro::proxiable<MockCopyableSmallPtr, RelocatableFacade>);
static_assert(pro::proxiable<MockTrivialPtr, RelocatableFacade>);
static_assert(pro::proxiable<MockFunctionPtr, RelocatableFacade>);
static_assert(std::is_nothrow_constructible_v<pro::proxy<RelocatableFacade>, MockMovablePtr>);
static_assert(std::is_nothrow_assignable_v<pro::proxy<RelocatableFacade>, MockMovablePtr>);
static_assert(std::is_nothrow_constructible_v<pro::proxy<RelocatableFacade>, MockCopyablePtr>);
Expand All @@ -63,6 +66,8 @@ static_assert(std::is_nothrow_constructible_v<pro::proxy<RelocatableFacade>, Moc
static_assert(std::is_nothrow_assignable_v<pro::proxy<RelocatableFacade>, MockCopyableSmallPtr>);
static_assert(std::is_nothrow_constructible_v<pro::proxy<RelocatableFacade>, MockTrivialPtr>);
static_assert(std::is_nothrow_assignable_v<pro::proxy<RelocatableFacade>, MockTrivialPtr>);
static_assert(std::is_nothrow_constructible_v<pro::proxy<RelocatableFacade>, MockFunctionPtr>);
static_assert(std::is_nothrow_assignable_v<pro::proxy<RelocatableFacade>, MockFunctionPtr>);

PRO_DEF_FACADE(CopyableFacade, PRO_MAKE_DISPATCH_PACK(), pro::copyable_pointer_constraints);
static_assert(std::is_copy_constructible_v<pro::proxy<CopyableFacade>>);
Expand All @@ -79,6 +84,7 @@ static_assert(!pro::proxiable<MockMovablePtr, CopyableFacade>);
static_assert(pro::proxiable<MockCopyablePtr, CopyableFacade>);
static_assert(pro::proxiable<MockCopyableSmallPtr, CopyableFacade>);
static_assert(pro::proxiable<MockTrivialPtr, CopyableFacade>);
static_assert(pro::proxiable<MockFunctionPtr, CopyableFacade>);
static_assert(!std::is_constructible_v<pro::proxy<CopyableFacade>, MockMovablePtr>);
static_assert(!std::is_assignable_v<pro::proxy<CopyableFacade>, MockMovablePtr>);
static_assert(std::is_nothrow_constructible_v<pro::proxy<CopyableFacade>, MockCopyablePtr>);
Expand All @@ -87,6 +93,8 @@ static_assert(std::is_nothrow_constructible_v<pro::proxy<CopyableFacade>, MockCo
static_assert(std::is_nothrow_assignable_v<pro::proxy<CopyableFacade>, MockCopyableSmallPtr>);
static_assert(std::is_nothrow_constructible_v<pro::proxy<CopyableFacade>, MockTrivialPtr>);
static_assert(std::is_nothrow_assignable_v<pro::proxy<CopyableFacade>, MockTrivialPtr>);
static_assert(std::is_nothrow_constructible_v<pro::proxy<CopyableFacade>, MockFunctionPtr>);
static_assert(std::is_nothrow_assignable_v<pro::proxy<CopyableFacade>, MockFunctionPtr>);

PRO_DEF_FACADE(CopyableSmallFacade, PRO_MAKE_DISPATCH_PACK(), pro::proxy_pointer_constraints{
.maximum_size = sizeof(void*),
Expand All @@ -99,6 +107,7 @@ static_assert(!pro::proxiable<MockMovablePtr, CopyableSmallFacade>);
static_assert(!pro::proxiable<MockCopyablePtr, CopyableSmallFacade>);
static_assert(pro::proxiable<MockCopyableSmallPtr, CopyableSmallFacade>);
static_assert(pro::proxiable<MockTrivialPtr, CopyableSmallFacade>);
static_assert(pro::proxiable<MockFunctionPtr, CopyableSmallFacade>);
static_assert(!std::is_constructible_v<pro::proxy<CopyableSmallFacade>, MockMovablePtr>);
static_assert(!std::is_assignable_v<pro::proxy<CopyableSmallFacade>, MockMovablePtr>);
static_assert(!std::is_constructible_v<pro::proxy<CopyableSmallFacade>, MockCopyablePtr>);
Expand All @@ -107,6 +116,8 @@ static_assert(std::is_nothrow_constructible_v<pro::proxy<CopyableSmallFacade>, M
static_assert(std::is_nothrow_assignable_v<pro::proxy<CopyableSmallFacade>, MockCopyableSmallPtr>);
static_assert(std::is_constructible_v<pro::proxy<CopyableSmallFacade>, MockTrivialPtr>);
static_assert(std::is_assignable_v<pro::proxy<CopyableSmallFacade>, MockTrivialPtr>);
static_assert(std::is_constructible_v<pro::proxy<CopyableSmallFacade>, MockFunctionPtr>);
static_assert(std::is_assignable_v<pro::proxy<CopyableSmallFacade>, MockFunctionPtr>);

PRO_DEF_FACADE(TrivialFacade, PRO_MAKE_DISPATCH_PACK(), pro::trivial_pointer_constraints);
static_assert(std::is_trivially_copy_constructible_v<pro::proxy<TrivialFacade>>);
Expand All @@ -120,6 +131,7 @@ static_assert(!pro::proxiable<MockMovablePtr, TrivialFacade>);
static_assert(!pro::proxiable<MockCopyablePtr, TrivialFacade>);
static_assert(!pro::proxiable<MockCopyableSmallPtr, TrivialFacade>);
static_assert(pro::proxiable<MockTrivialPtr, TrivialFacade>);
static_assert(pro::proxiable<MockFunctionPtr, TrivialFacade>);
static_assert(!std::is_constructible_v<pro::proxy<TrivialFacade>, MockMovablePtr>);
static_assert(!std::is_assignable_v<pro::proxy<TrivialFacade>, MockMovablePtr>);
static_assert(!std::is_constructible_v<pro::proxy<TrivialFacade>, MockCopyablePtr>);
Expand All @@ -128,5 +140,7 @@ static_assert(!std::is_constructible_v<pro::proxy<TrivialFacade>, MockCopyableSm
static_assert(!std::is_assignable_v<pro::proxy<TrivialFacade>, MockCopyableSmallPtr>);
static_assert(std::is_nothrow_constructible_v<pro::proxy<TrivialFacade>, MockTrivialPtr>);
static_assert(std::is_nothrow_assignable_v<pro::proxy<TrivialFacade>, MockTrivialPtr>);
static_assert(std::is_nothrow_constructible_v<pro::proxy<TrivialFacade>, MockFunctionPtr>);
static_assert(std::is_nothrow_assignable_v<pro::proxy<TrivialFacade>, MockFunctionPtr>);

} // namespace

0 comments on commit 30c87ef

Please sign in to comment.