diff mbox series

libstdc++: Fix char_traits move with overlap

Message ID DB7PR01MB4537D2735049BBC32F25E924A49F0@DB7PR01MB4537.eurprd01.prod.exchangelabs.com
State New
Headers show
Series libstdc++: Fix char_traits move with overlap | expand

Commit Message

Paul Keir June 14, 2020, 10:40 p.m. UTC
Hi,

Upon constexpr evaluation, char_traits move uses copy_backward, but its last argument should be to the range end rather than its beginning. I include the fix and a test.

This is my first patch, so if it looks OK, perhaps someone could commit for me.

Regards,
Paul




Please consider the environment and think before you print.

The University of the West of Scotland is a registered Scottish charity. Charity number SC002520.

This e-mail and any attachment is for authorised use by the intended recipient(s) only. It may contain proprietary material, confidential information and/or be subject to legal privilege. It should not be copied, disclosed to, retained or used by, any other party. If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender.

Please note that any views or opinions presented in this email are solely those of the author and do not necessarily represent those of the University of the West of Scotland.

As a public body, the University of the West of Scotland may be required to make available emails as well as other written forms of information as a result of a request made under the Freedom of Information (Scotland) Act 2002.

Comments

Jonathan Wakely June 15, 2020, 1:42 p.m. UTC | #1
On 14/06/20 22:40 +0000, Paul Keir wrote:
>Hi,
>
>Upon constexpr evaluation, char_traits move uses copy_backward, but its last argument should be to the range end rather than its beginning. I include the fix and a test.
>
>This is my first patch, so if it looks OK, perhaps someone could commit for me.

The patch is fine, and small enough to not need a copyright
assignment, so I've tested it and committed it. Thanks very much!

I've also committed the attached patch, which bumps the feature test
macro to indicate support for this feature. That macro is not defined
by the C++ committee, but I'm treating that as a defect and will get
it added.

Tested powerpc64le-linux, committed to master.
Jonathan Wakely June 15, 2020, 1:44 p.m. UTC | #2
On 15/06/20 14:42 +0100, Jonathan Wakely wrote:
>On 14/06/20 22:40 +0000, Paul Keir wrote:
>>Hi,
>>
>>Upon constexpr evaluation, char_traits move uses copy_backward, but its last argument should be to the range end rather than its beginning. I include the fix and a test.
>>
>>This is my first patch, so if it looks OK, perhaps someone could commit for me.
>
>The patch is fine, and small enough to not need a copyright
>assignment, so I've tested it and committed it. Thanks very much!

I'll also queue your patch for the gcc-10 branch, so it will get
applied next time I do some backports.


>I've also committed the attached patch, which bumps the feature test
>macro to indicate support for this feature. That macro is not defined
>by the C++ committee, but I'm treating that as a defect and will get
>it added.
diff mbox series

Patch

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index ee252236a..b54dccd2d 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,9 @@ 
+2020-06-12  Paul Keir  <paul.keir@uws.ac.uk>
+
+	* include/bits/char_traits.h: constexpr char_traits
+	move with overlap was using copy_backward incorrectly.
+	* testsuite/21_strings/char_traits/requirements/constexpr_functions_c++20.cc: New test.
+
 2020-06-04  Jonathan Wakely  <jwakely@redhat.com>
 
 	* include/bits/iterator_concepts.h (__detail::__ptr, __detail::__ref)
diff --git a/libstdc++-v3/include/bits/char_traits.h b/libstdc++-v3/include/bits/char_traits.h
index c6da184e4..c623a6713 100644
--- a/libstdc++-v3/include/bits/char_traits.h
+++ b/libstdc++-v3/include/bits/char_traits.h
@@ -196,7 +196,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       if (std::is_constant_evaluated())
 	{
 	  if (__s1 > __s2 && __s1 < __s2 + __n)
-	    std::copy_backward(__s2, __s2 + __n, __s1);
+	    std::copy_backward(__s2, __s2 + __n, __s1 + __n);
 	  else
 	    std::copy(__s2, __s2 + __n, __s1);
 	  return __s1;
diff --git a/libstdc++-v3/testsuite/21_strings/char_traits/requirements/constexpr_functions_c++20.cc b/libstdc++-v3/testsuite/21_strings/char_traits/requirements/constexpr_functions_c++20.cc
new file mode 100644
index 000000000..6358640c1
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/char_traits/requirements/constexpr_functions_c++20.cc
@@ -0,0 +1,52 @@ 
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2017-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/>.
+
+#include <string>
+
+template<typename CT>
+  constexpr bool
+  test_move()
+  {
+    using char_type = typename CT::char_type;
+    char_type s1[3] = {1, 2, 3};
+    CT::move(s1+1, s1, 2);
+    return s1[0]==char_type{1} && s1[1]==char_type{1} && s1[2]==char_type{2};
+  }
+
+#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_move<std::char_traits<char>>() );
+#ifdef _GLIBCXX_USE_WCHAR_T
+static_assert( test_move<std::char_traits<wchar_t>>() );
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+static_assert( test_move<std::char_traits<char8_t>>() );
+#endif
+static_assert( test_move<std::char_traits<char16_t>>() );
+static_assert( test_move<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_move<std::char_traits<C>>() );