[libcxx-commits] [libcxx] [libc++][test] Fixes constexpr nasty_char_traits. (PR #90981)
Mark de Wever via libcxx-commits
libcxx-commits at lists.llvm.org
Fri May 3 09:38:24 PDT 2024
https://github.com/mordante created https://github.com/llvm/llvm-project/pull/90981
This was discovered by @StephanTLavavej who provided the solution they use in MSVC STL. This solution is based on that example.
The same issue affects the constexpr_char_traits which was discovered in https://github.com/llvm/llvm-project/pull/88389. This uses the same fix.
Fixes: https://github.com/llvm/llvm-project/issues/74221
>From b7915417e2b1a1c4d801d8b4c500ef404cd13f94 Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Sun, 4 Feb 2024 18:52:19 +0100
Subject: [PATCH] [libc++][test] Fixes constexpr nasty_char_traits.
This was discovered by @StephanTLavavej who provided the solution they use
in MSVC STL. This solution is based on that example.
The same issue affects the constexpr_char_traits which was discovered in
https://github.com/llvm/llvm-project/pull/88389. This uses the same fix.
Fixes: https://github.com/llvm/llvm-project/issues/74221
---
libcxx/test/support/constexpr_char_traits.h | 56 ++++++++++++++-------
libcxx/test/support/nasty_string.h | 12 +++--
2 files changed, 47 insertions(+), 21 deletions(-)
diff --git a/libcxx/test/support/constexpr_char_traits.h b/libcxx/test/support/constexpr_char_traits.h
index 75380d5a7ffbb3..a6420da8849028 100644
--- a/libcxx/test/support/constexpr_char_traits.h
+++ b/libcxx/test/support/constexpr_char_traits.h
@@ -16,6 +16,30 @@
#include "test_macros.h"
+// Tests whether the range [p1, p1 + n) overlaps with the range [p2, p2 + n).
+//
+// precondition The ranges [p1, p1 + n) and [p2, p2 + n) are valid ranges.
+//
+// Typically the pointers are compared with less than. This is not allowed when
+// the pointers belong to different ranges. This is UB. Typically, this is
+// benign at run-time, however since UB is not allowed during constant
+// evaluation this does not compile. This function does the validation without
+// UB.
+//
+// When the ranges overlap the ranges can be copied from the beginning to the
+// end. Otherwise they need to be copied from the end to the beginning.
+template <class Traits>
+TEST_CONSTEXPR_CXX14 bool is_overlapping_range(Traits* p1, const Traits* p2, std::size_t n) {
+ if (p1 == p2) // Needed when n == 0
+ return true;
+
+ for (; n; --n, ++p1)
+ if (p1 == p2)
+ return true;
+
+ return false;
+}
+
template <class CharT>
struct constexpr_char_traits
{
@@ -98,23 +122,21 @@ constexpr_char_traits<CharT>::find(const char_type* s, std::size_t n, const char
}
template <class CharT>
-TEST_CONSTEXPR_CXX14 CharT*
-constexpr_char_traits<CharT>::move(char_type* s1, const char_type* s2, std::size_t n)
-{
- char_type* r = s1;
- if (s1 < s2)
- {
- for (; n; --n, ++s1, ++s2)
- assign(*s1, *s2);
- }
- else if (s2 < s1)
- {
- s1 += n;
- s2 += n;
- for (; n; --n)
- assign(*--s1, *--s2);
- }
- return r;
+TEST_CONSTEXPR_CXX14 CharT* constexpr_char_traits<CharT>::move(char_type* s1, const char_type* s2, std::size_t n) {
+ if (s1 == s2)
+ return s1;
+
+ char_type* r = s1;
+ if (is_overlapping_range(s1, s2, n)) {
+ for (; n; --n)
+ assign(*s1++, *s2++);
+ } else {
+ s1 += n;
+ s2 += n;
+ for (; n; --n)
+ assign(*--s1, *--s2);
+ }
+ return r;
}
template <class CharT>
diff --git a/libcxx/test/support/nasty_string.h b/libcxx/test/support/nasty_string.h
index 672c3cb4ed9ea5..90b24f02f1b3bf 100644
--- a/libcxx/test/support/nasty_string.h
+++ b/libcxx/test/support/nasty_string.h
@@ -16,6 +16,7 @@
#include "make_string.h"
#include "test_macros.h"
+#include "constexpr_char_traits.h" // is_nonoverlapping_range
// This defines a nasty_string similar to nasty_containers. This string's
// value_type does operator hijacking, which allows us to ensure that the
@@ -118,11 +119,14 @@ constexpr const nasty_char* nasty_char_traits::find(const nasty_char* s, std::si
}
constexpr nasty_char* nasty_char_traits::move(nasty_char* s1, const nasty_char* s2, std::size_t n) {
+ if (s1 == s2)
+ return s1;
+
nasty_char* r = s1;
- if (s1 < s2) {
- for (; n; --n, ++s1, ++s2)
- assign(*s1, *s2);
- } else if (s2 < s1) {
+ if (is_overlapping_range(s1, s2, n)) {
+ for (; n; --n)
+ assign(*s1++, *s2++);
+ } else {
s1 += n;
s2 += n;
for (; n; --n)
More information about the libcxx-commits
mailing list