Originally this header didn't use <type_traits>, but we install that for freestanding builds now, so it's always available. That means we can simplify things a bit, using remove_reference, enable_if etc.
This also implements the missing part of LWG 2484, so that we don't try to use dynamic_cast when the static type would make it ill-formed. * doc/xml/manual/intro.xml: Document LWG 2484 status. * libsupc++/nested_exception.h (_Throw_with_nested_impl) (_Throw_with_nested_helper): Remove. (__throw_with_nested_impl): New overloaded functions to implement throw_with_nested logic. (throw_with_nested): Call __throw_with_nested_impl. (_Rethrow_if_nested_impl): Remove (__rethrow_if_nested_impl): New overloaded functions to implement rethrow_if_nested logic. (rethrow_if_nested): Call __rethrow_if_nested_impl. * testsuite/18_support/nested_exception/rethrow_if_nested.cc: Test problem cases from LWG 2484. Tested powerpc64le-linux, committed to trunk.
commit 06046b8db3d2060cb52a87b6771031e70abfef00 Author: redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4> Date: Tue Oct 11 10:33:36 2016 +0000 Simplify std::rethrow_if_nested definition * doc/xml/manual/intro.xml: Document LWG 2484 status. * libsupc++/nested_exception.h (_Throw_with_nested_impl) (_Throw_with_nested_helper): Remove. (__throw_with_nested_impl): New overloaded functions to implement throw_with_nested logic. (throw_with_nested): Call __throw_with_nested_impl. (_Rethrow_if_nested_impl): Remove (__rethrow_if_nested_impl): New overloaded functions to implement rethrow_if_nested logic. (rethrow_if_nested): Call __rethrow_if_nested_impl. * testsuite/18_support/nested_exception/rethrow_if_nested.cc: Test problem cases from LWG 2484. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@240983 138bc75d-0d04-0410-961f-82ee72b054a4 diff --git a/libstdc++-v3/doc/xml/manual/intro.xml b/libstdc++-v3/doc/xml/manual/intro.xml index 265ef67..22b792a 100644 --- a/libstdc++-v3/doc/xml/manual/intro.xml +++ b/libstdc++-v3/doc/xml/manual/intro.xml @@ -1078,6 +1078,14 @@ requirements of the license of GCC. <listitem><para>Divide by the object type. </para></listitem></varlistentry> + <varlistentry><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="../ext/lwg-defects.html#2484">2484</link>: + <emphasis><code>rethrow_if_nested()</code> is doubly unimplementable + </emphasis> + </term> + <listitem><para>Avoid using <code>dynamic_cast</code> when it would be + ill-formed. + </para></listitem></varlistentry> + <varlistentry><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="../ext/lwg-defects.html#2583">2583</link>: <emphasis>There is no way to supply an allocator for <code> basic_string(str, pos)</code> </emphasis> diff --git a/libstdc++-v3/libsupc++/nested_exception.h b/libstdc++-v3/libsupc++/nested_exception.h index 377b803..0c00d74 100644 --- a/libstdc++-v3/libsupc++/nested_exception.h +++ b/libstdc++-v3/libsupc++/nested_exception.h @@ -92,41 +92,21 @@ namespace std { } }; - template<typename _Tp, - bool __with_nested = !__is_base_of(nested_exception, _Tp)> - struct _Throw_with_nested_impl + // [except.nested]/8 + // Throw an exception of unspecified type that is publicly derived from + // both remove_reference_t<_Tp> and nested_exception. + template<typename _Tp> + inline void + __throw_with_nested_impl(_Tp&& __t, true_type) { - template<typename _Up> - static void _S_throw(_Up&& __t) - { throw _Nested_exception<_Tp>{static_cast<_Up&&>(__t)}; } - }; + using _Up = typename remove_reference<_Tp>::type; + throw _Nested_exception<_Up>{std::forward<_Tp>(__t)}; + } template<typename _Tp> - struct _Throw_with_nested_impl<_Tp, false> - { - template<typename _Up> - static void _S_throw(_Up&& __t) - { throw static_cast<_Up&&>(__t); } - }; - - template<typename _Tp, bool = __is_class(_Tp) && !__is_final(_Tp)> - struct _Throw_with_nested_helper : _Throw_with_nested_impl<_Tp> - { }; - - template<typename _Tp> - struct _Throw_with_nested_helper<_Tp, false> - : _Throw_with_nested_impl<_Tp, false> - { }; - - template<typename _Tp> - struct _Throw_with_nested_helper<_Tp&, false> - : _Throw_with_nested_helper<_Tp> - { }; - - template<typename _Tp> - struct _Throw_with_nested_helper<_Tp&&, false> - : _Throw_with_nested_helper<_Tp> - { }; + inline void + __throw_with_nested_impl(_Tp&& __t, false_type) + { throw std::forward<_Tp>(__t); } /// If @p __t is derived from nested_exception, throws @p __t. /// Else, throws an implementation-defined object derived from both. @@ -135,33 +115,43 @@ namespace std inline void throw_with_nested(_Tp&& __t) { - _Throw_with_nested_helper<_Tp>::_S_throw(static_cast<_Tp&&>(__t)); + using _Up = typename remove_reference<_Tp>::type; + using _CopyConstructible + = __and_<is_copy_constructible<_Up>, is_move_constructible<_Up>>; + static_assert(_CopyConstructible::value, + "throw_with_nested argument must be CopyConstructible"); + using __nest = __and_<is_class<_Up>, __bool_constant<!__is_final(_Up)>, + __not_<is_base_of<nested_exception, _Up>>>; + return std::__throw_with_nested_impl(std::forward<_Tp>(__t), __nest{}); } - template<typename _Tp, bool = __is_polymorphic(_Tp)> - struct _Rethrow_if_nested_impl - { - static void _S_rethrow(const _Tp& __t) - { - if (auto __tp = - dynamic_cast<const nested_exception*>(std::__addressof(__t))) - __tp->rethrow_nested(); - } - }; - + // Determine if dynamic_cast<const nested_exception&> would be well-formed. template<typename _Tp> - struct _Rethrow_if_nested_impl<_Tp, false> + using __rethrow_if_nested_cond = typename enable_if< + __and_<is_polymorphic<_Tp>, + __or_<__not_<is_base_of<nested_exception, _Tp>>, + is_convertible<_Tp*, nested_exception*>>>::value + >::type; + + // Attempt dynamic_cast to nested_exception and call rethrow_nested(). + template<typename _Ex> + inline __rethrow_if_nested_cond<_Ex> + __rethrow_if_nested_impl(const _Ex* __ptr) { - static void _S_rethrow(const _Tp&) { } - }; + if (auto __ne_ptr = dynamic_cast<const nested_exception*>(__ptr)) + __ne_ptr->rethrow_nested(); + } + + // Otherwise, no effects. + inline void + __rethrow_if_nested_impl(const void*) + { } /// If @p __ex is derived from nested_exception, @p __ex.rethrow_nested(). template<typename _Ex> inline void rethrow_if_nested(const _Ex& __ex) - { - _Rethrow_if_nested_impl<_Ex>::_S_rethrow(__ex); - } + { std::__rethrow_if_nested_impl(std::__addressof(__ex)); } // @} group exceptions } // namespace std diff --git a/libstdc++-v3/testsuite/18_support/nested_exception/rethrow_if_nested.cc b/libstdc++-v3/testsuite/18_support/nested_exception/rethrow_if_nested.cc index 135679f..7751213 100644 --- a/libstdc++-v3/testsuite/18_support/nested_exception/rethrow_if_nested.cc +++ b/libstdc++-v3/testsuite/18_support/nested_exception/rethrow_if_nested.cc @@ -101,11 +101,30 @@ void test03() VERIFY( test ); } +void +test04() +{ + // LWG 2484 requires that these cases are well-formed, but don't rethrow. + + std::rethrow_if_nested(1); + + struct S { } nonpolymorphic; + std::rethrow_if_nested(nonpolymorphic); + + struct derived3 : derived, derived2 { }; + derived3 ambiguous_base; + std::rethrow_if_nested(ambiguous_base); + + struct derived4 : private std::nested_exception { }; + derived4 private_base; + std::rethrow_if_nested(private_base); +} int main() { test01(); test02(); test03(); + test04(); return 0; }