https://github.com/hvdijk created https://github.com/llvm/llvm-project/pull/231223
As commented in the source code, the reason isPrintable had a special exception to consider U+00AD printable regardless of its Unicode classification was for Clang, and because of how it renders in terminals. But this is a function in general support library, part of LLVM, not Clang, and is also used for things that are not sent to terminals, so this is not appropriate for this function. It also introduced a discrepancy where U+00AD was simultaneously considered a printable character by isPrintable, and a formatting character by isFormatting. Move the U+00AD check into Clang instead. >From 75949a692f03cb6b2f0b1377cade0582332fce1f Mon Sep 17 00:00:00 2001 From: Harald van Dijk <[email protected]> Date: Mon, 12 Oct 2026 17:49:03 +0100 Subject: [PATCH] Make isPrintable match Unicode As commented in the source code, the reason isPrintable had a special exception to consider U+00AD printable regardless of its Unicode classification was for Clang, and because of how it renders in terminals. But this is a function in general support library, part of LLVM, not Clang, and is also used for things that are not sent to terminals, so this is not appropriate for this function. It also introduced a discrepancy where U+00AD was simultaneously considered a printable character by isPrintable, and a formatting character by isFormatting. Move the U+00AD check into Clang instead. --- clang/lib/Basic/Diagnostic.cpp | 5 ++++- llvm/lib/Support/Unicode.cpp | 9 ++------- llvm/unittests/Support/YAMLIOTest.cpp | 20 ++++++++++---------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp index 251c8ba6e13db..020a3f5738798 100644 --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/lib/Basic/Diagnostic.cpp @@ -1108,7 +1108,10 @@ static void EscapeStringForDiagnostic(StringRef Str, assert(Begin == CodepointEnd && "we must be further along in the string now"); - if (llvm::sys::unicode::isPrintable(CodepointValue) || + // Clang special cases 0x00AD (SOFT HYPHEN) which is rendered as an actual + // hyphen in most terminals. + if (CodepointValue == 0x00AD || + llvm::sys::unicode::isPrintable(CodepointValue) || (!ForCodepoint && llvm::sys::unicode::isFormatting(CodepointValue))) { OutStream << (ForCodepoint ? "'" : "") << StringRef(reinterpret_cast<const char *>(CodepointBegin), diff --git a/llvm/lib/Support/Unicode.cpp b/llvm/lib/Support/Unicode.cpp index 6c89270d29f76..5294c917a8b37 100644 --- a/llvm/lib/Support/Unicode.cpp +++ b/llvm/lib/Support/Unicode.cpp @@ -25,15 +25,10 @@ extern const UnicodeCharSet::CharRanges GeneratedCombiningCharacterRanges; extern const UnicodeCharSet::CharRanges GeneratedDoubleWidthCharacterRanges; /// Unicode code points of the categories L, M, N, P, S and Zs are considered -/// printable. -/// In addition, U+00AD SOFT HYPHEN is also considered printable, as -/// it's actually displayed on most terminals. \return true if the character is -/// considered printable. +/// printable. \return true if the character is considered printable. bool isPrintable(int UCS) { static const UnicodeCharSet Printables(GeneratedPrintableRanges); - // Clang special cases 0x00AD (SOFT HYPHEN) which is rendered as an actual - // hyphen in most terminals. - return UCS == 0x00AD || Printables.contains(UCS); + return Printables.contains(UCS); } /// Unicode code points of the Cf category are considered diff --git a/llvm/unittests/Support/YAMLIOTest.cpp b/llvm/unittests/Support/YAMLIOTest.cpp index 78e19c5ff4f2c..1ceeec81181cb 100644 --- a/llvm/unittests/Support/YAMLIOTest.cpp +++ b/llvm/unittests/Support/YAMLIOTest.cpp @@ -3024,16 +3024,16 @@ TEST(YAMLIO, TestEscaped) { TestEscaped("parameter 'параметр' is unused", "\"parameter 'параметр' is unused\""); - // String with embedded non-printable multibyte UTF-8 sequence (U+200B - // zero-width space). The thing to test here is that we emit a - // unicode-scalar level escape like \uNNNN (at the YAML level), and don't - // just pass the UTF-8 byte sequence through as with quoted printables. - { - const unsigned char foobar[10] = {'f', 'o', 'o', - 0xE2, 0x80, 0x8B, // UTF-8 of U+200B - 'b', 'a', 'r', - 0x0}; - TestEscaped((char const *)foobar, "\"foo\\u200Bbar\""); + // String with embedded non-printable multibyte UTF-8 sequence (U+00AD soft + // hyphen and U+200B zero-width space). The thing to test here is that we + // emit a unicode-scalar level escape like \uNNNN (at the YAML level), and + // don't just pass the UTF-8 byte sequence through as with quoted printables. + { + const unsigned char foobar[15] = { + 'f', 'o', 'o', 0xC2, 0xAD, // UTF-8 of U+00AD + 'b', 'a', 'r', 0xE2, 0x80, 0x8B, // UTF-8 of U+200B + 'b', 'a', 'z', 0x0}; + TestEscaped((char const *)foobar, "\"foo\\u00ADbar\\u200Bbaz\""); } } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
