[gcc r10-7569] libstdc++: Make string_view::copy usable in constant expressions (PR 94498)

Jonathan Wakely redi@gcc.gnu.org
Mon Apr 6 17:31:06 GMT 2020


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

commit r10-7569-gb696698767ba45b4d61a93205167e2f1f744d3f1
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Apr 6 18:30:53 2020 +0100

    libstdc++: Make string_view::copy usable in constant expressions (PR 94498)
    
            PR libstdc++/94498
            * include/bits/char_traits.h (__gnu_cxx::char_traits::move): Make it
            usable in constant expressions for C++20.
            (__gnu_cxx::char_traits::copy, __gnu_cxx::char_traits::assign): Add
            _GLIBCXX20_CONSTEXPR.
            (std::char_traits<char>, std::char_traits<wchar_t>)
            (std::char_traits<char8_t>): Make move, copy and assign usable in
            constant expressions for C++20.
            (std::char_traits<char16_t>, std::char_traits<char32_t>): Make move
            and copy usable in constant expressions for C++20.
            * include/std/string_view (basic_string_view::copy): Add
            _GLIBCXX20_CONSTEXPR.
            * testsuite/21_strings/basic_string_view/operations/copy/char/
            constexpr.cc: New test.
            * testsuite/21_strings/basic_string_view/operations/copy/wchar_t/
            constexpr.cc: New test.

Diff:
---
 libstdc++-v3/ChangeLog                             |  19 ++++
 libstdc++-v3/include/bits/char_traits.h            | 101 +++++++++++++++++----
 libstdc++-v3/include/std/string_view               |   1 +
 .../operations/copy/char/constexpr.cc              |  32 +++++++
 .../operations/copy/wchar_t/constexpr.cc           |  32 +++++++
 5 files changed, 167 insertions(+), 18 deletions(-)

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index eb092792229..4d7b5780189 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,22 @@
+2020-04-06  Jonathan Wakely  <jwakely@redhat.com>
+
+	PR libstdc++/94498
+	* include/bits/char_traits.h (__gnu_cxx::char_traits::move): Make it
+	usable in constant expressions for C++20.
+	(__gnu_cxx::char_traits::copy, __gnu_cxx::char_traits::assign): Add
+	_GLIBCXX20_CONSTEXPR.
+	(std::char_traits<char>, std::char_traits<wchar_t>)
+	(std::char_traits<char8_t>): Make move, copy and assign usable in
+	constant expressions for C++20.
+	(std::char_traits<char16_t>, std::char_traits<char32_t>): Make move
+	and copy usable in constant expressions for C++20.
+	* include/std/string_view (basic_string_view::copy): Add
+	_GLIBCXX20_CONSTEXPR.
+	* testsuite/21_strings/basic_string_view/operations/copy/char/
+	constexpr.cc: New test.
+	* testsuite/21_strings/basic_string_view/operations/copy/wchar_t/
+	constexpr.cc: New test.
+
 2020-04-05  Gerald Pfeifer  <gerald@pfeifer.com>
 
 	* doc/xml/manual/appendix_contributing.xml: Refer to Git
diff --git a/libstdc++-v3/include/bits/char_traits.h b/libstdc++-v3/include/bits/char_traits.h
index 2edb84ca3b8..65031d3ac83 100644
--- a/libstdc++-v3/include/bits/char_traits.h
+++ b/libstdc++-v3/include/bits/char_traits.h
@@ -113,13 +113,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static _GLIBCXX14_CONSTEXPR const char_type*
       find(const char_type* __s, std::size_t __n, const char_type& __a);
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       move(char_type* __s1, const char_type* __s2, std::size_t __n);
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       copy(char_type* __s1, const char_type* __s2, std::size_t __n);
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       assign(char_type* __s, std::size_t __n, char_type __a);
 
       static _GLIBCXX_CONSTEXPR char_type
@@ -179,17 +179,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _CharT>
+    _GLIBCXX20_CONSTEXPR
     typename char_traits<_CharT>::char_type*
     char_traits<_CharT>::
     move(char_type* __s1, const char_type* __s2, std::size_t __n)
     {
       if (__n == 0)
 	return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+      if (std::is_constant_evaluated())
+	{
+	  if (__s1 > __s2 && __s1 < __s2 + __n)
+	    std::copy_backward(__s2, __s2 + __n, __s1);
+	  else
+	    std::copy(__s2, __s2 + __n, __s1);
+	  return __s1;
+	}
+#endif
       return static_cast<_CharT*>(__builtin_memmove(__s1, __s2,
 						    __n * sizeof(char_type)));
     }
 
   template<typename _CharT>
+    _GLIBCXX20_CONSTEXPR
     typename char_traits<_CharT>::char_type*
     char_traits<_CharT>::
     copy(char_type* __s1, const char_type* __s2, std::size_t __n)
@@ -200,6 +212,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _CharT>
+    _GLIBCXX20_CONSTEXPR
     typename char_traits<_CharT>::char_type*
     char_traits<_CharT>::
     assign(char_type* __s, std::size_t __n, char_type __a)
@@ -349,27 +362,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return static_cast<const char_type*>(__builtin_memchr(__s, __a, __n));
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       move(char_type* __s1, const char_type* __s2, size_t __n)
       {
 	if (__n == 0)
 	  return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::move(__s1, __s2, __n);
+#endif
 	return static_cast<char_type*>(__builtin_memmove(__s1, __s2, __n));
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       copy(char_type* __s1, const char_type* __s2, size_t __n)
       {
 	if (__n == 0)
 	  return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::copy(__s1, __s2, __n);
+#endif
 	return static_cast<char_type*>(__builtin_memcpy(__s1, __s2, __n));
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       assign(char_type* __s, size_t __n, char_type __a)
       {
 	if (__n == 0)
 	  return __s;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::assign(__s, __n, __a);
+#endif
 	return static_cast<char_type*>(__builtin_memset(__s, __a, __n));
       }
 
@@ -458,27 +483,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return wmemchr(__s, __a, __n);
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       move(char_type* __s1, const char_type* __s2, size_t __n)
       {
 	if (__n == 0)
 	  return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::move(__s1, __s2, __n);
+#endif
 	return wmemmove(__s1, __s2, __n);
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       copy(char_type* __s1, const char_type* __s2, size_t __n)
       {
 	if (__n == 0)
 	  return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::copy(__s1, __s2, __n);
+#endif
 	return wmemcpy(__s1, __s2, __n);
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       assign(char_type* __s, size_t __n, char_type __a)
       {
 	if (__n == 0)
 	  return __s;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::assign(__s, __n, __a);
+#endif
 	return wmemset(__s, __a, __n);
       }
 
@@ -567,27 +604,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return static_cast<const char_type*>(__builtin_memchr(__s, __a, __n));
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       move(char_type* __s1, const char_type* __s2, size_t __n)
       {
 	if (__n == 0)
 	  return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::move(__s1, __s2, __n);
+#endif
 	return static_cast<char_type*>(__builtin_memmove(__s1, __s2, __n));
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       copy(char_type* __s1, const char_type* __s2, size_t __n)
       {
 	if (__n == 0)
 	  return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::copy(__s1, __s2, __n);
+#endif
 	return static_cast<char_type*>(__builtin_memcpy(__s1, __s2, __n));
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       assign(char_type* __s, size_t __n, char_type __a)
       {
 	if (__n == 0)
 	  return __s;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::assign(__s, __n, __a);
+#endif
 	return static_cast<char_type*>(__builtin_memset(__s, __a, __n));
       }
 
@@ -680,25 +729,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return 0;
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       move(char_type* __s1, const char_type* __s2, size_t __n)
       {
 	if (__n == 0)
 	  return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::move(__s1, __s2, __n);
+#endif
 	return (static_cast<char_type*>
 		(__builtin_memmove(__s1, __s2, __n * sizeof(char_type))));
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       copy(char_type* __s1, const char_type* __s2, size_t __n)
       {
 	if (__n == 0)
 	  return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::copy(__s1, __s2, __n);
+#endif
 	return (static_cast<char_type*>
 		(__builtin_memcpy(__s1, __s2, __n * sizeof(char_type))));
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       assign(char_type* __s, size_t __n, char_type __a)
       {
 	for (size_t __i = 0; __i < __n; ++__i)
@@ -783,25 +840,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return 0;
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       move(char_type* __s1, const char_type* __s2, size_t __n)
       {
 	if (__n == 0)
 	  return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::move(__s1, __s2, __n);
+#endif
 	return (static_cast<char_type*>
 		(__builtin_memmove(__s1, __s2, __n * sizeof(char_type))));
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       copy(char_type* __s1, const char_type* __s2, size_t __n)
       { 
 	if (__n == 0)
 	  return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return __gnu_cxx::char_traits<char_type>::copy(__s1, __s2, __n);
+#endif
 	return (static_cast<char_type*>
 		(__builtin_memcpy(__s1, __s2, __n * sizeof(char_type))));
       }
 
-      static char_type*
+      static _GLIBCXX20_CONSTEXPR char_type*
       assign(char_type* __s, size_t __n, char_type __a)
       {
 	for (size_t __i = 0; __i < __n; ++__i)
diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view
index 99a81bb04fa..ea1ccc9bb21 100644
--- a/libstdc++-v3/include/std/string_view
+++ b/libstdc++-v3/include/std/string_view
@@ -263,6 +263,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       // [string.view.ops], string operations:
 
+      _GLIBCXX20_CONSTEXPR
       size_type
       copy(_CharT* __str, size_type __n, size_type __pos = 0) const
       {
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/copy/char/constexpr.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/copy/char/constexpr.cc
new file mode 100644
index 00000000000..f3042c25dc4
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/copy/char/constexpr.cc
@@ -0,0 +1,32 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <string_view>
+
+constexpr bool
+test01()
+{
+  std::string_view s = "Everything changes and nothing stands still.";
+  char buf[7];
+  auto n = s.copy(buf, 7, 11);
+  return std::string_view(buf, n) == "changes";
+}
+
+static_assert( test01() );
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/copy/wchar_t/constexpr.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/copy/wchar_t/constexpr.cc
new file mode 100644
index 00000000000..f48a17eade8
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/copy/wchar_t/constexpr.cc
@@ -0,0 +1,32 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <string_view>
+
+constexpr bool
+test01()
+{
+  std::wstring_view s = L"Everything changes and nothing stands still.";
+  wchar_t buf[7];
+  auto n = s.copy(buf, 7, 11);
+  return std::wstring_view(buf, n) == L"changes";
+}
+
+static_assert( test01() );


More information about the Libstdc++-cvs mailing list