From: Jonathan Wakely Date: Tue, 27 Oct 2020 16:32:53 +0000 (+0000) Subject: libstdc++: Fix ODR violations caused by X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d4fd8638be8a6f105bfaf1c0e3bcfad36aca03be;p=gcc.git libstdc++: Fix ODR violations caused by 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 can use it. The members of the std::placeholder namespace must not be defined by in C++98 mode, because "placeholders", "_1", "_2" etc. are not reserved names in C++98. Instead they can be declared in , 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 --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 #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 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 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 -#include +#include // for std::_Placeholder, std::_Bind, std::_Bind_result #include #include @@ -42,18 +41,49 @@ #include #include #include // for std::__addressof -#if __cplusplus >= 201103L -# include // for integral_constant, true_type, false_type -#endif namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -#if __cplusplus >= 201103L - template struct _Placeholder; - template class _Bind; - template class _Bind_result; -#endif + +#if __cplusplus < 201103L + // In C++98 mode, doesn't declare std::placeholders::_1 etc. + // because they are not reserved names in C++98. However, they are reserved + // by 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 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 struct is_placeholder<_Placeholder<_Num> > - { static const int value = _Num; }; - - template - const int is_placeholder<_Placeholder<_Num> >::value; - -#if __cplusplus >= 201103L - template - struct is_placeholder> - : std::integral_constant + : integral_constant { }; template - struct is_placeholder> - : std::integral_constant + struct is_placeholder > + : integral_constant { }; -#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 struct is_bind_expression> : true_type { }; @@ -2242,20 +2235,8 @@ namespace tr1 } #if __cplusplus >= 201103L - - template struct is_placeholder; - - template - struct is_placeholder> - : integral_constant - { }; - - template - struct is_placeholder> - : integral_constant - { }; - - template struct is_bind_expression; + // Specialize std::is_bind_expression for tr1::bind closure types, + // so that they can also work with std::bind. template struct is_bind_expression>