[libc-commits] [libc] [libc] Add iswctype and wctype (PR #191178)

Zile Xiong via libc-commits libc-commits at lists.llvm.org
Sat Apr 11 22:48:23 PDT 2026


https://github.com/xiongzile updated https://github.com/llvm/llvm-project/pull/191178

>From fb2afb54a19775c793adc4812438a8d7ddd3fe42 Mon Sep 17 00:00:00 2001
From: Zile Xiong <xiongzile99 at gmail.com>
Date: Thu, 9 Apr 2026 15:03:36 +0800
Subject: [PATCH 1/3] [libc] Add iswctype and wctype

Implement the iswctype and wctype functions from <wctype.h>.

- Add wctype_t type definition.
- Implement wctype to map property strings to classification descriptors.
- Implement iswctype as a dispatcher over existing wide character
  classification functions.
- Add corresponding entrypoints and unit tests.

Refs: https://github.com/llvm/llvm-project/issues/191076
---
 libc/config/baremetal/arm/entrypoints.txt   |   2 +
 libc/config/baremetal/riscv/entrypoints.txt |   2 +
 libc/config/darwin/aarch64/entrypoints.txt  |   2 +
 libc/config/linux/aarch64/entrypoints.txt   |   2 +
 libc/config/linux/arm/entrypoints.txt       |   2 +
 libc/config/linux/riscv/entrypoints.txt     |   2 +
 libc/config/linux/x86_64/entrypoints.txt    |   2 +
 libc/config/windows/entrypoints.txt         |   2 +
 libc/hdr/types/CMakeLists.txt               |   9 ++
 libc/hdr/types/wctype_t.h                   |  24 ++++
 libc/hdr/wctype_overlay.h                   |  70 +++++++++++
 libc/include/CMakeLists.txt                 |   1 +
 libc/include/llvm-libc-types/CMakeLists.txt |   1 +
 libc/include/llvm-libc-types/wctype_t.h     |  15 +++
 libc/include/wctype.yaml                    |  14 +++
 libc/src/__support/wctype_utils.h           | 127 ++++++++++++++++++++
 libc/src/wctype/CMakeLists.txt              |  21 ++++
 libc/src/wctype/iswctype.cpp                |  23 ++++
 libc/src/wctype/iswctype.h                  |  22 ++++
 libc/src/wctype/wctype.cpp                  |  21 ++++
 libc/src/wctype/wctype.h                    |  22 ++++
 libc/test/src/wctype/CMakeLists.txt         |  20 +++
 libc/test/src/wctype/iswctype_test.cpp      | 110 +++++++++++++++++
 libc/test/src/wctype/wctype_test.cpp        |  63 ++++++++++
 24 files changed, 579 insertions(+)
 create mode 100644 libc/hdr/types/wctype_t.h
 create mode 100644 libc/hdr/wctype_overlay.h
 create mode 100644 libc/include/llvm-libc-types/wctype_t.h
 create mode 100644 libc/src/wctype/iswctype.cpp
 create mode 100644 libc/src/wctype/iswctype.h
 create mode 100644 libc/src/wctype/wctype.cpp
 create mode 100644 libc/src/wctype/wctype.h
 create mode 100644 libc/test/src/wctype/iswctype_test.cpp
 create mode 100644 libc/test/src/wctype/wctype_test.cpp

diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 4cf34764916f7..a2c22ac32e3ac 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -313,6 +313,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.wctype.iswxdigit
     libc.src.wctype.iswpunct
     libc.src.wctype.iswprint
+    libc.src.wctype.iswctype
+    libc.src.wctype.wctype
     # internal entrypoints
     libc.startup.baremetal.init
     libc.startup.baremetal.fini
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index c4a11c6f87337..d5fc6258aff11 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -310,6 +310,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.wctype.iswxdigit
     libc.src.wctype.iswpunct
     libc.src.wctype.iswprint
+    libc.src.wctype.iswctype
+    libc.src.wctype.wctype
 
     # internal entrypoints
     libc.startup.baremetal.init
diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt
index 0888f4b0d922b..033183427de79 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -113,6 +113,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.wctype.iswxdigit
     libc.src.wctype.iswpunct
     libc.src.wctype.iswprint
+    libc.src.wctype.iswctype
+    libc.src.wctype.wctype
 )
 
 if(LLVM_LIBC_FULL_BUILD)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 72836d031c0e8..218ab215c1b47 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -385,6 +385,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.wctype.iswxdigit
     libc.src.wctype.iswpunct
     libc.src.wctype.iswprint
+    libc.src.wctype.iswctype
+    libc.src.wctype.wctype
 
     # sys/uio.h entrypoints
     libc.src.sys.uio.writev
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 31dcb31c67c7a..997263f364524 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -205,6 +205,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.wctype.iswxdigit
     libc.src.wctype.iswpunct
     libc.src.wctype.iswprint
+    libc.src.wctype.iswctype
+    libc.src.wctype.wctype
 )
 
 if(LLVM_LIBC_FULL_BUILD)
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 2038b776e539b..bd2c54b232eb1 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -389,6 +389,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.wctype.iswxdigit
     libc.src.wctype.iswpunct
     libc.src.wctype.iswprint
+    libc.src.wctype.iswctype
+    libc.src.wctype.wctype
 
     # sys/uio.h entrypoints
     libc.src.sys.uio.writev
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index b43ec51d1ece8..00ea48cff7145 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -439,6 +439,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.wctype.iswxdigit
     libc.src.wctype.iswpunct
     libc.src.wctype.iswprint
+    libc.src.wctype.iswctype
+    libc.src.wctype.wctype
 
     # sys/uio.h entrypoints
     libc.src.sys.uio.writev
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index e8080bc97c59a..7d32fab21fdb4 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -119,6 +119,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.wctype.iswxdigit
     libc.src.wctype.iswpunct
     libc.src.wctype.iswprint
+    libc.src.wctype.iswctype
+    libc.src.wctype.wctype
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index 7e1a8974fa486..7395f70c0d2aa 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -443,6 +443,15 @@ add_proxy_header_library(
     libc.include.wchar
 )
 
+
+add_proxy_header_library(
+  wctype_t
+  HDRS
+    wctype_t.h
+  FULL_BUILD_DEPENDS
+    libc.include.llvm-libc-types.wctype_t
+)
+
 add_proxy_header_library(
   uid_t
   HDRS
diff --git a/libc/hdr/types/wctype_t.h b/libc/hdr/types/wctype_t.h
new file mode 100644
index 0000000000000..f8e09969227dd
--- /dev/null
+++ b/libc/hdr/types/wctype_t.h
@@ -0,0 +1,24 @@
+//===-- Definition of wctype_t.h
+//--------------------------------------------===//
+//
+// 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
+//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_HDR_TYPES_WCTYPE_T_H
+#define LLVM_LIBC_HDR_TYPES_WCTYPE_T_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/wctype_t.h"
+
+#else // overlay mode
+
+#include "hdr/wctype_overlay.h"
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_TYPES_WCTYPE_T_H
diff --git a/libc/hdr/wctype_overlay.h b/libc/hdr/wctype_overlay.h
new file mode 100644
index 0000000000000..40a1a9a051a89
--- /dev/null
+++ b/libc/hdr/wctype_overlay.h
@@ -0,0 +1,70 @@
+//===-- Including wctype.h in overlay mode
+//---------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_HDR_WCTYPE_OVERLAY_H
+#define LLVM_LIBC_HDR_WCTYPE_OVERLAY_H
+
+#ifdef LIBC_FULL_BUILD
+#error "This header should only be included in overlay mode"
+#endif
+
+// Overlay mode
+
+// glibc <wctype.h> header might provide extern inline definitions for few
+// functions, causing external alias errors.  They are guarded by
+// `__USE_EXTERN_INLINES` macro.  We temporarily disable `__USE_EXTERN_INLINES`
+// macro by defining `__NO_INLINE__` before including <wctype.h>.
+// And the same with `__USE_FORTIFY_LEVEL`, which will be temporarily disabled
+// with `_FORTIFY_SOURCE`.
+
+#ifdef _FORTIFY_SOURCE
+#define LIBC_OLD_FORTIFY_SOURCE _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+
+#ifndef __NO_INLINE__
+#define __NO_INLINE__ 1
+#define LIBC_SET_NO_INLINE
+#endif
+
+#ifdef __USE_EXTERN_INLINES
+#define LIBC_OLD_USE_EXTERN_INLINES
+#undef __USE_EXTERN_INLINES
+#endif
+
+#ifdef __USE_FORTIFY_LEVEL
+#define LIBC_OLD_USE_FORTIFY_LEVEL __USE_FORTIFY_LEVEL
+#undef __USE_FORTIFY_LEVEL
+#define __USE_FORTIFY_LEVEL 0
+#endif
+
+#include <wctype.h>
+
+#ifdef LIBC_OLD_FORTIFY_SOURCE
+#define _FORTIFY_SOURCE LIBC_OLD_FORTIFY_SOURCE
+#undef LIBC_OLD_FORTIFY_SOURCE
+#endif
+
+#ifdef LIBC_SET_NO_INLINE
+#undef __NO_INLINE__
+#undef LIBC_SET_NO_INLINE
+#endif
+
+#ifdef LIBC_OLD_USE_FORTIFY_LEVEL
+#undef __USE_FORTIFY_LEVEL
+#define __USE_FORTIFY_LEVEL LIBC_OLD_USE_FORTIFY_LEVEL
+#undef LIBC_OLD_USE_FORTIFY_LEVEL
+#endif
+
+#ifdef LIBC_OLD_USE_EXTERN_INLINES
+#define __USE_EXTERN_INLINES
+#undef LIBC_OLD_USE_EXTERN_INLINES
+#endif
+
+#endif // LLVM_LIBC_HDR_WCTYPE_OVERLAY_H
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 41d541f475290..9041a84b8125f 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -872,6 +872,7 @@ add_header_macro(
   DEPENDS
     .llvm_libc_common_h
     .llvm-libc-types.wint_t
+    .llvm-libc-types.wctype_t
 )
 
 add_header_macro(
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 0d6bc0982b847..ea9a507836735 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -166,6 +166,7 @@ add_header(
     libc.include.llvm-libc-macros.stdint_macros
 )
 add_header(wint_t HDR wint_t.h)
+add_header(wctype_t HDR wctype_t.h)
 add_header(sa_family_t HDR sa_family_t.h)
 add_header(socklen_t HDR socklen_t.h)
 add_header(struct_sockaddr_un HDR struct_sockaddr_un.h DEPENDS .sa_family_t)
diff --git a/libc/include/llvm-libc-types/wctype_t.h b/libc/include/llvm-libc-types/wctype_t.h
new file mode 100644
index 0000000000000..b096c0061984a
--- /dev/null
+++ b/libc/include/llvm-libc-types/wctype_t.h
@@ -0,0 +1,15 @@
+//===-- Definition of wctype_t types
+//----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES_WCTYPE_T_H
+#define LLVM_LIBC_TYPES_WCTYPE_T_H
+
+typedef unsigned int wctype_t;
+
+#endif // LLVM_LIBC_TYPES_WCTYPE_T_H
diff --git a/libc/include/wctype.yaml b/libc/include/wctype.yaml
index 932ff6ac1b138..a5163ecc2d3f2 100644
--- a/libc/include/wctype.yaml
+++ b/libc/include/wctype.yaml
@@ -1,6 +1,7 @@
 header: wctype.h
 types:
   - type_name: wint_t
+  - type_name: wctype_t
 functions:
   - name: iswalpha
     standards:
@@ -74,3 +75,16 @@ functions:
     return_type: int
     arguments:
       - type: wint_t
+  - name: iswctype
+    standards:
+      - stdc
+    return_type: int
+    arguments:
+      - type: wint_t
+      - type: wctype_t
+  - name: wctype
+    standards:
+      - stdc
+    return_type: wctype_t
+    arguments:
+      - type: const char*
diff --git a/libc/src/__support/wctype_utils.h b/libc/src/__support/wctype_utils.h
index a80c78d54c796..e2b34e600f255 100644
--- a/libc/src/__support/wctype_utils.h
+++ b/libc/src/__support/wctype_utils.h
@@ -454,6 +454,74 @@ LIBC_INLINE constexpr wchar_t toupper(wchar_t wch) {
   }
 }
 
+LIBC_INLINE constexpr unsigned int wctype(const char *property) {
+  if (!property)
+    return 0; // WCTYPE_INVALID
+
+  constexpr const char *names[] = {
+      "unknown", // 0
+      "alnum",   // 1 - WCTYPE_ALNUM
+      "alpha",   // 2 - WCTYPE_ALPHA
+      "blank",   // 3 - WCTYPE_BLANK
+      "cntrl",   // 4 - WCTYPE_CNTRL
+      "digit",   // 5 - WCTYPE_DIGIT
+      "graph",   // 6 - WCTYPE_GRAPH
+      "lower",   // 7 - WCTYPE_LOWER
+      "print",   // 8 - WCTYPE_PRINT
+      "punct",   // 9 - WCTYPE_PUNCT
+      "space",   // 10 - WCTYPE_SPACE
+      "upper",   // 11 - WCTYPE_UPPER
+      "xdigit"   // 12 - WCTYPE_XDIGIT
+  };
+
+  for (unsigned int i = 1; i < sizeof(names) / sizeof(names[0]); ++i) {
+    const char *s1 = property;
+    const char *s2 = names[i];
+
+    while (*s1 && (*s1 == *s2)) {
+      ++s1;
+      ++s2;
+    }
+
+    if (*s1 == *s2) {
+      return i;
+    }
+  }
+
+  return 0; // WCTYPE_INVALID
+}
+
+LIBC_INLINE constexpr int iswctype(wchar_t c, unsigned int desc) {
+  switch (desc) {
+  case 1:
+    return isalnum(c); // alnum
+  case 2:
+    return isalpha(c); // alpha
+  case 3:
+    return isblank(c); // blank
+  case 4:
+    return iscntrl(c); // cntrl
+  case 5:
+    return isdigit(c); // digit
+  case 6:
+    return isgraph(c); // graph
+  case 7:
+    return islower(c); // lower
+  case 8:
+    return isprint(c); // print
+  case 9:
+    return ispunct(c); // punct
+  case 10:
+    return isspace(c); // space
+  case 11:
+    return isupper(c); // upper
+  case 12:
+    return isxdigit(c); // xdigit
+  default:
+    return 0;
+  }
+}
+
 } // namespace ascii
 
 LIBC_INLINE constexpr bool islower(wchar_t wch) {
@@ -552,6 +620,65 @@ LIBC_INLINE constexpr bool isprint(wchar_t wch) {
 #endif
 }
 
+LIBC_INLINE constexpr bool iswctype(wchar_t wch, unsigned int desc) {
+#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
+  return ascii::iswctype(wch, desc);
+#else
+  if (static_cast<uint32_t>(wch) < 128) {
+    return ascii::iswctype(wch, desc);
+  }
+
+  const unsigned prop = lookup_properties(wch);
+
+  switch (desc) {
+  case 1: // alnum
+    return prop & PropertyFlag::ALPHA;
+
+  case 2: // alpha
+    return prop & PropertyFlag::ALPHA;
+
+  case 3: // blank
+    return prop & PropertyFlag::BLANK;
+
+  case 4: // cntrl
+    return prop & PropertyFlag::CNTRL;
+
+  case 5: // digit
+    return ascii::isdigit(wch);
+
+  case 6: // graph
+    // print && !space
+    return (prop & (PropertyFlag::PRINT | PropertyFlag::SPACE)) ==
+           PropertyFlag::PRINT;
+
+  case 7: // lower
+    return prop & PropertyFlag::LOWER;
+
+  case 8: // print
+    return prop & PropertyFlag::PRINT;
+
+  case 9: // punct
+    return prop & PropertyFlag::PUNCT;
+
+  case 10: // space
+    return prop & PropertyFlag::SPACE;
+
+  case 11: // upper
+    return prop & PropertyFlag::UPPER;
+
+  case 12: // xdigit
+    return ascii::isxdigit(wch);
+
+  default:
+    return false;
+  }
+#endif
+}
+
+LIBC_INLINE constexpr unsigned int wctype(const char *property) {
+  return ascii::wctype(property);
+}
+
 LIBC_INLINE constexpr bool isxdigit(wchar_t wch) {
   // Hexadecimal digits are the same in C.UTF8 as in ASCII
   return ascii::isxdigit(wch);
diff --git a/libc/src/wctype/CMakeLists.txt b/libc/src/wctype/CMakeLists.txt
index 07bfed39980c2..57f9e7753a9f5 100644
--- a/libc/src/wctype/CMakeLists.txt
+++ b/libc/src/wctype/CMakeLists.txt
@@ -130,3 +130,24 @@ add_entrypoint_object(
     libc.src.__support.wctype_utils
     libc.hdr.types.wint_t
 )
+
+add_entrypoint_object(
+  iswctype
+  SRCS
+    iswctype.cpp
+  HDRS
+    iswctype.h
+  DEPENDS
+    libc.src.__support.wctype_utils
+    libc.hdr.types.wint_t
+)
+
+add_entrypoint_object(
+  wctype
+  SRCS
+    wctype.cpp
+  HDRS
+    wctype.h
+  DEPENDS
+    libc.src.__support.wctype_utils
+)
diff --git a/libc/src/wctype/iswctype.cpp b/libc/src/wctype/iswctype.cpp
new file mode 100644
index 0000000000000..87bf0e31fe463
--- /dev/null
+++ b/libc/src/wctype/iswctype.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of iswctype ----------------------------------------===//
+//
+// 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 "src/wctype/iswctype.h"
+#include "src/__support/common.h"
+#include "src/__support/wctype_utils.h"
+
+#include "hdr/types/wctype_t.h"
+#include "hdr/types/wint_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, iswctype, (wint_t c, wctype_t desc)) {
+  return internal::iswctype(static_cast<wchar_t>(c),
+                            static_cast<unsigned int>(desc));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wctype/iswctype.h b/libc/src/wctype/iswctype.h
new file mode 100644
index 0000000000000..10a0f3e969c8d
--- /dev/null
+++ b/libc/src/wctype/iswctype.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for iswctype ----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_WCTYPE_ISWCTYPE_H
+#define LLVM_LIBC_SRC_WCTYPE_ISWCTYPE_H
+
+#include "hdr/types/wctype_t.h"
+#include "hdr/types/wint_t.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int iswctype(wint_t c, wctype_t desc);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCTYPE_ISWCTYPE_H
diff --git a/libc/src/wctype/wctype.cpp b/libc/src/wctype/wctype.cpp
new file mode 100644
index 0000000000000..59c28dcf5a437
--- /dev/null
+++ b/libc/src/wctype/wctype.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of wctype ----------------------------------------===//
+//
+// 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 "src/wctype/wctype.h"
+#include "src/__support/common.h"
+#include "src/__support/wctype_utils.h"
+
+#include "hdr/types/wctype_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(wctype_t, wctype, (const char *property)) {
+  return internal::wctype(property);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wctype/wctype.h b/libc/src/wctype/wctype.h
new file mode 100644
index 0000000000000..98300e49f7e03
--- /dev/null
+++ b/libc/src/wctype/wctype.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for iswctype ----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_WCTYPE_WCTYPE_H
+#define LLVM_LIBC_SRC_WCTYPE_WCTYPE_H
+
+#include "hdr/types/wctype_t.h"
+#include "hdr/types/wint_t.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+wctype_t wctype(const char *property);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCTYPE_WCTYPE_H
diff --git a/libc/test/src/wctype/CMakeLists.txt b/libc/test/src/wctype/CMakeLists.txt
index a5f85856dfb38..2d02888ad2833 100644
--- a/libc/test/src/wctype/CMakeLists.txt
+++ b/libc/test/src/wctype/CMakeLists.txt
@@ -121,3 +121,23 @@ add_libc_test(
   DEPENDS
     libc.src.wctype.iswprint
 )
+
+add_libc_test(
+  iswctype_test
+  SUITE
+    libc_wctype_unittests
+  SRCS
+    iswctype_test.cpp
+  DEPENDS
+    libc.src.wctype.iswctype
+)
+
+add_libc_test(
+  wctype_test
+  SUITE
+    libc_wctype_unittests
+  SRCS
+    wctype_test.cpp
+  DEPENDS
+    libc.src.wctype.wctype
+)
diff --git a/libc/test/src/wctype/iswctype_test.cpp b/libc/test/src/wctype/iswctype_test.cpp
new file mode 100644
index 0000000000000..39ff350ab6673
--- /dev/null
+++ b/libc/test/src/wctype/iswctype_test.cpp
@@ -0,0 +1,110 @@
+//===-- Unittests for iswctype --------------------------------------------===//
+//
+// 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 "src/wctype/iswctype.h"
+
+#include "test/UnitTest/Test.h"
+
+// Simple tests, already properly tested in
+// libc/test/src/__support/wctype_utils_test.cpp
+
+static constexpr wctype_t WCTYPE_INVALID = static_cast<wctype_t>(0);
+static constexpr wctype_t WCTYPE_ALNUM = static_cast<wctype_t>(1);
+static constexpr wctype_t WCTYPE_ALPHA = static_cast<wctype_t>(2);
+static constexpr wctype_t WCTYPE_BLANK = static_cast<wctype_t>(3);
+static constexpr wctype_t WCTYPE_CNTRL = static_cast<wctype_t>(4);
+static constexpr wctype_t WCTYPE_DIGIT = static_cast<wctype_t>(5);
+static constexpr wctype_t WCTYPE_GRAPH = static_cast<wctype_t>(6);
+static constexpr wctype_t WCTYPE_LOWER = static_cast<wctype_t>(7);
+static constexpr wctype_t WCTYPE_PRINT = static_cast<wctype_t>(8);
+static constexpr wctype_t WCTYPE_PUNCT = static_cast<wctype_t>(9);
+static constexpr wctype_t WCTYPE_SPACE = static_cast<wctype_t>(10);
+static constexpr wctype_t WCTYPE_UPPER = static_cast<wctype_t>(11);
+static constexpr wctype_t WCTYPE_XDIGIT = static_cast<wctype_t>(12);
+
+TEST(LlvmLibciswctype, SimpleTest) {
+  using LIBC_NAMESPACE::iswctype;
+
+  // alnum
+  EXPECT_NE(iswctype('a', WCTYPE_ALNUM), 0);
+  EXPECT_NE(iswctype('Z', WCTYPE_ALNUM), 0);
+  EXPECT_NE(iswctype('5', WCTYPE_ALNUM), 0);
+  EXPECT_EQ(iswctype('!', WCTYPE_ALNUM), 0);
+
+  // alpha
+  EXPECT_NE(iswctype('a', WCTYPE_ALPHA), 0);
+  EXPECT_NE(iswctype('Z', WCTYPE_ALPHA), 0);
+  EXPECT_EQ(iswctype('1', WCTYPE_ALPHA), 0);
+  EXPECT_EQ(iswctype(' ', WCTYPE_ALPHA), 0);
+
+  // blank
+  EXPECT_NE(iswctype(' ', WCTYPE_BLANK), 0);
+  EXPECT_NE(iswctype('\t', WCTYPE_BLANK), 0);
+  EXPECT_EQ(iswctype('\n', WCTYPE_BLANK), 0);
+  EXPECT_EQ(iswctype('A', WCTYPE_BLANK), 0);
+
+  // cntrl
+  EXPECT_NE(iswctype('\0', WCTYPE_CNTRL), 0);
+  EXPECT_NE(iswctype('\n', WCTYPE_CNTRL), 0);
+  EXPECT_NE(iswctype(0x7f, WCTYPE_CNTRL), 0);
+  EXPECT_EQ(iswctype('A', WCTYPE_CNTRL), 0);
+
+  // digit
+  EXPECT_NE(iswctype('0', WCTYPE_DIGIT), 0);
+  EXPECT_NE(iswctype('9', WCTYPE_DIGIT), 0);
+  EXPECT_EQ(iswctype('a', WCTYPE_DIGIT), 0);
+  EXPECT_EQ(iswctype(' ', WCTYPE_DIGIT), 0);
+
+  // graph
+  EXPECT_NE(iswctype('A', WCTYPE_GRAPH), 0);
+  EXPECT_NE(iswctype('1', WCTYPE_GRAPH), 0);
+  EXPECT_NE(iswctype('!', WCTYPE_GRAPH), 0);
+  EXPECT_EQ(iswctype(' ', WCTYPE_GRAPH), 0);
+
+  // lower
+  EXPECT_NE(iswctype('a', WCTYPE_LOWER), 0);
+  EXPECT_NE(iswctype('z', WCTYPE_LOWER), 0);
+  EXPECT_EQ(iswctype('A', WCTYPE_LOWER), 0);
+  EXPECT_EQ(iswctype('1', WCTYPE_LOWER), 0);
+
+  // print
+  EXPECT_NE(iswctype(' ', WCTYPE_PRINT), 0);
+  EXPECT_NE(iswctype('A', WCTYPE_PRINT), 0);
+  EXPECT_NE(iswctype('~', WCTYPE_PRINT), 0);
+  EXPECT_EQ(iswctype('\n', WCTYPE_PRINT), 0);
+
+  // punct
+  EXPECT_NE(iswctype('!', WCTYPE_PUNCT), 0);
+  EXPECT_NE(iswctype('?', WCTYPE_PUNCT), 0);
+  EXPECT_EQ(iswctype('a', WCTYPE_PUNCT), 0);
+  EXPECT_EQ(iswctype('1', WCTYPE_PUNCT), 0);
+
+  // space
+  EXPECT_NE(iswctype(' ', WCTYPE_SPACE), 0);
+  EXPECT_NE(iswctype('\t', WCTYPE_SPACE), 0);
+  EXPECT_NE(iswctype('\n', WCTYPE_SPACE), 0);
+  EXPECT_EQ(iswctype('A', WCTYPE_SPACE), 0);
+
+  // upper
+  EXPECT_NE(iswctype('A', WCTYPE_UPPER), 0);
+  EXPECT_NE(iswctype('Z', WCTYPE_UPPER), 0);
+  EXPECT_EQ(iswctype('a', WCTYPE_UPPER), 0);
+  EXPECT_EQ(iswctype('1', WCTYPE_UPPER), 0);
+
+  // xdigit
+  EXPECT_NE(iswctype('0', WCTYPE_XDIGIT), 0);
+  EXPECT_NE(iswctype('9', WCTYPE_XDIGIT), 0);
+  EXPECT_NE(iswctype('a', WCTYPE_XDIGIT), 0);
+  EXPECT_NE(iswctype('F', WCTYPE_XDIGIT), 0);
+  EXPECT_EQ(iswctype('g', WCTYPE_XDIGIT), 0);
+  EXPECT_EQ(iswctype('?', WCTYPE_XDIGIT), 0);
+
+  // invalid descriptor
+  EXPECT_EQ(iswctype('a', WCTYPE_INVALID), 0);
+  EXPECT_EQ(iswctype('a', static_cast<wctype_t>(999)), 0);
+}
diff --git a/libc/test/src/wctype/wctype_test.cpp b/libc/test/src/wctype/wctype_test.cpp
new file mode 100644
index 0000000000000..22a3f6d1e7e2e
--- /dev/null
+++ b/libc/test/src/wctype/wctype_test.cpp
@@ -0,0 +1,63 @@
+//===-- Unittests for wctype --------------------------------------------===//
+//
+// 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 "src/wctype/wctype.h"
+
+#include "test/UnitTest/Test.h"
+
+// wctype descriptors (must match implementation)
+static constexpr wctype_t WCTYPE_INVALID = static_cast<wctype_t>(0);
+static constexpr wctype_t WCTYPE_ALNUM = static_cast<wctype_t>(1);
+static constexpr wctype_t WCTYPE_ALPHA = static_cast<wctype_t>(2);
+static constexpr wctype_t WCTYPE_BLANK = static_cast<wctype_t>(3);
+static constexpr wctype_t WCTYPE_CNTRL = static_cast<wctype_t>(4);
+static constexpr wctype_t WCTYPE_DIGIT = static_cast<wctype_t>(5);
+static constexpr wctype_t WCTYPE_GRAPH = static_cast<wctype_t>(6);
+static constexpr wctype_t WCTYPE_LOWER = static_cast<wctype_t>(7);
+static constexpr wctype_t WCTYPE_PRINT = static_cast<wctype_t>(8);
+static constexpr wctype_t WCTYPE_PUNCT = static_cast<wctype_t>(9);
+static constexpr wctype_t WCTYPE_SPACE = static_cast<wctype_t>(10);
+static constexpr wctype_t WCTYPE_UPPER = static_cast<wctype_t>(11);
+static constexpr wctype_t WCTYPE_XDIGIT = static_cast<wctype_t>(12);
+
+TEST(LlvmLibcwctype, SimpleTest) {
+  using LIBC_NAMESPACE::wctype;
+
+  auto alnum = wctype("alnum");
+  auto alpha = wctype("alpha");
+  auto blank = wctype("blank");
+  auto cntrl = wctype("cntrl");
+  auto digit = wctype("digit");
+  auto graph = wctype("graph");
+  auto lower = wctype("lower");
+  auto print = wctype("print");
+  auto punct = wctype("punct");
+  auto space = wctype("space");
+  auto upper = wctype("upper");
+  auto xdigit = wctype("xdigit");
+
+  // valid descriptors should be nonzero
+  EXPECT_EQ(alnum, WCTYPE_ALNUM);
+  EXPECT_EQ(alpha, WCTYPE_ALPHA);
+  EXPECT_EQ(blank, WCTYPE_BLANK);
+  EXPECT_EQ(cntrl, WCTYPE_CNTRL);
+  EXPECT_EQ(digit, WCTYPE_DIGIT);
+  EXPECT_EQ(graph, WCTYPE_GRAPH);
+  EXPECT_EQ(lower, WCTYPE_LOWER);
+  EXPECT_EQ(print, WCTYPE_PRINT);
+  EXPECT_EQ(punct, WCTYPE_PUNCT);
+  EXPECT_EQ(space, WCTYPE_SPACE);
+  EXPECT_EQ(upper, WCTYPE_UPPER);
+  EXPECT_EQ(xdigit, WCTYPE_XDIGIT);
+
+  // invalid properties should return zero
+  EXPECT_EQ(wctype(""), WCTYPE_INVALID);
+  EXPECT_EQ(wctype("invalid"), WCTYPE_INVALID);
+  EXPECT_EQ(wctype("Alpha"), WCTYPE_INVALID);
+  EXPECT_EQ(wctype("unknown"), WCTYPE_INVALID);
+}

>From 2a5211c4f478dd40c6ea7c4eb343da3517a83815 Mon Sep 17 00:00:00 2001
From: Zile Xiong <xiongzile99 at gmail.com>
Date: Fri, 10 Apr 2026 07:33:08 +0800
Subject: [PATCH 2/3] [libc] Add iswctype and wctype (v2)

- Change wctype_t from unsigned int to unsigned short
- Move iswctype and wctype out of the ascii namespace
- Use wctype_t instead of raw integer types in wctype_utils.h
- Introduce a mapping table to bind property names to descriptors
- Fix header formatting issues
---
 libc/hdr/types/wctype_t.h                     |   3 +-
 libc/hdr/wctype_overlay.h                     |   3 +-
 libc/include/llvm-libc-types/wctype_t.h       |   5 +-
 libc/src/__support/wctype_utils.h             | 210 +++++++-----------
 libc/src/wctype/iswctype.cpp                  |   3 +-
 libc/test/src/__support/wctype_utils_test.cpp |   9 +-
 6 files changed, 95 insertions(+), 138 deletions(-)

diff --git a/libc/hdr/types/wctype_t.h b/libc/hdr/types/wctype_t.h
index f8e09969227dd..39f33b87f3e15 100644
--- a/libc/hdr/types/wctype_t.h
+++ b/libc/hdr/types/wctype_t.h
@@ -1,5 +1,4 @@
-//===-- Definition of wctype_t.h
-//--------------------------------------------===//
+//===-- Definition of wctype_t.h ------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/hdr/wctype_overlay.h b/libc/hdr/wctype_overlay.h
index 40a1a9a051a89..3ae7fbe24ec8d 100644
--- a/libc/hdr/wctype_overlay.h
+++ b/libc/hdr/wctype_overlay.h
@@ -1,5 +1,4 @@
-//===-- Including wctype.h in overlay mode
-//---------------------------------===//
+//===-- Including wctype.h in overlay mode --------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/include/llvm-libc-types/wctype_t.h b/libc/include/llvm-libc-types/wctype_t.h
index b096c0061984a..e1d264b33150d 100644
--- a/libc/include/llvm-libc-types/wctype_t.h
+++ b/libc/include/llvm-libc-types/wctype_t.h
@@ -1,5 +1,4 @@
-//===-- Definition of wctype_t types
-//----------------------------------------===//
+//===-- Definition of wctype_t types --------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -10,6 +9,6 @@
 #ifndef LLVM_LIBC_TYPES_WCTYPE_T_H
 #define LLVM_LIBC_TYPES_WCTYPE_T_H
 
-typedef unsigned int wctype_t;
+typedef unsigned short wctype_t;
 
 #endif // LLVM_LIBC_TYPES_WCTYPE_T_H
diff --git a/libc/src/__support/wctype_utils.h b/libc/src/__support/wctype_utils.h
index e2b34e600f255..9c66990f8b9d7 100644
--- a/libc/src/__support/wctype_utils.h
+++ b/libc/src/__support/wctype_utils.h
@@ -10,6 +10,9 @@
 #define LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
 
 #include "hdr/types/wchar_t.h"
+#include "hdr/types/wctype_t.h"
+#include "src/__support/CPP/array.h"
+#include "src/__support/CPP/string_view.h"
 #include "src/__support/macros/attributes.h" // LIBC_INLINE
 #include "src/__support/macros/config.h"
 
@@ -454,74 +457,6 @@ LIBC_INLINE constexpr wchar_t toupper(wchar_t wch) {
   }
 }
 
-LIBC_INLINE constexpr unsigned int wctype(const char *property) {
-  if (!property)
-    return 0; // WCTYPE_INVALID
-
-  constexpr const char *names[] = {
-      "unknown", // 0
-      "alnum",   // 1 - WCTYPE_ALNUM
-      "alpha",   // 2 - WCTYPE_ALPHA
-      "blank",   // 3 - WCTYPE_BLANK
-      "cntrl",   // 4 - WCTYPE_CNTRL
-      "digit",   // 5 - WCTYPE_DIGIT
-      "graph",   // 6 - WCTYPE_GRAPH
-      "lower",   // 7 - WCTYPE_LOWER
-      "print",   // 8 - WCTYPE_PRINT
-      "punct",   // 9 - WCTYPE_PUNCT
-      "space",   // 10 - WCTYPE_SPACE
-      "upper",   // 11 - WCTYPE_UPPER
-      "xdigit"   // 12 - WCTYPE_XDIGIT
-  };
-
-  for (unsigned int i = 1; i < sizeof(names) / sizeof(names[0]); ++i) {
-    const char *s1 = property;
-    const char *s2 = names[i];
-
-    while (*s1 && (*s1 == *s2)) {
-      ++s1;
-      ++s2;
-    }
-
-    if (*s1 == *s2) {
-      return i;
-    }
-  }
-
-  return 0; // WCTYPE_INVALID
-}
-
-LIBC_INLINE constexpr int iswctype(wchar_t c, unsigned int desc) {
-  switch (desc) {
-  case 1:
-    return isalnum(c); // alnum
-  case 2:
-    return isalpha(c); // alpha
-  case 3:
-    return isblank(c); // blank
-  case 4:
-    return iscntrl(c); // cntrl
-  case 5:
-    return isdigit(c); // digit
-  case 6:
-    return isgraph(c); // graph
-  case 7:
-    return islower(c); // lower
-  case 8:
-    return isprint(c); // print
-  case 9:
-    return ispunct(c); // punct
-  case 10:
-    return isspace(c); // space
-  case 11:
-    return isupper(c); // upper
-  case 12:
-    return isxdigit(c); // xdigit
-  default:
-    return 0;
-  }
-}
-
 } // namespace ascii
 
 LIBC_INLINE constexpr bool islower(wchar_t wch) {
@@ -619,66 +554,6 @@ LIBC_INLINE constexpr bool isprint(wchar_t wch) {
   return lookup_properties(wch) & PropertyFlag::PRINT;
 #endif
 }
-
-LIBC_INLINE constexpr bool iswctype(wchar_t wch, unsigned int desc) {
-#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
-  return ascii::iswctype(wch, desc);
-#else
-  if (static_cast<uint32_t>(wch) < 128) {
-    return ascii::iswctype(wch, desc);
-  }
-
-  const unsigned prop = lookup_properties(wch);
-
-  switch (desc) {
-  case 1: // alnum
-    return prop & PropertyFlag::ALPHA;
-
-  case 2: // alpha
-    return prop & PropertyFlag::ALPHA;
-
-  case 3: // blank
-    return prop & PropertyFlag::BLANK;
-
-  case 4: // cntrl
-    return prop & PropertyFlag::CNTRL;
-
-  case 5: // digit
-    return ascii::isdigit(wch);
-
-  case 6: // graph
-    // print && !space
-    return (prop & (PropertyFlag::PRINT | PropertyFlag::SPACE)) ==
-           PropertyFlag::PRINT;
-
-  case 7: // lower
-    return prop & PropertyFlag::LOWER;
-
-  case 8: // print
-    return prop & PropertyFlag::PRINT;
-
-  case 9: // punct
-    return prop & PropertyFlag::PUNCT;
-
-  case 10: // space
-    return prop & PropertyFlag::SPACE;
-
-  case 11: // upper
-    return prop & PropertyFlag::UPPER;
-
-  case 12: // xdigit
-    return ascii::isxdigit(wch);
-
-  default:
-    return false;
-  }
-#endif
-}
-
-LIBC_INLINE constexpr unsigned int wctype(const char *property) {
-  return ascii::wctype(property);
-}
-
 LIBC_INLINE constexpr bool isxdigit(wchar_t wch) {
   // Hexadecimal digits are the same in C.UTF8 as in ASCII
   return ascii::isxdigit(wch);
@@ -706,6 +581,85 @@ LIBC_INLINE constexpr bool ispunct(wchar_t wch) {
 #endif
 }
 
+struct wctype_mapping {
+  cpp::string_view name;
+  wctype_t desc;
+};
+
+LIBC_INLINE constexpr wctype_t WCTYPE_INVALID = 0;
+LIBC_INLINE constexpr wctype_t WCTYPE_ALNUM = 1;
+LIBC_INLINE constexpr wctype_t WCTYPE_ALPHA = 2;
+LIBC_INLINE constexpr wctype_t WCTYPE_BLANK = 3;
+LIBC_INLINE constexpr wctype_t WCTYPE_CNTRL = 4;
+LIBC_INLINE constexpr wctype_t WCTYPE_DIGIT = 5;
+LIBC_INLINE constexpr wctype_t WCTYPE_GRAPH = 6;
+LIBC_INLINE constexpr wctype_t WCTYPE_LOWER = 7;
+LIBC_INLINE constexpr wctype_t WCTYPE_PRINT = 8;
+LIBC_INLINE constexpr wctype_t WCTYPE_PUNCT = 9;
+LIBC_INLINE constexpr wctype_t WCTYPE_SPACE = 10;
+LIBC_INLINE constexpr wctype_t WCTYPE_UPPER = 11;
+LIBC_INLINE constexpr wctype_t WCTYPE_XDIGIT = 12;
+
+LIBC_INLINE constexpr cpp::array<wctype_mapping, 12> mappings = {{
+    {"alnum", WCTYPE_ALNUM},
+    {"alpha", WCTYPE_ALPHA},
+    {"blank", WCTYPE_BLANK},
+    {"cntrl", WCTYPE_CNTRL},
+    {"digit", WCTYPE_DIGIT},
+    {"graph", WCTYPE_GRAPH},
+    {"lower", WCTYPE_LOWER},
+    {"print", WCTYPE_PRINT},
+    {"punct", WCTYPE_PUNCT},
+    {"space", WCTYPE_SPACE},
+    {"upper", WCTYPE_UPPER},
+    {"xdigit", WCTYPE_XDIGIT},
+}};
+
+LIBC_INLINE constexpr wctype_t wctype(const char *property) {
+  if (!property)
+    return WCTYPE_INVALID;
+
+  cpp::string_view prop(property);
+
+  for (const auto &wc : mappings) {
+    if (wc.name == prop) {
+      return wc.desc;
+    }
+  }
+  return WCTYPE_INVALID;
+}
+
+LIBC_INLINE constexpr int iswctype(wchar_t c, wctype_t desc) {
+  switch (desc) {
+  case WCTYPE_ALNUM:
+    return isalnum(c);
+  case WCTYPE_ALPHA:
+    return isalpha(c);
+  case WCTYPE_BLANK:
+    return isblank(c);
+  case WCTYPE_CNTRL:
+    return iscntrl(c);
+  case WCTYPE_DIGIT:
+    return isdigit(c);
+  case WCTYPE_GRAPH:
+    return isgraph(c);
+  case WCTYPE_LOWER:
+    return islower(c);
+  case WCTYPE_PRINT:
+    return isprint(c);
+  case WCTYPE_PUNCT:
+    return ispunct(c);
+  case WCTYPE_SPACE:
+    return isspace(c);
+  case WCTYPE_UPPER:
+    return isupper(c);
+  case WCTYPE_XDIGIT:
+    return isxdigit(c);
+  default:
+    return 0;
+  }
+}
+
 LIBC_INLINE constexpr wchar_t tolower(wchar_t wch) {
 #if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
   return ascii::tolower(wch);
diff --git a/libc/src/wctype/iswctype.cpp b/libc/src/wctype/iswctype.cpp
index 87bf0e31fe463..1604836225fee 100644
--- a/libc/src/wctype/iswctype.cpp
+++ b/libc/src/wctype/iswctype.cpp
@@ -16,8 +16,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(int, iswctype, (wint_t c, wctype_t desc)) {
-  return internal::iswctype(static_cast<wchar_t>(c),
-                            static_cast<unsigned int>(desc));
+  return internal::iswctype(static_cast<wchar_t>(c), desc);
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/__support/wctype_utils_test.cpp b/libc/test/src/__support/wctype_utils_test.cpp
index 9bc7e818cdbc6..39dc1678c04c1 100644
--- a/libc/test/src/__support/wctype_utils_test.cpp
+++ b/libc/test/src/__support/wctype_utils_test.cpp
@@ -1,7 +1,7 @@
+#include "hdr/types/wctype_t.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/wctype/wctype_classification_utils.h"
 #include "test/UnitTest/Test.h"
-
 namespace {
 
 namespace ascii_mode {
@@ -9,7 +9,12 @@ namespace ascii_mode {
 #define LIBC_CONF_WCTYPE_MODE LIBC_WCTYPE_MODE_ASCII
 
 #undef LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
+
+namespace LIBC_NAMESPACE_DECL {
+namespace cpp = ::LIBC_NAMESPACE::cpp;
+} // namespace LIBC_NAMESPACE_DECL
 #include "src/__support/wctype_utils.h"
+
 } // namespace ascii_mode
 
 namespace utf8_mode {
@@ -19,9 +24,11 @@ namespace utf8_mode {
 namespace LIBC_NAMESPACE_DECL {
 using ::LIBC_NAMESPACE::lookup_properties;
 using ::LIBC_NAMESPACE::PropertyFlag;
+namespace cpp = ::LIBC_NAMESPACE::cpp;
 } // namespace LIBC_NAMESPACE_DECL
 
 #undef LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
+
 #include "src/__support/wctype_utils.h"
 } // namespace utf8_mode
 

>From da05e55ce9ec7327dfba16ccf233a7ae32d683a3 Mon Sep 17 00:00:00 2001
From: Zile Xiong <xiongzile99 at gmail.com>
Date: Sat, 11 Apr 2026 12:25:28 +0800
Subject: [PATCH 3/3] [libc] Fix wctype_t type and update tests (v3)

- Change wctype_t back to unsigned int
- Update tests to validate API behavior instead of implementation details
- Add missing license headers
---
 libc/include/llvm-libc-types/wctype_t.h       |   2 +-
 libc/test/src/__support/wctype_utils_test.cpp |   8 +
 libc/test/src/wctype/CMakeLists.txt           |   1 +
 libc/test/src/wctype/iswctype_test.cpp        | 265 +++++++++++-------
 libc/test/src/wctype/wctype_test.cpp          |  72 ++---
 5 files changed, 200 insertions(+), 148 deletions(-)

diff --git a/libc/include/llvm-libc-types/wctype_t.h b/libc/include/llvm-libc-types/wctype_t.h
index e1d264b33150d..47840df02fc46 100644
--- a/libc/include/llvm-libc-types/wctype_t.h
+++ b/libc/include/llvm-libc-types/wctype_t.h
@@ -9,6 +9,6 @@
 #ifndef LLVM_LIBC_TYPES_WCTYPE_T_H
 #define LLVM_LIBC_TYPES_WCTYPE_T_H
 
-typedef unsigned short wctype_t;
+typedef unsigned int wctype_t;
 
 #endif // LLVM_LIBC_TYPES_WCTYPE_T_H
diff --git a/libc/test/src/__support/wctype_utils_test.cpp b/libc/test/src/__support/wctype_utils_test.cpp
index 39dc1678c04c1..88cd56cc0cae5 100644
--- a/libc/test/src/__support/wctype_utils_test.cpp
+++ b/libc/test/src/__support/wctype_utils_test.cpp
@@ -1,3 +1,11 @@
+//===-- Unittests for wctype utils ----------------------------------------===//
+//
+// 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/types/wctype_t.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/wctype/wctype_classification_utils.h"
diff --git a/libc/test/src/wctype/CMakeLists.txt b/libc/test/src/wctype/CMakeLists.txt
index 2d02888ad2833..f7cdcc77482e4 100644
--- a/libc/test/src/wctype/CMakeLists.txt
+++ b/libc/test/src/wctype/CMakeLists.txt
@@ -130,6 +130,7 @@ add_libc_test(
     iswctype_test.cpp
   DEPENDS
     libc.src.wctype.iswctype
+    libc.src.wctype.wctype
 )
 
 add_libc_test(
diff --git a/libc/test/src/wctype/iswctype_test.cpp b/libc/test/src/wctype/iswctype_test.cpp
index 39ff350ab6673..972af0963129d 100644
--- a/libc/test/src/wctype/iswctype_test.cpp
+++ b/libc/test/src/wctype/iswctype_test.cpp
@@ -7,104 +7,175 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/wctype/iswctype.h"
+#include "src/wctype/wctype.h"
 
 #include "test/UnitTest/Test.h"
 
-// Simple tests, already properly tested in
-// libc/test/src/__support/wctype_utils_test.cpp
-
-static constexpr wctype_t WCTYPE_INVALID = static_cast<wctype_t>(0);
-static constexpr wctype_t WCTYPE_ALNUM = static_cast<wctype_t>(1);
-static constexpr wctype_t WCTYPE_ALPHA = static_cast<wctype_t>(2);
-static constexpr wctype_t WCTYPE_BLANK = static_cast<wctype_t>(3);
-static constexpr wctype_t WCTYPE_CNTRL = static_cast<wctype_t>(4);
-static constexpr wctype_t WCTYPE_DIGIT = static_cast<wctype_t>(5);
-static constexpr wctype_t WCTYPE_GRAPH = static_cast<wctype_t>(6);
-static constexpr wctype_t WCTYPE_LOWER = static_cast<wctype_t>(7);
-static constexpr wctype_t WCTYPE_PRINT = static_cast<wctype_t>(8);
-static constexpr wctype_t WCTYPE_PUNCT = static_cast<wctype_t>(9);
-static constexpr wctype_t WCTYPE_SPACE = static_cast<wctype_t>(10);
-static constexpr wctype_t WCTYPE_UPPER = static_cast<wctype_t>(11);
-static constexpr wctype_t WCTYPE_XDIGIT = static_cast<wctype_t>(12);
-
-TEST(LlvmLibciswctype, SimpleTest) {
-  using LIBC_NAMESPACE::iswctype;
-
-  // alnum
-  EXPECT_NE(iswctype('a', WCTYPE_ALNUM), 0);
-  EXPECT_NE(iswctype('Z', WCTYPE_ALNUM), 0);
-  EXPECT_NE(iswctype('5', WCTYPE_ALNUM), 0);
-  EXPECT_EQ(iswctype('!', WCTYPE_ALNUM), 0);
-
-  // alpha
-  EXPECT_NE(iswctype('a', WCTYPE_ALPHA), 0);
-  EXPECT_NE(iswctype('Z', WCTYPE_ALPHA), 0);
-  EXPECT_EQ(iswctype('1', WCTYPE_ALPHA), 0);
-  EXPECT_EQ(iswctype(' ', WCTYPE_ALPHA), 0);
-
-  // blank
-  EXPECT_NE(iswctype(' ', WCTYPE_BLANK), 0);
-  EXPECT_NE(iswctype('\t', WCTYPE_BLANK), 0);
-  EXPECT_EQ(iswctype('\n', WCTYPE_BLANK), 0);
-  EXPECT_EQ(iswctype('A', WCTYPE_BLANK), 0);
-
-  // cntrl
-  EXPECT_NE(iswctype('\0', WCTYPE_CNTRL), 0);
-  EXPECT_NE(iswctype('\n', WCTYPE_CNTRL), 0);
-  EXPECT_NE(iswctype(0x7f, WCTYPE_CNTRL), 0);
-  EXPECT_EQ(iswctype('A', WCTYPE_CNTRL), 0);
-
-  // digit
-  EXPECT_NE(iswctype('0', WCTYPE_DIGIT), 0);
-  EXPECT_NE(iswctype('9', WCTYPE_DIGIT), 0);
-  EXPECT_EQ(iswctype('a', WCTYPE_DIGIT), 0);
-  EXPECT_EQ(iswctype(' ', WCTYPE_DIGIT), 0);
-
-  // graph
-  EXPECT_NE(iswctype('A', WCTYPE_GRAPH), 0);
-  EXPECT_NE(iswctype('1', WCTYPE_GRAPH), 0);
-  EXPECT_NE(iswctype('!', WCTYPE_GRAPH), 0);
-  EXPECT_EQ(iswctype(' ', WCTYPE_GRAPH), 0);
-
-  // lower
-  EXPECT_NE(iswctype('a', WCTYPE_LOWER), 0);
-  EXPECT_NE(iswctype('z', WCTYPE_LOWER), 0);
-  EXPECT_EQ(iswctype('A', WCTYPE_LOWER), 0);
-  EXPECT_EQ(iswctype('1', WCTYPE_LOWER), 0);
-
-  // print
-  EXPECT_NE(iswctype(' ', WCTYPE_PRINT), 0);
-  EXPECT_NE(iswctype('A', WCTYPE_PRINT), 0);
-  EXPECT_NE(iswctype('~', WCTYPE_PRINT), 0);
-  EXPECT_EQ(iswctype('\n', WCTYPE_PRINT), 0);
-
-  // punct
-  EXPECT_NE(iswctype('!', WCTYPE_PUNCT), 0);
-  EXPECT_NE(iswctype('?', WCTYPE_PUNCT), 0);
-  EXPECT_EQ(iswctype('a', WCTYPE_PUNCT), 0);
-  EXPECT_EQ(iswctype('1', WCTYPE_PUNCT), 0);
-
-  // space
-  EXPECT_NE(iswctype(' ', WCTYPE_SPACE), 0);
-  EXPECT_NE(iswctype('\t', WCTYPE_SPACE), 0);
-  EXPECT_NE(iswctype('\n', WCTYPE_SPACE), 0);
-  EXPECT_EQ(iswctype('A', WCTYPE_SPACE), 0);
-
-  // upper
-  EXPECT_NE(iswctype('A', WCTYPE_UPPER), 0);
-  EXPECT_NE(iswctype('Z', WCTYPE_UPPER), 0);
-  EXPECT_EQ(iswctype('a', WCTYPE_UPPER), 0);
-  EXPECT_EQ(iswctype('1', WCTYPE_UPPER), 0);
-
-  // xdigit
-  EXPECT_NE(iswctype('0', WCTYPE_XDIGIT), 0);
-  EXPECT_NE(iswctype('9', WCTYPE_XDIGIT), 0);
-  EXPECT_NE(iswctype('a', WCTYPE_XDIGIT), 0);
-  EXPECT_NE(iswctype('F', WCTYPE_XDIGIT), 0);
-  EXPECT_EQ(iswctype('g', WCTYPE_XDIGIT), 0);
-  EXPECT_EQ(iswctype('?', WCTYPE_XDIGIT), 0);
-
-  // invalid descriptor
-  EXPECT_EQ(iswctype('a', WCTYPE_INVALID), 0);
-  EXPECT_EQ(iswctype('a', static_cast<wctype_t>(999)), 0);
+TEST(LlvmLibciswctype, Alnum) {
+  const auto desc = LIBC_NAMESPACE::wctype("alnum");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('a', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('Z', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('5', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('!', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(' ', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('\n', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Alpha) {
+  const auto desc = LIBC_NAMESPACE::wctype("alpha");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('a', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('Z', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('1', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(' ', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('_', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Blank) {
+  const auto desc = LIBC_NAMESPACE::wctype("blank");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(' ', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('\t', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('\n', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('\r', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('A', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Cntrl) {
+  const auto desc = LIBC_NAMESPACE::wctype("cntrl");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('\0', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('\t', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('\n', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('\r', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(0x1f, desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(0x7f, desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('A', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(' ', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Digit) {
+  const auto desc = LIBC_NAMESPACE::wctype("digit");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('0', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('9', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('a', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(' ', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('/', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(':', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Graph) {
+  const auto desc = LIBC_NAMESPACE::wctype("graph");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('A', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('1', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('!', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('~', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(' ', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('\n', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('\t', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Lower) {
+  const auto desc = LIBC_NAMESPACE::wctype("lower");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('a', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('z', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('A', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('1', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('_', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Print) {
+  const auto desc = LIBC_NAMESPACE::wctype("print");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(' ', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('A', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('0', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('~', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('\n', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('\t', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('\0', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Punct) {
+  const auto desc = LIBC_NAMESPACE::wctype("punct");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('!', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('?', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('_', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('[', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('a', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('1', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(' ', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Space) {
+  const auto desc = LIBC_NAMESPACE::wctype("space");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype(' ', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('\t', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('\n', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('\v', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('\f', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('\r', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('A', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('1', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('!', desc), 0);
+}
+
+TEST(LlvmLibciswctype, Upper) {
+  const auto desc = LIBC_NAMESPACE::wctype("upper");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('A', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('Z', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('a', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('1', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('_', desc), 0);
+}
+
+TEST(LlvmLibciswctype, XDigit) {
+  const auto desc = LIBC_NAMESPACE::wctype("xdigit");
+  ASSERT_NE(desc, static_cast<wctype_t>(0));
+
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('0', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('9', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('a', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('f', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('A', desc), 0);
+  EXPECT_NE(LIBC_NAMESPACE::iswctype('F', desc), 0);
+
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('g', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('G', desc), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('?', desc), 0);
+}
+
+TEST(LlvmLibciswctype, InvalidDescriptor) {
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('a', 0), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype('0', 0), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::iswctype(' ', 0), 0);
 }
diff --git a/libc/test/src/wctype/wctype_test.cpp b/libc/test/src/wctype/wctype_test.cpp
index 22a3f6d1e7e2e..e4aa1bb6694d6 100644
--- a/libc/test/src/wctype/wctype_test.cpp
+++ b/libc/test/src/wctype/wctype_test.cpp
@@ -1,4 +1,4 @@
-//===-- Unittests for wctype --------------------------------------------===//
+//===-- Unittests for wctype ----------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -10,54 +10,26 @@
 
 #include "test/UnitTest/Test.h"
 
-// wctype descriptors (must match implementation)
-static constexpr wctype_t WCTYPE_INVALID = static_cast<wctype_t>(0);
-static constexpr wctype_t WCTYPE_ALNUM = static_cast<wctype_t>(1);
-static constexpr wctype_t WCTYPE_ALPHA = static_cast<wctype_t>(2);
-static constexpr wctype_t WCTYPE_BLANK = static_cast<wctype_t>(3);
-static constexpr wctype_t WCTYPE_CNTRL = static_cast<wctype_t>(4);
-static constexpr wctype_t WCTYPE_DIGIT = static_cast<wctype_t>(5);
-static constexpr wctype_t WCTYPE_GRAPH = static_cast<wctype_t>(6);
-static constexpr wctype_t WCTYPE_LOWER = static_cast<wctype_t>(7);
-static constexpr wctype_t WCTYPE_PRINT = static_cast<wctype_t>(8);
-static constexpr wctype_t WCTYPE_PUNCT = static_cast<wctype_t>(9);
-static constexpr wctype_t WCTYPE_SPACE = static_cast<wctype_t>(10);
-static constexpr wctype_t WCTYPE_UPPER = static_cast<wctype_t>(11);
-static constexpr wctype_t WCTYPE_XDIGIT = static_cast<wctype_t>(12);
-
-TEST(LlvmLibcwctype, SimpleTest) {
-  using LIBC_NAMESPACE::wctype;
-
-  auto alnum = wctype("alnum");
-  auto alpha = wctype("alpha");
-  auto blank = wctype("blank");
-  auto cntrl = wctype("cntrl");
-  auto digit = wctype("digit");
-  auto graph = wctype("graph");
-  auto lower = wctype("lower");
-  auto print = wctype("print");
-  auto punct = wctype("punct");
-  auto space = wctype("space");
-  auto upper = wctype("upper");
-  auto xdigit = wctype("xdigit");
-
-  // valid descriptors should be nonzero
-  EXPECT_EQ(alnum, WCTYPE_ALNUM);
-  EXPECT_EQ(alpha, WCTYPE_ALPHA);
-  EXPECT_EQ(blank, WCTYPE_BLANK);
-  EXPECT_EQ(cntrl, WCTYPE_CNTRL);
-  EXPECT_EQ(digit, WCTYPE_DIGIT);
-  EXPECT_EQ(graph, WCTYPE_GRAPH);
-  EXPECT_EQ(lower, WCTYPE_LOWER);
-  EXPECT_EQ(print, WCTYPE_PRINT);
-  EXPECT_EQ(punct, WCTYPE_PUNCT);
-  EXPECT_EQ(space, WCTYPE_SPACE);
-  EXPECT_EQ(upper, WCTYPE_UPPER);
-  EXPECT_EQ(xdigit, WCTYPE_XDIGIT);
+TEST(LlvmLibcwctype, ValidPropertiesReturnNonZero) {
+  EXPECT_NE(LIBC_NAMESPACE::wctype("alnum"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("alpha"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("blank"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("cntrl"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("digit"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("graph"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("lower"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("print"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("punct"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("space"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("upper"), static_cast<wctype_t>(0));
+  EXPECT_NE(LIBC_NAMESPACE::wctype("xdigit"), static_cast<wctype_t>(0));
+}
 
-  // invalid properties should return zero
-  EXPECT_EQ(wctype(""), WCTYPE_INVALID);
-  EXPECT_EQ(wctype("invalid"), WCTYPE_INVALID);
-  EXPECT_EQ(wctype("Alpha"), WCTYPE_INVALID);
-  EXPECT_EQ(wctype("unknown"), WCTYPE_INVALID);
+TEST(LlvmLibcwctype, InvalidPropertiesReturnZero) {
+  EXPECT_EQ(LIBC_NAMESPACE::wctype(nullptr), static_cast<wctype_t>(0));
+  EXPECT_EQ(LIBC_NAMESPACE::wctype(""), static_cast<wctype_t>(0));
+  EXPECT_EQ(LIBC_NAMESPACE::wctype("foo"), static_cast<wctype_t>(0));
+  EXPECT_EQ(LIBC_NAMESPACE::wctype("Alpha"), static_cast<wctype_t>(0));
+  EXPECT_EQ(LIBC_NAMESPACE::wctype("xdigit "), static_cast<wctype_t>(0));
+  EXPECT_EQ(LIBC_NAMESPACE::wctype(" alnum"), static_cast<wctype_t>(0));
 }



More information about the libc-commits mailing list