diff --git a/feed/history/boost_1_85_0.qbk b/feed/history/boost_1_85_0.qbk index f3cc8fa8..8e149b61 100644 --- a/feed/history/boost_1_85_0.qbk +++ b/feed/history/boost_1_85_0.qbk @@ -21,6 +21,17 @@ Formatting reference: https://www.boost.org/doc/tools/quickbook/ Please keep the list of libraries sorted in lexicographical order. ] +[section Known Issues] + +These are patches from library authors which were found too late to be fixed +in the release. + +* Container + * flat_map/multimap containers can crash or return invalid results in some compilers due to UB in the library, see [github container 273]. + [@/patches/1_85_0/0001-container-fix-flat_map.patch Patch]. + +[endsect] + [section New Libraries] [/ Example: diff --git a/patches/1_85_0/0001-container-fix-flat_map.patch b/patches/1_85_0/0001-container-fix-flat_map.patch new file mode 100644 index 00000000..5132e02d --- /dev/null +++ b/patches/1_85_0/0001-container-fix-flat_map.patch @@ -0,0 +1,588 @@ +--- boost/container/allocator_traits.hpp Thu Apr 11 20:48:02 2024 ++++ boost/container/allocator_traits.hpp Sat Jul 27 23:53:19 2024 +@@ -32,6 +32,8 @@ + #include + #include //is_empty + #include ++#include ++#include + #ifndef BOOST_CONTAINER_DETAIL_STD_FWD_HPP + #include + #endif +@@ -47,9 +49,10 @@ + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +-#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) ++#if defined(BOOST_CONTAINER_GCC_COMPATIBLE_HAS_DIAGNOSTIC_IGNORED) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-result" ++#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + #endif + + #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME allocate +@@ -73,7 +76,7 @@ + #define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 9 + #include + +-#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) ++#if defined(BOOST_CONTAINER_GCC_COMPATIBLE_HAS_DIAGNOSTIC_IGNORED) + #pragma GCC diagnostic pop + #endif + +@@ -81,6 +84,144 @@ + + namespace boost { + namespace container { ++namespace dtl { ++ ++#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) ++ ++template ++BOOST_CONTAINER_FORCEINLINE void construct_type(T *p, BOOST_FWD_REF(Args) ...args) ++{ ++ ::new((void*)p, boost_container_new_t()) T(::boost::forward(args)...); ++} ++ ++template < class Pair, class KeyType, class ... Args> ++typename dtl::enable_if< dtl::is_pair, void >::type ++construct_type ++ (Pair* p, try_emplace_t, BOOST_FWD_REF(KeyType) k, BOOST_FWD_REF(Args) ...args) ++{ ++ construct_type(dtl::addressof(p->first), ::boost::forward(k)); ++ BOOST_CONTAINER_TRY{ ++ construct_type(dtl::addressof(p->second), ::boost::forward(args)...); ++ } ++ BOOST_CONTAINER_CATCH(...) { ++ typedef typename Pair::first_type first_type; ++ dtl::addressof(p->first)->~first_type(); ++ BOOST_CONTAINER_RETHROW ++ } ++ BOOST_CONTAINER_CATCH_END ++} ++ ++#else ++ ++#define BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_TYPEJ(N) \ ++template\ ++BOOST_CONTAINER_FORCEINLINE \ ++ typename dtl::disable_if_c::value, void >::type \ ++construct_type(T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ ++{\ ++ ::new((void*)p, boost_container_new_t()) T( BOOST_MOVE_FWD##N );\ ++}\ ++// ++BOOST_MOVE_ITERATE_0TO8(BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_TYPEJ) ++#undef BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_TYPEJ ++ ++#define BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_TYPE(N) \ ++template < class Pair, class KeyType BOOST_MOVE_I##N BOOST_MOVE_CLASS##N>\ ++typename dtl::enable_if< dtl::is_pair, void >::type construct_type\ ++ (Pair* p, try_emplace_t, BOOST_FWD_REF(KeyType) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ ++{\ ++ construct_type(dtl::addressof(p->first), ::boost::forward(k));\ ++ BOOST_CONTAINER_TRY{\ ++ construct_type(dtl::addressof(p->second) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ ++ }\ ++ BOOST_CONTAINER_CATCH(...) {\ ++ typedef typename Pair::first_type first_type;\ ++ dtl::addressof(p->first)->~first_type();\ ++ BOOST_CONTAINER_RETHROW\ ++ }\ ++ BOOST_CONTAINER_CATCH_END\ ++}\ ++// ++BOOST_MOVE_ITERATE_0TO8(BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_TYPE) ++#undef BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_TYPE ++ ++#endif ++ ++template ++inline ++typename dtl::enable_if, void >::type ++construct_type(T* p) ++{ ++ dtl::construct_type(dtl::addressof(p->first)); ++ BOOST_CONTAINER_TRY{ ++ dtl::construct_type(dtl::addressof(p->second)); ++ } ++ BOOST_CONTAINER_CATCH(...) { ++ typedef typename T::first_type first_type; ++ dtl::addressof(p->first)->~first_type(); ++ BOOST_CONTAINER_RETHROW ++ } ++ BOOST_CONTAINER_CATCH_END ++} ++ ++ ++template ++inline ++typename dtl::enable_if_c ++ < dtl::is_pair::value ++ , void >::type ++construct_type(T* p, U &u) ++{ ++ dtl::construct_type(dtl::addressof(p->first), u.first); ++ BOOST_CONTAINER_TRY{ ++ dtl::construct_type(dtl::addressof(p->second), u.second); ++ } ++ BOOST_CONTAINER_CATCH(...) { ++ typedef typename T::first_type first_type; ++ dtl::addressof(p->first)->~first_type(); ++ BOOST_CONTAINER_RETHROW ++ } ++ BOOST_CONTAINER_CATCH_END ++} ++ ++template ++inline ++typename dtl::enable_if_c ++ < dtl::is_pair::type>::value && ++ !boost::move_detail::is_reference::value //This is needed for MSVC10 and ambiguous overloads ++ , void >::type ++construct_type(T* p, BOOST_RV_REF(U) u) ++{ ++ dtl::construct_type(dtl::addressof(p->first), ::boost::move(u.first)); ++ BOOST_CONTAINER_TRY{ ++ dtl::construct_type(dtl::addressof(p->second), ::boost::move(u.second)); ++ } ++ BOOST_CONTAINER_CATCH(...) { ++ typedef typename T::first_type first_type; ++ dtl::addressof(p->first)->~first_type(); ++ BOOST_CONTAINER_RETHROW ++ } ++ BOOST_CONTAINER_CATCH_END ++} ++ ++template ++inline ++typename dtl::enable_if, void >::type ++construct_type(T* p, BOOST_FWD_REF(U) x, BOOST_FWD_REF(V) y) ++{ ++ dtl::construct_type(dtl::addressof(p->first), ::boost::forward(x)); ++ BOOST_CONTAINER_TRY{ ++ dtl::construct_type(dtl::addressof(p->second), ::boost::forward(y)); ++ } ++ BOOST_CONTAINER_CATCH(...) { ++ typedef typename T::first_type first_type; ++ dtl::addressof(p->first)->~first_type(); ++ BOOST_CONTAINER_RETHROW ++ } ++ BOOST_CONTAINER_CATCH_END ++} ++ ++} //namespace dtl + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +@@ -100,19 +241,19 @@ + //supporting rvalue references + template + struct is_std_allocator +-{ static const bool value = false; }; ++{ BOOST_STATIC_CONSTEXPR bool value = false; }; + + template + struct is_std_allocator< std::allocator > +-{ static const bool value = true; }; ++{ BOOST_STATIC_CONSTEXPR bool value = true; }; + + template + struct is_std_allocator< small_vector_allocator, Options > > +-{ static const bool value = true; }; ++{ BOOST_STATIC_CONSTEXPR bool value = true; }; + + template + struct is_not_std_allocator +-{ static const bool value = !is_std_allocator::value; }; ++{ BOOST_STATIC_CONSTEXPR bool value = !is_std_allocator::value; }; + + BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(pointer) + BOOST_INTRUSIVE_INSTANTIATE_EVAL_DEFAULT_TYPE_TMPLT(const_pointer) +@@ -358,7 +499,7 @@ + template + inline static void construct(Allocator & a, T* p, BOOST_FWD_REF(Args)... args) + { +- static const bool value = ::boost::move_detail::and_ ++ BOOST_STATIC_CONSTEXPR bool value = ::boost::move_detail::and_ + < dtl::is_not_std_allocator + , boost::container::dtl::has_member_function_callable_with_construct + < Allocator, T*, Args... > +@@ -419,7 +560,7 @@ + + template + inline static void priv_construct(dtl::false_type, Allocator &, T *p, BOOST_FWD_REF(Args) ...args) +- { ::new((void*)p, boost_container_new_t()) T(::boost::forward(args)...); } ++ { dtl::construct_type(p, ::boost::forward(args)...); } + #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + public: + +@@ -427,7 +568,7 @@ + template\ + inline static void construct(Allocator &a, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ +- static const bool value = ::boost::move_detail::and_ \ ++ BOOST_STATIC_CONSTEXPR bool value = ::boost::move_detail::and_ \ + < dtl::is_not_std_allocator \ + , boost::container::dtl::has_member_function_callable_with_construct \ + < Allocator, T* BOOST_MOVE_I##N BOOST_MOVE_FWD_T##N > \ +@@ -450,7 +591,7 @@ + \ + template\ + inline static void priv_construct(dtl::false_type, Allocator &, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ +- { ::new((void*)p, boost_container_new_t()) T(BOOST_MOVE_FWD##N); }\ ++ { dtl::construct_type(p BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ + // + BOOST_MOVE_ITERATE_0TO8(BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL) + #undef BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL +--- boost/container/detail/construct_in_place.hpp Thu Apr 11 20:48:02 2024 ++++ boost/container/detail/construct_in_place.hpp Sat Jul 27 23:53:27 2024 +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + namespace boost { + namespace container { +@@ -62,9 +63,42 @@ + + //Assignment + ++template ++BOOST_CONTAINER_FORCEINLINE ++ typename dtl::disable_if_c ++ < dtl::is_pair::type>::value ++ && dtl::is_pair::type>::value ++ , void>::type ++assign_in_place_ref(T &t, BOOST_FWD_REF(U) u) ++{ t = ::boost::forward(u); } ++ ++template ++BOOST_CONTAINER_FORCEINLINE ++ typename dtl::enable_if_c ++ < dtl::is_pair::type>::value ++ && dtl::is_pair::type>::value ++ , void>::type ++assign_in_place_ref(T &t, const U &u) ++{ ++ assign_in_place_ref(t.first, u.first); ++ assign_in_place_ref(t.second, u.second); ++} ++ ++template ++BOOST_CONTAINER_FORCEINLINE ++ typename dtl::enable_if_c ++ < dtl::is_pair::type>::value ++ && dtl::is_pair::type>::value ++ , void>::type ++assign_in_place_ref(T &t, BOOST_RV_REF(U) u) ++{ ++ assign_in_place_ref(t.first, ::boost::move(u.first)); ++ assign_in_place_ref(t.second, ::boost::move(u.second)); ++} ++ + template + BOOST_CONTAINER_FORCEINLINE void assign_in_place(DstIt dest, InpIt source) +-{ *dest = *source; } ++{ assign_in_place_ref(*dest, *source); } + + template + BOOST_CONTAINER_FORCEINLINE void assign_in_place(DstIt dest, value_init_construct_iterator) +--- boost/container/flat_map.hpp Thu Apr 11 20:48:02 2024 ++++ boost/container/flat_map.hpp Sat Jul 27 23:55:40 2024 +@@ -31,6 +31,7 @@ + #include + #include //equal() + #include ++#include + // move + #include + #include +@@ -44,10 +45,22 @@ + #include //pair + #include //less, equal + ++ + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + #include + #endif + ++#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) ++#define BOOST_CONTAINER_STD_PAIR_IS_MOVABLE ++#endif ++ ++//for C++03 compilers, were type-puning is the only option for std::pair ++//disable strict aliasing to reduce problems. ++#if defined(BOOST_GCC) && (BOOST_GCC >= 100000) && !defined(BOOST_CONTAINER_STD_PAIR_IS_MOVABLE) ++#pragma GCC push_options ++#pragma GCC optimize("no-strict-aliasing") ++#endif ++ + namespace boost { + namespace container { + +@@ -58,6 +71,21 @@ + + namespace dtl{ + ++#if defined(BOOST_CONTAINER_STD_PAIR_IS_MOVABLE) ++template ++BOOST_CONTAINER_FORCEINLINE static D &force(S &s) ++{ return s; } ++ ++template ++BOOST_CONTAINER_FORCEINLINE static const D &force(const S &s) ++{ return s; } ++ ++template ++BOOST_CONTAINER_FORCEINLINE static D force_copy(D s) ++{ return s; } ++ ++#else //!BOOST_CONTAINER_DOXYGEN_INVOKED ++ + template + BOOST_CONTAINER_FORCEINLINE static D &force(S &s) + { return *move_detail::force_ptr(&s); } +@@ -74,6 +102,8 @@ + return ret_val; + } + ++#endif //BOOST_CONTAINER_DOXYGEN_INVOKED ++ + } //namespace dtl{ + + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +@@ -118,18 +148,27 @@ + private: + BOOST_COPYABLE_AND_MOVABLE(flat_map) + //This is the tree that we should store if pair was movable ++ typedef std::pair std_pair_t; + typedef dtl::flat_tree< +- std::pair, ++ std_pair_t, + dtl::select1st, + Compare, + AllocatorOrContainer> tree_t; + + //This is the real tree stored here. It's based on a movable pair ++ typedef dtl::pair dtl_pair_t; ++ ++ #ifdef BOOST_CONTAINER_STD_PAIR_IS_MOVABLE ++ typedef std_pair_t impl_pair_t; ++ #else ++ typedef dtl_pair_t impl_pair_t; ++ #endif ++ + typedef dtl::flat_tree< +- dtl::pair, ++ impl_pair_t, + dtl::select1st, + Compare, +- typename dtl::container_or_allocator_rebind >::type ++ typename dtl::container_or_allocator_rebind::type + > impl_tree_t; + impl_tree_t m_flat_tree; // flat tree representing flat_map + +@@ -851,7 +890,7 @@ + //! @copydoc ::boost::container::flat_set::nth(size_type) const + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline + const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW +- { return dtl::force_copy(m_flat_tree.nth(n)); } ++ { return dtl::force_copy(m_flat_tree.nth(n)); } + + //! @copydoc ::boost::container::flat_set::index_of(iterator) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline +@@ -1099,7 +1138,7 @@ + template + inline BOOST_CONTAINER_DOC1ST + ( std::pair +- , typename dtl::enable_if_c::value ++ , typename dtl::enable_if_c::value + BOOST_MOVE_I std::pair >::type) + insert(BOOST_FWD_REF(Pair) x) + { +@@ -1153,7 +1192,7 @@ + template + inline BOOST_CONTAINER_DOC1ST + ( iterator +- , typename dtl::enable_if_c::value ++ , typename dtl::enable_if_c::value + BOOST_MOVE_I iterator>::type) + insert(const_iterator p, BOOST_FWD_REF(Pair) x) + { +@@ -1277,6 +1316,23 @@ + inline size_type erase(const key_type& x) + { return m_flat_tree.erase_unique(x); } + ++ //! Requires: This overload is available only if ++ //! key_compare::is_transparent exists. ++ //! ++ //! Effects: If present, erases the element in the container with key equivalent to x. ++ //! ++ //! Returns: Returns the number of erased elements (0/1). ++ template ++ inline BOOST_CONTAINER_DOC1ST ++ (size_type ++ , typename dtl::enable_if_c< ++ dtl::is_transparent::value && //transparent ++ !dtl::is_convertible::value && //not convertible to iterator ++ !dtl::is_convertible::value //not convertible to const_iterator ++ BOOST_MOVE_I size_type>::type) ++ erase(const K& x) ++ { return m_flat_tree.erase_unique(x); } ++ + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. +@@ -1637,7 +1693,7 @@ + if (i == end() || key_comp()(k, (*i).first)){ + dtl::value_init m; + impl_value_type v(k, ::boost::move(m.m_t)); +- i = this->insert(i, ::boost::move(v)); ++ i = dtl::force_copy(this->m_flat_tree.insert_equal(::boost::move(v))); + } + return (*i).second; + } +@@ -1646,10 +1702,10 @@ + key_type &k = mk; + iterator i = this->lower_bound(k); + // i->first is greater than or equivalent to k. +- if (i == end() || key_comp()(k, (*i).first)){ ++ if (i == end() || key_comp()(k, (*i).first)) { + dtl::value_init m; + impl_value_type v(::boost::move(k), ::boost::move(m.m_t)); +- i = this->insert(i, ::boost::move(v)); ++ i = dtl::force_copy(this->m_flat_tree.insert_equal(::boost::move(v))); + } + return (*i).second; + } +@@ -1729,10 +1785,10 @@ + template + struct has_trivial_destructor_after_move > + { +- typedef ::boost::container::dtl::pair value_t; ++ typedef typename boost::container::flat_map::value_type value_t; + typedef typename ::boost::container::dtl::container_or_allocator_rebind::type alloc_or_cont_t; + typedef ::boost::container::dtl::flat_tree, Compare, alloc_or_cont_t> tree; +- static const bool value = ::boost::has_trivial_destructor_after_move::value; ++ BOOST_STATIC_CONSTEXPR bool value = ::boost::has_trivial_destructor_after_move::value; + }; + + namespace container { +@@ -1777,17 +1833,24 @@ + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + private: + BOOST_COPYABLE_AND_MOVABLE(flat_multimap) ++ typedef std::pair std_pair_t; + typedef dtl::flat_tree< +- std::pair, ++ std_pair_t, + dtl::select1st, + Compare, + AllocatorOrContainer> tree_t; + //This is the real tree stored here. It's based on a movable pair ++ typedef dtl::pair dtl_pair_t; ++ #ifdef BOOST_CONTAINER_STD_PAIR_IS_MOVABLE ++ typedef std_pair_t impl_pair_t; ++ #else ++ typedef dtl_pair_t impl_pair_t; ++ #endif + typedef dtl::flat_tree< +- dtl::pair, ++ impl_pair_t, + dtl::select1st, + Compare, +- typename dtl::container_or_allocator_rebind >::type ++ typename dtl::container_or_allocator_rebind::type + > impl_tree_t; + impl_tree_t m_flat_tree; // flat tree representing flat_map + +@@ -2388,7 +2451,7 @@ + //! @copydoc ::boost::container::flat_set::nth(size_type) const + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline + const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW +- { return dtl::force_copy(m_flat_tree.nth(n)); } ++ { return dtl::force_copy(m_flat_tree.nth(n)); } + + //! @copydoc ::boost::container::flat_set::index_of(iterator) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline +@@ -2477,7 +2540,7 @@ + template + inline BOOST_CONTAINER_DOC1ST + ( iterator +- , typename dtl::enable_if_c::value ++ , typename dtl::enable_if_c::value + BOOST_MOVE_I iterator >::type) + insert(BOOST_FWD_REF(Pair) x) + { return dtl::force_copy(m_flat_tree.emplace_equal(boost::forward(x))); } +@@ -2514,7 +2577,7 @@ + template + inline BOOST_CONTAINER_DOC1ST + ( iterator +- , typename dtl::enable_if_c::value ++ , typename dtl::enable_if_c::value + BOOST_MOVE_I iterator>::type) + insert(const_iterator p, BOOST_FWD_REF(Pair) x) + { +@@ -2633,6 +2696,23 @@ + inline size_type erase(const key_type& x) + { return m_flat_tree.erase(x); } + ++ //! Requires: This overload is available only if ++ //! key_compare::is_transparent exists. ++ //! ++ //! Effects: Erases all elements in the container with key equivalent to x. ++ //! ++ //! Returns: Returns the number of erased elements. ++ template ++ inline BOOST_CONTAINER_DOC1ST ++ (size_type ++ , typename dtl::enable_if_c< ++ dtl::is_transparent::value && //transparent ++ !dtl::is_convertible::value && //not convertible to iterator ++ !dtl::is_convertible::value //not convertible to const_iterator ++ BOOST_MOVE_I size_type>::type) ++ erase(const K& x) ++ { return m_flat_tree.erase(x); } ++ + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. +@@ -2977,6 +3057,10 @@ + { x.swap(y); } + }; + ++#if defined(BOOST_GCC) && (BOOST_GCC >= 100000) && !defined(BOOST_CONTAINER_STD_PAIR_IS_MOVABLE) ++#pragma GCC pop_options ++#endif ++ + #ifndef BOOST_CONTAINER_NO_CXX17_CTAD + + template +@@ -3052,10 +3136,10 @@ + template + struct has_trivial_destructor_after_move< boost::container::flat_multimap > + { +- typedef ::boost::container::dtl::pair value_t; ++ typedef typename boost::container::flat_multimap::value_type value_t; + typedef typename ::boost::container::dtl::container_or_allocator_rebind::type alloc_or_cont_t; + typedef ::boost::container::dtl::flat_tree, Compare, alloc_or_cont_t> tree; +- static const bool value = ::boost::has_trivial_destructor_after_move::value; ++ BOOST_STATIC_CONSTEXPR bool value = ::boost::has_trivial_destructor_after_move::value; + }; + + } //namespace boost { +--- boost/container/detail/workaround.hpp Thu Apr 11 20:48:02 2024 ++++ boost/container/detail/workaround.hpp Sun Jul 28 00:19:33 2024 +@@ -230,4 +230,10 @@ + # define BOOST_CONTAINER_STATIC_ASSERT_MSG( B, Msg ) BOOST_CONTAINER_STATIC_ASSERT( B ) + #endif + ++#if defined(__GNUC__) && ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40600) ++#define BOOST_CONTAINER_GCC_COMPATIBLE_HAS_DIAGNOSTIC_IGNORED ++#elif defined(__clang__) ++#define BOOST_CONTAINER_GCC_COMPATIBLE_HAS_DIAGNOSTIC_IGNORED ++#endif ++ + #endif //#ifndef BOOST_CONTAINER_DETAIL_WORKAROUND_HPP