Fix code causing spurious Wstringop-overflow warning

See #2989, #3054, and others
This commit is contained in:
Alecto Irene Perez 2023-03-03 12:53:25 -05:00
parent b94e1016fa
commit 46ae7ea83d
No known key found for this signature in database
GPG Key ID: 914D0B2EA4620466
2 changed files with 29 additions and 2 deletions

View File

@ -2204,20 +2204,32 @@ constexpr auto to_ascii(Char c) -> char {
return c <= 0xff ? static_cast<char>(c) : '\0'; return c <= 0xff ? static_cast<char>(c) : '\0';
} }
// Returns the length of a codepoint. Returns 0 for invalid codepoints.
FMT_CONSTEXPR inline auto code_point_length_impl(char c) -> int { FMT_CONSTEXPR inline auto code_point_length_impl(char c) -> int {
return "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4" return "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4"
[static_cast<unsigned char>(c) >> 3]; [static_cast<unsigned char>(c) >> 3];
} }
// Returns the length of a codepoint. Returns 1 for invalid codepoints.
// This is equivalent to
//
// int len = code_point_length_impl(c);
// return len + !len;
//
// This is useful because it allows the compiler to check that the
// length is within the range [1, 4]
FMT_CONSTEXPR inline auto code_point_length_impl_2(char c) -> int {
return ((0x3a55000000000000ull >> (2 * (static_cast<unsigned char>(c) >> 3))) & 0x3) + 1;
}
template <typename Char> template <typename Char>
FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int { FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int {
if (const_check(sizeof(Char) != 1)) return 1; if (const_check(sizeof(Char) != 1)) return 1;
int len = code_point_length_impl(static_cast<char>(*begin)); int len = code_point_length_impl_2(static_cast<char>(*begin));
// Compute the pointer to the next character early so that the next // Compute the pointer to the next character early so that the next
// iteration can start working on the next character. Neither Clang // iteration can start working on the next character. Neither Clang
// nor GCC figure out this reordering on their own. // nor GCC figure out this reordering on their own.
return len + !len; return len;
} }
// Return the result via the out param to workaround gcc bug 77539. // Return the result via the out param to workaround gcc bug 77539.

View File

@ -898,3 +898,18 @@ TEST(core_test, has_const_formatter) {
TEST(core_test, format_nonconst) { TEST(core_test, format_nonconst) {
EXPECT_EQ(fmt::format("{}", nonconst_formattable()), "test"); EXPECT_EQ(fmt::format("{}", nonconst_formattable()), "test");
} }
TEST(core_test, code_point_length_impl) {
// code_point_length_impl_2 is a bit-shifted version of code_point_length_impl
// that returns 1 for invalid codepoints, so that length is always in [1..4]
int min = CHAR_MIN;
int max = CHAR_MAX;
for(int ch = min; ch <= max; ch++) {
char c = static_cast<char>(ch);
int len1 = fmt::detail::code_point_length_impl(c);
int len2 = fmt::detail::code_point_length_impl_2(c);
ASSERT_EQ(len1 + !len1, len2);
}
}