diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h index 060652afb183ca671f0b613cf27b3b411cbc4b1c..2f9ce75e82c27bbb76791cc30c4396df2b69ae69 100644 --- a/libstdc++-v3/include/bits/cpp_type_traits.h +++ b/libstdc++-v3/include/bits/cpp_type_traits.h @@ -434,8 +434,6 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3) }; #endif - template<typename> struct iterator_traits; - // A type that is safe for use with memcpy, memmove, memcmp etc. template<typename _Tp> struct __is_nonvolatile_trivially_copyable @@ -459,16 +457,103 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3) enum { __value = 0 }; }; + // Allow memcpy when source and destination are pointers to the same type. template<typename _Tp> struct __memcpyable<_Tp*, _Tp*> : __is_nonvolatile_trivially_copyable<_Tp> { }; + // Source pointer can be const. template<typename _Tp> struct __memcpyable<_Tp*, const _Tp*> : __is_nonvolatile_trivially_copyable<_Tp> { }; + template<typename _Tp> struct __memcpyable_integer; + + // For heterogeneous types, allow memcpy between equal-sized integers. + template<typename _Tp, typename _Up> + struct __memcpyable<_Tp*, _Up*> + { + enum { + __value = __memcpyable_integer<_Tp>::__width != 0 + && ((int)__memcpyable_integer<_Tp>::__width + == (int)__memcpyable_integer<_Up>::__width) + }; + }; + + // Specialization for const U* because __is_integer<const U> is never true. + template<typename _Tp, typename _Up> + struct __memcpyable<_Tp*, const _Up*> + : __memcpyable<_Tp*, _Up*> + { }; + + template<typename _Tp> + struct __memcpyable_integer + { + enum { + __width = __is_integer<_Tp>::__value ? (sizeof(_Tp) * __CHAR_BIT__) : 0 + }; + }; + + // Cannot memcpy volatile memory. + template<typename _Tp> + struct __memcpyable_integer<volatile _Tp> + { enum { __width = 0 }; }; + + // Specializations for __intNN types with padding bits. +#if defined __GLIBCXX_TYPE_INT_N_0 && __GLIBCXX_BITSIZE_INT_N_0 % __CHAR_BIT__ + __extension__ + template<> + struct __memcpyable_integer<__GLIBCXX_TYPE_INT_N_0> + { enum { __width = __GLIBCXX_BITSIZE_INT_N_0 }; }; + __extension__ + template<> + struct __memcpyable_integer<unsigned __GLIBCXX_TYPE_INT_N_0> + { enum { __width = __GLIBCXX_BITSIZE_INT_N_0 }; }; +#endif +#if defined __GLIBCXX_TYPE_INT_N_1 && __GLIBCXX_BITSIZE_INT_N_1 % __CHAR_BIT__ + __extension__ + template<> + struct __memcpyable_integer<__GLIBCXX_TYPE_INT_N_1> + { enum { __width = __GLIBCXX_BITSIZE_INT_N_1 }; }; + __extension__ + template<> + struct __memcpyable_integer<unsigned __GLIBCXX_TYPE_INT_N_1> + { enum { __width = __GLIBCXX_BITSIZE_INT_N_1 }; }; +#endif +#if defined __GLIBCXX_TYPE_INT_N_2 && __GLIBCXX_BITSIZE_INT_N_2 % __CHAR_BIT__ + __extension__ + template<> + struct __memcpyable_integer<__GLIBCXX_TYPE_INT_N_2> + { enum { __width = __GLIBCXX_BITSIZE_INT_N_2 }; }; + __extension__ + template<> + struct __memcpyable_integer<unsigned __GLIBCXX_TYPE_INT_N_2> + { enum { __width = __GLIBCXX_BITSIZE_INT_N_2 }; }; +#endif +#if defined __GLIBCXX_TYPE_INT_N_3 && __GLIBCXX_BITSIZE_INT_N_3 % __CHAR_BIT__ + __extension__ + template<> + struct __memcpyable_integer<__GLIBCXX_TYPE_INT_N_3> + { enum { __width = __GLIBCXX_BITSIZE_INT_N_3 }; }; + __extension__ + template<> + struct __memcpyable_integer<unsigned __GLIBCXX_TYPE_INT_N_3> + { enum { __width = __GLIBCXX_BITSIZE_INT_N_3 }; }; +#endif + +#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ + // In strict modes __is_integer<__int128> is false, + // but we want to allow memcpy between signed/unsigned __int128. + __extension__ + template<> + struct __memcpyable_integer<__int128> { enum { __width = 128 }; }; + __extension__ + template<> + struct __memcpyable_integer<unsigned __int128> { enum { __width = 128 }; }; +#endif + // Whether two iterator types can be used with memcmp. // This trait only says it's well-formed to use memcmp, not that it // gives the right answer for a given algorithm. So for example, std::equal