diff --git a/libcxx/include/__algorithm/equal.h b/libcxx/include/__algorithm/equal.h --- a/libcxx/include/__algorithm/equal.h +++ b/libcxx/include/__algorithm/equal.h @@ -50,7 +50,7 @@ int> = 0> _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _BinaryPredicate&) { - return std::__constexpr_memcmp_equal(__first1, __first2, (__last1 - __first1) * sizeof(_Tp)); + return std::__constexpr_memcmp_equal(__first1, __first2, __element_count(__last1 - __first1)); } template @@ -100,7 +100,7 @@ int> = 0> _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_impl( _Tp* __first1, _Tp* __last1, _Up* __first2, _Up*, _Pred&, _Proj1&, _Proj2&) { - return std::__constexpr_memcmp_equal(__first1, __first2, (__last1 - __first1) * sizeof(_Tp)); + return std::__constexpr_memcmp_equal(__first1, __first2, __element_count(__last1 - __first1)); } template diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h --- a/libcxx/include/__string/char_traits.h +++ b/libcxx/include/__string/char_traits.h @@ -373,7 +373,7 @@ static _LIBCPP_HIDE_FROM_ABI constexpr int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { - return std::__constexpr_memcmp(__s1, __s2, __n); + return std::__constexpr_memcmp(__s1, __s2, __element_count(__n)); } static _LIBCPP_HIDE_FROM_ABI constexpr diff --git a/libcxx/include/__string/constexpr_c_functions.h b/libcxx/include/__string/constexpr_c_functions.h --- a/libcxx/include/__string/constexpr_c_functions.h +++ b/libcxx/include/__string/constexpr_c_functions.h @@ -23,6 +23,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD +// Type used to encode that a function takes an integer that represents a number +// of elements as opposed to a number of bytes. +enum class __element_count : size_t {}; + inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 size_t __constexpr_strlen(const char* __str) { // GCC currently doesn't support __builtin_strlen for heap-allocated memory during constant evaluation. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70816 @@ -42,14 +46,16 @@ // of invoking it on every object individually. template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int -__constexpr_memcmp(const _Tp* __lhs, const _Up* __rhs, size_t __count) { +__constexpr_memcmp(const _Tp* __lhs, const _Up* __rhs, __element_count __n) { static_assert(__libcpp_is_trivially_lexicographically_comparable<_Tp, _Up>::value, "_Tp and _Up have to be trivially lexicographically comparable"); + auto __count = static_cast(__n); + if (__libcpp_is_constant_evaluated()) { #ifdef _LIBCPP_COMPILER_CLANG_BASED if (sizeof(_Tp) == 1 && !is_same<_Tp, bool>::value) - return __builtin_memcmp(__lhs, __rhs, __count); + return __builtin_memcmp(__lhs, __rhs, __count * sizeof(_Tp)); #endif while (__count != 0) { @@ -58,13 +64,13 @@ if (*__rhs < *__lhs) return 1; - __count -= sizeof(_Tp); + --__count; ++__lhs; ++__rhs; } return 0; } else { - return __builtin_memcmp(__lhs, __rhs, __count); + return __builtin_memcmp(__lhs, __rhs, __count * sizeof(_Tp)); } } @@ -73,26 +79,28 @@ // of invoking it on every object individually. template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool -__constexpr_memcmp_equal(const _Tp* __lhs, const _Up* __rhs, size_t __count) { +__constexpr_memcmp_equal(const _Tp* __lhs, const _Up* __rhs, __element_count __n) { static_assert(__libcpp_is_trivially_equality_comparable<_Tp, _Up>::value, "_Tp and _Up have to be trivially equality comparable"); + auto __count = static_cast(__n); + if (__libcpp_is_constant_evaluated()) { #ifdef _LIBCPP_COMPILER_CLANG_BASED if (sizeof(_Tp) == 1 && is_integral<_Tp>::value && !is_same<_Tp, bool>::value) - return __builtin_memcmp(__lhs, __rhs, __count) == 0; + return __builtin_memcmp(__lhs, __rhs, __count * sizeof(_Tp)) == 0; #endif while (__count != 0) { if (*__lhs != *__rhs) return false; - __count -= sizeof(_Tp); + --__count; ++__lhs; ++__rhs; } return true; } else { - return __builtin_memcmp(__lhs, __rhs, __count) == 0; + return __builtin_memcmp(__lhs, __rhs, __count * sizeof(_Tp)) == 0; } } diff --git a/libcxx/test/libcxx/strings/c.strings/constexpr.cstring.compile.pass.cpp b/libcxx/test/libcxx/strings/c.strings/constexpr.cstring.compile.pass.cpp --- a/libcxx/test/libcxx/strings/c.strings/constexpr.cstring.compile.pass.cpp +++ b/libcxx/test/libcxx/strings/c.strings/constexpr.cstring.compile.pass.cpp @@ -19,12 +19,12 @@ constexpr unsigned char Bananf[] = "Bananf"; static_assert(std::__constexpr_strlen("Banane") == 6, ""); -static_assert(std::__constexpr_memcmp(Banane, Banand, 6) == 1, ""); -static_assert(std::__constexpr_memcmp(Banane, Banane, 6) == 0, ""); -static_assert(std::__constexpr_memcmp(Banane, Bananf, 6) == -1, ""); +static_assert(std::__constexpr_memcmp(Banane, Banand, std::__element_count(6)) == 1, ""); +static_assert(std::__constexpr_memcmp(Banane, Banane, std::__element_count(6)) == 0, ""); +static_assert(std::__constexpr_memcmp(Banane, Bananf, std::__element_count(6)) == -1, ""); -static_assert(!std::__constexpr_memcmp_equal(Banane, Banand, 6), ""); -static_assert(std::__constexpr_memcmp_equal(Banane, Banane, 6), ""); +static_assert(!std::__constexpr_memcmp_equal(Banane, Banand, std::__element_count(6)), ""); +static_assert(std::__constexpr_memcmp_equal(Banane, Banane, std::__element_count(6)), ""); constexpr bool test_constexpr_wmemchr() {