[libc-commits] [libc] [libc] Implement towupper and towlower entrypoints (PR #198659)
Muhammad Bassiouni via libc-commits
libc-commits at lists.llvm.org
Thu May 28 03:50:58 PDT 2026
https://github.com/bassiounix updated https://github.com/llvm/llvm-project/pull/198659
>From 9a73382ea10e8ec4bc01b2cb6db0116566a558d9 Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Tue, 19 May 2026 21:53:06 +0000
Subject: [PATCH 1/6] [libc] Implement towupper and towlower entrypoints
Following up on #187670 to add public entrypoints for the wctype
conversion functions.
Assisted-by: Automated tooling, human reviewed.
---
libc/config/linux/x86_64/entrypoints.txt | 2 +
libc/include/wctype.yaml | 12 ++++
libc/src/wctype/CMakeLists.txt | 22 ++++++++
libc/src/wctype/towlower.cpp | 28 ++++++++++
libc/src/wctype/towlower.h | 26 +++++++++
libc/src/wctype/towupper.cpp | 28 ++++++++++
libc/src/wctype/towupper.h | 26 +++++++++
libc/test/src/wctype/CMakeLists.txt | 24 +++++++-
libc/test/src/wctype/towlower_test.cpp | 70 ++++++++++++++++++++++++
libc/test/src/wctype/towupper_test.cpp | 70 ++++++++++++++++++++++++
10 files changed, 307 insertions(+), 1 deletion(-)
create mode 100644 libc/src/wctype/towlower.cpp
create mode 100644 libc/src/wctype/towlower.h
create mode 100644 libc/src/wctype/towupper.cpp
create mode 100644 libc/src/wctype/towupper.h
create mode 100644 libc/test/src/wctype/towlower_test.cpp
create mode 100644 libc/test/src/wctype/towupper_test.cpp
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index eda0426ff2578..adfe5b6374907 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -479,6 +479,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wctype.iswprint
libc.src.wctype.iswctype
libc.src.wctype.wctype
+ libc.src.wctype.towlower
+ libc.src.wctype.towupper
# sys/uio.h entrypoints
libc.src.sys.uio.writev
diff --git a/libc/include/wctype.yaml b/libc/include/wctype.yaml
index a5163ecc2d3f2..ac350c1f9956a 100644
--- a/libc/include/wctype.yaml
+++ b/libc/include/wctype.yaml
@@ -88,3 +88,15 @@ functions:
return_type: wctype_t
arguments:
- type: const char*
+ - name: towlower
+ standards:
+ - stdc
+ return_type: wint_t
+ arguments:
+ - type: wint_t
+ - name: towupper
+ standards:
+ - stdc
+ return_type: wint_t
+ arguments:
+ - type: wint_t
diff --git a/libc/src/wctype/CMakeLists.txt b/libc/src/wctype/CMakeLists.txt
index 84c72c7e6b7ae..234676e20739e 100644
--- a/libc/src/wctype/CMakeLists.txt
+++ b/libc/src/wctype/CMakeLists.txt
@@ -153,3 +153,25 @@ add_entrypoint_object(
libc.src.__support.wctype_impl
libc.hdr.types.wctype_t
)
+
+add_entrypoint_object(
+ towlower
+ SRCS
+ towlower.cpp
+ HDRS
+ towlower.h
+ DEPENDS
+ libc.src.__support.wctype_utils
+ libc.hdr.types.wint_t
+)
+
+add_entrypoint_object(
+ towupper
+ SRCS
+ towupper.cpp
+ HDRS
+ towupper.h
+ DEPENDS
+ libc.src.__support.wctype_utils
+ libc.hdr.types.wint_t
+)
diff --git a/libc/src/wctype/towlower.cpp b/libc/src/wctype/towlower.cpp
new file mode 100644
index 0000000000000..8c0667bfee426
--- /dev/null
+++ b/libc/src/wctype/towlower.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of towlower.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/wctype/towlower.h"
+#include "hdr/types/wint_t.h"
+#include "src/__support/common.h"
+#include "src/__support/wctype_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(wint_t, towlower, (wint_t c)) {
+ if (c == static_cast<wint_t>(static_cast<wchar_t>(c))) {
+ return static_cast<wint_t>(internal::tolower(static_cast<wchar_t>(c)));
+ }
+ return c;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wctype/towlower.h b/libc/src/wctype/towlower.h
new file mode 100644
index 0000000000000..01ed7cf652680
--- /dev/null
+++ b/libc/src/wctype/towlower.h
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for towlower.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_WCTYPE_TOWLOWER_H
+#define LLVM_LIBC_SRC_WCTYPE_TOWLOWER_H
+
+#include "hdr/types/wint_t.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+wint_t towlower(wint_t c);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCTYPE_TOWLOWER_H
diff --git a/libc/src/wctype/towupper.cpp b/libc/src/wctype/towupper.cpp
new file mode 100644
index 0000000000000..9d3ebc747f81c
--- /dev/null
+++ b/libc/src/wctype/towupper.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of towupper.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/wctype/towupper.h"
+#include "hdr/types/wint_t.h"
+#include "src/__support/common.h"
+#include "src/__support/wctype_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(wint_t, towupper, (wint_t c)) {
+ if (c == static_cast<wint_t>(static_cast<wchar_t>(c))) {
+ return static_cast<wint_t>(internal::toupper(static_cast<wchar_t>(c)));
+ }
+ return c;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wctype/towupper.h b/libc/src/wctype/towupper.h
new file mode 100644
index 0000000000000..9a146c081c0cf
--- /dev/null
+++ b/libc/src/wctype/towupper.h
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for towupper.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_WCTYPE_TOWUPPER_H
+#define LLVM_LIBC_SRC_WCTYPE_TOWUPPER_H
+
+#include "hdr/types/wint_t.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+wint_t towupper(wint_t c);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCTYPE_TOWUPPER_H
diff --git a/libc/test/src/wctype/CMakeLists.txt b/libc/test/src/wctype/CMakeLists.txt
index f7cdcc77482e4..79b5993e00180 100644
--- a/libc/test/src/wctype/CMakeLists.txt
+++ b/libc/test/src/wctype/CMakeLists.txt
@@ -42,7 +42,7 @@ add_libc_test(
libc.src.wctype.iswgraph
)
-add_libc_test(
+add_libc_test(
iswlower_test
SUITE
libc_wctype_unittests
@@ -142,3 +142,25 @@ add_libc_test(
DEPENDS
libc.src.wctype.wctype
)
+
+add_libc_test(
+ towlower_test
+ SUITE
+ libc_wctype_unittests
+ SRCS
+ towlower_test.cpp
+ DEPENDS
+ libc.src.wctype.towlower
+ libc.src.__support.wctype_utils
+)
+
+add_libc_test(
+ towupper_test
+ SUITE
+ libc_wctype_unittests
+ SRCS
+ towupper_test.cpp
+ DEPENDS
+ libc.src.wctype.towupper
+ libc.src.__support.wctype_utils
+)
diff --git a/libc/test/src/wctype/towlower_test.cpp b/libc/test/src/wctype/towlower_test.cpp
new file mode 100644
index 0000000000000..68448e17aac26
--- /dev/null
+++ b/libc/test/src/wctype/towlower_test.cpp
@@ -0,0 +1,70 @@
+//===-- Unittests for towlower --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "hdr/wchar_macros.h" // for WEOF
+#include "src/__support/wctype_utils.h"
+#include "src/wctype/towlower.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcTowLower, SimpleTest) {
+ // ASCII Conversions
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'A'), static_cast<wint_t>(L'a'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Z'), static_cast<wint_t>(L'z'));
+
+ // ASCII Unchanged
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'a'), static_cast<wint_t>(L'a'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'z'), static_cast<wint_t>(L'z'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'1'), static_cast<wint_t>(L'1'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'\0'), static_cast<wint_t>(L'\0'));
+
+ // WEOF Test
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(WEOF), static_cast<wint_t>(WEOF));
+
+ // Boundary / Out-of-domain Tests (should return unchanged)
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(0xFFFF), static_cast<wint_t>(0xFFFF));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(0x110000), static_cast<wint_t>(0x110000));
+
+ // Non-ASCII tests
+#if LIBC_CONF_WCTYPE_MODE == 1 // UTF8 Mode
+ // Greek conversions
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Α'), static_cast<wint_t>(L'α')); // alpha
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Ω'), static_cast<wint_t>(L'ω')); // omega
+
+ // Cyrillic conversions
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'А'), static_cast<wint_t>(L'а')); // A
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Я'), static_cast<wint_t>(L'я')); // Ya
+
+ // Accented Latin
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'É'), static_cast<wint_t>(L'é'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Ü'), static_cast<wint_t>(L'ü'));
+
+#if WCHAR_MAX > 0xFFFF
+ // Deseret (Unicode Plane 1) conversions
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'\U00010400'),
+ static_cast<wint_t>(L'\U00010428'));
+#endif
+
+ // Already lowercase / unchanged
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'α'), static_cast<wint_t>(L'α'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'а'), static_cast<wint_t>(L'а'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'é'), static_cast<wint_t>(L'é'));
+#else // ASCII Mode
+ // Non-ASCII should remain unchanged
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Α'), static_cast<wint_t>(L'Α'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Ω'), static_cast<wint_t>(L'Ω'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'А'), static_cast<wint_t>(L'А'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Я'), static_cast<wint_t>(L'Я'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'É'), static_cast<wint_t>(L'É'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Ü'), static_cast<wint_t>(L'Ü'));
+
+#if WCHAR_MAX > 0xFFFF
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'\U00010400'),
+ static_cast<wint_t>(L'\U00010400'));
+#endif
+#endif
+}
diff --git a/libc/test/src/wctype/towupper_test.cpp b/libc/test/src/wctype/towupper_test.cpp
new file mode 100644
index 0000000000000..e85969a6fa742
--- /dev/null
+++ b/libc/test/src/wctype/towupper_test.cpp
@@ -0,0 +1,70 @@
+//===-- Unittests for towupper --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "hdr/wchar_macros.h" // for WEOF
+#include "src/__support/wctype_utils.h"
+#include "src/wctype/towupper.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcTowUpper, SimpleTest) {
+ // ASCII Conversions
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'a'), static_cast<wint_t>(L'A'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'z'), static_cast<wint_t>(L'Z'));
+
+ // ASCII Unchanged
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'A'), static_cast<wint_t>(L'A'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'Z'), static_cast<wint_t>(L'Z'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'1'), static_cast<wint_t>(L'1'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'\0'), static_cast<wint_t>(L'\0'));
+
+ // WEOF Test
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(WEOF), static_cast<wint_t>(WEOF));
+
+ // Boundary / Out-of-domain Tests (should return unchanged)
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(0xFFFF), static_cast<wint_t>(0xFFFF));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(0x110000), static_cast<wint_t>(0x110000));
+
+ // Non-ASCII tests
+#if LIBC_CONF_WCTYPE_MODE == 1 // UTF8 Mode
+ // Greek conversions
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'α'), static_cast<wint_t>(L'Α')); // alpha
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'ω'), static_cast<wint_t>(L'Ω')); // omega
+
+ // Cyrillic conversions
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'а'), static_cast<wint_t>(L'А')); // A
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'я'), static_cast<wint_t>(L'Я')); // Ya
+
+ // Accented Latin
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'é'), static_cast<wint_t>(L'É'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'ü'), static_cast<wint_t>(L'Ü'));
+
+#if WCHAR_MAX > 0xFFFF
+ // Deseret (Unicode Plane 1) conversions
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'\U00010428'),
+ static_cast<wint_t>(L'\U00010400'));
+#endif
+
+ // Already uppercase / unchanged
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'Α'), static_cast<wint_t>(L'Α'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'А'), static_cast<wint_t>(L'А'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'É'), static_cast<wint_t>(L'É'));
+#else // ASCII Mode
+ // Non-ASCII should remain unchanged
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'α'), static_cast<wint_t>(L'α'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'ω'), static_cast<wint_t>(L'ω'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'а'), static_cast<wint_t>(L'а'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'я'), static_cast<wint_t>(L'я'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'é'), static_cast<wint_t>(L'é'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'ü'), static_cast<wint_t>(L'ü'));
+
+#if WCHAR_MAX > 0xFFFF
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'\U00010428'),
+ static_cast<wint_t>(L'\U00010428'));
+#endif
+#endif
+}
>From 3df6d439acd13c39184422712dac266ba3f63162 Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Tue, 19 May 2026 22:01:50 +0000
Subject: [PATCH 2/6] also add to aarch64 and risc-v
---
libc/config/linux/aarch64/entrypoints.txt | 2 ++
libc/config/linux/riscv/entrypoints.txt | 2 ++
2 files changed, 4 insertions(+)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 35f91c18f4bfb..9eea8d8d2e2c0 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -415,6 +415,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wctype.iswprint
libc.src.wctype.iswctype
libc.src.wctype.wctype
+ libc.src.wctype.towlower
+ libc.src.wctype.towupper
# sys/uio.h entrypoints
libc.src.sys.uio.writev
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index da4dd8406fd81..41e321774a82e 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -419,6 +419,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wctype.iswprint
libc.src.wctype.iswctype
libc.src.wctype.wctype
+ libc.src.wctype.towlower
+ libc.src.wctype.towupper
# sys/uio.h entrypoints
libc.src.sys.uio.writev
>From 6e709a5b90481f2d537b3b6293aadd806e9670a1 Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Wed, 20 May 2026 18:07:51 +0000
Subject: [PATCH 3/6] cleanup deps and tests
---
libc/src/wctype/CMakeLists.txt | 6 ++++--
libc/src/wctype/towlower.cpp | 3 +--
libc/src/wctype/towupper.cpp | 3 +--
libc/test/src/wctype/towlower_test.cpp | 13 -------------
libc/test/src/wctype/towupper_test.cpp | 13 -------------
5 files changed, 6 insertions(+), 32 deletions(-)
diff --git a/libc/src/wctype/CMakeLists.txt b/libc/src/wctype/CMakeLists.txt
index 234676e20739e..83fc0312296da 100644
--- a/libc/src/wctype/CMakeLists.txt
+++ b/libc/src/wctype/CMakeLists.txt
@@ -161,8 +161,9 @@ add_entrypoint_object(
HDRS
towlower.h
DEPENDS
- libc.src.__support.wctype_utils
libc.hdr.types.wint_t
+ libc.src.__support.common
+ libc.src.__support.wctype_utils
)
add_entrypoint_object(
@@ -172,6 +173,7 @@ add_entrypoint_object(
HDRS
towupper.h
DEPENDS
- libc.src.__support.wctype_utils
libc.hdr.types.wint_t
+ libc.src.__support.common
+ libc.src.__support.wctype_utils
)
diff --git a/libc/src/wctype/towlower.cpp b/libc/src/wctype/towlower.cpp
index 8c0667bfee426..8f1028e5d8d32 100644
--- a/libc/src/wctype/towlower.cpp
+++ b/libc/src/wctype/towlower.cpp
@@ -19,9 +19,8 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(wint_t, towlower, (wint_t c)) {
- if (c == static_cast<wint_t>(static_cast<wchar_t>(c))) {
+ if (c == static_cast<wint_t>(static_cast<wchar_t>(c)))
return static_cast<wint_t>(internal::tolower(static_cast<wchar_t>(c)));
- }
return c;
}
diff --git a/libc/src/wctype/towupper.cpp b/libc/src/wctype/towupper.cpp
index 9d3ebc747f81c..9fdea4dcde4bf 100644
--- a/libc/src/wctype/towupper.cpp
+++ b/libc/src/wctype/towupper.cpp
@@ -19,9 +19,8 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(wint_t, towupper, (wint_t c)) {
- if (c == static_cast<wint_t>(static_cast<wchar_t>(c))) {
+ if (c == static_cast<wint_t>(static_cast<wchar_t>(c)))
return static_cast<wint_t>(internal::toupper(static_cast<wchar_t>(c)));
- }
return c;
}
diff --git a/libc/test/src/wctype/towlower_test.cpp b/libc/test/src/wctype/towlower_test.cpp
index 68448e17aac26..cf2dd9f53ef57 100644
--- a/libc/test/src/wctype/towlower_test.cpp
+++ b/libc/test/src/wctype/towlower_test.cpp
@@ -53,18 +53,5 @@ TEST(LlvmLibcTowLower, SimpleTest) {
EXPECT_EQ(LIBC_NAMESPACE::towlower(L'α'), static_cast<wint_t>(L'α'));
EXPECT_EQ(LIBC_NAMESPACE::towlower(L'а'), static_cast<wint_t>(L'а'));
EXPECT_EQ(LIBC_NAMESPACE::towlower(L'é'), static_cast<wint_t>(L'é'));
-#else // ASCII Mode
- // Non-ASCII should remain unchanged
- EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Α'), static_cast<wint_t>(L'Α'));
- EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Ω'), static_cast<wint_t>(L'Ω'));
- EXPECT_EQ(LIBC_NAMESPACE::towlower(L'А'), static_cast<wint_t>(L'А'));
- EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Я'), static_cast<wint_t>(L'Я'));
- EXPECT_EQ(LIBC_NAMESPACE::towlower(L'É'), static_cast<wint_t>(L'É'));
- EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Ü'), static_cast<wint_t>(L'Ü'));
-
-#if WCHAR_MAX > 0xFFFF
- EXPECT_EQ(LIBC_NAMESPACE::towlower(L'\U00010400'),
- static_cast<wint_t>(L'\U00010400'));
-#endif
#endif
}
diff --git a/libc/test/src/wctype/towupper_test.cpp b/libc/test/src/wctype/towupper_test.cpp
index e85969a6fa742..a26e08cd5b92f 100644
--- a/libc/test/src/wctype/towupper_test.cpp
+++ b/libc/test/src/wctype/towupper_test.cpp
@@ -53,18 +53,5 @@ TEST(LlvmLibcTowUpper, SimpleTest) {
EXPECT_EQ(LIBC_NAMESPACE::towupper(L'Α'), static_cast<wint_t>(L'Α'));
EXPECT_EQ(LIBC_NAMESPACE::towupper(L'А'), static_cast<wint_t>(L'А'));
EXPECT_EQ(LIBC_NAMESPACE::towupper(L'É'), static_cast<wint_t>(L'É'));
-#else // ASCII Mode
- // Non-ASCII should remain unchanged
- EXPECT_EQ(LIBC_NAMESPACE::towupper(L'α'), static_cast<wint_t>(L'α'));
- EXPECT_EQ(LIBC_NAMESPACE::towupper(L'ω'), static_cast<wint_t>(L'ω'));
- EXPECT_EQ(LIBC_NAMESPACE::towupper(L'а'), static_cast<wint_t>(L'а'));
- EXPECT_EQ(LIBC_NAMESPACE::towupper(L'я'), static_cast<wint_t>(L'я'));
- EXPECT_EQ(LIBC_NAMESPACE::towupper(L'é'), static_cast<wint_t>(L'é'));
- EXPECT_EQ(LIBC_NAMESPACE::towupper(L'ü'), static_cast<wint_t>(L'ü'));
-
-#if WCHAR_MAX > 0xFFFF
- EXPECT_EQ(LIBC_NAMESPACE::towupper(L'\U00010428'),
- static_cast<wint_t>(L'\U00010428'));
-#endif
#endif
}
>From 04678e108fb89fad7cec99d4186ac0062baf9255 Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Wed, 20 May 2026 22:37:56 +0000
Subject: [PATCH 4/6] fix test header comments, deps, yaml standard.
---
libc/include/wctype.yaml | 2 ++
libc/test/src/wctype/CMakeLists.txt | 2 ++
libc/test/src/wctype/towlower_test.cpp | 7 ++++++-
libc/test/src/wctype/towupper_test.cpp | 7 ++++++-
4 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/libc/include/wctype.yaml b/libc/include/wctype.yaml
index ac350c1f9956a..816c7716db97f 100644
--- a/libc/include/wctype.yaml
+++ b/libc/include/wctype.yaml
@@ -1,4 +1,6 @@
header: wctype.h
+standards:
+ - stdc
types:
- type_name: wint_t
- type_name: wctype_t
diff --git a/libc/test/src/wctype/CMakeLists.txt b/libc/test/src/wctype/CMakeLists.txt
index 79b5993e00180..229e63ec966c4 100644
--- a/libc/test/src/wctype/CMakeLists.txt
+++ b/libc/test/src/wctype/CMakeLists.txt
@@ -150,6 +150,7 @@ add_libc_test(
SRCS
towlower_test.cpp
DEPENDS
+ libc.hdr.wchar_macros
libc.src.wctype.towlower
libc.src.__support.wctype_utils
)
@@ -161,6 +162,7 @@ add_libc_test(
SRCS
towupper_test.cpp
DEPENDS
+ libc.hdr.wchar_macros
libc.src.wctype.towupper
libc.src.__support.wctype_utils
)
diff --git a/libc/test/src/wctype/towlower_test.cpp b/libc/test/src/wctype/towlower_test.cpp
index cf2dd9f53ef57..1d50be28be862 100644
--- a/libc/test/src/wctype/towlower_test.cpp
+++ b/libc/test/src/wctype/towlower_test.cpp
@@ -1,10 +1,15 @@
-//===-- Unittests for towlower --------------------------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for towlower.
+///
+//===----------------------------------------------------------------------===//
#include "hdr/wchar_macros.h" // for WEOF
#include "src/__support/wctype_utils.h"
diff --git a/libc/test/src/wctype/towupper_test.cpp b/libc/test/src/wctype/towupper_test.cpp
index a26e08cd5b92f..346df7af2f8da 100644
--- a/libc/test/src/wctype/towupper_test.cpp
+++ b/libc/test/src/wctype/towupper_test.cpp
@@ -1,10 +1,15 @@
-//===-- Unittests for towupper --------------------------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for towupper.
+///
+//===----------------------------------------------------------------------===//
#include "hdr/wchar_macros.h" // for WEOF
#include "src/__support/wctype_utils.h"
>From 1ea85a0db6350f14ad730f1da924ee9c1903b8f3 Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Wed, 27 May 2026 23:58:12 +0000
Subject: [PATCH 5/6] fix conversion utils not being properly used.
I also had to fix the usage of constexpr.
---
libc/src/__support/CMakeLists.txt | 1 +
libc/src/__support/wctype/CMakeLists.txt | 18 ++++++++
libc/src/__support/wctype/perfect_hash_map.h | 4 --
.../wctype/wctype_conversion_utils.cpp | 46 +++++++++++++++++++
.../wctype/wctype_conversion_utils.h | 34 ++++++++++++++
libc/src/__support/wctype_utils.h | 7 ++-
libc/test/src/__support/wctype/CMakeLists.txt | 1 +
libc/test/src/__support/wctype_utils_test.cpp | 5 ++
libc/test/src/wctype/towlower_test.cpp | 35 +++++++++++---
libc/test/src/wctype/towupper_test.cpp | 35 +++++++++++---
10 files changed, 166 insertions(+), 20 deletions(-)
create mode 100644 libc/src/__support/wctype/wctype_conversion_utils.cpp
create mode 100644 libc/src/__support/wctype/wctype_conversion_utils.h
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index ada489046ef9e..9eba115330fb9 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -165,6 +165,7 @@ list(APPEND wctype_utils_deps
if ("${LIBC_CONF_WCTYPE_MODE}" STREQUAL "LIBC_WCTYPE_MODE_UTF8")
list(APPEND wctype_utils_deps
libc.src.__support.wctype.wctype_classification_utils
+ libc.src.__support.wctype.wctype_conversion_utils
)
endif()
diff --git a/libc/src/__support/wctype/CMakeLists.txt b/libc/src/__support/wctype/CMakeLists.txt
index 338f9ba397ab2..64708fe6a40da 100644
--- a/libc/src/__support/wctype/CMakeLists.txt
+++ b/libc/src/__support/wctype/CMakeLists.txt
@@ -49,3 +49,21 @@ add_object_library(
libc.src.__support.CPP.limits
libc.src.__support.libc_assert
)
+
+add_object_library(
+ wctype_conversion_utils
+ HDRS
+ wctype_conversion_utils.h
+ SRCS
+ wctype_conversion_utils.cpp
+ COMPILE_OPTIONS
+ "-DLIBC_ENABLE_CONSTEXPR=1"
+ DEPENDS
+ libc.hdr.types.wchar_t
+ libc.hdr.types.wint_t
+ libc.src.__support.macros.attributes
+ libc.src.__support.macros.config
+ .lower_to_upper
+ .upper_to_lower
+)
+
diff --git a/libc/src/__support/wctype/perfect_hash_map.h b/libc/src/__support/wctype/perfect_hash_map.h
index 5b3823c2a8309..a5562d589bff7 100644
--- a/libc/src/__support/wctype/perfect_hash_map.h
+++ b/libc/src/__support/wctype/perfect_hash_map.h
@@ -9,8 +9,6 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_WCTYPE_PERFECT_HASH_MAP_H
#define LLVM_LIBC_SRC___SUPPORT_WCTYPE_PERFECT_HASH_MAP_H
-#define LIBC_ENABLE_CONSTEXPR 1
-
#include "hdr/types/size_t.h"
#include "hdr/types/wint_t.h"
#include "src/__support/CPP/array.h"
@@ -29,8 +27,6 @@
#include "src/__support/OSUtil/io.h"
#endif
-#undef LIBC_ENABLE_CONSTEXPR
-
namespace LIBC_NAMESPACE_DECL {
namespace wctype_internal {
diff --git a/libc/src/__support/wctype/wctype_conversion_utils.cpp b/libc/src/__support/wctype/wctype_conversion_utils.cpp
new file mode 100644
index 0000000000000..13893a82d816c
--- /dev/null
+++ b/libc/src/__support/wctype/wctype_conversion_utils.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of wctype conversion helpers.
+///
+//===----------------------------------------------------------------------===//
+
+#include "wctype_conversion_utils.h"
+#include "lower_to_upper.h"
+#include "upper_to_lower.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace wctype_internal {
+
+wint_t tolower(wchar_t wch) {
+ if (auto mapped = UPPER_TO_LOWER_MAP.find(wch)) {
+ return mapped.value();
+ }
+#if WINT_MAX > 0xFFFF
+ if (auto mapped = UPPER_TO_LOWER_MAP_32.find(wch)) {
+ return mapped.value();
+ }
+#endif
+ return wch;
+}
+
+wint_t toupper(wchar_t wch) {
+ if (auto mapped = LOWER_TO_UPPER_MAP.find(wch)) {
+ return mapped.value();
+ }
+#if WINT_MAX > 0xFFFF
+ if (auto mapped = LOWER_TO_UPPER_MAP_32.find(wch)) {
+ return mapped.value();
+ }
+#endif
+ return wch;
+}
+
+} // namespace wctype_internal
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/wctype/wctype_conversion_utils.h b/libc/src/__support/wctype/wctype_conversion_utils.h
new file mode 100644
index 0000000000000..0b799250d675e
--- /dev/null
+++ b/libc/src/__support/wctype/wctype_conversion_utils.h
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Interface for wctype conversion functions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CONVERSION_UTILS_H
+#define LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CONVERSION_UTILS_H
+
+#include "hdr/types/wchar_t.h"
+#include "hdr/types/wint_t.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace wctype_internal {
+
+// Helper functions for non-ASCII case conversions.
+// These are implemented in wctype_conversion_utils.cpp using the generated
+// maps.
+wint_t tolower(wchar_t wch);
+wint_t toupper(wchar_t wch);
+
+} // namespace wctype_internal
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CONVERSION_UTILS_H
diff --git a/libc/src/__support/wctype_utils.h b/libc/src/__support/wctype_utils.h
index 3008e749f0bd3..4d0ecd2c1c0dc 100644
--- a/libc/src/__support/wctype_utils.h
+++ b/libc/src/__support/wctype_utils.h
@@ -22,6 +22,7 @@
#if LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_UTF8
#include "src/__support/wctype/wctype_classification_utils.h"
+#include "src/__support/wctype/wctype_conversion_utils.h"
#endif
namespace LIBC_NAMESPACE_DECL {
@@ -585,8 +586,7 @@ LIBC_INLINE constexpr wchar_t tolower(wchar_t wch) {
if (static_cast<uint32_t>(wch) < 128) {
return ascii::tolower(wch);
}
- // TODO: Add UTF8 implementation.
- return wch;
+ return static_cast<wchar_t>(wctype_internal::tolower(wch));
#endif
}
@@ -597,8 +597,7 @@ LIBC_INLINE constexpr wchar_t toupper(wchar_t wch) {
if (static_cast<uint32_t>(wch) < 128) {
return ascii::toupper(wch);
}
- // TODO: Add UTF8 implementation.
- return wch;
+ return static_cast<wchar_t>(wctype_internal::toupper(wch));
#endif
}
diff --git a/libc/test/src/__support/wctype/CMakeLists.txt b/libc/test/src/__support/wctype/CMakeLists.txt
index 17c98dc3d2770..a79909f5eb6c7 100644
--- a/libc/test/src/__support/wctype/CMakeLists.txt
+++ b/libc/test/src/__support/wctype/CMakeLists.txt
@@ -9,6 +9,7 @@ add_libc_test(
COMPILE_OPTIONS
$<$<CXX_COMPILER_ID:Clang>:-Xclang -fconstexpr-steps=10000000>
$<$<CXX_COMPILER_ID:GNU>:-fconstexpr-ops-limit=10000000>
+ -DLIBC_ENABLE_CONSTEXPR=1
DEPENDS
libc.src.__support.wctype.lower_to_upper
libc.src.__support.wctype.upper_to_lower
diff --git a/libc/test/src/__support/wctype_utils_test.cpp b/libc/test/src/__support/wctype_utils_test.cpp
index 88cd56cc0cae5..b2140ab72a3be 100644
--- a/libc/test/src/__support/wctype_utils_test.cpp
+++ b/libc/test/src/__support/wctype_utils_test.cpp
@@ -9,6 +9,7 @@
#include "hdr/types/wctype_t.h"
#include "src/__support/macros/config.h"
#include "src/__support/wctype/wctype_classification_utils.h"
+#include "src/__support/wctype/wctype_conversion_utils.h"
#include "test/UnitTest/Test.h"
namespace {
@@ -32,6 +33,10 @@ namespace utf8_mode {
namespace LIBC_NAMESPACE_DECL {
using ::LIBC_NAMESPACE::lookup_properties;
using ::LIBC_NAMESPACE::PropertyFlag;
+namespace wctype_internal {
+using ::LIBC_NAMESPACE::wctype_internal::tolower;
+using ::LIBC_NAMESPACE::wctype_internal::toupper;
+} // namespace wctype_internal
namespace cpp = ::LIBC_NAMESPACE::cpp;
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/wctype/towlower_test.cpp b/libc/test/src/wctype/towlower_test.cpp
index 1d50be28be862..cc5613668e947 100644
--- a/libc/test/src/wctype/towlower_test.cpp
+++ b/libc/test/src/wctype/towlower_test.cpp
@@ -32,10 +32,19 @@ TEST(LlvmLibcTowLower, SimpleTest) {
// Boundary / Out-of-domain Tests (should return unchanged)
EXPECT_EQ(LIBC_NAMESPACE::towlower(0xFFFF), static_cast<wint_t>(0xFFFF));
+#if WCHAR_MAX > 0xFFFF
EXPECT_EQ(LIBC_NAMESPACE::towlower(0x110000), static_cast<wint_t>(0x110000));
+#endif
- // Non-ASCII tests
-#if LIBC_CONF_WCTYPE_MODE == 1 // UTF8 Mode
+ // Non-ASCII Lowercase (Already lowercase: should remain unchanged
+ // unconditionally in BOTH modes)
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'α'), static_cast<wint_t>(L'α'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'а'), static_cast<wint_t>(L'а'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'é'), static_cast<wint_t>(L'é'));
+}
+
+#if LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_UTF8
+TEST(LlvmLibcTowLower, NonAsciiTestUtf8) {
// Greek conversions
EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Α'), static_cast<wint_t>(L'α')); // alpha
EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Ω'), static_cast<wint_t>(L'ω')); // omega
@@ -53,10 +62,24 @@ TEST(LlvmLibcTowLower, SimpleTest) {
EXPECT_EQ(LIBC_NAMESPACE::towlower(L'\U00010400'),
static_cast<wint_t>(L'\U00010428'));
#endif
+}
+#endif
- // Already lowercase / unchanged
- EXPECT_EQ(LIBC_NAMESPACE::towlower(L'α'), static_cast<wint_t>(L'α'));
- EXPECT_EQ(LIBC_NAMESPACE::towlower(L'а'), static_cast<wint_t>(L'а'));
- EXPECT_EQ(LIBC_NAMESPACE::towlower(L'é'), static_cast<wint_t>(L'é'));
+#if LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_ASCII
+TEST(LlvmLibcTowLower, NonAsciiTestAscii) {
+ // Non-ASCII uppercase characters must return unchanged under ASCII-only mode
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Α'), static_cast<wint_t>(L'Α'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Ω'), static_cast<wint_t>(L'Ω'));
+
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'А'), static_cast<wint_t>(L'А'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Я'), static_cast<wint_t>(L'Я'));
+
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'É'), static_cast<wint_t>(L'É'));
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'Ü'), static_cast<wint_t>(L'Ü'));
+
+#if WCHAR_MAX > 0xFFFF
+ EXPECT_EQ(LIBC_NAMESPACE::towlower(L'\U00010400'),
+ static_cast<wint_t>(L'\U00010400'));
#endif
}
+#endif
diff --git a/libc/test/src/wctype/towupper_test.cpp b/libc/test/src/wctype/towupper_test.cpp
index 346df7af2f8da..a1cf0bd25d760 100644
--- a/libc/test/src/wctype/towupper_test.cpp
+++ b/libc/test/src/wctype/towupper_test.cpp
@@ -32,10 +32,19 @@ TEST(LlvmLibcTowUpper, SimpleTest) {
// Boundary / Out-of-domain Tests (should return unchanged)
EXPECT_EQ(LIBC_NAMESPACE::towupper(0xFFFF), static_cast<wint_t>(0xFFFF));
+#if WCHAR_MAX > 0xFFFF
EXPECT_EQ(LIBC_NAMESPACE::towupper(0x110000), static_cast<wint_t>(0x110000));
+#endif
- // Non-ASCII tests
-#if LIBC_CONF_WCTYPE_MODE == 1 // UTF8 Mode
+ // Non-ASCII Uppercase (Already uppercase: should remain unchanged
+ // unconditionally in BOTH modes)
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'Α'), static_cast<wint_t>(L'Α'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'А'), static_cast<wint_t>(L'А'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'É'), static_cast<wint_t>(L'É'));
+}
+
+#if LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_UTF8
+TEST(LlvmLibcTowUpper, NonAsciiTestUtf8) {
// Greek conversions
EXPECT_EQ(LIBC_NAMESPACE::towupper(L'α'), static_cast<wint_t>(L'Α')); // alpha
EXPECT_EQ(LIBC_NAMESPACE::towupper(L'ω'), static_cast<wint_t>(L'Ω')); // omega
@@ -53,10 +62,24 @@ TEST(LlvmLibcTowUpper, SimpleTest) {
EXPECT_EQ(LIBC_NAMESPACE::towupper(L'\U00010428'),
static_cast<wint_t>(L'\U00010400'));
#endif
+}
+#endif
- // Already uppercase / unchanged
- EXPECT_EQ(LIBC_NAMESPACE::towupper(L'Α'), static_cast<wint_t>(L'Α'));
- EXPECT_EQ(LIBC_NAMESPACE::towupper(L'А'), static_cast<wint_t>(L'А'));
- EXPECT_EQ(LIBC_NAMESPACE::towupper(L'É'), static_cast<wint_t>(L'É'));
+#if LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_ASCII
+TEST(LlvmLibcTowUpper, NonAsciiTestAscii) {
+ // Non-ASCII lowercase characters must return unchanged under ASCII-only mode
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'α'), static_cast<wint_t>(L'α'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'ω'), static_cast<wint_t>(L'ω'));
+
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'а'), static_cast<wint_t>(L'а'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'я'), static_cast<wint_t>(L'я'));
+
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'é'), static_cast<wint_t>(L'é'));
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'ü'), static_cast<wint_t>(L'ü'));
+
+#if WCHAR_MAX > 0xFFFF
+ EXPECT_EQ(LIBC_NAMESPACE::towupper(L'\U00010428'),
+ static_cast<wint_t>(L'\U00010428'));
#endif
}
+#endif
>From e9317ae52cdca5c548259309063f2e65d4c4082b Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Thu, 28 May 2026 00:07:04 +0000
Subject: [PATCH 6/6] fix iswprint
---
libc/test/src/wctype/iswprint_test.cpp | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/libc/test/src/wctype/iswprint_test.cpp b/libc/test/src/wctype/iswprint_test.cpp
index 6f5dfc4e0a600..51bb5ca295ea1 100644
--- a/libc/test/src/wctype/iswprint_test.cpp
+++ b/libc/test/src/wctype/iswprint_test.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "src/__support/wctype_utils.h"
#include "src/wctype/iswprint.h"
#include "test/UnitTest/Test.h"
@@ -15,7 +16,21 @@ TEST(LlvmLibciswprint, SimpleTest) {
if (' ' <= ch && ch <= '~') {
EXPECT_NE(LIBC_NAMESPACE::iswprint(ch), 0);
} else {
+#if LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_UTF8
+ // In UTF-8 mode, characters above 127 can be printable.
+ if (ch < 128) {
+ EXPECT_EQ(LIBC_NAMESPACE::iswprint(ch), 0);
+ }
+#else
+ // In ASCII mode, everything outside ASCII printable is not printable.
EXPECT_EQ(LIBC_NAMESPACE::iswprint(ch), 0);
+#endif
}
}
+
+#if LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_UTF8
+ EXPECT_NE(LIBC_NAMESPACE::iswprint(L'á'), 0);
+#else
+ EXPECT_EQ(LIBC_NAMESPACE::iswprint(L'á'), 0);
+#endif
}
More information about the libc-commits
mailing list