libstdc++: Fix up constexpr std::char_traits<char>::compare [PR99181]
Because of LWG 467, std::char_traits<char>::lt compares the values cast to unsigned char rather than char, so even when char is signed we get unsigned comparision. std::char_traits<char>::compare uses __builtin_memcmp and that works the same, but during constexpr evaluation we were calling __gnu_cxx::char_traits<char_type>::compare. As char_traits::lt is not virtual, __gnu_cxx::char_traits<char_type>::compare used __gnu_cxx::char_traits<char_type>::lt rather than std::char_traits<char>::lt and thus compared chars as signed if char is signed. This change fixes it by inlining __gnu_cxx::char_traits<char_type>::compare into std::char_traits<char>::compare by hand, so that it calls the right lt method. 2021-02-23 Jakub Jelinek <jakub@redhat.com> PR libstdc++/99181 * include/bits/char_traits.h (char_traits<char>::compare): For constexpr evaluation don't call __gnu_cxx::char_traits<char_type>::compare but do the comparison loop directly. * testsuite/21_strings/char_traits/requirements/char/99181.cc: New test.
This commit is contained in:
parent
7e647d71d5
commit
efa64fcce1
2 changed files with 48 additions and 1 deletions
|
@ -349,7 +349,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
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);
|
||||
{
|
||||
for (size_t __i = 0; __i < __n; ++__i)
|
||||
if (lt(__s1[__i], __s2[__i]))
|
||||
return -1;
|
||||
else if (lt(__s2[__i], __s1[__i]))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return __builtin_memcmp(__s1, __s2, __n);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// { dg-options "-std=gnu++17" }
|
||||
// { dg-do run { target c++17 } }
|
||||
|
||||
// Copyright (C) 2021 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>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void test01()
|
||||
{
|
||||
const char *a = "\x7f";
|
||||
const char *b = "\x80";
|
||||
int c = std::char_traits<char>::compare(a, b, 2);
|
||||
constexpr int d = std::char_traits<char>::compare("\x7f", "\x80", 2);
|
||||
|
||||
VERIFY( c && (c < 0) == (static_cast<unsigned char>(a[0])
|
||||
< static_cast<unsigned char>(b[0])) );
|
||||
VERIFY( d && (c < 0) == (d < 0) );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue