libstdc++: Fix multiple definitions of std::exception_ptr functions [PR 97729]
authorJonathan Wakely <jwakely@redhat.com>
Thu, 5 Nov 2020 16:19:15 +0000 (16:19 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Thu, 5 Nov 2020 18:01:25 +0000 (18:01 +0000)
This fixes some multiple definition errors caused by the changes for
PR libstdc++/90295. The previous solution for inlining the members of
std::exception_ptr but still exporting them from the library was to
suppress the 'inline' keyword on those functions when compiling
libsupc++/eh_ptr.cc, so they get defined in that file. That produces ODR
violations though, because there are now both inline and non-inline
definitions in the library, due to the use of std::exception_ptr in
other files sucg as src/c++11/future.cc.

The new solution is to define all the relevant members as 'inline'
unconditionally, but use __attribute__((used)) to cause definitions to
be emitted in libsupc++/eh_ptr.cc as before. This doesn't quite work
however, because PR c++/67453 means the attribute is ignored on
constructors and destructors. As a workaround, the old solution
(conditionally inline) is still used for those members, but they are
given the always_inline attribute so that they aren't emitted in
src/c++11/future.o as inline definitions.

libstdc++-v3/ChangeLog:

PR libstdc++/97729
* include/std/future (__basic_future::_M_get_result): Use
nullptr for null pointer constant.
* libsupc++/eh_ptr.cc (operator==, operator!=): Remove
definitions.
* libsupc++/exception_ptr.h (_GLIBCXX_EH_PTR_USED): Define
macro to conditionally add __attribute__((__used__)).
(operator==, operator!=, exception_ptr::exception_ptr())
(exception_ptr::exception_ptr(const exception_ptr&))
(exception_ptr::~exception_ptr())
(exception_ptr::operator=(const exception_ptr&))
(exception_ptr::swap(exception_ptr&)): Always define as
inline. Add macro to be conditionally "used".

libstdc++-v3/include/std/future
libstdc++-v3/libsupc++/eh_ptr.cc
libstdc++-v3/libsupc++/exception_ptr.h

index 3c2aaa1..5d94801 100644 (file)
@@ -709,7 +709,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       {
         _State_base::_S_check(_M_state);
         _Result_base& __res = _M_state->wait();
-        if (!(__res._M_error == 0))
+        if (!(__res._M_error == nullptr))
           rethrow_exception(__res._M_error);
         return static_cast<__result_type>(__res);
       }
index c41bdca..7e68635 100644 (file)
 #include <bits/c++config.h>
 #include "eh_atomics.h"
 
+#if ! _GLIBCXX_INLINE_VERSION
+// This macro causes exception_ptr to declare an older API (with corresponding
+// definitions in this file) and to mark some inline functions as "used" so
+// that definitions will be emitted in this translation unit.
 #define _GLIBCXX_EH_PTR_COMPAT
+#endif
 
 #include <exception>
 #include <bits/exception_ptr.h>
@@ -61,6 +66,8 @@ static_assert( adjptr<__cxa_exception>()
 #endif
 }
 
+// Define non-inline functions.
+
 std::__exception_ptr::exception_ptr::exception_ptr(void* obj) noexcept
 : _M_exception_object(obj)  { _M_addref(); }
 
@@ -130,19 +137,6 @@ std::__exception_ptr::exception_ptr::__cxa_exception_type() const noexcept
   return eh->exceptionType;
 }
 
-// Retained for compatibility with CXXABI_1.3.12.
-bool
-std::__exception_ptr::operator==(const exception_ptr& lhs,
-                                const exception_ptr& rhs) noexcept
-{ return lhs._M_exception_object == rhs._M_exception_object; }
-
-// Retained for compatibility with CXXABI_1.3.12.
-bool
-std::__exception_ptr::operator!=(const exception_ptr& lhs,
-                                const exception_ptr& rhs) noexcept
-{ return !(lhs == rhs); }
-
-
 std::exception_ptr
 std::current_exception() noexcept
 {
index 4497d0e..001343a 100644 (file)
 #include <typeinfo>
 #include <new>
 
+#ifdef _GLIBCXX_EH_PTR_COMPAT
+# define _GLIBCXX_EH_PTR_USED __attribute__((__used__))
+#else
+# define _GLIBCXX_EH_PTR_USED
+#endif
+
 extern "C++" {
 
 namespace std 
@@ -146,20 +152,17 @@ namespace std
       { return _M_exception_object; }
 #endif
 
-#ifdef _GLIBCXX_EH_PTR_COMPAT
-      friend bool
-      operator==(const exception_ptr&, const exception_ptr&)
-       _GLIBCXX_USE_NOEXCEPT __attribute__ ((__pure__));
-#elif __cpp_impl_three_way_comparison >= 201907L
+#if __cpp_impl_three_way_comparison >= 201907L \
+      && ! defined _GLIBCXX_EH_PTR_COMPAT
       friend bool
       operator==(const exception_ptr&, const exception_ptr&) noexcept = default;
 #else
-      friend bool
+      friend _GLIBCXX_EH_PTR_USED bool
       operator==(const exception_ptr& __x, const exception_ptr& __y)
       _GLIBCXX_USE_NOEXCEPT
       { return __x._M_exception_object == __y._M_exception_object; }
 
-      friend bool
+      friend _GLIBCXX_EH_PTR_USED bool
       operator!=(const exception_ptr& __x, const exception_ptr& __y)
       _GLIBCXX_USE_NOEXCEPT
       { return __x._M_exception_object != __y._M_exception_object; }
@@ -170,25 +173,30 @@ namespace std
        __attribute__ ((__pure__));
     };
 
-#ifndef _GLIBCXX_EH_PTR_COMPAT
+    _GLIBCXX_EH_PTR_USED
+#ifndef  _GLIBCXX_EH_PTR_COMPAT
+    __attribute__((__always_inline__)) // XXX see PR 97729
     inline
 #endif
     exception_ptr::exception_ptr() _GLIBCXX_NOEXCEPT
     : _M_exception_object(0)
     { }
 
-#ifndef _GLIBCXX_EH_PTR_COMPAT
+    _GLIBCXX_EH_PTR_USED
+#ifndef  _GLIBCXX_EH_PTR_COMPAT
+    __attribute__((__always_inline__))
     inline
 #endif
-    exception_ptr::exception_ptr(const exception_ptr& __other)
-      _GLIBCXX_NOEXCEPT
+    exception_ptr::exception_ptr(const exception_ptr& __other) _GLIBCXX_NOEXCEPT
     : _M_exception_object(__other._M_exception_object)
     {
       if (_M_exception_object)
        _M_addref();
     }
 
-#ifndef _GLIBCXX_EH_PTR_COMPAT
+    _GLIBCXX_EH_PTR_USED
+#ifndef  _GLIBCXX_EH_PTR_COMPAT
+    __attribute__((__always_inline__))
     inline
 #endif
     exception_ptr::~exception_ptr() _GLIBCXX_USE_NOEXCEPT
@@ -197,20 +205,16 @@ namespace std
        _M_release();
     }
 
-#ifndef _GLIBCXX_EH_PTR_COMPAT
-    inline
-#endif
-    exception_ptr&
+    _GLIBCXX_EH_PTR_USED
+    inline exception_ptr&
     exception_ptr::operator=(const exception_ptr& __other) _GLIBCXX_USE_NOEXCEPT
     {
       exception_ptr(__other).swap(*this);
       return *this;
     }
 
-#ifndef _GLIBCXX_EH_PTR_COMPAT
-    inline
-#endif
-    void
+    _GLIBCXX_EH_PTR_USED
+    inline void
     exception_ptr::swap(exception_ptr &__other) _GLIBCXX_USE_NOEXCEPT
     {
       void *__tmp = _M_exception_object;
@@ -218,16 +222,6 @@ namespace std
       __other._M_exception_object = __tmp;
     }
 
-#ifdef _GLIBCXX_EH_PTR_COMPAT
-    bool 
-    operator==(const exception_ptr&, const exception_ptr&)
-      _GLIBCXX_USE_NOEXCEPT __attribute__ ((__pure__));
-
-    bool 
-    operator!=(const exception_ptr&, const exception_ptr&)
-      _GLIBCXX_USE_NOEXCEPT __attribute__ ((__pure__));
-#endif
-
     /// @relates exception_ptr
     inline void
     swap(exception_ptr& __lhs, exception_ptr& __rhs)
@@ -276,6 +270,8 @@ namespace std
 #endif
     }
 
+#undef _GLIBCXX_EH_PTR_USED
+
   // @} group exceptions
 } // namespace std