[PATCH] Implement P0426R1 "Constexpr for std::char_traits" for C++17 (partial)

Jonathan Wakely jwakely@redhat.com
Mon Apr 3 17:18:00 GMT 2017


We can't fully implement this without compiler support (see PR80265)
but this adds _GLIBCXX17_CONSTEXPR where possible.

I've left /* _GLIBCXX17_CONSTEXPR */ comments where we need to add it
once the compiler allows it.

	* include/bits/char_traits.h (__gnu_cxx::char_traits): Add
	_GLIBCXX14_CONSTEXPR on assign, compare, find, and length.
	(std::char_traits<char>, std::char_traits<wchar_t>): Add
	_GLIBCXX17_CONSTEXPR on assign.
	(std::char_traits<char16_t>, std::char_traits<char32_t>): Add
	_GLIBCXX17_CONSTEXPR on assign, compare, find, and length.
	* testsuite/21_strings/char_traits/requirements/
	constexpr_functions_c++17.cc: New test.

Tested powerpc64le-linux, committed to trunk.

-------------- next part --------------
commit c7ce2e6d809422aa7440c64f0929492fb88c7634
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Mar 31 13:36:43 2017 +0100

    Implement P0426R1 "Constexpr for std::char_traits" for C++17 (partial)
    
    	* include/bits/char_traits.h (__gnu_cxx::char_traits): Add
    	_GLIBCXX14_CONSTEXPR on assign, compare, find, and length.
    	(std::char_traits<char>, std::char_traits<wchar_t>): Add
    	_GLIBCXX17_CONSTEXPR on assign.
    	(std::char_traits<char16_t>, std::char_traits<char32_t>): Add
    	_GLIBCXX17_CONSTEXPR on assign, compare, find, and length.
    	* testsuite/21_strings/char_traits/requirements/
    	constexpr_functions_c++17.cc: New test.

diff --git a/libstdc++-v3/include/bits/char_traits.h b/libstdc++-v3/include/bits/char_traits.h
index bcfc23a..75db5b8 100644
--- a/libstdc++-v3/include/bits/char_traits.h
+++ b/libstdc++-v3/include/bits/char_traits.h
@@ -88,7 +88,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef typename _Char_types<_CharT>::off_type    off_type;
       typedef typename _Char_types<_CharT>::state_type  state_type;
 
-      static void
+      static _GLIBCXX14_CONSTEXPR void
       assign(char_type& __c1, const char_type& __c2)
       { __c1 = __c2; }
 
@@ -100,13 +100,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       lt(const char_type& __c1, const char_type& __c2)
       { return __c1 < __c2; }
 
-      static int
+      static _GLIBCXX14_CONSTEXPR int
       compare(const char_type* __s1, const char_type* __s2, std::size_t __n);
 
-      static std::size_t
+      static _GLIBCXX14_CONSTEXPR std::size_t
       length(const char_type* __s);
 
-      static const char_type*
+      static _GLIBCXX14_CONSTEXPR const char_type*
       find(const char_type* __s, std::size_t __n, const char_type& __a);
 
       static char_type*
@@ -139,8 +139,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return !eq_int_type(__c, eof()) ? __c : to_int_type(char_type()); }
     };
 
+// #define __cpp_lib_constexpr_char_traits 201611
+
   template<typename _CharT>
-    int
+    _GLIBCXX14_CONSTEXPR int
     char_traits<_CharT>::
     compare(const char_type* __s1, const char_type* __s2, std::size_t __n)
     {
@@ -153,7 +155,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _CharT>
-    std::size_t
+    _GLIBCXX14_CONSTEXPR std::size_t
     char_traits<_CharT>::
     length(const char_type* __p)
     {
@@ -164,7 +166,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _CharT>
-    const typename char_traits<_CharT>::char_type*
+    _GLIBCXX14_CONSTEXPR const typename char_traits<_CharT>::char_type*
     char_traits<_CharT>::
     find(const char_type* __s, std::size_t __n, const char_type& __a)
     {
@@ -238,7 +240,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef streamoff         off_type;
       typedef mbstate_t         state_type;
 
-      static void
+      static _GLIBCXX17_CONSTEXPR void
       assign(char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
       { __c1 = __c2; }
 
@@ -254,7 +256,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		< static_cast<unsigned char>(__c2));
       }
 
-      static int
+      static /* _GLIBCXX17_CONSTEXPR */ int
       compare(const char_type* __s1, const char_type* __s2, size_t __n)
       {
 	if (__n == 0)
@@ -262,11 +264,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return __builtin_memcmp(__s1, __s2, __n);
       }
 
-      static size_t
+      static /* _GLIBCXX17_CONSTEXPR */ size_t
       length(const char_type* __s)
       { return __builtin_strlen(__s); }
 
-      static const char_type*
+      static /* _GLIBCXX17_CONSTEXPR */ const char_type*
       find(const char_type* __s, size_t __n, const char_type& __a)
       {
 	if (__n == 0)
@@ -333,7 +335,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef wstreampos        pos_type;
       typedef mbstate_t         state_type;
 
-      static void
+      static _GLIBCXX17_CONSTEXPR void
       assign(char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
       { __c1 = __c2; }
 
@@ -345,7 +347,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       lt(const char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
       { return __c1 < __c2; }
 
-      static int
+      static /* _GLIBCXX17_CONSTEXPR */ int
       compare(const char_type* __s1, const char_type* __s2, size_t __n)
       {
 	if (__n == 0)
@@ -353,11 +355,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return wmemcmp(__s1, __s2, __n);
       }
 
-      static size_t
+      static /* _GLIBCXX17_CONSTEXPR */ size_t
       length(const char_type* __s)
       { return wcslen(__s); }
 
-      static const char_type*
+      static /* _GLIBCXX17_CONSTEXPR */ const char_type*
       find(const char_type* __s, size_t __n, const char_type& __a)
       {
 	if (__n == 0)
@@ -432,7 +434,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef u16streampos      pos_type;
       typedef mbstate_t         state_type;
 
-      static void
+      static _GLIBCXX17_CONSTEXPR void
       assign(char_type& __c1, const char_type& __c2) noexcept
       { __c1 = __c2; }
 
@@ -444,7 +446,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       lt(const char_type& __c1, const char_type& __c2) noexcept
       { return __c1 < __c2; }
 
-      static int
+      static _GLIBCXX17_CONSTEXPR int
       compare(const char_type* __s1, const char_type* __s2, size_t __n)
       {
 	for (size_t __i = 0; __i < __n; ++__i)
@@ -455,7 +457,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return 0;
       }
 
-      static size_t
+      static _GLIBCXX17_CONSTEXPR size_t
       length(const char_type* __s)
       {
 	size_t __i = 0;
@@ -464,7 +466,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return __i;
       }
 
-      static const char_type*
+      static _GLIBCXX17_CONSTEXPR const char_type*
       find(const char_type* __s, size_t __n, const char_type& __a)
       {
 	for (size_t __i = 0; __i < __n; ++__i)
@@ -529,7 +531,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef u32streampos      pos_type;
       typedef mbstate_t         state_type;
 
-      static void
+      static _GLIBCXX17_CONSTEXPR void
       assign(char_type& __c1, const char_type& __c2) noexcept
       { __c1 = __c2; }
 
@@ -541,7 +543,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       lt(const char_type& __c1, const char_type& __c2) noexcept
       { return __c1 < __c2; }
 
-      static int
+      static _GLIBCXX17_CONSTEXPR int
       compare(const char_type* __s1, const char_type* __s2, size_t __n)
       {
 	for (size_t __i = 0; __i < __n; ++__i)
@@ -552,7 +554,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return 0;
       }
 
-      static size_t
+      static _GLIBCXX17_CONSTEXPR size_t
       length(const char_type* __s)
       {
 	size_t __i = 0;
@@ -561,7 +563,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return __i;
       }
 
-      static const char_type*
+      static _GLIBCXX17_CONSTEXPR const char_type*
       find(const char_type* __s, size_t __n, const char_type& __a)
       {
 	for (size_t __i = 0; __i < __n; ++__i)
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
new file mode 100644
index 0000000..014caa0
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/char_traits/requirements/constexpr_functions_c++17.cc
@@ -0,0 +1,107 @@
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++1z } }
+
+// Copyright (C) 2017 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/>.
+
+#include <string>
+
+template<typename CT>
+  constexpr bool
+  test_assign()
+  {
+    using char_type = typename CT::char_type;
+    char_type s1[2] = {};
+    const char_type s2[2] = {1, 0};
+    CT::assign(s1[0], s2[0]);
+    return s1[0] == char_type{1};
+  }
+
+template<typename CT>
+  constexpr bool
+  test_compare()
+  {
+    using char_type = typename CT::char_type;
+    const char_type s1[3] = {1, 2, 3};
+    const char_type s2[3] = {1, 2, 3};
+    if (CT::compare(s1, s2, 3) != 0)
+      return false;
+    if (CT::compare(s2, s1, 3) != 0)
+      return false;
+    if (CT::compare(s1+1, s2, 2) <= 0)
+      return false;
+    return true;
+  }
+
+template<typename CT>
+  constexpr bool
+  test_length()
+  {
+    using char_type = typename CT::char_type;
+    const char_type s1[4] = {1, 2, 3, 0};
+    if (CT::length(s1) != 3)
+      return false;
+    if (CT::length(s1+1) != 2)
+      return false;
+    return true;
+  }
+
+template<typename CT>
+  constexpr bool
+  test_find()
+  {
+    using char_type = typename CT::char_type;
+    const char_type s1[3] = {1, 2, 3};
+    if (CT::find(s1, 3, char_type{2}) != s1+1)
+      return false;
+    if (CT::find(s1, 3, char_type{4}) != nullptr)
+      return false;
+    return true;
+  }
+
+#ifndef __cpp_lib_constexpr_char_traits
+// #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
+#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>>() );
+#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>>() );
+#endif
+static_assert( test_assign<std::char_traits<char16_t>>() );
+static_assert( test_compare<std::char_traits<char16_t>>() );
+static_assert( test_length<std::char_traits<char16_t>>() );
+static_assert( test_find<std::char_traits<char16_t>>() );
+static_assert( test_assign<std::char_traits<char32_t>>() );
+static_assert( test_compare<std::char_traits<char32_t>>() );
+static_assert( test_length<std::char_traits<char32_t>>() );
+static_assert( test_find<std::char_traits<char32_t>>() );
+
+struct C { unsigned char c; };
+constexpr bool operator==(const C& c1, const C& c2) { return c1.c == c2.c; }
+constexpr bool operator<(const C& c1, const C& c2) { return c1.c < c2.c; }
+static_assert( test_assign<std::char_traits<C>>() );
+static_assert( test_compare<std::char_traits<C>>() );
+static_assert( test_length<std::char_traits<C>>() );
+static_assert( test_find<std::char_traits<C>>() );


More information about the Gcc-patches mailing list