diff mbox

libstdc++/62154 fix throw_with_nested and rethrow_if_nested

Message ID 20140815152655.GM6927@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely Aug. 15, 2014, 3:26 p.m. UTC
Rewritten to meet the C++11 spec, not the 2009 draft I used when
adding nested_exception.

I've used the builtin traits directly, to avoid making libsupc++
depend on <type_traits>, which shouldn't be necessary because
<type_traits> should be present for freestanding implementations, but
it isn't (PR 62159).

Tested x86_64-linux, committed to trunk.
diff mbox

Patch

commit 0203c348d18fabe2f48b4701f9130439710adee0
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Aug 15 13:33:00 2014 +0100

    	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.

diff --git a/libstdc++-v3/libsupc++/nested_exception.h b/libstdc++-v3/libsupc++/nested_exception.h
index 7e2b2f2..841c223 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<typename _Except>
     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<typename _Ex>
-    struct __get_nested_helper
+  template<typename _Tp,
+	   bool __with_nested = !__is_base_of(nested_exception, _Tp)>
+    struct _Throw_with_nested_impl
     {
-      static const nested_exception*
-      _S_get(const _Ex& __ex)
-      { return dynamic_cast<const nested_exception*>(&__ex); }
+      template<typename _Up>
+	static void _S_throw(_Up&& __t)
+	{ throw _Nested_exception<_Tp>{static_cast<_Up&&>(__t)}; }
     };
 
-  template<typename _Ex>
-    struct __get_nested_helper<_Ex*>
+  template<typename _Tp>
+    struct _Throw_with_nested_impl<_Tp, false>
     {
-      static const nested_exception*
-      _S_get(const _Ex* __ex)
-      { return dynamic_cast<const nested_exception*>(__ex); }
+      template<typename _Up>
+	static void _S_throw(_Up&& __t)
+	{ throw static_cast<_Up&&>(__t); }
     };
 
-  template<typename _Ex>
-    inline const nested_exception*
-    __get_nested_exception(const _Ex& __ex)
-    { return __get_nested_helper<_Ex>::_S_get(__ex); }
-
-  template<typename _Ex>
-    void
-    __throw_with_nested(_Ex&&, const nested_exception* = 0)
-    __attribute__ ((__noreturn__));
-
-  template<typename _Ex>
-    void
-    __throw_with_nested(_Ex&&, ...) __attribute__ ((__noreturn__));
-
-  // 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<typename _Ex>
+  template<typename _Tp, bool = __is_class(_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>
+    { };
+
+  /// If @p __t is derived from nested_exception, throws @p __t.
+  /// Else, throws an implementation-defined object derived from both.
+  template<typename _Tp>
+    [[noreturn]]
     inline void
-    __throw_with_nested(_Ex&& __ex, const nested_exception*)
-    { throw __ex; }
+    throw_with_nested(_Tp&& __t)
+    {
+      _Throw_with_nested_helper<_Tp>::_S_throw(static_cast<_Tp&&>(__t));
+    }
 
-  template<typename _Ex>
-    inline void
-    __throw_with_nested(_Ex&& __ex, ...)
-    { throw _Nested_exception<_Ex>(static_cast<_Ex&&>(__ex)); }
-  
-  template<typename _Ex>
-    void
-    throw_with_nested(_Ex __ex) __attribute__ ((__noreturn__));
+  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*>(&__t))
+	  __tp->rethrow_nested();
+      }
+    };
 
-  /// If @p __ex is derived from nested_exception, @p __ex. 
-  /// Else, an implementation-defined object derived from both.
-  template<typename _Ex>
-    inline void
-    throw_with_nested(_Ex __ex)
+  template<typename _Tp>
+    struct _Rethrow_if_nested_impl<_Tp, false>
     {
-      if (__get_nested_exception(__ex))
-        throw __ex;
-      __throw_with_nested(static_cast<_Ex&&>(__ex), &__ex);
-    }
+      static void _S_rethrow(const _Tp&) { }
+    };
 
   /// If @p __ex is derived from nested_exception, @p __ex.rethrow_nested().
   template<typename _Ex>
     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 0000000..9c6725f
--- /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
+// <http://www.gnu.org/licenses/>.
+
+#include <exception>
+#include <testsuite_hooks.h>
+
+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();
+}