Skip to content

Commit 8167dac

Browse files
committed
Workaround for MinGW/libstdc++ bug
This is from zaphoyd/websocketpp#479
1 parent f55581a commit 8167dac

File tree

1 file changed

+65
-1
lines changed

1 file changed

+65
-1
lines changed

src/lib/websocketpp/transport/asio/endpoint.hpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,69 @@ namespace ws_websocketpp {
4545
namespace transport {
4646
namespace asio {
4747

48+
/***
49+
* In current versions of libstdc++, the error_constants.h code associated to mingw32
50+
* does not define certain standard enum values for `std::errc`. (In C++11 standard,
51+
* sections 19.5.2, 19.5.3.) Asio uses these for lib::asio::errc when it is compiled
52+
* as a stand-alone library, so because of the libstdc++ defect, code below referring
53+
* to lib::asio::errc::operation_canceled fails to compile on mingw.
54+
*
55+
* This workaround detects the defect using SFINAE and returns 'false' for the check
56+
* if operation_canceled is not defined, instead of failing to compile.
57+
*
58+
* If upstream patches this later by defining those enum values, then the workaround
59+
* will stop having any effect.
60+
*
61+
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68307
62+
*/
63+
namespace _workaround_gcc_libstdcpp_issue_68307_missing_values {
64+
/***
65+
* Same as std::enable_if, but don't want to introduce dependency on <type_traits>
66+
* since that's C++11 only
67+
*/
68+
template<bool B, class T = void>
69+
struct enable_if {};
70+
71+
template<class T>
72+
struct enable_if<true, T> { typedef T type; };
73+
74+
/***
75+
* Metafunction to test "operation_canceled" value
76+
*/
77+
template <typename T, typename ENABLE=void>
78+
struct op_canceled_helper {
79+
template <typename U>
80+
static inline bool is_op_canceled(const U & u) { return false; }
81+
};
82+
83+
template <typename T>
84+
struct op_canceled_helper<T, enable_if<T::operation_canceled == T::operation_canceled, void> > {
85+
template<typename U>
86+
static inline bool is_op_canceled(const U & u) { return u == T::operation_canceled; }
87+
};
88+
89+
/***
90+
* This function is intended to be a drop-in replacement for
91+
* (asio_ec == lib::asio::errc::operation_canceled)
92+
*
93+
* except that if lib::asio::errc::operation_canceled does not exist, it returns false,
94+
* instead of failing to compile.
95+
*
96+
* When using boost and not asio standalone, then lib::asio::errc is a namespace, not an enum class.
97+
* So the template code will fail to compile and we need to block it from being instantiated, with this
98+
* ifdef. When using boost the standard library symbol definitions aren't relevant afaik.
99+
*/
100+
#ifdef ASIO_STANDALONE
101+
static inline bool is_op_canceled(const lib::asio::error_code & asio_ec) {
102+
return op_canceled_helper<lib::asio::errc, void>::is_op_canceled(asio_ec);
103+
}
104+
#else
105+
static inline bool is_op_canceled(const lib::asio::error_code & asio_ec) {
106+
return asio_ec == lib::asio::errc::operation_canceled;
107+
}
108+
#endif
109+
} // namespace _workaround
110+
48111
/// Asio based endpoint transport component
49112
/**
50113
* transport::asio::endpoint implements an endpoint transport component using
@@ -833,7 +896,8 @@ class endpoint : public config::socket_type {
833896
m_alog->write(log::alevel::devel, "asio::handle_accept");
834897

835898
if (asio_ec) {
836-
if (asio_ec == lib::asio::errc::operation_canceled) {
899+
// if (asio_ec == lib::asio::errc::operation_canceled) {
900+
if (_workaround_gcc_libstdcpp_issue_68307_missing_values::is_op_canceled(asio_ec)) {
837901
ret_ec = make_error_code(ws_websocketpp::error::operation_canceled);
838902
} else {
839903
log_err(log::elevel::info,"asio handle_accept",asio_ec);

0 commit comments

Comments
 (0)