Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions include/embed/embed_function.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1465,7 +1465,6 @@ inline namespace fn_traits {
template <typename T>
struct is_register_passable {
static constexpr std::size_t obj_size = sizeof(T);
static constexpr bool is_trivial_for_calls = is_itanium_trivial_for_calls<T>::value;

#if defined(__sparc_v8__) || defined(__sparcv8)
// Class and union object are not allowed to pass by reg in SPARC V8 (32bit).
Expand All @@ -1474,10 +1473,10 @@ inline namespace fn_traits {
// See <https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-180#parameter-passing>.
static_assert(sizeof(void*) == 8, EMBED_DETAIL_REPORT_IE("sizeof(void*) != 8 in Windows x64."));
static constexpr bool size_is_ok = obj_size == 1 || obj_size == 2 || obj_size == 4 || obj_size == 8;
static constexpr bool value = !std::is_reference<T>::value && is_trivial_for_calls && size_is_ok;
static constexpr bool value = is_itanium_trivial_for_calls<T>::value && size_is_ok;
#else
static constexpr bool size_is_ok = sizeof(T) <= 2 * sizeof(void*);
static constexpr bool value = !std::is_reference<T>::value && is_trivial_for_calls && size_is_ok;
static constexpr bool value = is_itanium_trivial_for_calls<T>::value && size_is_ok;
#endif
};

Expand Down Expand Up @@ -2853,13 +2852,12 @@ namespace crtp_mixins {
/// and returns a value convertible to `Ret`. (The Signature is `Ret(Args...)`)
/// @note Used for function reference only. (NON-OWNING)
EMBED_DETAIL_TEMPLATE_BEGIN(typename Functor,
typename Tp = remove_reference_t<Functor>,
typename Tp_cv = add_cv_like_sig_t<Tp>)
typename Tp = remove_reference_t<Functor>)
EMBED_DETAIL_REQUIRES_END(
(!is_self<Functor, function>::value)
&& is_invocable_using<Tp_cv&>::value
&& (!std::is_member_pointer<Tp>::value)
&& (!fn_can_convert<function, Functor>::value)
&& (!std::is_member_pointer<Tp>::value)
&& is_invocable_using<add_cv_like_sig_t<Tp>&>::value
&& Config::isView
) EMBED_CXX20_CONSTEXPR function(Functor&& functor) noexcept
: MemberVariableBase(nullptr) {
Expand Down
17 changes: 17 additions & 0 deletions test/conformance/fn_ref/conformance.addition.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ struct empty_trivial_but_state {
std::uintptr_t operator()() const { return reinterpret_cast<std::uintptr_t>(this); }
};

#if (EMBED_CXX_VERSION >= 202302L && __cpp_static_call_operator >= 202207L)

struct Static_call_operator_test {
int operator()(int) const { return 0; }
static int operator()(long) { return 1; }
};

#endif

TEST(Conformance_fn_ref, conformance_addition_pass) {

{
Expand Down Expand Up @@ -205,6 +214,14 @@ TEST(Conformance_fn_ref, conformance_addition_pass) {
static_assert(std::is_same_v<decltype(f2), ebd::fn_ref<int(int, int) const noexcept>>, "BUG");
ASSERT_EQ(f2(1, 42), 43);
}
{
// static call operator
Static_call_operator_test obj{};
ebd::fn_ref<int(long)> f = obj;
ASSERT_EQ(f(0), 1);
ebd::fn_ref<int(long) const> f1 = obj;
ASSERT_EQ(f1(0), 1);
}
#endif

{
Expand Down
43 changes: 43 additions & 0 deletions test/test_AssignAndConvert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,46 @@ TEST(AssignAndConvert, ConstToNonConst) {
f_non_const = f_const; // OK
// f_const = f_non_const; // Error
}

// AssignAndConvert[5]
TEST(AssignAndConvert, StatelessAssign) {
{
ebd::fn<bool(int, int)> f1 = std::less<int>{};
auto f2 = f1;
ASSERT_EQ(f1(1, 2), true);
ASSERT_EQ(f1(2, 1), false);
ASSERT_EQ(f2(1, 2), true);
ASSERT_EQ(f2(2, 1), false);
auto f3 = std::move(f2);
ASSERT_EQ(f3(1, 2), true);
ASSERT_EQ(f3(2, 1), false);
}
{
ebd::safe_fn<bool(int, int)> f1 = std::less<int>{};
auto f2 = f1;
ASSERT_EQ(f1(1, 2), true);
ASSERT_EQ(f1(2, 1), false);
ASSERT_EQ(f2(1, 2), true);
ASSERT_EQ(f2(2, 1), false);
auto f3 = std::move(f2);
ASSERT_EQ(f3(1, 2), true);
ASSERT_EQ(f3(2, 1), false);
}
{
ebd::fn_ref<bool(int, int)> f1 = std::less<int>{};
auto f2 = f1;
ASSERT_EQ(f1(1, 2), true);
ASSERT_EQ(f1(2, 1), false);
ASSERT_EQ(f2(1, 2), true);
ASSERT_EQ(f2(2, 1), false);
auto f3 = std::move(f2);
ASSERT_EQ(f3(1, 2), true);
ASSERT_EQ(f3(2, 1), false);
}
{
ebd::unique_fn<bool(int, int)> f1 = std::less<int>{};
auto f2 = std::move(f1);
ASSERT_EQ(f2(1, 2), true);
ASSERT_EQ(f2(2, 1), false);
}
}