Unverified Commit 1f25d8e8 authored by Dominik Charousset's avatar Dominik Charousset Committed by GitHub

Merge pull request #915

Fix several warnings on GCC and Clang
parents 77cf8948 69727629
...@@ -176,7 +176,7 @@ public: ...@@ -176,7 +176,7 @@ public:
lhs = static_cast<underlying>(rhs); lhs = static_cast<underlying>(rhs);
} }
} assign; } assign;
underlying tmp; underlying tmp = 0;
return convert_apply(dref(), x, tmp, assign); return convert_apply(dref(), x, tmp, assign);
} }
...@@ -227,7 +227,7 @@ public: ...@@ -227,7 +227,7 @@ public:
lhs.resize((rhs.size() - 1) / 8 + 1, 0); lhs.resize((rhs.size() - 1) / 8 + 1, 0);
for (bool b: rhs) { for (bool b: rhs) {
if (b) if (b)
lhs[k / 8] |= (1 << (k % 8)); lhs[k / 8] |= static_cast<uint8_t>(1 << (k % 8));
++k; ++k;
} }
} }
......
...@@ -194,8 +194,6 @@ public: ...@@ -194,8 +194,6 @@ public:
ini_consumer(const config_option_set& options, settings& cfg); ini_consumer(const config_option_set& options, settings& cfg);
ini_consumer(ini_consumer&&) = default;
// -- properties ------------------------------------------------------------- // -- properties -------------------------------------------------------------
ini_category_consumer begin_map(); ini_category_consumer begin_map();
......
...@@ -37,12 +37,12 @@ bool add_ascii(T& x, char c, enable_if_tt<std::is_integral<T>, int> u = 0) { ...@@ -37,12 +37,12 @@ bool add_ascii(T& x, char c, enable_if_tt<std::is_integral<T>, int> u = 0) {
CAF_IGNORE_UNUSED(u); CAF_IGNORE_UNUSED(u);
if (x > (std::numeric_limits<T>::max() / Base)) if (x > (std::numeric_limits<T>::max() / Base))
return false; return false;
x *= Base; x *= static_cast<T>(Base);
ascii_to_int<Base, T> f; ascii_to_int<Base, T> f;
auto y = f(c); auto y = f(c);
if (x > (std::numeric_limits<T>::max() - y)) if (x > (std::numeric_limits<T>::max() - y))
return false; return false;
x += y; x += static_cast<T>(y);
return true; return true;
} }
...@@ -58,4 +58,3 @@ bool add_ascii(T& x, char c, ...@@ -58,4 +58,3 @@ bool add_ascii(T& x, char c,
} // namespace parser } // namespace parser
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
...@@ -37,12 +37,12 @@ bool sub_ascii(T& x, char c, enable_if_tt<std::is_integral<T>, int> u = 0) { ...@@ -37,12 +37,12 @@ bool sub_ascii(T& x, char c, enable_if_tt<std::is_integral<T>, int> u = 0) {
CAF_IGNORE_UNUSED(u); CAF_IGNORE_UNUSED(u);
if (x < (std::numeric_limits<T>::min() / Base)) if (x < (std::numeric_limits<T>::min() / Base))
return false; return false;
x *= Base; x *= static_cast<T>(Base);
ascii_to_int<Base, T> f; ascii_to_int<Base, T> f;
auto y = f(c); auto y = f(c);
if (x < (std::numeric_limits<T>::min() + y)) if (x < (std::numeric_limits<T>::min() + y))
return false; return false;
x -= y; x -= static_cast<T>(y);
return true; return true;
} }
...@@ -51,12 +51,10 @@ bool sub_ascii(T& x, char c, ...@@ -51,12 +51,10 @@ bool sub_ascii(T& x, char c,
enable_if_tt<std::is_floating_point<T>, int> u = 0) { enable_if_tt<std::is_floating_point<T>, int> u = 0) {
CAF_IGNORE_UNUSED(u); CAF_IGNORE_UNUSED(u);
ascii_to_int<Base, T> f; ascii_to_int<Base, T> f;
x = (x * Base) - f(c); x = static_cast<T>((x * Base) - f(c));
return true; return true;
} }
} // namespace parser } // namespace parser
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
...@@ -20,9 +20,9 @@ ...@@ -20,9 +20,9 @@
#include "caf/behavior.hpp" #include "caf/behavior.hpp"
#include "caf/deduce_mpi.hpp" #include "caf/deduce_mpi.hpp"
#include "caf/interface_mismatch.hpp"
#include "caf/message_handler.hpp" #include "caf/message_handler.hpp"
#include "caf/system_messages.hpp" #include "caf/system_messages.hpp"
#include "caf/interface_mismatch.hpp"
#include "caf/detail/typed_actor_util.hpp" #include "caf/detail/typed_actor_util.hpp"
...@@ -48,9 +48,11 @@ struct same_input : std::is_same<Input, typename RepliesToWith::input_types> {}; ...@@ -48,9 +48,11 @@ struct same_input : std::is_same<Input, typename RepliesToWith::input_types> {};
template <class Output, class RepliesToWith> template <class Output, class RepliesToWith>
struct same_output_or_skip_t { struct same_output_or_skip_t {
using other = typename RepliesToWith::output_types; using other = typename RepliesToWith::output_types;
static constexpr bool value = static constexpr bool value = std::is_same<
std::is_same<Output, typename RepliesToWith::output_types>::value || Output,
std::is_same<Output, type_list<skip_t>>::value; typename RepliesToWith::output_types>::value
|| std::is_same<Output,
type_list<skip_t>>::value;
}; };
template <class SList> template <class SList>
...@@ -60,35 +62,31 @@ struct valid_input_predicate { ...@@ -60,35 +62,31 @@ struct valid_input_predicate {
using input_types = typename Expr::input_types; using input_types = typename Expr::input_types;
using output_types = typename Expr::output_types; using output_types = typename Expr::output_types;
// get matching elements for input type // get matching elements for input type
using filtered_slist = using filtered_slist = typename tl_filter<
typename tl_filter< SList, tbind<same_input, input_types>::template type>::type;
SList,
tbind<same_input, input_types>::template type
>::type;
static_assert(tl_size<filtered_slist>::value > 0, static_assert(tl_size<filtered_slist>::value > 0,
"cannot assign given match expression to " "cannot assign given match expression to "
"typed behavior, because the expression " "typed behavior, because the expression "
"contains at least one pattern that is " "contains at least one pattern that is "
"not defined in the actor's type"); "not defined in the actor's type");
static constexpr bool value = tl_exists< static constexpr bool value = tl_exists<
filtered_slist, tbind<same_output_or_skip_t, filtered_slist,
output_types>::template type>::value; tbind<same_output_or_skip_t, output_types>::template type>::value;
// check whether given output matches in the filtered list // check whether given output matches in the filtered list
static_assert(value, static_assert(value, "cannot assign given match expression to "
"cannot assign given match expression to " "typed behavior, because at least one return "
"typed behavior, because at least one return " "type does not match");
"type does not match");
}; };
}; };
template <class T> template <class T>
struct is_system_msg_handler : std::false_type { }; struct is_system_msg_handler : std::false_type {};
template <> template <>
struct is_system_msg_handler<reacts_to<exit_msg>> : std::true_type { }; struct is_system_msg_handler<reacts_to<exit_msg>> : std::true_type {};
template <> template <>
struct is_system_msg_handler<reacts_to<down_msg>> : std::true_type { }; struct is_system_msg_handler<reacts_to<down_msg>> : std::true_type {};
// Tests whether the input list (IList) matches the // Tests whether the input list (IList) matches the
// signature list (SList) for a typed actor behavior // signature list (SList) for a typed actor behavior
...@@ -96,28 +94,22 @@ template <class SList, class IList> ...@@ -96,28 +94,22 @@ template <class SList, class IList>
struct valid_input { struct valid_input {
// strip exit_msg and down_msg from input types, // strip exit_msg and down_msg from input types,
// because they're always allowed // because they're always allowed
using adjusted_slist = using adjusted_slist = typename tl_filter_not<SList,
typename tl_filter_not< is_system_msg_handler>::type;
SList, using adjusted_ilist = typename tl_filter_not<IList,
is_system_msg_handler is_system_msg_handler>::type;
>::type;
using adjusted_ilist =
typename tl_filter_not<
IList,
is_system_msg_handler
>::type;
// check for each element in IList that there's an element in SList that // check for each element in IList that there's an element in SList that
// (1) has an identical input type list // (1) has an identical input type list
// (2) has an identical output type list // (2) has an identical output type list
// OR the output of the element in IList is skip_t // OR the output of the element in IList is skip_t
static_assert(detail::tl_is_distinct<IList>::value, static_assert(detail::tl_is_distinct<IList>::value,
"given pattern is not distinct"); "given pattern is not distinct");
static constexpr bool value = static constexpr bool value = tl_size<adjusted_slist>::value
tl_size<adjusted_slist>::value == tl_size<adjusted_ilist>::value == tl_size<adjusted_ilist>::value
&& tl_forall< && tl_forall<
adjusted_ilist, adjusted_ilist,
valid_input_predicate<adjusted_slist>::template inner valid_input_predicate<
>::value; adjusted_slist>::template inner>::value;
}; };
// this function is called from typed_behavior<...>::set and its whole // this function is called from typed_behavior<...>::set and its whole
...@@ -130,9 +122,8 @@ void static_check_typed_behavior_input() { ...@@ -130,9 +122,8 @@ void static_check_typed_behavior_input() {
// InputList if its return type is identical to all "missing" // InputList if its return type is identical to all "missing"
// input types ... however, it might lead to unexpected results // input types ... however, it might lead to unexpected results
// and would cause a lot of not-so-straightforward code here // and would cause a lot of not-so-straightforward code here
static_assert(is_valid, static_assert(is_valid, "given pattern cannot be used to initialize "
"given pattern cannot be used to initialize " "typed behavior (exact match needed)");
"typed behavior (exact match needed)");
} }
} // namespace detail } // namespace detail
...@@ -165,7 +156,7 @@ public: ...@@ -165,7 +156,7 @@ public:
using signatures = detail::type_list<Sigs...>; using signatures = detail::type_list<Sigs...>;
/// Empty struct tag for constructing from an untyped behavior. /// Empty struct tag for constructing from an untyped behavior.
struct unsafe_init { }; struct unsafe_init {};
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
...@@ -179,8 +170,9 @@ public: ...@@ -179,8 +170,9 @@ public:
using other_signatures = detail::type_list<Ts...>; using other_signatures = detail::type_list<Ts...>;
using m = interface_mismatch_t<other_signatures, signatures>; using m = interface_mismatch_t<other_signatures, signatures>;
// trigger static assert on mismatch // trigger static assert on mismatch
detail::static_error_printer<sizeof...(Ts), m::value, detail::static_error_printer<static_cast<int>(sizeof...(Ts)), m::value,
typename m::xs, typename m::ys> guard; typename m::xs, typename m::ys>
guard;
CAF_IGNORE_UNUSED(guard); CAF_IGNORE_UNUSED(guard);
} }
...@@ -200,7 +192,7 @@ public: ...@@ -200,7 +192,7 @@ public:
// -- modifiers -------------------------------------------------------------- // -- modifiers --------------------------------------------------------------
/// Exchanges the contents of this and other. /// Exchanges the contents of this and other.
inline void swap(typed_behavior& other) { void swap(typed_behavior& other) {
bhvr_.swap(other.bhvr_); bhvr_.swap(other.bhvr_);
} }
...@@ -242,8 +234,9 @@ private: ...@@ -242,8 +234,9 @@ private:
using found_signatures = detail::type_list<deduce_mpi_t<Ts>...>; using found_signatures = detail::type_list<deduce_mpi_t<Ts>...>;
using m = interface_mismatch_t<found_signatures, signatures>; using m = interface_mismatch_t<found_signatures, signatures>;
// trigger static assert on mismatch // trigger static assert on mismatch
detail::static_error_printer<sizeof...(Ts), m::value, detail::static_error_printer<static_cast<int>(sizeof...(Ts)), m::value,
typename m::xs, typename m::ys> guard; typename m::xs, typename m::ys>
guard;
CAF_IGNORE_UNUSED(guard); CAF_IGNORE_UNUSED(guard);
// final (type-erasure) step // final (type-erasure) step
intrusive_ptr<detail::behavior_impl> ptr = std::move(bp); intrusive_ptr<detail::behavior_impl> ptr = std::move(bp);
...@@ -254,10 +247,9 @@ private: ...@@ -254,10 +247,9 @@ private:
}; };
template <class T> template <class T>
struct is_typed_behavior : std::false_type { }; struct is_typed_behavior : std::false_type {};
template <class... Sigs> template <class... Sigs>
struct is_typed_behavior<typed_behavior<Sigs...>> : std::true_type { }; struct is_typed_behavior<typed_behavior<Sigs...>> : std::true_type {};
} // namespace caf } // namespace caf
...@@ -18,41 +18,42 @@ ...@@ -18,41 +18,42 @@
#include "caf/detail/fnv_hash.hpp" #include "caf/detail/fnv_hash.hpp"
#include <cstdint>
namespace caf { namespace caf {
namespace detail { namespace detail {
namespace { namespace {
template <size_t IntegerSize> #if SIZE_MAX == 0xFFFFFFFF
struct hash_conf_helper;
constexpr size_t basis = 2166136261u;
constexpr size_t prime = 16777619u;
#elif SIZE_MAX == 0xFFFFFFFFFFFFFFFF
template <> constexpr size_t basis = 14695981039346656037u;
struct hash_conf_helper<4> {
static constexpr size_t basis = 2166136261u;
static constexpr size_t prime = 16777619u; constexpr size_t prime = 1099511628211u;
};
template <> #else
struct hash_conf_helper<8> {
static constexpr size_t basis = 14695981039346656037u;
static constexpr size_t prime = 1099511628211u; # error Platform and/or compiler not supported
};
struct hash_conf : hash_conf_helper<sizeof(size_t)> {}; #endif
} // namespace } // namespace
size_t fnv_hash(const unsigned char* first, const unsigned char* last) { size_t fnv_hash(const unsigned char* first, const unsigned char* last) {
return fnv_hash_append(hash_conf::basis, first, last); return fnv_hash_append(basis, first, last);
} }
size_t fnv_hash_append(size_t intermediate, const unsigned char* first, size_t fnv_hash_append(size_t intermediate, const unsigned char* first,
const unsigned char* last) { const unsigned char* last) {
auto result = intermediate; auto result = intermediate;
for (; first != last; ++first) { for (; first != last; ++first) {
result *= hash_conf::prime; result *= prime;
result ^= *first; result ^= *first;
} }
return result; return result;
......
...@@ -204,7 +204,7 @@ error node_id::serialize(serializer& sink) const { ...@@ -204,7 +204,7 @@ error node_id::serialize(serializer& sink) const {
} }
error node_id::deserialize(deserializer& source) { error node_id::deserialize(deserializer& source) {
atom_value impl; auto impl = static_cast<atom_value>(0);
if (auto err = source(impl)) if (auto err = source(impl))
return err; return err;
if (impl == atom("")) { if (impl == atom("")) {
......
...@@ -228,22 +228,49 @@ CAF_TEST(stringification_inspector) { ...@@ -228,22 +228,49 @@ CAF_TEST(stringification_inspector) {
} }
namespace { namespace {
template <class T>
struct is_integral_or_enum {
static constexpr bool value = std::is_integral<T>::value
|| std::is_enum<T>::value;
};
struct binary_serialization_policy { struct binary_serialization_policy {
execution_unit& context; execution_unit& context;
template <class T> template <class T>
bool operator()(T& x) { std::vector<char> to_buf(const T& x) {
std::vector<char> buf; std::vector<char> result;
binary_serializer f{&context, buf}; binary_serializer sink{&context, result};
f(x); if (auto err = sink(x))
binary_deserializer g{&context, buf}; CAF_FAIL("failed to serialize " << x << ": " << err);
return result;
}
template <class T>
detail::enable_if_t<is_integral_or_enum<T>::value, bool> operator()(T& x) {
auto buf = to_buf(x);
binary_deserializer source{&context, buf};
auto y = static_cast<T>(0);
if (auto err = source(y))
CAF_FAIL("failed to deserialize from buffer: " << err);
CAF_CHECK_EQUAL(x, y);
return detail::safe_equal(x, y);
}
template <class T>
detail::enable_if_t<!is_integral_or_enum<T>::value, bool> operator()(T& x) {
auto buf = to_buf(x);
binary_deserializer source{&context, buf};
T y; T y;
g(y); if (auto err = source(y))
CAF_FAIL("failed to deserialize from buffer: " << err);
CAF_CHECK_EQUAL(x, y); CAF_CHECK_EQUAL(x, y);
return detail::safe_equal(x, y); return detail::safe_equal(x, y);
} }
}; };
} // namespace <anonymous>
} // namespace
CAF_TEST(binary_serialization_inspectors) { CAF_TEST(binary_serialization_inspectors) {
actor_system_config cfg; actor_system_config cfg;
......
...@@ -95,7 +95,7 @@ struct fixture { ...@@ -95,7 +95,7 @@ struct fixture {
auto last = end(invoked); auto last = end(invoked);
auto i = find(first, last, true); auto i = find(first, last, true);
if (i != last) { if (i != last) {
CAF_REQUIRE_EQUAL(count(i, last, true), 1u); CAF_REQUIRE(count(i, last, true) == 1);
return distance(first, i); return distance(first, i);
} }
return -1; return -1;
......
...@@ -240,6 +240,7 @@ struct is_message { ...@@ -240,6 +240,7 @@ struct is_message {
} // namespace <anonymous> } // namespace <anonymous>
#define SERIALIZATION_TEST(name) \ #define SERIALIZATION_TEST(name) \
namespace { \
template <class Serializer, class Deserializer> \ template <class Serializer, class Deserializer> \
struct name##_tpl : fixture<Serializer, Deserializer> { \ struct name##_tpl : fixture<Serializer, Deserializer> { \
using super = fixture<Serializer, Deserializer>; \ using super = fixture<Serializer, Deserializer>; \
...@@ -263,7 +264,6 @@ struct is_message { ...@@ -263,7 +264,6 @@ struct is_message {
using super::msg_roundtrip; \ using super::msg_roundtrip; \
void run_test_impl(); \ void run_test_impl(); \
}; \ }; \
namespace { \
using name##_binary = name##_tpl<binary_serializer, binary_deserializer>; \ using name##_binary = name##_tpl<binary_serializer, binary_deserializer>; \
using name##_stream = name##_tpl<stream_serializer<vectorbuf>, \ using name##_stream = name##_tpl<stream_serializer<vectorbuf>, \
stream_deserializer<charbuf>>; \ stream_deserializer<charbuf>>; \
......
...@@ -33,8 +33,6 @@ using atomic_count = std::atomic<size_t>; ...@@ -33,8 +33,6 @@ using atomic_count = std::atomic<size_t>;
size_t assumed_thread_count; size_t assumed_thread_count;
size_t assumed_init_calls; size_t assumed_init_calls;
std::mutex mx;
struct dummy_thread_hook : thread_hook { struct dummy_thread_hook : thread_hook {
void init(actor_system&) override { void init(actor_system&) override {
// nop // nop
......
...@@ -45,7 +45,7 @@ public: ...@@ -45,7 +45,7 @@ public:
bool shutting_down : 1; bool shutting_down : 1;
/// Stores what receive policy is currently active. /// Stores what receive policy is currently active.
receive_policy_flag rd_flag : 2; unsigned rd_flag : 2;
}; };
event_handler(default_multiplexer& dm, native_socket sockfd); event_handler(default_multiplexer& dm, native_socket sockfd);
......
...@@ -33,6 +33,10 @@ enum class receive_policy_flag : unsigned { ...@@ -33,6 +33,10 @@ enum class receive_policy_flag : unsigned {
exactly exactly
}; };
constexpr unsigned to_integer(receive_policy_flag x) {
return static_cast<unsigned>(x);
}
inline std::string to_string(receive_policy_flag x) { inline std::string to_string(receive_policy_flag x) {
return x == receive_policy_flag::at_least return x == receive_policy_flag::at_least
? "at_least" ? "at_least"
...@@ -45,17 +49,17 @@ public: ...@@ -45,17 +49,17 @@ public:
using config = std::pair<receive_policy_flag, size_t>; using config = std::pair<receive_policy_flag, size_t>;
static inline config at_least(size_t num_bytes) { static config at_least(size_t num_bytes) {
CAF_ASSERT(num_bytes > 0); CAF_ASSERT(num_bytes > 0);
return {receive_policy_flag::at_least, num_bytes}; return {receive_policy_flag::at_least, num_bytes};
} }
static inline config at_most(size_t num_bytes) { static config at_most(size_t num_bytes) {
CAF_ASSERT(num_bytes > 0); CAF_ASSERT(num_bytes > 0);
return {receive_policy_flag::at_most, num_bytes}; return {receive_policy_flag::at_most, num_bytes};
} }
static inline config exactly(size_t num_bytes) { static config exactly(size_t num_bytes) {
CAF_ASSERT(num_bytes > 0); CAF_ASSERT(num_bytes > 0);
return {receive_policy_flag::exactly, num_bytes}; return {receive_policy_flag::exactly, num_bytes};
} }
......
...@@ -33,10 +33,11 @@ namespace io { ...@@ -33,10 +33,11 @@ namespace io {
namespace network { namespace network {
event_handler::event_handler(default_multiplexer& dm, native_socket sockfd) event_handler::event_handler(default_multiplexer& dm, native_socket sockfd)
: fd_(sockfd), : fd_(sockfd),
state_{true, false, false, false, receive_policy_flag::at_least}, state_{true, false, false, false,
eventbf_(0), to_integer(receive_policy_flag::at_least)},
backend_(dm) { eventbf_(0),
backend_(dm) {
set_fd_flags(); set_fd_flags();
} }
......
...@@ -55,7 +55,7 @@ void stream::activate(stream_manager* mgr) { ...@@ -55,7 +55,7 @@ void stream::activate(stream_manager* mgr) {
} }
void stream::configure_read(receive_policy::config config) { void stream::configure_read(receive_policy::config config) {
state_.rd_flag = config.first; state_.rd_flag = to_integer(config.first);
max_ = config.second; max_ = config.second;
} }
......
...@@ -120,8 +120,8 @@ peer::behavior_type peer_fun(peer::broker_pointer self, connection_handle hdl, ...@@ -120,8 +120,8 @@ peer::behavior_type peer_fun(peer::broker_pointer self, connection_handle hdl,
}, },
[=](const new_data_msg& msg) { [=](const new_data_msg& msg) {
CAF_MESSAGE("received new_data_msg"); CAF_MESSAGE("received new_data_msg");
atom_value x; auto x = static_cast<atom_value>(0);
int y; auto y = 0;
binary_deserializer source{self->system(), msg.buf}; binary_deserializer source{self->system(), msg.buf};
auto e = source(x, y); auto e = source(x, y);
CAF_REQUIRE(!e); CAF_REQUIRE(!e);
......
...@@ -35,23 +35,23 @@ CAF_POP_WARNINGS ...@@ -35,23 +35,23 @@ CAF_POP_WARNINGS
#include "caf/detail/scope_guard.hpp" #include "caf/detail/scope_guard.hpp"
#include <signal.h> #include <signal.h>
#define CAF_BLOCK_SIGPIPE() \ # define CAF_BLOCK_SIGPIPE() \
sigset_t sigpipe_mask; \ sigset_t sigpipe_mask; \
sigemptyset(&sigpipe_mask); \ sigemptyset(&sigpipe_mask); \
sigaddset(&sigpipe_mask, SIGPIPE); \ sigaddset(&sigpipe_mask, SIGPIPE); \
sigset_t saved_mask; \ sigset_t saved_mask; \
if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { \ if (pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &saved_mask) == -1) { \
perror("pthread_sigmask"); \ perror("pthread_sigmask"); \
exit(1); \ exit(1); \
} \ } \
auto sigpipe_restore_guard = ::caf::detail::make_scope_guard([&] { \ auto sigpipe_restore_guard = ::caf::detail::make_scope_guard([&] { \
struct timespec zerotime = {0}; \ struct timespec zerotime = {}; \
sigtimedwait(&sigpipe_mask, 0, &zerotime); \ sigtimedwait(&sigpipe_mask, 0, &zerotime); \
if (pthread_sigmask(SIG_SETMASK, &saved_mask, 0) == -1) { \ if (pthread_sigmask(SIG_SETMASK, &saved_mask, 0) == -1) { \
perror("pthread_sigmask"); \ perror("pthread_sigmask"); \
exit(1); \ exit(1); \
} \ } \
}) })
#else #else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment