diff options
author | Pedro Alves <palves@redhat.com> | 2017-06-12 22:22:39 +0000 |
---|---|---|
committer | Pedro Alves <palves@gcc.gnu.org> | 2017-06-12 22:22:39 +0000 |
commit | b51483f48f3cc67cf4b508bdd9c4b6a47b44c53a (patch) | |
tree | 8fe8182274a7fa45124f605da11d566d091e8373 | |
parent | 07cfc2d75d85c5fc961bdd8434673f0a5f40587d (diff) | |
download | gcc-b51483f48f3cc67cf4b508bdd9c4b6a47b44c53a.zip gcc-b51483f48f3cc67cf4b508bdd9c4b6a47b44c53a.tar.gz gcc-b51483f48f3cc67cf4b508bdd9c4b6a47b44c53a.tar.bz2 |
Finish implementing P0426R1 "Constexpr for std::char_traits" for C++17
As discussed in PR c++/80265 ("__builtin_{memcmp,memchr,strlen} are
not usable in constexpr functions"), use __builtin_constant_p to tell
whether we can defer to a constexpr algorithm.
I used __always_inline__ just to be thorough. It isn't really really
necessary as far as I could determine.
Changes like these:
if (__n == 0)
return 0;
- return wmemcmp(__s1, __s2, __n);
+ else
+ return wmemcmp(__s1, __s2, __n);
are necessary otherwise G++ complains that we're calling a
non-constexpr function, which looks like a a manifestation of PR67026
to me.
libstdc++-v3:
2017-06-12 Pedro Alves <palves@redhat.com>
* doc/xml/manual/status_cxx2017.xml: Update C++17 constexpr
char_traits status.
* doc/html/*: Regenerate.
* include/bits/char_traits.h (_GLIBCXX_ALWAYS_INLINE): Define if
not already defined.
(__cpp_lib_constexpr_char_traits): Uncomment.
(__constant_string_p, __constant_char_array_p): New.
(std::char_traits<char>, std::char_traits<wchar_t>): Add
_GLIBCXX17_CONSTEXPR on compare, length and find and use
__constant_string_p, __constant_char_array_p and
__builtin_constant_p to defer to __gnu_cxx::char_traits at compile
time.
* testsuite/21_strings/char_traits/requirements/
constexpr_functions_c++17.cc: Uncomment
__cpp_lib_constexpr_char_traits tests. Uncomment
test_compare<char>, test_length<char>, test_find<char>,
test_compare<wchar_t>, test_length<wchar_t> and test_find<wchar_t>
static_assert tests.
From-SVN: r249137
-rw-r--r-- | libstdc++-v3/ChangeLog | 23 | ||||
-rw-r--r-- | libstdc++-v3/doc/xml/manual/status_cxx2017.xml | 5 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/char_traits.h | 101 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/21_strings/char_traits/requirements/constexpr_functions_c++17.cc | 16 |
4 files changed, 123 insertions, 22 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 5ee9e68..05efaa0 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,26 @@ +2017-06-12 Pedro Alves <palves@redhat.com> + + * doc/xml/manual/status_cxx2017.xml: Update C++17 constexpr + char_traits status. + * doc/html/*: Regenerate. + + * include/bits/char_traits.h (_GLIBCXX_ALWAYS_INLINE): Define if + not already defined. + (__cpp_lib_constexpr_char_traits): Uncomment. + (__constant_string_p, __constant_char_array_p): New. + (std::char_traits<char>, std::char_traits<wchar_t>): Add + _GLIBCXX17_CONSTEXPR on compare, length and find and use + __constant_string_p, __constant_char_array_p and + __builtin_constant_p to defer to __gnu_cxx::char_traits at compile + time. + + * testsuite/21_strings/char_traits/requirements/ + constexpr_functions_c++17.cc: Uncomment + __cpp_lib_constexpr_char_traits tests. Uncomment + test_compare<char>, test_length<char>, test_find<char>, + test_compare<wchar_t>, test_length<wchar_t> and test_find<wchar_t> + static_assert tests. + 2017-06-12 François Dumont <fdumont@gcc.gnu.org> * include/bits/stl_tree.h (_Rb_tree_impl()): Restore _Node_allocator diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml index a208238..85e193d 100644 --- a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml +++ b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml @@ -482,15 +482,14 @@ Feature-testing recommendations for C++</link>. </row> <row> - <?dbhtml bgcolor="#B0B0B0" ?> <entry> Constexpr for <code>std::char_traits</code> </entry> <entry> <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0426r1.html"> P0426R1 </link> </entry> - <entry align="center"> 7 (partial) </entry> - <entry><code> ??? </code></entry> + <entry align="center"> 8 </entry> + <entry><code> __cpp_lib_constexpr_char_traits >= 201611 </code></entry> </row> <row> diff --git a/libstdc++-v3/include/bits/char_traits.h b/libstdc++-v3/include/bits/char_traits.h index f19120b..5ccb439 100644 --- a/libstdc++-v3/include/bits/char_traits.h +++ b/libstdc++-v3/include/bits/char_traits.h @@ -40,6 +40,10 @@ #include <bits/postypes.h> // For streampos #include <cwchar> // For WEOF, wmemmove, wmemset, etc. +#ifndef _GLIBCXX_ALWAYS_INLINE +#define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__)) +#endif + namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -139,7 +143,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return !eq_int_type(__c, eof()) ? __c : to_int_type(char_type()); } }; -// #define __cpp_lib_constexpr_char_traits 201611 +#define __cpp_lib_constexpr_char_traits 201611 template<typename _CharT> _GLIBCXX14_CONSTEXPR int @@ -212,6 +216,42 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION +#if __cplusplus > 201402 + /** + * @brief Determine whether the characters of a NULL-terminated + * string are known at compile time. + * @param __s The string. + * + * Assumes that _CharT is a built-in character type. + */ + template<typename _CharT> + static _GLIBCXX_ALWAYS_INLINE constexpr bool + __constant_string_p(const _CharT* __s) + { + while (__builtin_constant_p(*__s) && *__s) + __s++; + return __builtin_constant_p(*__s); + } + + /** + * @brief Determine whether the characters of a character array are + * known at compile time. + * @param __a The character array. + * @param __n Number of characters. + * + * Assumes that _CharT is a built-in character type. + */ + template<typename _CharT> + static _GLIBCXX_ALWAYS_INLINE constexpr bool + __constant_char_array_p(const _CharT* __a, size_t __n) + { + size_t __i = 0; + while (__builtin_constant_p(__a[__i]) && __i < __n) + __i++; + return __i == __n; + } +#endif + // 21.1 /** * @brief Basis for explicit traits specializations. @@ -256,21 +296,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION < static_cast<unsigned char>(__c2)); } - static /* _GLIBCXX17_CONSTEXPR */ int + static _GLIBCXX17_CONSTEXPR int compare(const char_type* __s1, const char_type* __s2, size_t __n) { +#if __cplusplus > 201402 + if (__builtin_constant_p(__n) + && __constant_char_array_p(__s1, __n) + && __constant_char_array_p(__s2, __n)) + return __gnu_cxx::char_traits<char_type>::compare(__s1, __s2, __n); +#endif if (__n == 0) return 0; return __builtin_memcmp(__s1, __s2, __n); } - static /* _GLIBCXX17_CONSTEXPR */ size_t + static _GLIBCXX17_CONSTEXPR size_t length(const char_type* __s) - { return __builtin_strlen(__s); } + { +#if __cplusplus > 201402 + if (__constant_string_p(__s)) + return __gnu_cxx::char_traits<char_type>::length(__s); +#endif + return __builtin_strlen(__s); + } - static /* _GLIBCXX17_CONSTEXPR */ const char_type* + static _GLIBCXX17_CONSTEXPR const char_type* find(const char_type* __s, size_t __n, const char_type& __a) { +#if __cplusplus > 201402 + if (__builtin_constant_p(__n) + && __builtin_constant_p(__a) + && __constant_char_array_p(__s, __n)) + return __gnu_cxx::char_traits<char_type>::find(__s, __n, __a); +#endif if (__n == 0) return 0; return static_cast<const char_type*>(__builtin_memchr(__s, __a, __n)); @@ -347,24 +405,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION lt(const char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT { return __c1 < __c2; } - static /* _GLIBCXX17_CONSTEXPR */ int + static _GLIBCXX17_CONSTEXPR int compare(const char_type* __s1, const char_type* __s2, size_t __n) { +#if __cplusplus > 201402 + if (__builtin_constant_p(__n) + && __constant_char_array_p(__s1, __n) + && __constant_char_array_p(__s2, __n)) + return __gnu_cxx::char_traits<char_type>::compare(__s1, __s2, __n); +#endif if (__n == 0) return 0; - return wmemcmp(__s1, __s2, __n); + else + return wmemcmp(__s1, __s2, __n); } - static /* _GLIBCXX17_CONSTEXPR */ size_t + static _GLIBCXX17_CONSTEXPR size_t length(const char_type* __s) - { return wcslen(__s); } + { +#if __cplusplus > 201402 + if (__constant_string_p(__s)) + return __gnu_cxx::char_traits<char_type>::length(__s); + else +#endif + return wcslen(__s); + } - static /* _GLIBCXX17_CONSTEXPR */ const char_type* + static _GLIBCXX17_CONSTEXPR const char_type* find(const char_type* __s, size_t __n, const char_type& __a) { +#if __cplusplus > 201402 + if (__builtin_constant_p(__n) + && __builtin_constant_p(__a) + && __constant_char_array_p(__s, __n)) + return __gnu_cxx::char_traits<char_type>::find(__s, __n, __a); +#endif if (__n == 0) return 0; - return wmemchr(__s, __a, __n); + else + return wmemchr(__s, __a, __n); } static char_type* diff --git a/libstdc++-v3/testsuite/21_strings/char_traits/requirements/constexpr_functions_c++17.cc b/libstdc++-v3/testsuite/21_strings/char_traits/requirements/constexpr_functions_c++17.cc index 014caa0..efd280f 100644 --- a/libstdc++-v3/testsuite/21_strings/char_traits/requirements/constexpr_functions_c++17.cc +++ b/libstdc++-v3/testsuite/21_strings/char_traits/requirements/constexpr_functions_c++17.cc @@ -74,20 +74,20 @@ template<typename CT> } #ifndef __cpp_lib_constexpr_char_traits -// #error Feature-test macro for constexpr char_traits is missing +# error Feature-test macro for constexpr char_traits is missing #elif __cpp_lib_constexpr_char_traits != 201611 -// #error Feature-test macro for constexpr char_traits has the wrong value +# error Feature-test macro for constexpr char_traits has the wrong value #endif static_assert( test_assign<std::char_traits<char>>() ); -// static_assert( test_compare<std::char_traits<char>>() ); -// static_assert( test_length<std::char_traits<char>>() ); -// static_assert( test_find<std::char_traits<char>>() ); +static_assert( test_compare<std::char_traits<char>>() ); +static_assert( test_length<std::char_traits<char>>() ); +static_assert( test_find<std::char_traits<char>>() ); #ifdef _GLIBCXX_USE_WCHAR_T static_assert( test_assign<std::char_traits<wchar_t>>() ); -// static_assert( test_compare<std::char_traits<wchar_t>>() ); -// static_assert( test_length<std::char_traits<wchar_t>>() ); -// static_assert( test_find<std::char_traits<wchar_t>>() ); +static_assert( test_compare<std::char_traits<wchar_t>>() ); +static_assert( test_length<std::char_traits<wchar_t>>() ); +static_assert( test_find<std::char_traits<wchar_t>>() ); #endif static_assert( test_assign<std::char_traits<char16_t>>() ); static_assert( test_compare<std::char_traits<char16_t>>() ); |