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

Reply via email to