From 2ce8cb99a64ed8512be9b3ae5e5bef2c18353baf Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 15 Aug 2014 16:22:44 +0100 Subject: [PATCH] re PR libstdc++/62154 (std::throw_with_nested should not require a polymorphic type) PR libstdc++/62154 * libsupc++/nested_exception.h (throw_with_nested, rethrow_if_nested): Rewrite to conform to C++11 requirements. * testsuite/18_support/nested_exception/62154.cc: New. From-SVN: r214025 --- libstdc++-v3/ChangeLog | 7 + libstdc++-v3/libsupc++/nested_exception.h | 121 +++++++++--------- .../18_support/nested_exception/62154.cc | 60 +++++++++ 3 files changed, 131 insertions(+), 57 deletions(-) create mode 100644 libstdc++-v3/testsuite/18_support/nested_exception/62154.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 6b304096a059..71541111c756 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,10 @@ +2014-08-15 Jonathan Wakely + + PR libstdc++/62154 + * libsupc++/nested_exception.h (throw_with_nested, rethrow_if_nested): + Rewrite to conform to C++11 requirements. + * testsuite/18_support/nested_exception/62154.cc: New. + 2014-08-14 Matthias Klose * testsuite/ext/random/uniform_on_sphere_distribution/requirements: diff --git a/libstdc++-v3/libsupc++/nested_exception.h b/libstdc++-v3/libsupc++/nested_exception.h index 7e2b2f264ee0..841c2237f666 100644 --- a/libstdc++-v3/libsupc++/nested_exception.h +++ b/libstdc++-v3/libsupc++/nested_exception.h @@ -59,101 +59,108 @@ namespace std public: nested_exception() noexcept : _M_ptr(current_exception()) { } - nested_exception(const nested_exception&) = default; + nested_exception(const nested_exception&) noexcept = default; - nested_exception& operator=(const nested_exception&) = default; + nested_exception& operator=(const nested_exception&) noexcept = default; virtual ~nested_exception() noexcept; + [[noreturn]] void - rethrow_nested() const __attribute__ ((__noreturn__)) - { rethrow_exception(_M_ptr); } + rethrow_nested() const + { + if (_M_ptr) + rethrow_exception(_M_ptr); + std::terminate(); + } exception_ptr - nested_ptr() const + nested_ptr() const noexcept { return _M_ptr; } }; template struct _Nested_exception : public _Except, public nested_exception { + explicit _Nested_exception(const _Except& __ex) + : _Except(__ex) + { } + explicit _Nested_exception(_Except&& __ex) : _Except(static_cast<_Except&&>(__ex)) { } }; - template - struct __get_nested_helper + template + struct _Throw_with_nested_impl { - static const nested_exception* - _S_get(const _Ex& __ex) - { return dynamic_cast(&__ex); } + template + static void _S_throw(_Up&& __t) + { throw _Nested_exception<_Tp>{static_cast<_Up&&>(__t)}; } }; - template - struct __get_nested_helper<_Ex*> + template + struct _Throw_with_nested_impl<_Tp, false> { - static const nested_exception* - _S_get(const _Ex* __ex) - { return dynamic_cast(__ex); } + template + static void _S_throw(_Up&& __t) + { throw static_cast<_Up&&>(__t); } }; - template - inline const nested_exception* - __get_nested_exception(const _Ex& __ex) - { return __get_nested_helper<_Ex>::_S_get(__ex); } + template + struct _Throw_with_nested_helper : _Throw_with_nested_impl<_Tp> + { }; - template - void - __throw_with_nested(_Ex&&, const nested_exception* = 0) - __attribute__ ((__noreturn__)); + template + struct _Throw_with_nested_helper<_Tp, false> + : _Throw_with_nested_impl<_Tp, false> + { }; - template - void - __throw_with_nested(_Ex&&, ...) __attribute__ ((__noreturn__)); + template + struct _Throw_with_nested_helper<_Tp&, false> + : _Throw_with_nested_helper<_Tp> + { }; - // This function should never be called, but is needed to avoid a warning - // about ambiguous base classes when instantiating throw_with_nested<_Ex>() - // with a type that has an accessible nested_exception base. - template + template + struct _Throw_with_nested_helper<_Tp&&, false> + : _Throw_with_nested_helper<_Tp> + { }; + + /// If @p __t is derived from nested_exception, throws @p __t. + /// Else, throws an implementation-defined object derived from both. + template + [[noreturn]] inline void - __throw_with_nested(_Ex&& __ex, const nested_exception*) - { throw __ex; } - - template - inline void - __throw_with_nested(_Ex&& __ex, ...) - { throw _Nested_exception<_Ex>(static_cast<_Ex&&>(__ex)); } - - template - void - throw_with_nested(_Ex __ex) __attribute__ ((__noreturn__)); - - /// If @p __ex is derived from nested_exception, @p __ex. - /// Else, an implementation-defined object derived from both. - template - inline void - throw_with_nested(_Ex __ex) + throw_with_nested(_Tp&& __t) { - if (__get_nested_exception(__ex)) - throw __ex; - __throw_with_nested(static_cast<_Ex&&>(__ex), &__ex); + _Throw_with_nested_helper<_Tp>::_S_throw(static_cast<_Tp&&>(__t)); } + template + struct _Rethrow_if_nested_impl + { + static void _S_rethrow(const _Tp& __t) + { + if (auto __tp = dynamic_cast(&__t)) + __tp->rethrow_nested(); + } + }; + + template + struct _Rethrow_if_nested_impl<_Tp, false> + { + static void _S_rethrow(const _Tp&) { } + }; + /// If @p __ex is derived from nested_exception, @p __ex.rethrow_nested(). template inline void rethrow_if_nested(const _Ex& __ex) { - if (const nested_exception* __nested = __get_nested_exception(__ex)) - __nested->rethrow_nested(); + _Rethrow_if_nested_impl<_Ex>::_S_rethrow(__ex); } - /// Overload, See N2619 - inline void - rethrow_if_nested(const nested_exception& __ex) - { __ex.rethrow_nested(); } - // @} group exceptions } // namespace std diff --git a/libstdc++-v3/testsuite/18_support/nested_exception/62154.cc b/libstdc++-v3/testsuite/18_support/nested_exception/62154.cc new file mode 100644 index 000000000000..9c6725f603a7 --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/nested_exception/62154.cc @@ -0,0 +1,60 @@ +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2014 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include +#include + +struct E { E(int) {} }; + +void +test01() +{ + bool caught = false; + try + { + std::throw_with_nested(E(42)); + } + catch (const std::nested_exception& e) + { + caught = true; + } + VERIFY(caught); +} + +void +test02() +{ + bool caught = false; + try + { + std::throw_with_nested(42); + } + catch (int) + { + caught = true; + } + VERIFY(caught); +} + +int +main() +{ + test01(); + test02(); +}