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).