diff --git a/include/boost/capy/buffers/make_buffer.hpp b/include/boost/capy/buffers/make_buffer.hpp index 4ba7cb36..791d2c35 100644 --- a/include/boost/capy/buffers/make_buffer.hpp +++ b/include/boost/capy/buffers/make_buffer.hpp @@ -22,10 +22,8 @@ #include #include -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4459) -#endif +BOOST_CAPY_MSVC_WARNING_PUSH +BOOST_CAPY_MSVC_WARNING_DISABLE(4459) namespace boost { namespace capy { @@ -531,8 +529,6 @@ make_buffer( } // capy } // boost -#ifdef _MSC_VER -#pragma warning(pop) -#endif +BOOST_CAPY_MSVC_WARNING_POP #endif diff --git a/include/boost/capy/delay.hpp b/include/boost/capy/delay.hpp index 52774083..823a4018 100644 --- a/include/boost/capy/delay.hpp +++ b/include/boost/capy/delay.hpp @@ -88,15 +88,11 @@ class delay_awaitable // Aligned storage for the stop callback. // Declared last: its destructor may block while // the callback accesses the members above. -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4324) -#endif + BOOST_CAPY_MSVC_WARNING_PUSH + BOOST_CAPY_MSVC_WARNING_DISABLE(4324) alignas(stop_cb_t) unsigned char stop_cb_buf_[sizeof(stop_cb_t)]; -#ifdef _MSC_VER -# pragma warning(pop) -#endif + BOOST_CAPY_MSVC_WARNING_POP stop_cb_t& stop_cb_() noexcept { diff --git a/include/boost/capy/detail/await_suspend_helper.hpp b/include/boost/capy/detail/await_suspend_helper.hpp index 13d9f377..4dbdfec9 100644 --- a/include/boost/capy/detail/await_suspend_helper.hpp +++ b/include/boost/capy/detail/await_suspend_helper.hpp @@ -51,7 +51,7 @@ namespace detail { @param h The coroutine handle to transfer to. */ -#ifdef _MSC_VER +#if BOOST_CAPY_WORKAROUND(_MSC_VER, >= 1) inline void symmetric_transfer(std::coroutine_handle<> h) noexcept { h.resume(); diff --git a/include/boost/capy/detail/config.hpp b/include/boost/capy/detail/config.hpp index 36235531..865a5382 100644 --- a/include/boost/capy/detail/config.hpp +++ b/include/boost/capy/detail/config.hpp @@ -15,6 +15,58 @@ # define BOOST_CAPY_ASSERT(expr) assert(expr) #endif +//------------------------------------------------ +// +// Compiler bug workarounds +// +//------------------------------------------------ + +/* Standalone workaround macro modeled on Boost.Config's BOOST_WORKAROUND. + + Guard mechanism: when a compiler symbol is not defined, the + corresponding _WORKAROUND_GUARD macro is 1, which makes + BOOST_CAPY_WORKAROUND evaluate to 0 on that compiler. + + Usage: + #if BOOST_CAPY_WORKAROUND(_MSC_VER, >= 1) // any MSVC + #if BOOST_CAPY_WORKAROUND(_MSC_VER, <= 1900) // MSVC 14.0 and earlier + #if BOOST_CAPY_WORKAROUND(__GNUC__, < 12) // GCC before 12 +*/ + +#ifndef _MSC_VER +# define _MSC_VER_WORKAROUND_GUARD 1 +#else +# define _MSC_VER_WORKAROUND_GUARD 0 +#endif + +#ifndef __GNUC__ +# define __GNUC___WORKAROUND_GUARD 1 +#else +# define __GNUC___WORKAROUND_GUARD 0 +#endif + +#ifndef __clang_major__ +# define __clang_major___WORKAROUND_GUARD 1 +#else +# define __clang_major___WORKAROUND_GUARD 0 +#endif + +#define BOOST_CAPY_WORKAROUND(symbol, test) \ + ((symbol ## _WORKAROUND_GUARD + 0 == 0) && \ + (symbol != 0) && (1 % (( (symbol test) ) + 1))) + +// MSVC warning suppression helpers. +// On MSVC these expand to __pragma(); elsewhere they are empty. +#ifdef _MSC_VER +# define BOOST_CAPY_MSVC_WARNING_PUSH __pragma(warning(push)) +# define BOOST_CAPY_MSVC_WARNING_DISABLE(x) __pragma(warning(disable: x)) +# define BOOST_CAPY_MSVC_WARNING_POP __pragma(warning(pop)) +#else +# define BOOST_CAPY_MSVC_WARNING_PUSH +# define BOOST_CAPY_MSVC_WARNING_DISABLE(x) +# define BOOST_CAPY_MSVC_WARNING_POP +#endif + // Efficient thread-local storage keyword for POD types #if !defined(BOOST_CAPY_TLS_KEYWORD) # if defined(_MSC_VER) diff --git a/include/boost/capy/ex/async_event.hpp b/include/boost/capy/ex/async_event.hpp index 288cdb54..db89053a 100644 --- a/include/boost/capy/ex/async_event.hpp +++ b/include/boost/capy/ex/async_event.hpp @@ -145,15 +145,11 @@ class async_event // Aligned storage for stop_cb_t. Declared last: // its destructor may block while the callback // accesses the members above. -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4324) // padded due to alignas -#endif + BOOST_CAPY_MSVC_WARNING_PUSH + BOOST_CAPY_MSVC_WARNING_DISABLE(4324) // padded due to alignas alignas(stop_cb_t) unsigned char stop_cb_buf_[sizeof(stop_cb_t)]; -#ifdef _MSC_VER -# pragma warning(pop) -#endif + BOOST_CAPY_MSVC_WARNING_POP stop_cb_t& stop_cb_() noexcept { diff --git a/include/boost/capy/ex/async_mutex.hpp b/include/boost/capy/ex/async_mutex.hpp index 1fdbcf22..26acd313 100644 --- a/include/boost/capy/ex/async_mutex.hpp +++ b/include/boost/capy/ex/async_mutex.hpp @@ -194,15 +194,11 @@ class async_mutex // Aligned storage for stop_cb_t. Declared last: // its destructor may block while the callback // accesses the members above. -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4324) // padded due to alignas -#endif + BOOST_CAPY_MSVC_WARNING_PUSH + BOOST_CAPY_MSVC_WARNING_DISABLE(4324) // padded due to alignas alignas(stop_cb_t) unsigned char stop_cb_buf_[sizeof(stop_cb_t)]; -#ifdef _MSC_VER -# pragma warning(pop) -#endif + BOOST_CAPY_MSVC_WARNING_POP stop_cb_t& stop_cb_() noexcept { diff --git a/include/boost/capy/ex/detail/timer_service.hpp b/include/boost/capy/ex/detail/timer_service.hpp index 6b93ffbf..c383c539 100644 --- a/include/boost/capy/ex/detail/timer_service.hpp +++ b/include/boost/capy/ex/detail/timer_service.hpp @@ -104,10 +104,8 @@ class BOOST_CAPY_DECL void run(); // warning C4251: std types need to have dll-interface -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4251) -#endif + BOOST_CAPY_MSVC_WARNING_PUSH + BOOST_CAPY_MSVC_WARNING_DISABLE(4251) std::mutex mutex_; std::condition_variable cv_; std::condition_variable cancel_cv_; @@ -120,9 +118,7 @@ class BOOST_CAPY_DECL timer_id executing_id_ = 0; bool stopped_ = false; std::thread thread_; -#ifdef _MSC_VER -# pragma warning(pop) -#endif + BOOST_CAPY_MSVC_WARNING_POP }; } // detail diff --git a/include/boost/capy/ex/execution_context.hpp b/include/boost/capy/ex/execution_context.hpp index 9b6d7e74..1000dec7 100644 --- a/include/boost/capy/ex/execution_context.hpp +++ b/include/boost/capy/ex/execution_context.hpp @@ -163,15 +163,11 @@ class BOOST_CAPY_DECL service* next_ = nullptr; // warning C4251: 'std::type_index' needs to have dll-interface -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4251) -#endif + BOOST_CAPY_MSVC_WARNING_PUSH + BOOST_CAPY_MSVC_WARNING_DISABLE(4251) detail::type_index t0_{detail::type_id()}; detail::type_index t1_{detail::type_id()}; -#ifdef _MSC_VER -# pragma warning(pop) -#endif + BOOST_CAPY_MSVC_WARNING_POP }; //------------------------------------------------ @@ -503,16 +499,12 @@ class BOOST_CAPY_DECL struct BOOST_CAPY_DECL factory { -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4251) -#endif // warning C4251: 'std::type_index' needs to have dll-interface + BOOST_CAPY_MSVC_WARNING_PUSH + BOOST_CAPY_MSVC_WARNING_DISABLE(4251) detail::type_index t0; detail::type_index t1; -#ifdef _MSC_VER -# pragma warning(pop) -#endif + BOOST_CAPY_MSVC_WARNING_POP factory( detail::type_info const& t0_, @@ -531,16 +523,12 @@ class BOOST_CAPY_DECL service& use_service_impl(factory& f); service& make_service_impl(factory& f); -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4251) -#endif -// warning C4251: 'std::type_index' needs to have dll-interface +// warning C4251: std::mutex, std::shared_ptr need dll-interface + BOOST_CAPY_MSVC_WARNING_PUSH + BOOST_CAPY_MSVC_WARNING_DISABLE(4251) mutable std::mutex mutex_; std::shared_ptr owned_; -#ifdef _MSC_VER -# pragma warning(pop) -#endif + BOOST_CAPY_MSVC_WARNING_POP std::pmr::memory_resource* frame_alloc_ = nullptr; service* head_ = nullptr; bool shutdown_ = false; diff --git a/include/boost/capy/ex/recycling_memory_resource.hpp b/include/boost/capy/ex/recycling_memory_resource.hpp index 604c538b..5b9c3ed2 100644 --- a/include/boost/capy/ex/recycling_memory_resource.hpp +++ b/include/boost/capy/ex/recycling_memory_resource.hpp @@ -46,10 +46,8 @@ namespace capy { @see get_recycling_memory_resource @see run_async */ -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4275) // non dll-interface base class -#endif +BOOST_CAPY_MSVC_WARNING_PUSH +BOOST_CAPY_MSVC_WARNING_DISABLE(4275) // non dll-interface base class class BOOST_CAPY_DECL recycling_memory_resource : public std::pmr::memory_resource { static constexpr std::size_t num_classes = 6; @@ -184,9 +182,7 @@ class BOOST_CAPY_DECL recycling_memory_resource : public std::pmr::memory_resour return this == &other; } }; -#ifdef _MSC_VER -# pragma warning(pop) -#endif +BOOST_CAPY_MSVC_WARNING_POP /** Returns pointer to the default recycling memory resource. diff --git a/include/boost/capy/io_result.hpp b/include/boost/capy/io_result.hpp index 3e6e0c89..26aed0fd 100644 --- a/include/boost/capy/io_result.hpp +++ b/include/boost/capy/io_result.hpp @@ -63,7 +63,7 @@ struct [[nodiscard]] io_result<> /** The error code from the operation. */ std::error_code ec; -#ifdef _MSC_VER +#if BOOST_CAPY_WORKAROUND(_MSC_VER, >= 1) // Tuple protocol (unconditional - io_result<> is not an aggregate) template auto& get() & noexcept @@ -108,7 +108,7 @@ struct [[nodiscard]] io_result /// The first payload value. Unspecified when `ec` is set. T1 t1{}; -#ifdef _MSC_VER +#if BOOST_CAPY_WORKAROUND(_MSC_VER, >= 1) template auto& get() & noexcept { @@ -164,7 +164,7 @@ struct [[nodiscard]] io_result /// The second payload value. Unspecified when `ec` is set. T2 t2{}; -#ifdef _MSC_VER +#if BOOST_CAPY_WORKAROUND(_MSC_VER, >= 1) template auto& get() & noexcept { @@ -227,7 +227,7 @@ struct [[nodiscard]] io_result /// The third payload value. Unspecified when `ec` is set. T3 t3{}; -#ifdef _MSC_VER +#if BOOST_CAPY_WORKAROUND(_MSC_VER, >= 1) template auto& get() & noexcept { @@ -260,7 +260,7 @@ struct [[nodiscard]] io_result #endif }; -#ifdef _MSC_VER +#if BOOST_CAPY_WORKAROUND(_MSC_VER, >= 1) // Free-standing get() overloads for ADL (MSVC aggregate workaround). /// @cond @@ -339,12 +339,12 @@ auto&& get(io_result&& r) noexcept /// @endcond -#endif // _MSC_VER +#endif // BOOST_CAPY_WORKAROUND(_MSC_VER, >= 1) } // namespace capy } // namespace boost -#ifdef _MSC_VER +#if BOOST_CAPY_WORKAROUND(_MSC_VER, >= 1) // Tuple protocol for structured bindings (MSVC workaround) // MSVC has a bug with aggregate decomposition in coroutines, so we use @@ -448,6 +448,6 @@ struct tuple_element<3, boost::capy::io_result> } // namespace std -#endif // _MSC_VER +#endif // BOOST_CAPY_WORKAROUND(_MSC_VER, >= 1) #endif // BOOST_CAPY_IO_RESULT_HPP diff --git a/src/cond.cpp b/src/cond.cpp index 33c585cb..ba54d304 100644 --- a/src/cond.cpp +++ b/src/cond.cpp @@ -76,9 +76,9 @@ equivalent( // msvc 14.0 has a bug that warns about inability // to use constexpr construction here, even though // there's no constexpr construction -#if defined(_MSC_VER) && _MSC_VER <= 1900 -# pragma warning( push ) -# pragma warning( disable : 4592 ) +#if BOOST_CAPY_WORKAROUND(_MSC_VER, <= 1900) +BOOST_CAPY_MSVC_WARNING_PUSH +BOOST_CAPY_MSVC_WARNING_DISABLE(4592) #endif #if defined(__cpp_constinit) && __cpp_constinit >= 201907L @@ -87,8 +87,8 @@ constinit cond_cat_type cond_cat; cond_cat_type cond_cat; #endif -#if defined(_MSC_VER) && _MSC_VER <= 1900 -# pragma warning( pop ) +#if BOOST_CAPY_WORKAROUND(_MSC_VER, <= 1900) +BOOST_CAPY_MSVC_WARNING_POP #endif } // detail diff --git a/src/error.cpp b/src/error.cpp index 4bbb8198..99f5c83b 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -43,9 +43,9 @@ message(int code) const // msvc 14.0 has a bug that warns about inability // to use constexpr construction here, even though // there's no constexpr construction -#if defined(_MSC_VER) && _MSC_VER <= 1900 -# pragma warning( push ) -# pragma warning( disable : 4592 ) +#if BOOST_CAPY_WORKAROUND(_MSC_VER, <= 1900) +BOOST_CAPY_MSVC_WARNING_PUSH +BOOST_CAPY_MSVC_WARNING_DISABLE(4592) #endif #if defined(__cpp_constinit) && __cpp_constinit >= 201907L @@ -54,8 +54,8 @@ constinit error_cat_type error_cat; error_cat_type error_cat; #endif -#if defined(_MSC_VER) && _MSC_VER <= 1900 -# pragma warning( pop ) +#if BOOST_CAPY_WORKAROUND(_MSC_VER, <= 1900) +BOOST_CAPY_MSVC_WARNING_POP #endif } // detail diff --git a/test/unit/test_helpers.hpp b/test/unit/test_helpers.hpp index c6e6c19b..4e9c268f 100644 --- a/test/unit/test_helpers.hpp +++ b/test/unit/test_helpers.hpp @@ -272,15 +272,11 @@ struct stop_only_awaitable // When ~jthread calls request_stop() before join(), the // destructor's _M_reset (on the requesting thread) races with // emplace's _M_engaged write (on the registering thread). -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4324) // padded due to alignas -#endif + BOOST_CAPY_MSVC_WARNING_PUSH + BOOST_CAPY_MSVC_WARNING_DISABLE(4324) // padded due to alignas alignas(stop_resume_callback) unsigned char stop_cb_buf_[sizeof(stop_resume_callback)]{}; -#ifdef _MSC_VER -# pragma warning(pop) -#endif + BOOST_CAPY_MSVC_WARNING_POP std::atomic active_{false}; ~stop_only_awaitable()