public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r11-4451] libstdc++: Fix ODR violations caused by <tr1/functional>
@ 2020-10-27 16:33 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2020-10-27 16:33 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:d4fd8638be8a6f105bfaf1c0e3bcfad36aca03be

commit r11-4451-gd4fd8638be8a6f105bfaf1c0e3bcfad36aca03be
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Oct 27 16:32:53 2020 +0000

    libstdc++: Fix ODR violations caused by <tr1/functional>
    
    The placeholders for std::tr1::bind are defined in an anonymous
    namespace, which means they have internal linkage. This will cause ODR
    violations when used in function templates (such as std::tr1::bind) from
    multiple translation units. Although probably harmless (every definition
    will generate identical code, even if technically ill-formed) we can
    avoid the ODR violations by reusing the std::placeholder objects as the
    std::tr1::placeholder objects.
    
    To make this work, the std::_Placeholder type needs to be defined for
    C++98 mode, so that <tr1/functional> can use it. The members of the
    std::placeholder namespace must not be defined by <functional> in C++98
    mode, because "placeholders", "_1", "_2" etc. are not reserved names in
    C++98. Instead they can be declared in <tr1/functional>, because those
    names *are* reserved in that header. With the std::placeholders objects
    declared, a simple using-directive suffices to redeclare them in
    namespace std::tr1::placeholders. This means any use of the TR1
    placeholders actually refers to the C++11 placeholders, which are
    defined with external linkage and exported from the library, so don't
    cause ODR violations.
    
    libstdc++-v3/ChangeLog:
    
            * include/std/functional (std::_Placeholder): Define for C++98
            as well as later standards.
            * include/tr1/functional (std::placeholders::_1 etc): Declare
            for C++98.
            (tr1::_Placeholder): Replace with using-declaration for
            std::_Placeholder.
            (tr1::placeholders::_1 etc.): Replace with using-directive for
            std::placeholders.

Diff:
---
 libstdc++-v3/include/std/functional |  17 +++--
 libstdc++-v3/include/tr1/functional | 131 +++++++++++++++---------------------
 2 files changed, 66 insertions(+), 82 deletions(-)

diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index 9bad692f2ad..4e2d053f778 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -69,10 +69,19 @@
 # include <compare>
 #endif
 
+#endif // C++11
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+  /** @brief The type of placeholder objects defined by libstdc++.
+   *  @ingroup binders
+   */
+  template<int _Num> struct _Placeholder { };
+
+#if __cplusplus >= 201103L
+
 #if __cplusplus >= 201703L
 # define __cpp_lib_invoke 201411L
 # if __cplusplus > 201703L
@@ -203,11 +212,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     = is_placeholder<_Tp>::value;
 #endif // C++17
 
-  /** @brief The type of placeholder objects defined by libstdc++.
-   *  @ingroup binders
-   */
-  template<int _Num> struct _Placeholder { };
-
   /** @namespace std::placeholders
    *  @brief ISO C++ 2011 namespace for std::bind placeholders.
    *  @ingroup binders
@@ -1271,10 +1275,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #endif // C++17
 #endif // C++14
+#endif // C++11
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
-#endif // C++11
-
 #endif // _GLIBCXX_FUNCTIONAL
diff --git a/libstdc++-v3/include/tr1/functional b/libstdc++-v3/include/tr1/functional
index 2a72c331af6..79eaeb8b99f 100644
--- a/libstdc++-v3/include/tr1/functional
+++ b/libstdc++-v3/include/tr1/functional
@@ -31,8 +31,7 @@
 
 #pragma GCC system_header
 
-#include <bits/c++config.h>
-#include <bits/stl_function.h>
+#include <functional> // for std::_Placeholder, std::_Bind, std::_Bind_result
 
 #include <typeinfo>
 #include <new>
@@ -42,18 +41,49 @@
 #include <tr1/functional_hash.h>
 #include <ext/type_traits.h>
 #include <bits/move.h> // for std::__addressof
-#if __cplusplus >= 201103L
-#  include <type_traits> // for integral_constant, true_type, false_type
-#endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
-#if __cplusplus >= 201103L
-  template<int> struct _Placeholder;
-  template<typename> class _Bind;
-  template<typename, typename> class _Bind_result;
-#endif
+
+#if __cplusplus < 201103L
+  // In C++98 mode, <functional> doesn't declare std::placeholders::_1 etc.
+  // because they are not reserved names in C++98. However, they are reserved
+  // by <tr1/functional> so we can declare them here, in order to redeclare
+  // them in the std::tr1::placeholders namespace below.
+  namespace placeholders
+  {
+    extern const _Placeholder<1> _1;
+    extern const _Placeholder<2> _2;
+    extern const _Placeholder<3> _3;
+    extern const _Placeholder<4> _4;
+    extern const _Placeholder<5> _5;
+    extern const _Placeholder<6> _6;
+    extern const _Placeholder<7> _7;
+    extern const _Placeholder<8> _8;
+    extern const _Placeholder<9> _9;
+    extern const _Placeholder<10> _10;
+    extern const _Placeholder<11> _11;
+    extern const _Placeholder<12> _12;
+    extern const _Placeholder<13> _13;
+    extern const _Placeholder<14> _14;
+    extern const _Placeholder<15> _15;
+    extern const _Placeholder<16> _16;
+    extern const _Placeholder<17> _17;
+    extern const _Placeholder<18> _18;
+    extern const _Placeholder<19> _19;
+    extern const _Placeholder<20> _20;
+    extern const _Placeholder<21> _21;
+    extern const _Placeholder<22> _22;
+    extern const _Placeholder<23> _23;
+    extern const _Placeholder<24> _24;
+    extern const _Placeholder<25> _25;
+    extern const _Placeholder<26> _26;
+    extern const _Placeholder<27> _27;
+    extern const _Placeholder<28> _28;
+    extern const _Placeholder<29> _29;
+  }
+#endif // C++98
 
 namespace tr1
 {
@@ -850,49 +880,18 @@ namespace tr1
     const int is_placeholder<_Tp>::value;
 
   /// The type of placeholder objects defined by libstdc++.
-  template<int _Num> struct _Placeholder { };
+  using ::std::_Placeholder;
 
   /** @namespace std::tr1::placeholders
    *  @brief Sub-namespace for tr1/functional.
    */
-  namespace placeholders 
-  { 
-    /*  Define a large number of placeholders. There is no way to
-     *  simplify this with variadic templates, because we're introducing
-     *  unique names for each.
-     */
-    namespace 
-    {
-      _Placeholder<1> _1;
-      _Placeholder<2> _2;
-      _Placeholder<3> _3;
-      _Placeholder<4> _4;
-      _Placeholder<5> _5;
-      _Placeholder<6> _6;
-      _Placeholder<7> _7;
-      _Placeholder<8> _8;
-      _Placeholder<9> _9;
-      _Placeholder<10> _10;
-      _Placeholder<11> _11;
-      _Placeholder<12> _12;
-      _Placeholder<13> _13;
-      _Placeholder<14> _14;
-      _Placeholder<15> _15;
-      _Placeholder<16> _16;
-      _Placeholder<17> _17;
-      _Placeholder<18> _18;
-      _Placeholder<19> _19;
-      _Placeholder<20> _20;
-      _Placeholder<21> _21;
-      _Placeholder<22> _22;
-      _Placeholder<23> _23;
-      _Placeholder<24> _24;
-      _Placeholder<25> _25;
-      _Placeholder<26> _26;
-      _Placeholder<27> _27;
-      _Placeholder<28> _28;
-      _Placeholder<29> _29;
-    } 
+  namespace placeholders
+  {
+    // The C++11 std::placeholders are already exported from the library.
+    // Reusing them here avoids needing to export additional symbols for
+    // the TR1 placeholders, and avoids ODR violations due to defining
+    // them with internal linkage (as we used to do).
+    using namespace ::std::placeholders;
   }
 
   /**
@@ -901,22 +900,13 @@ namespace tr1
    */
   template<int _Num>
     struct is_placeholder<_Placeholder<_Num> >
-    { static const int value = _Num; };
-
-  template<int _Num>
-    const int is_placeholder<_Placeholder<_Num> >::value;
-
-#if __cplusplus >= 201103L
-  template<int _Num>
-    struct is_placeholder<std::_Placeholder<_Num>>
-    : std::integral_constant<int, _Num>
+    : integral_constant<int, _Num>
     { };
 
   template<int _Num>
-    struct is_placeholder<const std::_Placeholder<_Num>>
-    : std::integral_constant<int, _Num>
+    struct is_placeholder<const _Placeholder<_Num> >
+    : integral_constant<int, _Num>
     { };
-#endif
 
   /**
    * Stores a tuple of indices. Used by bind() to extract the elements
@@ -1423,6 +1413,9 @@ namespace tr1
                                                    _Signature> >::value;
 
 #if __cplusplus >= 201103L
+  // Specialize tr1::is_bind_expression for std::bind closure types,
+  // so that they can also work with tr1::bind.
+
   template<typename _Signature>
     struct is_bind_expression<std::_Bind<_Signature>>
     : true_type { };
@@ -2242,20 +2235,8 @@ namespace tr1
 }
 
 #if __cplusplus >= 201103L
-
-  template<typename> struct is_placeholder;
-
-  template<int _Num>
-    struct is_placeholder<tr1::_Placeholder<_Num>>
-    : integral_constant<int, _Num>
-    { };
-
-  template<int _Num>
-    struct is_placeholder<const tr1::_Placeholder<_Num>>
-    : integral_constant<int, _Num>
-    { };
-
-  template<typename> struct is_bind_expression;
+  // Specialize std::is_bind_expression for tr1::bind closure types,
+  // so that they can also work with std::bind.
 
   template<typename _Signature>
     struct is_bind_expression<tr1::_Bind<_Signature>>


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-10-27 16:33 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-27 16:33 [gcc r11-4451] libstdc++: Fix ODR violations caused by <tr1/functional> Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).