Skip to content

Commit

Permalink
Merge pull request facebookexperimental#430 from ericniebler/clang-on…
Browse files Browse the repository at this point in the history
…-windows

compiles and passes tests with clang-cl on windows
  • Loading branch information
ericniebler authored Sep 20, 2022
2 parents 944d0e4 + 7732a8c commit 849a9d1
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 79 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ if (PROJECT_IS_TOP_LEVEL)
include(gtest)
target_compile_features(gtest PUBLIC cxx_std_17)
target_compile_features(gtest_main PUBLIC cxx_std_17)
if (UNIFEX_CXX_COMPILER_CLANGCL)
target_compile_options(gtest PRIVATE -Wno-error)
target_compile_options(gtest_main PRIVATE -Wno-error)
endif()
add_subdirectory(test)
endif(BUILD_TESTING)
endif(BUILD_TESTING OR UNIFEX_BUILD_EXAMPLES)
Expand Down
2 changes: 1 addition & 1 deletion cmake/unifex_env.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ else()
message(WARNING "[unifex warning]: unknown compiler ${CMAKE_CXX_COMPILER_ID} !")
endif()

if (MSVC)
if (UNIFEX_CXX_COMPILER_MSVC)
# warning level 3 and all warnings as errors
add_compile_options(/W3 /WX)
else()
Expand Down
5 changes: 3 additions & 2 deletions include/unifex/config.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
# if __has_include(<coroutine>) && defined(__cpp_lib_coroutine)
# define UNIFEX_COROUTINES_HEADER <coroutine>
# define UNIFEX_COROUTINES_NAMESPACE std
# elif __has_include(<experimental/coroutine>)
# elif __has_include(<experimental/coroutine>) && \
!(defined(_MSC_VER) && defined(__clang__)) // clang-cl.exe
# define UNIFEX_COROUTINES_HEADER <experimental/coroutine>
# define UNIFEX_COROUTINES_NAMESPACE std::experimental
# else
Expand Down Expand Up @@ -129,7 +130,7 @@

#if defined(_MSC_VER)
# define UNIFEX_DECLARE_NON_DEDUCED_TYPE(NAME, ...) \
typename NAME, \
typename NAME = void, \
std::enable_if_t<std::is_same_v<NAME, __VA_ARGS__>, int> = 0
# define UNIFEX_USE_NON_DEDUCED_TYPE(NAME, ...) NAME
#else
Expand Down
17 changes: 1 addition & 16 deletions include/unifex/get_stop_token.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,11 @@ namespace _get_stop_token {
return (StopToken&&) stoken_;
}
};
#if !defined(__GNUC__) || defined(__clang__)
// gcc bug 79501 - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79501
//
// GCC currently does not permit member deduction guides unless they
// are at a namespace scope and fails with error:
// deduction guide '...' must be declared at namespace scope
// This deduction guide is probably not necessary, per P0091, and
// compiles on GCC without it, but clang-12 on macOS requires it.
//
// The above compile guard will ensure clang has the guide and GCC
// does not until 79501 is solved.
template <typename StopToken>
_awaiter(StopToken) -> _awaiter<StopToken>;

#endif // !defined(__GNUC__) || defined(__clang__)

template (typename Tag, typename Promise)
(requires same_as<Tag, tag_t<await_transform>>)
friend auto tag_invoke(Tag, Promise& promise, _awaitable) noexcept {
return _awaiter{_fn{}(promise)};
return _awaiter<callable_result_t<_fn, Promise&>>{_fn{}(promise)};
}
};

Expand Down
25 changes: 18 additions & 7 deletions include/unifex/let_error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,16 @@ class _rcvr<Source, Func, Receiver>::type final {
unifex::set_done(std::move(op->receiver_));
}

#if defined(_MSC_VER) && !defined(__clang__) // cl.exe
template <typename ErrorValue>
#else
template (typename ErrorValue)
(requires callable<Func, ErrorValue> AND
// For some reason, MSVC chokes on this when compiling with real concepts
sender_to<
callable_result_t<Func, ErrorValue>,
final_receiver<ErrorValue>>)
#endif
void set_error(ErrorValue e) noexcept {
// local copy, b/c deactivate_union_member deletes this
auto op = op_;
Expand Down Expand Up @@ -326,6 +335,10 @@ class _sndr<Source, Func>::type {
using final_senders_list =
map_type_list_t<sender_error_type_list_t<Source>, final_sender>;

template <typename Sender, typename Receiver>
using source_receiver =
receiver_type<member_t<Sender, Source>, Func, Receiver>;

template <typename... Errors>
using sends_done_impl = any_sends_done<Source, final_sender<Errors>...>;

Expand Down Expand Up @@ -365,18 +378,16 @@ class _sndr<Source, Func>::type {
, func_((Func2&&)func)
{}

template(
typename Sender,
typename Receiver,
typename...,
typename SourceReceiver = receiver_type<member_t<Sender, Source>, Func, Receiver>)
template(typename Sender, typename Receiver)
(requires same_as<remove_cvref_t<Sender>, type> AND
constructible_from<Func, member_t<Sender, Func>> AND
constructible_from<remove_cvref_t<Receiver>, Receiver> AND
sender_to<Source, SourceReceiver>)
sender_to<Source, source_receiver<Sender, Receiver>>)
friend auto tag_invoke(tag_t<unifex::connect>, Sender&& s, Receiver&& r)
noexcept(
is_nothrow_connectable_v<member_t<Sender, Source>, SourceReceiver> &&
is_nothrow_connectable_v<
member_t<Sender, Source>,
source_receiver<Sender, Receiver>> &&
std::is_nothrow_constructible_v<Func, member_t<Sender, Func>> &&
std::is_nothrow_constructible_v<remove_cvref_t<Receiver>, Receiver>)
-> operation_type<Source, Func, Receiver> {
Expand Down
10 changes: 5 additions & 5 deletions include/unifex/scheduler_concepts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ using schedule_result_t = decltype(schedule(UNIFEX_DECLVAL(S&&)));
template <typename S>
concept //
scheduler = //
copy_constructible<remove_cvref_t<S>> &&
equality_comparable<remove_cvref_t<S>> &&
requires(S&& s) {
schedule((S&&) s);
};
} &&
equality_comparable<remove_cvref_t<S>> &&
copy_constructible<remove_cvref_t<S>>;
#else
template <typename S>
UNIFEX_CONCEPT_FRAGMENT( //
Expand All @@ -114,9 +114,9 @@ UNIFEX_CONCEPT_FRAGMENT( //
template <typename S>
UNIFEX_CONCEPT //
scheduler = //
copy_constructible<remove_cvref_t<S>> &&
UNIFEX_FRAGMENT(unifex::_scheduler, S) &&
equality_comparable<remove_cvref_t<S>> &&
UNIFEX_FRAGMENT(unifex::_scheduler, S);
copy_constructible<remove_cvref_t<S>>;
#endif

namespace _get_scheduler {
Expand Down
8 changes: 4 additions & 4 deletions include/unifex/sender_concepts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ namespace _connect {
} // namespace _connect
inline const _connect::_cpo::_fn connect {};

template <typename Sender, typename Receiver>
using connect_result_t =
decltype(connect(UNIFEX_DECLVAL(Sender), UNIFEX_DECLVAL(Receiver)));

#if UNIFEX_CXX_CONCEPTS
// Define the sender_to concept without macros for
// improved diagnostics:
Expand All @@ -273,10 +277,6 @@ UNIFEX_CONCEPT //
UNIFEX_FRAGMENT(_sender_to, Sender, Receiver);
#endif

template <typename Sender, typename Receiver>
using connect_result_t =
decltype(connect(UNIFEX_DECLVAL(Sender), UNIFEX_DECLVAL(Receiver)));

/// \cond
template <typename Sender, typename Receiver>
using operation_t [[deprecated("Use connect_result_t instead of operation_t")]] =
Expand Down
10 changes: 5 additions & 5 deletions include/unifex/tag_invoke.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ namespace unifex {
using yes_type = char;
using no_type = char(&)[2];

template <typename CPO, typename... Args>
auto try_tag_invoke(int) //
template <typename CPO,
typename... Args,
typename = tag_invoke_result_t<CPO, Args...>>
yes_type try_tag_invoke(int) //
noexcept(noexcept(tag_invoke(
UNIFEX_DECLVAL(CPO &&), UNIFEX_DECLVAL(Args &&)...)))
-> decltype(static_cast<void>(tag_invoke(
UNIFEX_DECLVAL(CPO &&), UNIFEX_DECLVAL(Args &&)...)), yes_type{});
UNIFEX_DECLVAL(CPO &&), UNIFEX_DECLVAL(Args &&)...)));

template <typename CPO, typename... Args>
no_type try_tag_invoke(...) noexcept(false);
Expand Down
16 changes: 13 additions & 3 deletions include/unifex/win32/detail/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,14 @@ namespace unifex::win32
using long_t = long; // LONG

#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4201) // non-standard anonymous struct/union
# if defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wgnu-anonymous-struct"
# pragma GCC diagnostic ignored "-Wnested-anon-types"
# else
# pragma warning(push)
# pragma warning(disable : 4201) // non-standard anonymous struct/union
# endif
#endif
#if defined(__GNUC__)
# define UNIFEX_NAMELESS_UNION __extension__
Expand All @@ -50,7 +56,11 @@ namespace unifex::win32
};
#undef UNIFEX_NAMELESS_UNION
#if defined(_MSC_VER)
# pragma warning(pop)
# if defined(__clang__)
# pragma GCC diagnostic pop
# else
# pragma warning(pop)
# endif
#endif

struct wsabuf {
Expand Down
4 changes: 2 additions & 2 deletions test/any_sender_of_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ namespace {
// receiver pairs are also noexcept when the same pair is connected through
// an any_sender_of/any_receiver_of pair

template <bool Noexcept, typename... T>
template <bool NoExcept, typename... T>
struct AnySenderOfTestImpl : Test {
using any_sender = any_sender_of<T...>;

static constexpr size_t value_count = sizeof...(T);

static_assert(typed_sender<any_sender>);
static_assert(sender_to<any_sender, mock_receiver<void(T...)>>);
static_assert(sender_to<any_sender, mock_receiver<void(T...) noexcept(NoExcept)>>);
static_assert(std::is_same_v<std::variant<std::tuple<T...>>,
sender_value_types_t<any_sender, std::variant, std::tuple>>);
static_assert(std::is_same_v<std::variant<std::exception_ptr>,
Expand Down
73 changes: 39 additions & 34 deletions test/mock_receiver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,54 +23,59 @@

namespace unifex_test {

template <typename Sig>
struct mock_receiver_body_base;
template <typename Sig, bool NoExcept>
struct mock_receiver_body_base_impl;

template <>
struct mock_receiver_body_base<void()> {
MOCK_METHOD(void, set_value, (), ());
};
template <>
struct mock_receiver_body_base<void() noexcept> {
MOCK_METHOD(void, set_value, (), (noexcept));
template <bool NoExcept>
struct mock_receiver_body_base_impl<void(), NoExcept> {
MOCK_METHOD(void, set_value, (), (noexcept(NoExcept)));
};

template <typename T>
struct mock_receiver_body_base<void(T)> {
MOCK_METHOD(void, set_value, (T), ());
};
template <typename T>
struct mock_receiver_body_base<void(T) noexcept> {
MOCK_METHOD(void, set_value, (T), (noexcept));
template <typename T, bool NoExcept>
struct mock_receiver_body_base_impl<void(T), NoExcept> {
MOCK_METHOD(void, set_value, (T), (noexcept(NoExcept)));
};

template <typename T, typename U>
struct mock_receiver_body_base<void(T, U)> {
MOCK_METHOD(void, set_value, (T, U), ());
template <typename T, typename U, bool NoExcept>
struct mock_receiver_body_base_impl<void(T, U), NoExcept> {
MOCK_METHOD(void, set_value, (T, U), (noexcept(NoExcept)));
};
template <typename T, typename U>
struct mock_receiver_body_base<void(T, U) noexcept> {
MOCK_METHOD(void, set_value, (T, U), (noexcept));

template <typename T, typename U, typename V, bool NoExcept>
struct mock_receiver_body_base_impl<void(T, U, V), NoExcept> {
MOCK_METHOD(void, set_value, (T, U, V), (noexcept(NoExcept)));
};

template <typename T, typename U, typename V>
struct mock_receiver_body_base<void(T, U, V)> {
MOCK_METHOD(void, set_value, (T, U, V), ());
template <typename Sig>
struct mock_receiver_body_base;

template <typename R, typename... As>
struct mock_receiver_body_base<R(As...)> {
using type = mock_receiver_body_base_impl<R(As...), false>;
};
template <typename T, typename U, typename V>
struct mock_receiver_body_base<void(T, U, V) noexcept> {
MOCK_METHOD(void, set_value, (T, U, V), (noexcept));

template <typename R, typename... As>
struct mock_receiver_body_base<R(As...) noexcept> {
using type = mock_receiver_body_base_impl<R(As...), true>;
};

template <typename... Sigs>
struct mock_receiver_body : mock_receiver_body_base<Sigs>... {
using mock_receiver_body_base<Sigs>::gmock_set_value...;
using mock_receiver_body_base<Sigs>::set_value...;
template <typename Sig>
using mock_receiver_body_base_t =
typename mock_receiver_body_base<Sig>::type;

template <typename... Bases>
struct mock_receiver_body_impl : Bases... {
using Bases::gmock_set_value...;
using Bases::set_value...;

MOCK_METHOD(void, set_error, (std::exception_ptr), (noexcept));
MOCK_METHOD(void, set_done, (), (noexcept));
};

template <typename... Sigs>
using mock_receiver_body =
mock_receiver_body_impl<mock_receiver_body_base_t<Sigs>...>;

template <typename... Sigs>
struct mock_receiver {
private:
Expand All @@ -92,11 +97,11 @@ struct mock_receiver {
body_->set_done();
}

auto& operator*() noexcept {
mock_receiver_body<Sigs...>& operator*() noexcept {
return *body_;
}

const auto& operator*() const noexcept {
const mock_receiver_body<Sigs...>& operator*() const noexcept {
return *body_;
}
};
Expand Down

0 comments on commit 849a9d1

Please sign in to comment.