public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb,  char8_t
@ 2022-01-08  0:39 Tom Honermann
  2022-01-11  0:53 ` Joseph Myers
  0 siblings, 1 reply; 27+ messages in thread
From: Tom Honermann @ 2022-01-08  0:39 UTC (permalink / raw)
  To: libc-alpha

[-- Attachment #1: Type: text/plain, Size: 831 bytes --]

This patch provides implementations for the mbrtoc8 and c8rtomb 
functions adopted for C++20 via WG21 P0482R6 [1] and proposed for C2X 
via WG14 N2653 [2]. It also provides the char8_t typedef from WG14 N2653 
[2].

The mbrtoc8 and c8rtomb functions are declared in uchar.h if either of 
the C++20 __cpp_char8_t or _GNU_SOURCE feature test macros are defined.

The char8_t typedef is declared in uchar.h if _GNU_SOURCE is defined and 
__cpp_char8_t is not defined (if __cpp_char8_t is defined, then char8_t 
is a builtin type).

Tested on Linux x86_64.

Tom.

[1]: WG21 P0482R6
      "char8_t: A type for UTF-8 characters and strings (Revision 6)"
      https://wg21.link/p0482r6

[2]: WG14 N2653
      "char8_t: A type for UTF-8 characters and strings (Revision 1)"
      http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2653.htm

[-- Attachment #2: n2653-2.patch --]
[-- Type: text/x-patch, Size: 27563 bytes --]

commit 0710b1004c1eb151d739c73090c4eab81e454eb1
Author: Tom Honermann <tom@honermann.net>
Date:   Wed Jan 5 18:42:03 2022 -0500

    Implement mbrtoc8(), c8rtomb(), and the char8_t typedef.
    
    This change provides implementations for the mbrtoc8 and c8rtomb
    functions adopted for C++20 via WG21 P0482R6 and proposed for C2X
    via WG14 N2653.  It also provides the char8_t typedef from N2653.
    
    The mbrtoc8 and c8rtomb functions are declared in uchar.h if
    either of the C++20 __cpp_char8_t feature test macro or the
    _GNU_SOURCE macro are defined.
    
    The char8_t typedef is declared in uchar.h if _GNU_SOURCE is
    defined and __cpp_char8_t is not defined (if __cpp_char8_t is
    defined, then char8_t is a builtin type).

diff --git a/NEWS b/NEWS
index 4762bfcc4e..ccb22553f2 100644
--- a/NEWS
+++ b/NEWS
@@ -237,6 +237,14 @@ Major new features:
 * The audit libraries will avoid unnecessary slowdown if it is not required
   PLT tracking (by not implementing the la_pltenter or la_pltexit callbacks).
 
+* The mbrtoc8 and c8rtomb functions are added for implementation of the
+  C++20 P0482R6 and C2X N2653 proposals.  These functions perform conversions
+  between multibyte sequences and the UTF-8 character encoding.  A char8_t
+  typedef is added for the C2X N2653 proposal.  The functions are declared
+  in uchar.h if the C++20 __cpp_char8_t feature test macro or _GNU_SOURCE
+  macro is defined.  The char8_t typedef is declared in uchar.h if _GNU_SOURCE
+  is defined and __cpp_char8_t is not defined.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The function pthread_mutex_consistent_np has been deprecated; programs
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index ecf8c0992e..d1188a83a5 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2287,7 +2287,9 @@ GLIBC_2.34 shm_unlink F
 GLIBC_2.34 timespec_getres F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
 GLIBC_2.35 close_range F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index fed942ed4b..35586c023f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2613,4 +2613,6 @@ GLIBC_2.34 tss_delete F
 GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
+GLIBC_2.35 c8rtomb F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 2867932704..4969c57a37 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2711,6 +2711,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 239db7bab0..fccd1f8662 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2375,3 +2375,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index bc79dcfe8a..1cb2d4fd66 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -493,6 +493,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 614607fd6b..b36859f8e1 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -490,6 +490,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 2b61543f0d..4f7828d822 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2649,3 +2649,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 6b3cb1adb4..d59accc822 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2598,6 +2598,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 7f608c1b64..37a065f555 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2782,6 +2782,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 865deec43f..69839c86fd 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2549,6 +2549,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index a172d74632..b8418d612c 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -494,6 +494,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 174e9c7739..8cfbb5f235 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2725,6 +2725,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index d042be1369..0d729329aa 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2698,3 +2698,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 332da62de2..3980c6df0d 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2695,3 +2695,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 2d6ec0d0e8..f8c2087559 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2690,6 +2690,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 6c5befa72b..ce87791286 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2688,6 +2688,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 5fb24c97e1..ee547ceb78 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2696,6 +2696,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index f4f29fc15e..4c558a283e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2600,6 +2600,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 2e7300cd05..234ab84125 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2737,3 +2737,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 129a2f16a7..e383bac9bd 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2752,6 +2752,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 7e23226779..ddbcb3e085 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2785,6 +2785,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 6f97392b70..daaa374fa0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2508,6 +2508,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 29058a041a..a24f6b4751 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2810,3 +2810,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index d2924766d2..3dc0e04f64 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2377,3 +2377,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index b770e05da3..af3bbfc83b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2577,3 +2577,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index bed3433a2b..4025a7f913 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2750,6 +2750,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 4f1a143da5..55febf9508 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2545,6 +2545,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 92c8dec8ec..cc37920ee2 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2605,6 +2605,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 263da58cb7..298654b119 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2602,6 +2602,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 0171efe7db..ed214429f0 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2745,6 +2745,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 7f8d45f362..0dcc3674eb 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2572,6 +2572,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index c2f1a8ecc6..ec4e0b73e4 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2523,6 +2523,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 8b43acf100..b60cd45821 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2629,3 +2629,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
index 3a3be9cd95..390d94bbb2 100644
--- a/wcsmbs/Makefile
+++ b/wcsmbs/Makefile
@@ -42,7 +42,7 @@ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
 	    wcsmbsload mbsrtowcs_l \
 	    isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf \
 	    isoc99_swscanf isoc99_vswscanf \
-	    mbrtoc16 c16rtomb mbrtoc32 c32rtomb
+	    mbrtoc8 c8rtomb mbrtoc16 c16rtomb mbrtoc32 c32rtomb
 
 strop-tests :=  wcscmp wcsncmp wmemcmp wcslen wcschr wcsrchr wcscpy wcsnlen \
 		wcpcpy wcsncpy wcpncpy wcscat wcsncat wcschrnul wcsspn wcspbrk \
diff --git a/wcsmbs/Versions b/wcsmbs/Versions
index 0b31c1b940..d578518fad 100644
--- a/wcsmbs/Versions
+++ b/wcsmbs/Versions
@@ -49,4 +49,7 @@ libc {
     wcstof32; wcstof64; wcstof32x;
     wcstof32_l; wcstof64_l; wcstof32x_l;
   }
+  GLIBC_2.35 {
+    c8rtomb; mbrtoc8;
+  }
 }
diff --git a/wcsmbs/c8rtomb.c b/wcsmbs/c8rtomb.c
new file mode 100644
index 0000000000..8a5ffeab23
--- /dev/null
+++ b/wcsmbs/c8rtomb.c
@@ -0,0 +1,132 @@
+/* UTF-8 to multibyte conversion.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <uchar.h>
+#include <wchar.h>
+
+
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
+
+size_t
+c8rtomb (char *s, char8_t c8, mbstate_t *ps)
+{
+  /* This implementation depends on the converter invoked by wcrtomb not
+     needing to retain state in either the top most bit of ps->__count or
+     in ps->__value between invocations.  This implementation uses the
+     top most bit of ps->__count to indicate that trailing code units are
+     expected and uses ps->__value to store previously seen code units.  */
+
+  wchar_t wc;
+
+  if (ps == NULL)
+    ps = &state;
+
+  if (s == NULL)
+    {
+      /* if 's' is a null pointer, behave as if u8'\0' was passed as 'c8'.  If
+         this occurs for an incomplete code unit sequence, then an error will
+         be reported below.  */
+      c8 = u8""[0];
+    }
+
+  if (! (ps->__count & 0x80000000))
+    {
+      /* Initial state.  */
+      if ((c8 >= 0x80 && c8 <= 0xC1) || c8 >= 0xF5)
+	{
+	  /* An invalid lead code unit.  */
+	  __set_errno (EILSEQ);
+	  return -1;
+	}
+      if (c8 >= 0xC2)
+	{
+	  /* A valid lead code unit.  */
+	  ps->__count |= 0x80000000;
+	  ps->__value.__wchb[0] = c8;
+          ps->__value.__wchb[3] = 1;
+	  return 0;
+	}
+      /* A single byte (ASCII) code unit.  */
+      wc = c8;
+    }
+  else
+    {
+      char8_t cu1 = ps->__value.__wchb[0];
+      if (ps->__value.__wchb[3] == 1)
+	{
+	  /* A single lead code unit was previously seen.  */
+	  if ((c8 < 0x80 || c8 > 0xBF) ||
+               (cu1 == 0xE0 && c8 < 0xA0) ||
+               (cu1 == 0xED && c8 > 0x9F) ||
+               (cu1 == 0xF0 && c8 < 0x90) ||
+               (cu1 == 0xF4 && c8 > 0x8F))
+	    {
+	      /* An invalid second code unit.  */
+	      __set_errno (EILSEQ);
+	      return -1;
+	    }
+	  if (cu1 >= 0xE0)
+	    {
+	      /* A three or four code unit sequence.  */
+	      ps->__value.__wchb[1] = c8;
+	      ++ps->__value.__wchb[3];
+	      return 0;
+	    }
+	  wc = ((cu1 & 0x1F) << 6) +
+	       (c8 & 0x3F);
+	}
+      else
+	{
+	  char8_t cu2 = ps->__value.__wchb[1];
+	  /* A three or four byte code unit sequence.  */
+	  if (c8 < 0x80 || c8 > 0xBF)
+	    {
+	      /* An invalid third or fourth code unit.  */
+	      __set_errno (EILSEQ);
+	      return -1;
+	    }
+	  if (ps->__value.__wchb[3] == 2 && cu1 >= 0xF0)
+	    {
+	      /* A four code unit sequence.  */
+	      ps->__value.__wchb[2] = c8;
+	      ++ps->__value.__wchb[3];
+	      return 0;
+	    }
+	  if (cu1 < 0xF0)
+	    {
+	      wc = ((cu1 & 0x0F) << 12) +
+		   ((cu2 & 0x3F) << 6) +
+		   (c8 & 0x3F);
+	    }
+	  else
+	    {
+	      char8_t cu3 = ps->__value.__wchb[2];
+	      wc = ((cu1 & 0x07) << 18) +
+		   ((cu2 & 0x3F) << 12) +
+		   ((cu3 & 0x3F) << 6) +
+		   (c8 & 0x3F);
+	    }
+	}
+      ps->__count &= 0x7fffffff;
+      ps->__value.__wch = 0;
+    }
+
+  return wcrtomb (s, wc, ps);
+}
diff --git a/wcsmbs/mbrtoc8.c b/wcsmbs/mbrtoc8.c
new file mode 100644
index 0000000000..8ca457088d
--- /dev/null
+++ b/wcsmbs/mbrtoc8.c
@@ -0,0 +1,126 @@
+/* Multibyte to UTF-8 conversion.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <gconv.h>
+#include <uchar.h>
+#include <wcsmbsload.h>
+
+#include <sysdep.h>
+
+#ifndef EILSEQ
+# define EILSEQ EINVAL
+#endif
+
+
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
+
+size_t
+mbrtoc8 (char8_t *pc8, const char *s, size_t n, mbstate_t *ps)
+{
+  /* This implementation depends on the converter invoked by mbrtowc() not
+     needing to retain state in either the top most bit of ps->__count or
+     in ps->__value between invocations.  This implementation uses the
+     top most bit of ps->__count to indicate that trailing code units are
+     yet to be written and uses ps->__value to store those code units.  */
+
+  if (ps == NULL)
+    ps = &state;
+
+  /* If state indicates that trailing code units are yet to be written, write
+     those first regardless of whether 's' is a null pointer.  */
+  if (ps->__count & 0x80000000)
+    {
+      /* ps->__value.__wchb[3] stores the index of the next code unit to
+         write.  Code units are stored in reverse order.  */
+      size_t i = ps->__value.__wchb[3];
+      if (pc8 != NULL)
+	{
+	  *pc8 = ps->__value.__wchb[i];
+	}
+      if (i == 0)
+	{
+	  ps->__count &= 0x7fffffff;
+	  ps->__value.__wch = 0;
+	}
+      else
+	--ps->__value.__wchb[3];
+      return -3;
+    }
+
+  if (s == NULL)
+    {
+      /* if 's' is a null pointer, behave as if a null pointer was passed for
+         'pc8', an empty string was passed for 's', and 1 passed for 'n'.  */
+      pc8 = NULL;
+      s = "";
+      n = 1;
+    }
+
+  wchar_t wc;
+  size_t result;
+
+  result = mbrtowc(&wc, s, n, ps);
+  if (result <= n)
+    {
+      if (wc <= 0x7F)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = wc;
+	}
+      else if (wc <= 0x7FF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xC0 + ((wc >> 6) & 0x1F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 0;
+	  ps->__count |= 0x80000000;
+	}
+      else if (wc <= 0xFFFF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xE0 + ((wc >> 12) & 0x0F);
+	  ps->__value.__wchb[1] = 0x80 + ((wc >> 6) & 0x3F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 1;
+	  ps->__count |= 0x80000000;
+	}
+      else if (wc <= 0x10FFFF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xF0 + ((wc >> 18) & 0x07);
+	  ps->__value.__wchb[2] = 0x80 + ((wc >> 12) & 0x3F);
+	  ps->__value.__wchb[1] = 0x80 + ((wc >> 6) & 0x3F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 2;
+	  ps->__count |= 0x80000000;
+	}
+    }
+  if (result == 0 && wc != 0)
+    {
+      /* mbrtowc() never returns -3.  When a MB sequence converts to multiple
+         WCs, no input is consumed when writing the subsequent WCs resulting
+         in a result of 0 even if a null character wasn't written.  */
+      result = -3;
+    }
+
+  return result;
+}
diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
index 6020f66cf6..2f15c6f74d 100644
--- a/wcsmbs/uchar.h
+++ b/wcsmbs/uchar.h
@@ -31,6 +31,13 @@
 #include <bits/types.h>
 #include <bits/types/mbstate_t.h>
 
+/* Declare the char8_t typedef in _GNU_SOURCE mode, but only if the C++
+   __cpp_char8_t feature test macro is not defined.  */
+#if defined __USE_GNU && !defined __cpp_char8_t
+/* Define the 8-bit character type.  */
+typedef unsigned char char8_t;
+#endif
+
 #ifndef __USE_ISOCXX11
 /* Define the 16-bit and 32-bit character types.  */
 typedef __uint_least16_t char16_t;
@@ -40,6 +47,20 @@ typedef __uint_least32_t char32_t;
 
 __BEGIN_DECLS
 
+/* Declare mbrtoc8() and c8rtomb() in _GNU_SOURCE mode or if the C++
+   __cpp_char8_t feature test macro is defined.  */
+#if defined __USE_GNU || defined __cpp_char8_t
+/* Write char8_t representation of multibyte character pointed
+   to by S to PC8.  */
+extern size_t mbrtoc8  (char8_t *__restrict __pc8,
+			const char *__restrict __s, size_t __n,
+			mbstate_t *__restrict __p) __THROW;
+
+/* Write multibyte representation of char8_t C8 to S.  */
+extern size_t c8rtomb  (char *__restrict __s, char8_t __c8,
+			mbstate_t *__restrict __ps) __THROW;
+#endif
+
 /* Write char16_t representation of multibyte character pointed
    to by S to PC16.  */
 extern size_t mbrtoc16 (char16_t *__restrict __pc16,

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb,  char8_t
  2022-01-08  0:39 [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t Tom Honermann
@ 2022-01-11  0:53 ` Joseph Myers
  2022-01-11 19:23   ` Tom Honermann
  0 siblings, 1 reply; 27+ messages in thread
From: Joseph Myers @ 2022-01-11  0:53 UTC (permalink / raw)
  To: Tom Honermann; +Cc: libc-alpha

This patch is adding a NEWS entry for 2.34.  Since the next release is 
2.35, it should add an entry there instead (except we've started release 
slush for 2.35, so it might be better to aim this at 2.36).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-01-11  0:53 ` Joseph Myers
@ 2022-01-11 19:23   ` Tom Honermann
  2022-01-20 23:17     ` Tom Honermann
  0 siblings, 1 reply; 27+ messages in thread
From: Tom Honermann @ 2022-01-11 19:23 UTC (permalink / raw)
  To: Joseph Myers; +Cc: libc-alpha

[-- Attachment #1: Type: text/plain, Size: 497 bytes --]

On 1/10/22 7:53 PM, Joseph Myers wrote:
> This patch is adding a NEWS entry for 2.34.  Since the next release is
> 2.35, it should add an entry there instead (except we've started release
> slush for 2.35, so it might be better to aim this at 2.36).
>
Thank you for spotting that; this was due to a bad merge conflict 
resolution on my part. Fixed patch attached.

If this needs to wait for 2.36, I understand, but I would love to have 
this in 2.35 to close out this gap in C++20 support.

Tom.


[-- Attachment #2: n2653-2.patch --]
[-- Type: text/x-patch, Size: 27486 bytes --]

commit 935e33e5c7f4bff05c37433c2f6c50eb33074d63
Author: Tom Honermann <tom@honermann.net>
Date:   Wed Jan 5 18:42:03 2022 -0500

    Implement mbrtoc8(), c8rtomb(), and the char8_t typedef.
    
    This change provides implementations for the mbrtoc8 and c8rtomb
    functions adopted for C++20 via WG21 P0482R6 and proposed for C2X
    via WG14 N2653.  It also provides the char8_t typedef from N2653.
    
    The mbrtoc8 and c8rtomb functions are declared in uchar.h if
    either of the C++20 __cpp_char8_t feature test macro or the
    _GNU_SOURCE macro are defined.
    
    The char8_t typedef is declared in uchar.h if _GNU_SOURCE is
    defined and __cpp_char8_t is not defined (if __cpp_char8_t is
    defined, then char8_t is a builtin type).

diff --git a/NEWS b/NEWS
index 4762bfcc4e..3d7f619737 100644
--- a/NEWS
+++ b/NEWS
@@ -106,6 +106,14 @@ Major new features:
   can use it to efficiently locate unwinding information for a code
   address.
 
+* The mbrtoc8 and c8rtomb functions are added for implementation of the
+  C++20 P0482R6 and C2X N2653 proposals.  These functions perform conversions
+  between multibyte sequences and the UTF-8 character encoding.  A char8_t
+  typedef is added for the C2X N2653 proposal.  The functions are declared
+  in uchar.h if the C++20 __cpp_char8_t feature test macro or _GNU_SOURCE
+  macro is defined.  The char8_t typedef is declared in uchar.h if _GNU_SOURCE
+  is defined and __cpp_char8_t is not defined.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * On x86-64, the LD_PREFER_MAP_32BIT_EXEC environment variable support
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index ecf8c0992e..d1188a83a5 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2287,7 +2287,9 @@ GLIBC_2.34 shm_unlink F
 GLIBC_2.34 timespec_getres F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
 GLIBC_2.35 close_range F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index fed942ed4b..35586c023f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2613,4 +2613,6 @@ GLIBC_2.34 tss_delete F
 GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
+GLIBC_2.35 c8rtomb F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 2867932704..4969c57a37 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2711,6 +2711,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 239db7bab0..fccd1f8662 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2375,3 +2375,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index bc79dcfe8a..1cb2d4fd66 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -493,6 +493,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 614607fd6b..b36859f8e1 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -490,6 +490,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 2b61543f0d..4f7828d822 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2649,3 +2649,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 6b3cb1adb4..d59accc822 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2598,6 +2598,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 7f608c1b64..37a065f555 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2782,6 +2782,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 865deec43f..69839c86fd 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2549,6 +2549,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index a172d74632..b8418d612c 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -494,6 +494,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 174e9c7739..8cfbb5f235 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2725,6 +2725,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index d042be1369..0d729329aa 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2698,3 +2698,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 332da62de2..3980c6df0d 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2695,3 +2695,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 2d6ec0d0e8..f8c2087559 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2690,6 +2690,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 6c5befa72b..ce87791286 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2688,6 +2688,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 5fb24c97e1..ee547ceb78 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2696,6 +2696,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index f4f29fc15e..4c558a283e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2600,6 +2600,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 2e7300cd05..234ab84125 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2737,3 +2737,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 129a2f16a7..e383bac9bd 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2752,6 +2752,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 7e23226779..ddbcb3e085 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2785,6 +2785,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 6f97392b70..daaa374fa0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2508,6 +2508,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 29058a041a..a24f6b4751 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2810,3 +2810,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index d2924766d2..3dc0e04f64 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2377,3 +2377,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index b770e05da3..af3bbfc83b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2577,3 +2577,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index bed3433a2b..4025a7f913 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2750,6 +2750,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 4f1a143da5..55febf9508 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2545,6 +2545,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 92c8dec8ec..cc37920ee2 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2605,6 +2605,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 263da58cb7..298654b119 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2602,6 +2602,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 0171efe7db..ed214429f0 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2745,6 +2745,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 7f8d45f362..0dcc3674eb 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2572,6 +2572,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index c2f1a8ecc6..ec4e0b73e4 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2523,6 +2523,8 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 8b43acf100..b60cd45821 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2629,3 +2629,5 @@ GLIBC_2.34 tss_get F
 GLIBC_2.34 tss_set F
 GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 c8rtomb F
+GLIBC_2.35 mbrtoc8 F
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
index 3a3be9cd95..390d94bbb2 100644
--- a/wcsmbs/Makefile
+++ b/wcsmbs/Makefile
@@ -42,7 +42,7 @@ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
 	    wcsmbsload mbsrtowcs_l \
 	    isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf \
 	    isoc99_swscanf isoc99_vswscanf \
-	    mbrtoc16 c16rtomb mbrtoc32 c32rtomb
+	    mbrtoc8 c8rtomb mbrtoc16 c16rtomb mbrtoc32 c32rtomb
 
 strop-tests :=  wcscmp wcsncmp wmemcmp wcslen wcschr wcsrchr wcscpy wcsnlen \
 		wcpcpy wcsncpy wcpncpy wcscat wcsncat wcschrnul wcsspn wcspbrk \
diff --git a/wcsmbs/Versions b/wcsmbs/Versions
index 0b31c1b940..d578518fad 100644
--- a/wcsmbs/Versions
+++ b/wcsmbs/Versions
@@ -49,4 +49,7 @@ libc {
     wcstof32; wcstof64; wcstof32x;
     wcstof32_l; wcstof64_l; wcstof32x_l;
   }
+  GLIBC_2.35 {
+    c8rtomb; mbrtoc8;
+  }
 }
diff --git a/wcsmbs/c8rtomb.c b/wcsmbs/c8rtomb.c
new file mode 100644
index 0000000000..8a5ffeab23
--- /dev/null
+++ b/wcsmbs/c8rtomb.c
@@ -0,0 +1,132 @@
+/* UTF-8 to multibyte conversion.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <uchar.h>
+#include <wchar.h>
+
+
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
+
+size_t
+c8rtomb (char *s, char8_t c8, mbstate_t *ps)
+{
+  /* This implementation depends on the converter invoked by wcrtomb not
+     needing to retain state in either the top most bit of ps->__count or
+     in ps->__value between invocations.  This implementation uses the
+     top most bit of ps->__count to indicate that trailing code units are
+     expected and uses ps->__value to store previously seen code units.  */
+
+  wchar_t wc;
+
+  if (ps == NULL)
+    ps = &state;
+
+  if (s == NULL)
+    {
+      /* if 's' is a null pointer, behave as if u8'\0' was passed as 'c8'.  If
+         this occurs for an incomplete code unit sequence, then an error will
+         be reported below.  */
+      c8 = u8""[0];
+    }
+
+  if (! (ps->__count & 0x80000000))
+    {
+      /* Initial state.  */
+      if ((c8 >= 0x80 && c8 <= 0xC1) || c8 >= 0xF5)
+	{
+	  /* An invalid lead code unit.  */
+	  __set_errno (EILSEQ);
+	  return -1;
+	}
+      if (c8 >= 0xC2)
+	{
+	  /* A valid lead code unit.  */
+	  ps->__count |= 0x80000000;
+	  ps->__value.__wchb[0] = c8;
+          ps->__value.__wchb[3] = 1;
+	  return 0;
+	}
+      /* A single byte (ASCII) code unit.  */
+      wc = c8;
+    }
+  else
+    {
+      char8_t cu1 = ps->__value.__wchb[0];
+      if (ps->__value.__wchb[3] == 1)
+	{
+	  /* A single lead code unit was previously seen.  */
+	  if ((c8 < 0x80 || c8 > 0xBF) ||
+               (cu1 == 0xE0 && c8 < 0xA0) ||
+               (cu1 == 0xED && c8 > 0x9F) ||
+               (cu1 == 0xF0 && c8 < 0x90) ||
+               (cu1 == 0xF4 && c8 > 0x8F))
+	    {
+	      /* An invalid second code unit.  */
+	      __set_errno (EILSEQ);
+	      return -1;
+	    }
+	  if (cu1 >= 0xE0)
+	    {
+	      /* A three or four code unit sequence.  */
+	      ps->__value.__wchb[1] = c8;
+	      ++ps->__value.__wchb[3];
+	      return 0;
+	    }
+	  wc = ((cu1 & 0x1F) << 6) +
+	       (c8 & 0x3F);
+	}
+      else
+	{
+	  char8_t cu2 = ps->__value.__wchb[1];
+	  /* A three or four byte code unit sequence.  */
+	  if (c8 < 0x80 || c8 > 0xBF)
+	    {
+	      /* An invalid third or fourth code unit.  */
+	      __set_errno (EILSEQ);
+	      return -1;
+	    }
+	  if (ps->__value.__wchb[3] == 2 && cu1 >= 0xF0)
+	    {
+	      /* A four code unit sequence.  */
+	      ps->__value.__wchb[2] = c8;
+	      ++ps->__value.__wchb[3];
+	      return 0;
+	    }
+	  if (cu1 < 0xF0)
+	    {
+	      wc = ((cu1 & 0x0F) << 12) +
+		   ((cu2 & 0x3F) << 6) +
+		   (c8 & 0x3F);
+	    }
+	  else
+	    {
+	      char8_t cu3 = ps->__value.__wchb[2];
+	      wc = ((cu1 & 0x07) << 18) +
+		   ((cu2 & 0x3F) << 12) +
+		   ((cu3 & 0x3F) << 6) +
+		   (c8 & 0x3F);
+	    }
+	}
+      ps->__count &= 0x7fffffff;
+      ps->__value.__wch = 0;
+    }
+
+  return wcrtomb (s, wc, ps);
+}
diff --git a/wcsmbs/mbrtoc8.c b/wcsmbs/mbrtoc8.c
new file mode 100644
index 0000000000..8ca457088d
--- /dev/null
+++ b/wcsmbs/mbrtoc8.c
@@ -0,0 +1,126 @@
+/* Multibyte to UTF-8 conversion.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <gconv.h>
+#include <uchar.h>
+#include <wcsmbsload.h>
+
+#include <sysdep.h>
+
+#ifndef EILSEQ
+# define EILSEQ EINVAL
+#endif
+
+
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
+
+size_t
+mbrtoc8 (char8_t *pc8, const char *s, size_t n, mbstate_t *ps)
+{
+  /* This implementation depends on the converter invoked by mbrtowc() not
+     needing to retain state in either the top most bit of ps->__count or
+     in ps->__value between invocations.  This implementation uses the
+     top most bit of ps->__count to indicate that trailing code units are
+     yet to be written and uses ps->__value to store those code units.  */
+
+  if (ps == NULL)
+    ps = &state;
+
+  /* If state indicates that trailing code units are yet to be written, write
+     those first regardless of whether 's' is a null pointer.  */
+  if (ps->__count & 0x80000000)
+    {
+      /* ps->__value.__wchb[3] stores the index of the next code unit to
+         write.  Code units are stored in reverse order.  */
+      size_t i = ps->__value.__wchb[3];
+      if (pc8 != NULL)
+	{
+	  *pc8 = ps->__value.__wchb[i];
+	}
+      if (i == 0)
+	{
+	  ps->__count &= 0x7fffffff;
+	  ps->__value.__wch = 0;
+	}
+      else
+	--ps->__value.__wchb[3];
+      return -3;
+    }
+
+  if (s == NULL)
+    {
+      /* if 's' is a null pointer, behave as if a null pointer was passed for
+         'pc8', an empty string was passed for 's', and 1 passed for 'n'.  */
+      pc8 = NULL;
+      s = "";
+      n = 1;
+    }
+
+  wchar_t wc;
+  size_t result;
+
+  result = mbrtowc(&wc, s, n, ps);
+  if (result <= n)
+    {
+      if (wc <= 0x7F)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = wc;
+	}
+      else if (wc <= 0x7FF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xC0 + ((wc >> 6) & 0x1F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 0;
+	  ps->__count |= 0x80000000;
+	}
+      else if (wc <= 0xFFFF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xE0 + ((wc >> 12) & 0x0F);
+	  ps->__value.__wchb[1] = 0x80 + ((wc >> 6) & 0x3F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 1;
+	  ps->__count |= 0x80000000;
+	}
+      else if (wc <= 0x10FFFF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xF0 + ((wc >> 18) & 0x07);
+	  ps->__value.__wchb[2] = 0x80 + ((wc >> 12) & 0x3F);
+	  ps->__value.__wchb[1] = 0x80 + ((wc >> 6) & 0x3F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 2;
+	  ps->__count |= 0x80000000;
+	}
+    }
+  if (result == 0 && wc != 0)
+    {
+      /* mbrtowc() never returns -3.  When a MB sequence converts to multiple
+         WCs, no input is consumed when writing the subsequent WCs resulting
+         in a result of 0 even if a null character wasn't written.  */
+      result = -3;
+    }
+
+  return result;
+}
diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
index 6020f66cf6..2f15c6f74d 100644
--- a/wcsmbs/uchar.h
+++ b/wcsmbs/uchar.h
@@ -31,6 +31,13 @@
 #include <bits/types.h>
 #include <bits/types/mbstate_t.h>
 
+/* Declare the char8_t typedef in _GNU_SOURCE mode, but only if the C++
+   __cpp_char8_t feature test macro is not defined.  */
+#if defined __USE_GNU && !defined __cpp_char8_t
+/* Define the 8-bit character type.  */
+typedef unsigned char char8_t;
+#endif
+
 #ifndef __USE_ISOCXX11
 /* Define the 16-bit and 32-bit character types.  */
 typedef __uint_least16_t char16_t;
@@ -40,6 +47,20 @@ typedef __uint_least32_t char32_t;
 
 __BEGIN_DECLS
 
+/* Declare mbrtoc8() and c8rtomb() in _GNU_SOURCE mode or if the C++
+   __cpp_char8_t feature test macro is defined.  */
+#if defined __USE_GNU || defined __cpp_char8_t
+/* Write char8_t representation of multibyte character pointed
+   to by S to PC8.  */
+extern size_t mbrtoc8  (char8_t *__restrict __pc8,
+			const char *__restrict __s, size_t __n,
+			mbstate_t *__restrict __p) __THROW;
+
+/* Write multibyte representation of char8_t C8 to S.  */
+extern size_t c8rtomb  (char *__restrict __s, char8_t __c8,
+			mbstate_t *__restrict __ps) __THROW;
+#endif
+
 /* Write char16_t representation of multibyte character pointed
    to by S to PC16.  */
 extern size_t mbrtoc16 (char16_t *__restrict __pc16,

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-01-11 19:23   ` Tom Honermann
@ 2022-01-20 23:17     ` Tom Honermann
  2022-01-21 20:01       ` Adhemerval Zanella
  0 siblings, 1 reply; 27+ messages in thread
From: Tom Honermann @ 2022-01-20 23:17 UTC (permalink / raw)
  To: Joseph Myers; +Cc: libc-alpha

On 1/11/22 2:23 PM, Tom Honermann via Libc-alpha wrote:
> On 1/10/22 7:53 PM, Joseph Myers wrote:
>> This patch is adding a NEWS entry for 2.34.  Since the next release is
>> 2.35, it should add an entry there instead (except we've started release
>> slush for 2.35, so it might be better to aim this at 2.36).
>>
> Thank you for spotting that; this was due to a bad merge conflict 
> resolution on my part. Fixed patch attached.
>
> If this needs to wait for 2.36, I understand, but I would love to have 
> this in 2.35 to close out this gap in C++20 support.

Any further comments on this patch series?

Tom.


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-01-20 23:17     ` Tom Honermann
@ 2022-01-21 20:01       ` Adhemerval Zanella
  2022-01-22 12:24         ` Tom Honermann
  0 siblings, 1 reply; 27+ messages in thread
From: Adhemerval Zanella @ 2022-01-21 20:01 UTC (permalink / raw)
  To: Tom Honermann, Joseph Myers; +Cc: libc-alpha



On 20/01/2022 20:17, Tom Honermann via Libc-alpha wrote:
> On 1/11/22 2:23 PM, Tom Honermann via Libc-alpha wrote:
>> On 1/10/22 7:53 PM, Joseph Myers wrote:
>>> This patch is adding a NEWS entry for 2.34.  Since the next release is
>>> 2.35, it should add an entry there instead (except we've started release
>>> slush for 2.35, so it might be better to aim this at 2.36).
>>>
>> Thank you for spotting that; this was due to a bad merge conflict resolution on my part. Fixed patch attached.
>>
>> If this needs to wait for 2.36, I understand, but I would love to have this in 2.35 to close out this gap in C++20 support.
> 
> Any further comments on this patch series?
> 
> Tom.
> 

I think it is too late for 2.35, but I will take to check when 2.36 opens.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-01-21 20:01       ` Adhemerval Zanella
@ 2022-01-22 12:24         ` Tom Honermann
  2022-02-16 18:29           ` Joseph Myers
  0 siblings, 1 reply; 27+ messages in thread
From: Tom Honermann @ 2022-01-22 12:24 UTC (permalink / raw)
  To: Adhemerval Zanella, Joseph Myers; +Cc: libc-alpha

On 1/21/22 3:01 PM, Adhemerval Zanella wrote:
>
> On 20/01/2022 20:17, Tom Honermann via Libc-alpha wrote:
>> On 1/11/22 2:23 PM, Tom Honermann via Libc-alpha wrote:
>>> On 1/10/22 7:53 PM, Joseph Myers wrote:
>>>> This patch is adding a NEWS entry for 2.34.  Since the next release is
>>>> 2.35, it should add an entry there instead (except we've started release
>>>> slush for 2.35, so it might be better to aim this at 2.36).
>>>>
>>> Thank you for spotting that; this was due to a bad merge conflict resolution on my part. Fixed patch attached.
>>>
>>> If this needs to wait for 2.36, I understand, but I would love to have this in 2.35 to close out this gap in C++20 support.
>> Any further comments on this patch series?
>>
>> Tom.
>>
> I think it is too late for 2.35, but I will take to check when 2.36 opens.

I understand. Thank you! I'll repost the patch series with the changes 
needed for 2.36 once 2.35 is released.

Tom.



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-01-22 12:24         ` Tom Honermann
@ 2022-02-16 18:29           ` Joseph Myers
  2022-02-16 19:14             ` tom
  0 siblings, 1 reply; 27+ messages in thread
From: Joseph Myers @ 2022-02-16 18:29 UTC (permalink / raw)
  To: Tom Honermann; +Cc: Adhemerval Zanella, libc-alpha

On Sat, 22 Jan 2022, Tom Honermann via Libc-alpha wrote:

> I understand. Thank you! I'll repost the patch series with the changes needed
> for 2.36 once 2.35 is released.

Now that this feature has been accepted for C2X at today's WG14 meeting, a 
repost should condition the header declarations on __GLIBC_USE (ISOC2X) 
(plus whatever is appropriate for C++), as well as using 2.36 symbol 
versions, adding a NEWS entry in the 2.36 section and making that NEWS 
entry reflect that the feature is in C2X.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-02-16 18:29           ` Joseph Myers
@ 2022-02-16 19:14             ` tom
  0 siblings, 0 replies; 27+ messages in thread
From: tom @ 2022-02-16 19:14 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Adhemerval Zanella, libc-alpha


 
On Wednesday, February 16, 2022 1:29pm, "Joseph Myers" <joseph@codesourcery.com> said:



> On Sat, 22 Jan 2022, Tom Honermann via Libc-alpha wrote:
> 
> > I understand. Thank you! I'll repost the patch series with the changes
> needed
> > for 2.36 once 2.35 is released.
> 
> Now that this feature has been accepted for C2X at today's WG14 meeting, a
> repost should condition the header declarations on __GLIBC_USE (ISOC2X)
> (plus whatever is appropriate for C++), as well as using 2.36 symbol
> versions, adding a NEWS entry in the 2.36 section and making that NEWS
> entry reflect that the feature is in C2X.
 
Sounds good, thank you! I'll get a new set of patches posted soon.
 
Tom.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-05-18 17:40                 ` Florian Weimer
@ 2022-05-18 17:57                   ` Adhemerval Zanella
  0 siblings, 0 replies; 27+ messages in thread
From: Adhemerval Zanella @ 2022-05-18 17:57 UTC (permalink / raw)
  To: Florian Weimer
  Cc: Tom Honermann, Adhemerval Zanella via Libc-alpha, Joseph Myers



On 18/05/2022 14:40, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> Do we need to keep distinct states for each one or can use the a shared
>> one?
> 
> I think per-function state is required.  We can allocate it on demand
> because these functions may return ENOMEM.

That was I suggested to Tom as well.  In any case I think this is orthogonal
to the mbrtoc8/c8rtomb patch.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-05-18 16:17               ` Adhemerval Zanella
  2022-05-18 17:26                 ` Tom Honermann
@ 2022-05-18 17:40                 ` Florian Weimer
  2022-05-18 17:57                   ` Adhemerval Zanella
  1 sibling, 1 reply; 27+ messages in thread
From: Florian Weimer @ 2022-05-18 17:40 UTC (permalink / raw)
  To: Adhemerval Zanella
  Cc: Tom Honermann, Adhemerval Zanella via Libc-alpha, Joseph Myers

* Adhemerval Zanella:

> Do we need to keep distinct states for each one or can use the a shared
> one?

I think per-function state is required.  We can allocate it on demand
because these functions may return ENOMEM.

Thanks,
Florian


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-05-18 17:26                 ` Tom Honermann
@ 2022-05-18 17:39                   ` Adhemerval Zanella
  0 siblings, 0 replies; 27+ messages in thread
From: Adhemerval Zanella @ 2022-05-18 17:39 UTC (permalink / raw)
  To: Tom Honermann, Florian Weimer, Adhemerval Zanella via Libc-alpha
  Cc: Joseph Myers



On 18/05/2022 14:26, Tom Honermann wrote:
> On 5/18/22 12:17 PM, Adhemerval Zanella wrote:
>> On 18/05/2022 12:32, Tom Honermann wrote:
>>> On 5/17/22 5:33 PM, Florian Weimer wrote:
>>>> * Adhemerval Zanella via Libc-alpha:
>>>>
>>>>> On 17/05/2022 15:12, Joseph Myers wrote:
>>>>>> On Tue, 17 May 2022, Adhemerval Zanella wrote:
>>>>>>
>>>>>>>> +/* This is the private state used if PS is NULL.  */
>>>>>>>> +static mbstate_t state;
>>>>>>> Although it was done for other convertion interfaces, I wonder if we should
>>>>>>> keep supporting this mt-unsafe usage for newer ones.  It was not clear from
>>>>>> In C23 it's implementation-defined whether the internal state for such
>>>>>> functions has static or thread storage duration (see the general
>>>>>> introduction to the uchar.h functions).
>>>>>>
>>>>> Right, so glibc still need to support either mode.
>>>> No, I think we can and should switch.  Maybe with new symbol versions
>>>> (but the same implementation) if we want to play it conservative.
>>>>
>>>> The intent in POSIX and C has been for a long time that thread-local
>>>> state is permitted for these functions, only the wording did not
>>>> technically allow it.  The phrase was “not required to avoid data
>>>> races”.  The problem is that it's possible to tell the difference
>>>> without data races (with external synchronization).  Many libcs already
>>>> use thread-local state for these functions, without any apparent ill
>>>> effects.
>>> I would err on the side of maintaining consistency across these functions for now and then transition them all at once if there is a desire to do so.
>> Do we need to keep distinct states for each one or can use the a shared
>> one?
> 
> Each is required to maintain its own state. The relevant wording from C17 7.28.1 (Restartable multibyte/wide character conversion functions) paragraph 1 states:
> 
> These functions have a parameter, ps, of type pointer to mbstate_t that points to an object that can completely describe the current conversion state of the associated multibyte character sequence, which the functions alter as necessary. *If ps is a null pointer, each function uses its own internal **mbstate_t**object instead, which is initialized at program startup to the initial conversion state; the****functions are not required to avoid data races with other calls to the same function in this case. The **implementation behaves as if no library function calls these functions with a null pointer for ps.*

Yeah, I forgot that I just read this very sentence yesterday reviewing you patch.
So it it currently 88 bytes per thread (104 considering the mbrtoc8, c8rtomb)
per thread state if we make it thread-local.  We can maybe lazy allocate the
whole wcsmbs state, so we just keep a pointer per thread.

We already have the internal scheme to allocate ion tcb (tls-internal.h) so
it does not exhaust static tls allocation.  

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-05-18 16:17               ` Adhemerval Zanella
@ 2022-05-18 17:26                 ` Tom Honermann
  2022-05-18 17:39                   ` Adhemerval Zanella
  2022-05-18 17:40                 ` Florian Weimer
  1 sibling, 1 reply; 27+ messages in thread
From: Tom Honermann @ 2022-05-18 17:26 UTC (permalink / raw)
  To: Adhemerval Zanella, Florian Weimer, Adhemerval Zanella via Libc-alpha
  Cc: Joseph Myers

On 5/18/22 12:17 PM, Adhemerval Zanella wrote:
>
> On 18/05/2022 12:32, Tom Honermann wrote:
>> On 5/17/22 5:33 PM, Florian Weimer wrote:
>>> * Adhemerval Zanella via Libc-alpha:
>>>
>>>> On 17/05/2022 15:12, Joseph Myers wrote:
>>>>> On Tue, 17 May 2022, Adhemerval Zanella wrote:
>>>>>
>>>>>>> +/* This is the private state used if PS is NULL.  */
>>>>>>> +static mbstate_t state;
>>>>>> Although it was done for other convertion interfaces, I wonder if we should
>>>>>> keep supporting this mt-unsafe usage for newer ones.  It was not clear from
>>>>> In C23 it's implementation-defined whether the internal state for such
>>>>> functions has static or thread storage duration (see the general
>>>>> introduction to the uchar.h functions).
>>>>>
>>>> Right, so glibc still need to support either mode.
>>> No, I think we can and should switch.  Maybe with new symbol versions
>>> (but the same implementation) if we want to play it conservative.
>>>
>>> The intent in POSIX and C has been for a long time that thread-local
>>> state is permitted for these functions, only the wording did not
>>> technically allow it.  The phrase was “not required to avoid data
>>> races”.  The problem is that it's possible to tell the difference
>>> without data races (with external synchronization).  Many libcs already
>>> use thread-local state for these functions, without any apparent ill
>>> effects.
>> I would err on the side of maintaining consistency across these functions for now and then transition them all at once if there is a desire to do so.
> Do we need to keep distinct states for each one or can use the a shared
> one?

Each is required to maintain its own state. The relevant wording from 
C17 7.28.1 (Restartable multibyte/wide character conversion functions) 
paragraph 1 states:

These functions have a parameter, ps, of type pointer to mbstate_t that 
points to an object that can completely describe the current conversion 
state of the associated multibyte character sequence, which the 
functions alter as necessary. *If ps is a null pointer, each function 
uses its own internal **mbstate_t**object instead, which is initialized 
at program startup to the initial conversion state; the****functions are 
not required to avoid data races with other calls to the same function 
in this case. The **implementation behaves as if no library function 
calls these functions with a null pointer for ps.*

Tom.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-05-18 15:32             ` Tom Honermann
@ 2022-05-18 16:17               ` Adhemerval Zanella
  2022-05-18 17:26                 ` Tom Honermann
  2022-05-18 17:40                 ` Florian Weimer
  0 siblings, 2 replies; 27+ messages in thread
From: Adhemerval Zanella @ 2022-05-18 16:17 UTC (permalink / raw)
  To: Tom Honermann, Florian Weimer, Adhemerval Zanella via Libc-alpha
  Cc: Joseph Myers



On 18/05/2022 12:32, Tom Honermann wrote:
> On 5/17/22 5:33 PM, Florian Weimer wrote:
>> * Adhemerval Zanella via Libc-alpha:
>>
>>> On 17/05/2022 15:12, Joseph Myers wrote:
>>>> On Tue, 17 May 2022, Adhemerval Zanella wrote:
>>>>
>>>>>> +/* This is the private state used if PS is NULL.  */
>>>>>> +static mbstate_t state;
>>>>> Although it was done for other convertion interfaces, I wonder if we should
>>>>> keep supporting this mt-unsafe usage for newer ones.  It was not clear from
>>>> In C23 it's implementation-defined whether the internal state for such
>>>> functions has static or thread storage duration (see the general
>>>> introduction to the uchar.h functions).
>>>>
>>> Right, so glibc still need to support either mode.
>> No, I think we can and should switch.  Maybe with new symbol versions
>> (but the same implementation) if we want to play it conservative.
>>
>> The intent in POSIX and C has been for a long time that thread-local
>> state is permitted for these functions, only the wording did not
>> technically allow it.  The phrase was “not required to avoid data
>> races”.  The problem is that it's possible to tell the difference
>> without data races (with external synchronization).  Many libcs already
>> use thread-local state for these functions, without any apparent ill
>> effects.
> 
> I would err on the side of maintaining consistency across these functions for now and then transition them all at once if there is a desire to do so.

Do we need to keep distinct states for each one or can use the a shared
one?

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-05-17 21:33           ` Florian Weimer
@ 2022-05-18 15:32             ` Tom Honermann
  2022-05-18 16:17               ` Adhemerval Zanella
  0 siblings, 1 reply; 27+ messages in thread
From: Tom Honermann @ 2022-05-18 15:32 UTC (permalink / raw)
  To: Florian Weimer, Adhemerval Zanella via Libc-alpha
  Cc: Joseph Myers, Adhemerval Zanella

On 5/17/22 5:33 PM, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
>
>> On 17/05/2022 15:12, Joseph Myers wrote:
>>> On Tue, 17 May 2022, Adhemerval Zanella wrote:
>>>
>>>>> +/* This is the private state used if PS is NULL.  */
>>>>> +static mbstate_t state;
>>>> Although it was done for other convertion interfaces, I wonder if we should
>>>> keep supporting this mt-unsafe usage for newer ones.  It was not clear from
>>> In C23 it's implementation-defined whether the internal state for such
>>> functions has static or thread storage duration (see the general
>>> introduction to the uchar.h functions).
>>>
>> Right, so glibc still need to support either mode.
> No, I think we can and should switch.  Maybe with new symbol versions
> (but the same implementation) if we want to play it conservative.
>
> The intent in POSIX and C has been for a long time that thread-local
> state is permitted for these functions, only the wording did not
> technically allow it.  The phrase was “not required to avoid data
> races”.  The problem is that it's possible to tell the difference
> without data races (with external synchronization).  Many libcs already
> use thread-local state for these functions, without any apparent ill
> effects.

I would err on the side of maintaining consistency across these 
functions for now and then transition them all at once if there is a 
desire to do so.

Tom.

>
> Thanks,
> Florian
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-05-17 18:17         ` Adhemerval Zanella
@ 2022-05-17 21:33           ` Florian Weimer
  2022-05-18 15:32             ` Tom Honermann
  0 siblings, 1 reply; 27+ messages in thread
From: Florian Weimer @ 2022-05-17 21:33 UTC (permalink / raw)
  To: Adhemerval Zanella via Libc-alpha
  Cc: Joseph Myers, Adhemerval Zanella, Tom Honermann

* Adhemerval Zanella via Libc-alpha:

> On 17/05/2022 15:12, Joseph Myers wrote:
>> On Tue, 17 May 2022, Adhemerval Zanella wrote:
>> 
>>>> +/* This is the private state used if PS is NULL.  */
>>>> +static mbstate_t state;
>>>
>>> Although it was done for other convertion interfaces, I wonder if we should
>>> keep supporting this mt-unsafe usage for newer ones.  It was not clear from 
>> 
>> In C23 it's implementation-defined whether the internal state for such 
>> functions has static or thread storage duration (see the general 
>> introduction to the uchar.h functions).
>> 
>
> Right, so glibc still need to support either mode.

No, I think we can and should switch.  Maybe with new symbol versions
(but the same implementation) if we want to play it conservative.

The intent in POSIX and C has been for a long time that thread-local
state is permitted for these functions, only the wording did not
technically allow it.  The phrase was “not required to avoid data
races”.  The problem is that it's possible to tell the difference
without data races (with external synchronization).  Many libcs already
use thread-local state for these functions, without any apparent ill
effects.

Thanks,
Florian


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-05-17 18:12       ` Joseph Myers
@ 2022-05-17 18:17         ` Adhemerval Zanella
  2022-05-17 21:33           ` Florian Weimer
  0 siblings, 1 reply; 27+ messages in thread
From: Adhemerval Zanella @ 2022-05-17 18:17 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Tom Honermann, libc-alpha



On 17/05/2022 15:12, Joseph Myers wrote:
> On Tue, 17 May 2022, Adhemerval Zanella wrote:
> 
>>> +/* This is the private state used if PS is NULL.  */
>>> +static mbstate_t state;
>>
>> Although it was done for other convertion interfaces, I wonder if we should
>> keep supporting this mt-unsafe usage for newer ones.  It was not clear from 
> 
> In C23 it's implementation-defined whether the internal state for such 
> functions has static or thread storage duration (see the general 
> introduction to the uchar.h functions).
> 

Right, so glibc still need to support either mode.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-05-17 18:05     ` Adhemerval Zanella
@ 2022-05-17 18:12       ` Joseph Myers
  2022-05-17 18:17         ` Adhemerval Zanella
  0 siblings, 1 reply; 27+ messages in thread
From: Joseph Myers @ 2022-05-17 18:12 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: Tom Honermann, libc-alpha

On Tue, 17 May 2022, Adhemerval Zanella wrote:

> > +/* This is the private state used if PS is NULL.  */
> > +static mbstate_t state;
> 
> Although it was done for other convertion interfaces, I wonder if we should
> keep supporting this mt-unsafe usage for newer ones.  It was not clear from 

In C23 it's implementation-defined whether the internal state for such 
functions has static or thread storage duration (see the general 
introduction to the uchar.h functions).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-03-01  3:40   ` Tom Honermann
  2022-05-17 15:57     ` Carlos O'Donell
@ 2022-05-17 18:05     ` Adhemerval Zanella
  2022-05-17 18:12       ` Joseph Myers
  1 sibling, 1 reply; 27+ messages in thread
From: Adhemerval Zanella @ 2022-05-17 18:05 UTC (permalink / raw)
  To: Tom Honermann, Joseph Myers; +Cc: libc-alpha



On 01/03/2022 00:40, Tom Honermann via Libc-alpha wrote:
> Subject:
> Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
> From:
> Tom Honermann via Libc-alpha <libc-alpha@sourceware.org>
> Date:
> 01/03/2022 00:40
> 
> To:
> Joseph Myers <joseph@codesourcery.com>
> CC:
> libc-alpha <libc-alpha@sourceware.org>
> 
> 
> 
> On 2/28/22 6:01 PM, Joseph Myers wrote:
>> On Sun, 27 Feb 2022, Tom Honermann via Libc-alpha wrote:
>>
>>> This patch provides implementations for the mbrtoc8 and c8rtomb functions
>>> adopted for C++20 via WG21 P0482R6 [1] and for C2X via WG14 N2653 [2]. It also
>>> provides the char8_t typedef adopted for C2X via WG14 N2653 [2].

I think you have missed the links for [1] and [2] (they are on previous message).
Usually I put the link references after the remarks.

>>>
>>> The mbrtoc8 and c8rtomb functions are declared in uchar.h in C2X mode or when
>>> the _GNU_SOURCE macro or C++20 __cpp_char8_t feature test macro is defined.
>>>
>>> The char8_t typedef is declared in uchar.h in C2X mode or when the _GNU_SOURCE
>>> macro is defined and the C++20 __cpp_char8_t feature test macro is not defined
>>> (if __cpp_char8_t is defined, then char8_t is a builtin type).
>> You should almost never have "defined __USE_GNU || ..." in header
>> conditionals, because _GNU_SOURCE implies the other feature test macros.
> 
> Ah, right. Thank you, a corrected patch is attached.

Patch looks ok, some comments below.

> 
> Tom.
> Attachments:
> 
> n2653-2.patch	28,4 KB

As before, please send the patch inline instead of attachment (even if it is large
as this one).

On a next version, use git send-mail or similar and put the initial message as
the cover letter.

> 
> commit f163269acc109dc41bbf09ea56135ae94dc1e963
> Author: Tom Honermann <tom@honermann.net>
> Date:   Sun Feb 27 10:28:58 2022 -0500
> 
>     Implement mbrtoc8(), c8rtomb(), and the char8_t typedef.
>     
>     This change provides implementations for the mbrtoc8 and c8rtomb
>     functions adopted for C++20 via WG21 P0482R6 and for C2X via WG14
>     N2653.  It also provides the char8_t typedef from WG14 N2653.
>     
>     The mbrtoc8 and c8rtomb functions are declared in uchar.h in C2X
>     mode or when the _GNU_SOURCE macro or C++20 __cpp_char8_t feature
>     test macro is defined.
>     
>     The char8_t typedef is declared in uchar.h in C2X mode or when the
>     _GNU_SOURCE macro is defined and the C++20 __cpp_char8_t feature
>     test macro is not defined (if __cpp_char8_t is defined, then char8_t
>     is a builtin type).
> 
> diff --git a/NEWS b/NEWS
> index 626eeabf5d..3c4b597ab3 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -9,6 +9,15 @@ Version 2.36
>  
>  Major new features:
>  
> +* Support for the mbrtoc8 and c8rtomb multibyte/UTF-8 character conversion
> +  functions has been added per the ISO C2X N2653 and C++20 P0482R6 proposals.
> +  Support for the char8_t typedef has been added per the ISO C2X N2653
> +  proposal. The functions are declared in uchar.h in C2X mode or when the

Double space after period.

> +  _GNU_SOURCE macro or C++20 __cpp_char8_t feature test macro is defined.
> +  The char8_t typedef is declared in uchar.h in C2X mode or when the
> +  _GNU_SOURCE macro is defined and the C++20 __cpp_char8_t feature test macro
> +  is not defined (if __cpp_char8_t is defined, then char8_t is a builtin type).
> +
>    [Add new features here]

Once a new feature is added the '[...]' mark can be removed.

>  
>  Deprecated and removed features, and other changes affecting compatibility:
> diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
> index 4dc87e9061..66fb0e28fa 100644
> --- a/sysdeps/mach/hurd/i386/libc.abilist
> +++ b/sysdeps/mach/hurd/i386/libc.abilist
> @@ -2289,6 +2289,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 close_range F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index 1b63d9e447..82dfae3421 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2616,3 +2616,5 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index e7e4cf7d2a..56d9094a58 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2713,6 +2713,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
> index bc3d228e31..fb7fc117f3 100644
> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
> @@ -2377,3 +2377,5 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> index db7039c4ab..f7c3b87bc0 100644
> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> @@ -496,6 +496,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 _Exit F
>  GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
>  GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> index d2add4fb49..19f44510ee 100644
> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> @@ -493,6 +493,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 _Exit F
>  GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
>  GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 355d72a30c..fce3ee63ea 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2652,3 +2652,5 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 3df39bb28c..307b77c25b 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2601,6 +2601,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index c4da358f80..99f3b0dde1 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2785,6 +2785,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index 241bac70ea..3fe18c1bea 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -2551,6 +2551,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 78bf372b72..aee8cb576b 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -497,6 +497,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 _Exit F
>  GLIBC_2.4 _IO_2_1_stderr_ D 0x98
>  GLIBC_2.4 _IO_2_1_stdin_ D 0x98
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 00df5c901f..9b204c5cf9 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2728,6 +2728,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> index e8118569c3..6ec81952e1 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> @@ -2701,3 +2701,5 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> index c0d2373e64..7b484a8419 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> @@ -2698,3 +2698,5 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index 2d0fd04f54..26e4321f80 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2693,6 +2693,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index e39ccfb312..2c5e66e2c0 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2691,6 +2691,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 1e900f86e4..f2e0a4818a 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2699,6 +2699,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 9145ba7931..e0505441f6 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2602,6 +2602,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index e95d60d926..d0260261e2 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2740,3 +2740,5 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> index ca934e374b..506853ee25 100644
> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> @@ -2123,3 +2123,5 @@ GLIBC_2.35 wprintf F
>  GLIBC_2.35 write F
>  GLIBC_2.35 writev F
>  GLIBC_2.35 wscanf F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 3820b9f235..0096aa7a97 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -2755,6 +2755,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index 464dc27fcd..5869941ec6 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -2788,6 +2788,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index 2f7e58747f..dc6277f1d8 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2510,6 +2510,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index 4f3043d913..fd8adceee6 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2812,3 +2812,5 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> index 84b6ac815a..2f0b08fe30 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> @@ -2379,3 +2379,5 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index 4d5c19c56a..ad49621c76 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2579,3 +2579,5 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 7c5ee8d569..ab25e964f1 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -2753,6 +2753,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index 50de0b46cf..3851645690 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2547,6 +2547,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> index 66fba013ca..b606bad5dc 100644
> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> @@ -2608,6 +2608,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> index 38703f8aa0..9b7e03a290 100644
> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> @@ -2605,6 +2605,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index 6df55eb765..04651211d7 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -2748,6 +2748,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index b90569d881..5ce2c90903 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2574,6 +2574,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index e88b0f101f..85a7fb3152 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2525,6 +2525,8 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index e0755272eb..975e78eaa5 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2631,3 +2631,5 @@ GLIBC_2.35 __memcmpeq F
>  GLIBC_2.35 _dl_find_object F
>  GLIBC_2.35 epoll_pwait2 F
>  GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
> +GLIBC_2.36 c8rtomb F
> +GLIBC_2.36 mbrtoc8 F
> diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
> index df9a85f4a9..bda281ad70 100644
> --- a/wcsmbs/Makefile
> +++ b/wcsmbs/Makefile
> @@ -42,7 +42,7 @@ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
>  	    wcsmbsload mbsrtowcs_l \
>  	    isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf \
>  	    isoc99_swscanf isoc99_vswscanf \
> -	    mbrtoc16 c16rtomb mbrtoc32 c32rtomb
> +	    mbrtoc8 c8rtomb mbrtoc16 c16rtomb mbrtoc32 c32rtomb
>  
>  strop-tests :=  wcscmp wcsncmp wmemcmp wcslen wcschr wcsrchr wcscpy wcsnlen \
>  		wcpcpy wcsncpy wcpncpy wcscat wcsncat wcschrnul wcsspn wcspbrk \
> diff --git a/wcsmbs/Versions b/wcsmbs/Versions
> index 0b31c1b940..ec28acfb73 100644
> --- a/wcsmbs/Versions
> +++ b/wcsmbs/Versions
> @@ -49,4 +49,7 @@ libc {
>      wcstof32; wcstof64; wcstof32x;
>      wcstof32_l; wcstof64_l; wcstof32x_l;
>    }
> +  GLIBC_2.36 {
> +    c8rtomb; mbrtoc8;
> +  }
>  }
> diff --git a/wcsmbs/c8rtomb.c b/wcsmbs/c8rtomb.c
> new file mode 100644
> index 0000000000..8a5ffeab23
> --- /dev/null
> +++ b/wcsmbs/c8rtomb.c
> @@ -0,0 +1,132 @@
> +/* UTF-8 to multibyte conversion.
> +   Copyright (C) 2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <errno.h>
> +#include <uchar.h>
> +#include <wchar.h>
> +
> +
> +/* This is the private state used if PS is NULL.  */
> +static mbstate_t state;

Although it was done for other convertion interfaces, I wonder if we should
keep supporting this mt-unsafe usage for newer ones.  It was not clear from 
n2653 how the function should behave for PS equal to NULL, so I think it 
would be conformant to either define PS as nonull or return -1/EINVAL.

> +
> +size_t
> +c8rtomb (char *s, char8_t c8, mbstate_t *ps)
> +{
> +  /* This implementation depends on the converter invoked by wcrtomb not
> +     needing to retain state in either the top most bit of ps->__count or
> +     in ps->__value between invocations.  This implementation uses the
> +     top most bit of ps->__count to indicate that trailing code units are
> +     expected and uses ps->__value to store previously seen code units.  */
> +
> +  wchar_t wc;
> +
> +  if (ps == NULL)
> +    ps = &state;
> +
> +  if (s == NULL)
> +    {
> +      /* if 's' is a null pointer, behave as if u8'\0' was passed as 'c8'.  If
> +         this occurs for an incomplete code unit sequence, then an error will
> +         be reported below.  */
> +      c8 = u8""[0];
> +    }
> +
> +  if (! (ps->__count & 0x80000000))
> +    {
> +      /* Initial state.  */
> +      if ((c8 >= 0x80 && c8 <= 0xC1) || c8 >= 0xF5)
> +	{
> +	  /* An invalid lead code unit.  */
> +	  __set_errno (EILSEQ);
> +	  return -1;
> +	}
> +      if (c8 >= 0xC2)
> +	{
> +	  /* A valid lead code unit.  */
> +	  ps->__count |= 0x80000000;
> +	  ps->__value.__wchb[0] = c8;
> +          ps->__value.__wchb[3] = 1;

Indentation seems off here (you used tabs and this one was done with whitespaces).

> +	  return 0;
> +	}
> +      /* A single byte (ASCII) code unit.  */
> +      wc = c8;
> +    }
> +  else
> +    {
> +      char8_t cu1 = ps->__value.__wchb[0];
> +      if (ps->__value.__wchb[3] == 1)
> +	{
> +	  /* A single lead code unit was previously seen.  */
> +	  if ((c8 < 0x80 || c8 > 0xBF) ||
> +               (cu1 == 0xE0 && c8 < 0xA0) ||
> +               (cu1 == 0xED && c8 > 0x9F) ||
> +               (cu1 == 0xF0 && c8 < 0x90) ||
> +               (cu1 == 0xF4 && c8 > 0x8F))

I think the GNU style place the comparison on a newer line:

    if ((c8 < 0x80 || c8 > 0xBF)
	|| (cu1 == 0xE0 && c8 < 0xA0)
        [...]

> +	    {
> +	      /* An invalid second code unit.  */
> +	      __set_errno (EILSEQ);
> +	      return -1;
> +	    }
> +	  if (cu1 >= 0xE0)
> +	    {
> +	      /* A three or four code unit sequence.  */
> +	      ps->__value.__wchb[1] = c8;
> +	      ++ps->__value.__wchb[3];
> +	      return 0;
> +	    }
> +	  wc = ((cu1 & 0x1F) << 6) +
> +	       (c8 & 0x3F);

Same as before for the addition:

    wc = ((cu1 & 0x1F) << 64)
	 + (c8 & 0x3F);

> +	}
> +      else
> +	{
> +	  char8_t cu2 = ps->__value.__wchb[1];
> +	  /* A three or four byte code unit sequence.  */
> +	  if (c8 < 0x80 || c8 > 0xBF)
> +	    {
> +	      /* An invalid third or fourth code unit.  */
> +	      __set_errno (EILSEQ);
> +	      return -1;
> +	    }
> +	  if (ps->__value.__wchb[3] == 2 && cu1 >= 0xF0)
> +	    {
> +	      /* A four code unit sequence.  */
> +	      ps->__value.__wchb[2] = c8;
> +	      ++ps->__value.__wchb[3];
> +	      return 0;
> +	    }
> +	  if (cu1 < 0xF0)
> +	    {
> +	      wc = ((cu1 & 0x0F) << 12) +
> +		   ((cu2 & 0x3F) << 6) +
> +		   (c8 & 0x3F);

Same as before.

> +	    }
> +	  else
> +	    {
> +	      char8_t cu3 = ps->__value.__wchb[2];
> +	      wc = ((cu1 & 0x07) << 18) +
> +		   ((cu2 & 0x3F) << 12) +
> +		   ((cu3 & 0x3F) << 6) +
> +		   (c8 & 0x3F);

Same as before.

> +	    }
> +	}
> +      ps->__count &= 0x7fffffff;
> +      ps->__value.__wch = 0;
> +    }
> +
> +  return wcrtomb (s, wc, ps);
> +}

The UTF-8 decoders seems to follow the RFC 3629 ABNF definition.

> diff --git a/wcsmbs/mbrtoc8.c b/wcsmbs/mbrtoc8.c
> new file mode 100644
> index 0000000000..8ca457088d
> --- /dev/null
> +++ b/wcsmbs/mbrtoc8.c
> @@ -0,0 +1,126 @@
> +/* Multibyte to UTF-8 conversion.
> +   Copyright (C) 2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <assert.h>
> +#include <dlfcn.h>
> +#include <errno.h>
> +#include <gconv.h>
> +#include <uchar.h>
> +#include <wcsmbsload.h>
> +
> +#include <sysdep.h>
> +
> +#ifndef EILSEQ
> +# define EILSEQ EINVAL
> +#endif
> +
> +
> +/* This is the private state used if PS is NULL.  */
> +static mbstate_t state;
> +
> +size_t
> +mbrtoc8 (char8_t *pc8, const char *s, size_t n, mbstate_t *ps)
> +{
> +  /* This implementation depends on the converter invoked by mbrtowc() not
> +     needing to retain state in either the top most bit of ps->__count or
> +     in ps->__value between invocations.  This implementation uses the
> +     top most bit of ps->__count to indicate that trailing code units are
> +     yet to be written and uses ps->__value to store those code units.  */
> +
> +  if (ps == NULL)
> +    ps = &state;
> +
> +  /* If state indicates that trailing code units are yet to be written, write
> +     those first regardless of whether 's' is a null pointer.  */
> +  if (ps->__count & 0x80000000)
> +    {
> +      /* ps->__value.__wchb[3] stores the index of the next code unit to
> +         write.  Code units are stored in reverse order.  */
> +      size_t i = ps->__value.__wchb[3];
> +      if (pc8 != NULL)
> +	{
> +	  *pc8 = ps->__value.__wchb[i];
> +	}
> +      if (i == 0)
> +	{
> +	  ps->__count &= 0x7fffffff;
> +	  ps->__value.__wch = 0;
> +	}
> +      else
> +	--ps->__value.__wchb[3];
> +      return -3;
> +    }
> +
> +  if (s == NULL)
> +    {
> +      /* if 's' is a null pointer, behave as if a null pointer was passed for
> +         'pc8', an empty string was passed for 's', and 1 passed for 'n'.  */
> +      pc8 = NULL;
> +      s = "";
> +      n = 1;
> +    }
> +
> +  wchar_t wc;
> +  size_t result;
> +
> +  result = mbrtowc(&wc, s, n, ps);

Missing space before '('.

> +  if (result <= n)
> +    {
> +      if (wc <= 0x7F)
> +	{
> +	  if (pc8 != NULL)
> +	    *pc8 = wc;
> +	}
> +      else if (wc <= 0x7FF)
> +	{
> +	  if (pc8 != NULL)
> +	    *pc8 = 0xC0 + ((wc >> 6) & 0x1F);
> +	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
> +	  ps->__value.__wchb[3] = 0;
> +	  ps->__count |= 0x80000000;
> +	}
> +      else if (wc <= 0xFFFF)
> +	{
> +	  if (pc8 != NULL)
> +	    *pc8 = 0xE0 + ((wc >> 12) & 0x0F);
> +	  ps->__value.__wchb[1] = 0x80 + ((wc >> 6) & 0x3F);
> +	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
> +	  ps->__value.__wchb[3] = 1;
> +	  ps->__count |= 0x80000000;
> +	}
> +      else if (wc <= 0x10FFFF)
> +	{
> +	  if (pc8 != NULL)
> +	    *pc8 = 0xF0 + ((wc >> 18) & 0x07);
> +	  ps->__value.__wchb[2] = 0x80 + ((wc >> 12) & 0x3F);
> +	  ps->__value.__wchb[1] = 0x80 + ((wc >> 6) & 0x3F);
> +	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
> +	  ps->__value.__wchb[3] = 2;
> +	  ps->__count |= 0x80000000;
> +	}
> +    }
> +  if (result == 0 && wc != 0)
> +    {
> +      /* mbrtowc() never returns -3.  When a MB sequence converts to multiple
> +         WCs, no input is consumed when writing the subsequent WCs resulting
> +         in a result of 0 even if a null character wasn't written.  */
> +      result = -3;
> +    }
> +
> +  return result;
> +}

Ok.

> diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
> index 051cdcbeb5..c37e8619a0 100644
> --- a/wcsmbs/uchar.h
> +++ b/wcsmbs/uchar.h
> @@ -31,6 +31,13 @@
>  #include <bits/types.h>
>  #include <bits/types/mbstate_t.h>
>  
> +/* Declare the C2x char8_t typedef in C2x modes, but only if the C++
> +  __cpp_char8_t feature test macro is not defined.  */
> +#if __GLIBC_USE (ISOC2X) && !defined __cpp_char8_t
> +/* Define the 8-bit character type.  */
> +typedef unsigned char char8_t;
> +#endif
> +
>  #ifndef __USE_ISOCXX11
>  /* Define the 16-bit and 32-bit character types.  */
>  typedef __uint_least16_t char16_t;
> @@ -40,6 +47,20 @@ typedef __uint_least32_t char32_t;
>  
>  __BEGIN_DECLS
>  
> +/* Declare the C2x mbrtoc8() and c8rtomb() functions in C2x modes or if
> +   the C++ __cpp_char8_t feature test macro is defined.  */
> +#if __GLIBC_USE (ISOC2X) || defined __cpp_char8_t
> +/* Write char8_t representation of multibyte character pointed
> +   to by S to PC8.  */
> +extern size_t mbrtoc8  (char8_t *__restrict __pc8,
> +			const char *__restrict __s, size_t __n,
> +			mbstate_t *__restrict __p) __THROW;
> +
> +/* Write multibyte representation of char8_t C8 to S.  */
> +extern size_t c8rtomb  (char *__restrict __s, char8_t __c8,
> +			mbstate_t *__restrict __ps) __THROW;
> +#endif
> +
>  /* Write char16_t representation of multibyte character pointed
>     to by S to PC16.  */
>  extern size_t mbrtoc16 (char16_t *__restrict __pc16,

Ok.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-03-01  3:40   ` Tom Honermann
@ 2022-05-17 15:57     ` Carlos O'Donell
  2022-05-17 18:05     ` Adhemerval Zanella
  1 sibling, 0 replies; 27+ messages in thread
From: Carlos O'Donell @ 2022-05-17 15:57 UTC (permalink / raw)
  To: Tom Honermann, Joseph Myers; +Cc: libc-alpha

On 2/28/22 22:40, Tom Honermann via Libc-alpha wrote:
> 
> On 2/28/22 6:01 PM, Joseph Myers wrote:
>> On Sun, 27 Feb 2022, Tom Honermann via Libc-alpha wrote:
>>
>>> This patch provides implementations for the mbrtoc8 and c8rtomb functions
>>> adopted for C++20 via WG21 P0482R6 [1] and for C2X via WG14 N2653 [2]. It also
>>> provides the char8_t typedef adopted for C2X via WG14 N2653 [2].
>>>
>>> The mbrtoc8 and c8rtomb functions are declared in uchar.h in C2X mode or when
>>> the _GNU_SOURCE macro or C++20 __cpp_char8_t feature test macro is defined.
>>>
>>> The char8_t typedef is declared in uchar.h in C2X mode or when the _GNU_SOURCE
>>> macro is defined and the C++20 __cpp_char8_t feature test macro is not defined
>>> (if __cpp_char8_t is defined, then char8_t is a builtin type).
>> You should almost never have "defined __USE_GNU || ..." in header
>> conditionals, because _GNU_SOURCE implies the other feature test macros.
> 
> Ah, right. Thank you, a corrected patch is attached.

Tom,

Could you please repost a v2 with Joseph's change incorporated?

Your subject is also a bit odd with a leading colon.

My suggestion is to use git send-email to post the series with a cover-letter
to the list.

The cover-letter can explain anything that the commit message doesn't include.

-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2022-02-28 23:01 ` Joseph Myers
@ 2022-03-01  3:40   ` Tom Honermann
  2022-05-17 15:57     ` Carlos O'Donell
  2022-05-17 18:05     ` Adhemerval Zanella
  0 siblings, 2 replies; 27+ messages in thread
From: Tom Honermann @ 2022-03-01  3:40 UTC (permalink / raw)
  To: Joseph Myers; +Cc: libc-alpha

[-- Attachment #1: Type: text/plain, Size: 928 bytes --]


On 2/28/22 6:01 PM, Joseph Myers wrote:
> On Sun, 27 Feb 2022, Tom Honermann via Libc-alpha wrote:
>
>> This patch provides implementations for the mbrtoc8 and c8rtomb functions
>> adopted for C++20 via WG21 P0482R6 [1] and for C2X via WG14 N2653 [2]. It also
>> provides the char8_t typedef adopted for C2X via WG14 N2653 [2].
>>
>> The mbrtoc8 and c8rtomb functions are declared in uchar.h in C2X mode or when
>> the _GNU_SOURCE macro or C++20 __cpp_char8_t feature test macro is defined.
>>
>> The char8_t typedef is declared in uchar.h in C2X mode or when the _GNU_SOURCE
>> macro is defined and the C++20 __cpp_char8_t feature test macro is not defined
>> (if __cpp_char8_t is defined, then char8_t is a builtin type).
> You should almost never have "defined __USE_GNU || ..." in header
> conditionals, because _GNU_SOURCE implies the other feature test macros.

Ah, right. Thank you, a corrected patch is attached.

Tom.

[-- Attachment #2: n2653-2.patch --]
[-- Type: text/x-patch, Size: 29115 bytes --]

commit f163269acc109dc41bbf09ea56135ae94dc1e963
Author: Tom Honermann <tom@honermann.net>
Date:   Sun Feb 27 10:28:58 2022 -0500

    Implement mbrtoc8(), c8rtomb(), and the char8_t typedef.
    
    This change provides implementations for the mbrtoc8 and c8rtomb
    functions adopted for C++20 via WG21 P0482R6 and for C2X via WG14
    N2653.  It also provides the char8_t typedef from WG14 N2653.
    
    The mbrtoc8 and c8rtomb functions are declared in uchar.h in C2X
    mode or when the _GNU_SOURCE macro or C++20 __cpp_char8_t feature
    test macro is defined.
    
    The char8_t typedef is declared in uchar.h in C2X mode or when the
    _GNU_SOURCE macro is defined and the C++20 __cpp_char8_t feature
    test macro is not defined (if __cpp_char8_t is defined, then char8_t
    is a builtin type).

diff --git a/NEWS b/NEWS
index 626eeabf5d..3c4b597ab3 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,15 @@ Version 2.36
 
 Major new features:
 
+* Support for the mbrtoc8 and c8rtomb multibyte/UTF-8 character conversion
+  functions has been added per the ISO C2X N2653 and C++20 P0482R6 proposals.
+  Support for the char8_t typedef has been added per the ISO C2X N2653
+  proposal. The functions are declared in uchar.h in C2X mode or when the
+  _GNU_SOURCE macro or C++20 __cpp_char8_t feature test macro is defined.
+  The char8_t typedef is declared in uchar.h in C2X mode or when the
+  _GNU_SOURCE macro is defined and the C++20 __cpp_char8_t feature test macro
+  is not defined (if __cpp_char8_t is defined, then char8_t is a builtin type).
+
   [Add new features here]
 
 Deprecated and removed features, and other changes affecting compatibility:
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index 4dc87e9061..66fb0e28fa 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2289,6 +2289,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 close_range F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 1b63d9e447..82dfae3421 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2616,3 +2616,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index e7e4cf7d2a..56d9094a58 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2713,6 +2713,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index bc3d228e31..fb7fc117f3 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2377,3 +2377,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index db7039c4ab..f7c3b87bc0 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -496,6 +496,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index d2add4fb49..19f44510ee 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -493,6 +493,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 355d72a30c..fce3ee63ea 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2652,3 +2652,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 3df39bb28c..307b77c25b 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2601,6 +2601,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index c4da358f80..99f3b0dde1 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2785,6 +2785,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 241bac70ea..3fe18c1bea 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2551,6 +2551,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 78bf372b72..aee8cb576b 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -497,6 +497,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 00df5c901f..9b204c5cf9 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2728,6 +2728,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index e8118569c3..6ec81952e1 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2701,3 +2701,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index c0d2373e64..7b484a8419 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2698,3 +2698,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 2d0fd04f54..26e4321f80 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2693,6 +2693,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index e39ccfb312..2c5e66e2c0 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2691,6 +2691,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 1e900f86e4..f2e0a4818a 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2699,6 +2699,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 9145ba7931..e0505441f6 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2602,6 +2602,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index e95d60d926..d0260261e2 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2740,3 +2740,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
index ca934e374b..506853ee25 100644
--- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
+++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
@@ -2123,3 +2123,5 @@ GLIBC_2.35 wprintf F
 GLIBC_2.35 write F
 GLIBC_2.35 writev F
 GLIBC_2.35 wscanf F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 3820b9f235..0096aa7a97 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2755,6 +2755,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 464dc27fcd..5869941ec6 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2788,6 +2788,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 2f7e58747f..dc6277f1d8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2510,6 +2510,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 4f3043d913..fd8adceee6 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2812,3 +2812,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 84b6ac815a..2f0b08fe30 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2379,3 +2379,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 4d5c19c56a..ad49621c76 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2579,3 +2579,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 7c5ee8d569..ab25e964f1 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2753,6 +2753,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 50de0b46cf..3851645690 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2547,6 +2547,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 66fba013ca..b606bad5dc 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2608,6 +2608,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 38703f8aa0..9b7e03a290 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2605,6 +2605,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 6df55eb765..04651211d7 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2748,6 +2748,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index b90569d881..5ce2c90903 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2574,6 +2574,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index e88b0f101f..85a7fb3152 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2525,6 +2525,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index e0755272eb..975e78eaa5 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2631,3 +2631,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
index df9a85f4a9..bda281ad70 100644
--- a/wcsmbs/Makefile
+++ b/wcsmbs/Makefile
@@ -42,7 +42,7 @@ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
 	    wcsmbsload mbsrtowcs_l \
 	    isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf \
 	    isoc99_swscanf isoc99_vswscanf \
-	    mbrtoc16 c16rtomb mbrtoc32 c32rtomb
+	    mbrtoc8 c8rtomb mbrtoc16 c16rtomb mbrtoc32 c32rtomb
 
 strop-tests :=  wcscmp wcsncmp wmemcmp wcslen wcschr wcsrchr wcscpy wcsnlen \
 		wcpcpy wcsncpy wcpncpy wcscat wcsncat wcschrnul wcsspn wcspbrk \
diff --git a/wcsmbs/Versions b/wcsmbs/Versions
index 0b31c1b940..ec28acfb73 100644
--- a/wcsmbs/Versions
+++ b/wcsmbs/Versions
@@ -49,4 +49,7 @@ libc {
     wcstof32; wcstof64; wcstof32x;
     wcstof32_l; wcstof64_l; wcstof32x_l;
   }
+  GLIBC_2.36 {
+    c8rtomb; mbrtoc8;
+  }
 }
diff --git a/wcsmbs/c8rtomb.c b/wcsmbs/c8rtomb.c
new file mode 100644
index 0000000000..8a5ffeab23
--- /dev/null
+++ b/wcsmbs/c8rtomb.c
@@ -0,0 +1,132 @@
+/* UTF-8 to multibyte conversion.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <uchar.h>
+#include <wchar.h>
+
+
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
+
+size_t
+c8rtomb (char *s, char8_t c8, mbstate_t *ps)
+{
+  /* This implementation depends on the converter invoked by wcrtomb not
+     needing to retain state in either the top most bit of ps->__count or
+     in ps->__value between invocations.  This implementation uses the
+     top most bit of ps->__count to indicate that trailing code units are
+     expected and uses ps->__value to store previously seen code units.  */
+
+  wchar_t wc;
+
+  if (ps == NULL)
+    ps = &state;
+
+  if (s == NULL)
+    {
+      /* if 's' is a null pointer, behave as if u8'\0' was passed as 'c8'.  If
+         this occurs for an incomplete code unit sequence, then an error will
+         be reported below.  */
+      c8 = u8""[0];
+    }
+
+  if (! (ps->__count & 0x80000000))
+    {
+      /* Initial state.  */
+      if ((c8 >= 0x80 && c8 <= 0xC1) || c8 >= 0xF5)
+	{
+	  /* An invalid lead code unit.  */
+	  __set_errno (EILSEQ);
+	  return -1;
+	}
+      if (c8 >= 0xC2)
+	{
+	  /* A valid lead code unit.  */
+	  ps->__count |= 0x80000000;
+	  ps->__value.__wchb[0] = c8;
+          ps->__value.__wchb[3] = 1;
+	  return 0;
+	}
+      /* A single byte (ASCII) code unit.  */
+      wc = c8;
+    }
+  else
+    {
+      char8_t cu1 = ps->__value.__wchb[0];
+      if (ps->__value.__wchb[3] == 1)
+	{
+	  /* A single lead code unit was previously seen.  */
+	  if ((c8 < 0x80 || c8 > 0xBF) ||
+               (cu1 == 0xE0 && c8 < 0xA0) ||
+               (cu1 == 0xED && c8 > 0x9F) ||
+               (cu1 == 0xF0 && c8 < 0x90) ||
+               (cu1 == 0xF4 && c8 > 0x8F))
+	    {
+	      /* An invalid second code unit.  */
+	      __set_errno (EILSEQ);
+	      return -1;
+	    }
+	  if (cu1 >= 0xE0)
+	    {
+	      /* A three or four code unit sequence.  */
+	      ps->__value.__wchb[1] = c8;
+	      ++ps->__value.__wchb[3];
+	      return 0;
+	    }
+	  wc = ((cu1 & 0x1F) << 6) +
+	       (c8 & 0x3F);
+	}
+      else
+	{
+	  char8_t cu2 = ps->__value.__wchb[1];
+	  /* A three or four byte code unit sequence.  */
+	  if (c8 < 0x80 || c8 > 0xBF)
+	    {
+	      /* An invalid third or fourth code unit.  */
+	      __set_errno (EILSEQ);
+	      return -1;
+	    }
+	  if (ps->__value.__wchb[3] == 2 && cu1 >= 0xF0)
+	    {
+	      /* A four code unit sequence.  */
+	      ps->__value.__wchb[2] = c8;
+	      ++ps->__value.__wchb[3];
+	      return 0;
+	    }
+	  if (cu1 < 0xF0)
+	    {
+	      wc = ((cu1 & 0x0F) << 12) +
+		   ((cu2 & 0x3F) << 6) +
+		   (c8 & 0x3F);
+	    }
+	  else
+	    {
+	      char8_t cu3 = ps->__value.__wchb[2];
+	      wc = ((cu1 & 0x07) << 18) +
+		   ((cu2 & 0x3F) << 12) +
+		   ((cu3 & 0x3F) << 6) +
+		   (c8 & 0x3F);
+	    }
+	}
+      ps->__count &= 0x7fffffff;
+      ps->__value.__wch = 0;
+    }
+
+  return wcrtomb (s, wc, ps);
+}
diff --git a/wcsmbs/mbrtoc8.c b/wcsmbs/mbrtoc8.c
new file mode 100644
index 0000000000..8ca457088d
--- /dev/null
+++ b/wcsmbs/mbrtoc8.c
@@ -0,0 +1,126 @@
+/* Multibyte to UTF-8 conversion.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <gconv.h>
+#include <uchar.h>
+#include <wcsmbsload.h>
+
+#include <sysdep.h>
+
+#ifndef EILSEQ
+# define EILSEQ EINVAL
+#endif
+
+
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
+
+size_t
+mbrtoc8 (char8_t *pc8, const char *s, size_t n, mbstate_t *ps)
+{
+  /* This implementation depends on the converter invoked by mbrtowc() not
+     needing to retain state in either the top most bit of ps->__count or
+     in ps->__value between invocations.  This implementation uses the
+     top most bit of ps->__count to indicate that trailing code units are
+     yet to be written and uses ps->__value to store those code units.  */
+
+  if (ps == NULL)
+    ps = &state;
+
+  /* If state indicates that trailing code units are yet to be written, write
+     those first regardless of whether 's' is a null pointer.  */
+  if (ps->__count & 0x80000000)
+    {
+      /* ps->__value.__wchb[3] stores the index of the next code unit to
+         write.  Code units are stored in reverse order.  */
+      size_t i = ps->__value.__wchb[3];
+      if (pc8 != NULL)
+	{
+	  *pc8 = ps->__value.__wchb[i];
+	}
+      if (i == 0)
+	{
+	  ps->__count &= 0x7fffffff;
+	  ps->__value.__wch = 0;
+	}
+      else
+	--ps->__value.__wchb[3];
+      return -3;
+    }
+
+  if (s == NULL)
+    {
+      /* if 's' is a null pointer, behave as if a null pointer was passed for
+         'pc8', an empty string was passed for 's', and 1 passed for 'n'.  */
+      pc8 = NULL;
+      s = "";
+      n = 1;
+    }
+
+  wchar_t wc;
+  size_t result;
+
+  result = mbrtowc(&wc, s, n, ps);
+  if (result <= n)
+    {
+      if (wc <= 0x7F)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = wc;
+	}
+      else if (wc <= 0x7FF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xC0 + ((wc >> 6) & 0x1F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 0;
+	  ps->__count |= 0x80000000;
+	}
+      else if (wc <= 0xFFFF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xE0 + ((wc >> 12) & 0x0F);
+	  ps->__value.__wchb[1] = 0x80 + ((wc >> 6) & 0x3F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 1;
+	  ps->__count |= 0x80000000;
+	}
+      else if (wc <= 0x10FFFF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xF0 + ((wc >> 18) & 0x07);
+	  ps->__value.__wchb[2] = 0x80 + ((wc >> 12) & 0x3F);
+	  ps->__value.__wchb[1] = 0x80 + ((wc >> 6) & 0x3F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 2;
+	  ps->__count |= 0x80000000;
+	}
+    }
+  if (result == 0 && wc != 0)
+    {
+      /* mbrtowc() never returns -3.  When a MB sequence converts to multiple
+         WCs, no input is consumed when writing the subsequent WCs resulting
+         in a result of 0 even if a null character wasn't written.  */
+      result = -3;
+    }
+
+  return result;
+}
diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
index 051cdcbeb5..c37e8619a0 100644
--- a/wcsmbs/uchar.h
+++ b/wcsmbs/uchar.h
@@ -31,6 +31,13 @@
 #include <bits/types.h>
 #include <bits/types/mbstate_t.h>
 
+/* Declare the C2x char8_t typedef in C2x modes, but only if the C++
+  __cpp_char8_t feature test macro is not defined.  */
+#if __GLIBC_USE (ISOC2X) && !defined __cpp_char8_t
+/* Define the 8-bit character type.  */
+typedef unsigned char char8_t;
+#endif
+
 #ifndef __USE_ISOCXX11
 /* Define the 16-bit and 32-bit character types.  */
 typedef __uint_least16_t char16_t;
@@ -40,6 +47,20 @@ typedef __uint_least32_t char32_t;
 
 __BEGIN_DECLS
 
+/* Declare the C2x mbrtoc8() and c8rtomb() functions in C2x modes or if
+   the C++ __cpp_char8_t feature test macro is defined.  */
+#if __GLIBC_USE (ISOC2X) || defined __cpp_char8_t
+/* Write char8_t representation of multibyte character pointed
+   to by S to PC8.  */
+extern size_t mbrtoc8  (char8_t *__restrict __pc8,
+			const char *__restrict __s, size_t __n,
+			mbstate_t *__restrict __p) __THROW;
+
+/* Write multibyte representation of char8_t C8 to S.  */
+extern size_t c8rtomb  (char *__restrict __s, char8_t __c8,
+			mbstate_t *__restrict __ps) __THROW;
+#endif
+
 /* Write char16_t representation of multibyte character pointed
    to by S to PC16.  */
 extern size_t mbrtoc16 (char16_t *__restrict __pc16,

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb,  char8_t
  2022-02-27 16:53 Tom Honermann
@ 2022-02-28 23:01 ` Joseph Myers
  2022-03-01  3:40   ` Tom Honermann
  0 siblings, 1 reply; 27+ messages in thread
From: Joseph Myers @ 2022-02-28 23:01 UTC (permalink / raw)
  To: Tom Honermann; +Cc: libc-alpha

On Sun, 27 Feb 2022, Tom Honermann via Libc-alpha wrote:

> This patch provides implementations for the mbrtoc8 and c8rtomb functions
> adopted for C++20 via WG21 P0482R6 [1] and for C2X via WG14 N2653 [2]. It also
> provides the char8_t typedef adopted for C2X via WG14 N2653 [2].
> 
> The mbrtoc8 and c8rtomb functions are declared in uchar.h in C2X mode or when
> the _GNU_SOURCE macro or C++20 __cpp_char8_t feature test macro is defined.
> 
> The char8_t typedef is declared in uchar.h in C2X mode or when the _GNU_SOURCE
> macro is defined and the C++20 __cpp_char8_t feature test macro is not defined
> (if __cpp_char8_t is defined, then char8_t is a builtin type).

You should almost never have "defined __USE_GNU || ..." in header 
conditionals, because _GNU_SOURCE implies the other feature test macros.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb,  char8_t
@ 2022-02-27 16:53 Tom Honermann
  2022-02-28 23:01 ` Joseph Myers
  0 siblings, 1 reply; 27+ messages in thread
From: Tom Honermann @ 2022-02-27 16:53 UTC (permalink / raw)
  To: libc-alpha

[-- Attachment #1: Type: text/plain, Size: 905 bytes --]

This patch provides implementations for the mbrtoc8 and c8rtomb 
functions adopted for C++20 via WG21 P0482R6 [1] and for C2X via WG14 
N2653 [2]. It also provides the char8_t typedef adopted for C2X via WG14 
N2653 [2].

The mbrtoc8 and c8rtomb functions are declared in uchar.h in C2X mode or 
when the _GNU_SOURCE macro or C++20 __cpp_char8_t feature test macro is 
defined.

The char8_t typedef is declared in uchar.h in C2X mode or when the 
_GNU_SOURCE macro is defined and the C++20 __cpp_char8_t feature test 
macro is not defined (if __cpp_char8_t is defined, then char8_t is a 
builtin type).

Tested on Linux x86_64.

Tom.

[1]: WG21 P0482R6
      "char8_t: A type for UTF-8 characters and strings (Revision 6)"
      https://wg21.link/p0482r6

[2]: WG14 N2653
      "char8_t: A type for UTF-8 characters and strings (Revision 1)"
      http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2653.htm

[-- Attachment #2: n2653-2.patch --]
[-- Type: text/x-patch, Size: 29192 bytes --]

commit d29ff21403913f7014fe3deebe65c9294e6c1d44
Author: Tom Honermann <tom@honermann.net>
Date:   Sun Feb 27 10:28:58 2022 -0500

    Implement mbrtoc8(), c8rtomb(), and the char8_t typedef.
    
    This change provides implementations for the mbrtoc8 and c8rtomb
    functions adopted for C++20 via WG21 P0482R6 and for C2X via WG14
    N2653.  It also provides the char8_t typedef from WG14 N2653.
    
    The mbrtoc8 and c8rtomb functions are declared in uchar.h in C2X
    mode or when the _GNU_SOURCE macro or C++20 __cpp_char8_t feature
    test macro is defined.
    
    The char8_t typedef is declared in uchar.h in C2X mode or when the
    _GNU_SOURCE macro is defined and the C++20 __cpp_char8_t feature
    test macro is not defined (if __cpp_char8_t is defined, then char8_t
    is a builtin type).

diff --git a/NEWS b/NEWS
index 626eeabf5d..3c4b597ab3 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,15 @@ Version 2.36
 
 Major new features:
 
+* Support for the mbrtoc8 and c8rtomb multibyte/UTF-8 character conversion
+  functions has been added per the ISO C2X N2653 and C++20 P0482R6 proposals.
+  Support for the char8_t typedef has been added per the ISO C2X N2653
+  proposal. The functions are declared in uchar.h in C2X mode or when the
+  _GNU_SOURCE macro or C++20 __cpp_char8_t feature test macro is defined.
+  The char8_t typedef is declared in uchar.h in C2X mode or when the
+  _GNU_SOURCE macro is defined and the C++20 __cpp_char8_t feature test macro
+  is not defined (if __cpp_char8_t is defined, then char8_t is a builtin type).
+
   [Add new features here]
 
 Deprecated and removed features, and other changes affecting compatibility:
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index 4dc87e9061..66fb0e28fa 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2289,6 +2289,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 close_range F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 1b63d9e447..82dfae3421 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2616,3 +2616,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index e7e4cf7d2a..56d9094a58 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2713,6 +2713,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index bc3d228e31..fb7fc117f3 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2377,3 +2377,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index db7039c4ab..f7c3b87bc0 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -496,6 +496,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index d2add4fb49..19f44510ee 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -493,6 +493,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 355d72a30c..fce3ee63ea 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2652,3 +2652,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 3df39bb28c..307b77c25b 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2601,6 +2601,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index c4da358f80..99f3b0dde1 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2785,6 +2785,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 241bac70ea..3fe18c1bea 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2551,6 +2551,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 78bf372b72..aee8cb576b 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -497,6 +497,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 00df5c901f..9b204c5cf9 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2728,6 +2728,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index e8118569c3..6ec81952e1 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2701,3 +2701,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index c0d2373e64..7b484a8419 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2698,3 +2698,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 2d0fd04f54..26e4321f80 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2693,6 +2693,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index e39ccfb312..2c5e66e2c0 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2691,6 +2691,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 1e900f86e4..f2e0a4818a 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2699,6 +2699,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 9145ba7931..e0505441f6 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2602,6 +2602,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index e95d60d926..d0260261e2 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2740,3 +2740,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
index ca934e374b..506853ee25 100644
--- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
+++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
@@ -2123,3 +2123,5 @@ GLIBC_2.35 wprintf F
 GLIBC_2.35 write F
 GLIBC_2.35 writev F
 GLIBC_2.35 wscanf F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 3820b9f235..0096aa7a97 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2755,6 +2755,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 464dc27fcd..5869941ec6 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2788,6 +2788,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 2f7e58747f..dc6277f1d8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2510,6 +2510,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 4f3043d913..fd8adceee6 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2812,3 +2812,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 84b6ac815a..2f0b08fe30 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2379,3 +2379,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 4d5c19c56a..ad49621c76 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2579,3 +2579,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 7c5ee8d569..ab25e964f1 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2753,6 +2753,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 50de0b46cf..3851645690 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2547,6 +2547,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 66fba013ca..b606bad5dc 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2608,6 +2608,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 38703f8aa0..9b7e03a290 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2605,6 +2605,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 6df55eb765..04651211d7 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2748,6 +2748,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index b90569d881..5ce2c90903 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2574,6 +2574,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index e88b0f101f..85a7fb3152 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2525,6 +2525,8 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index e0755272eb..975e78eaa5 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2631,3 +2631,5 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 c8rtomb F
+GLIBC_2.36 mbrtoc8 F
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
index df9a85f4a9..bda281ad70 100644
--- a/wcsmbs/Makefile
+++ b/wcsmbs/Makefile
@@ -42,7 +42,7 @@ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
 	    wcsmbsload mbsrtowcs_l \
 	    isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf \
 	    isoc99_swscanf isoc99_vswscanf \
-	    mbrtoc16 c16rtomb mbrtoc32 c32rtomb
+	    mbrtoc8 c8rtomb mbrtoc16 c16rtomb mbrtoc32 c32rtomb
 
 strop-tests :=  wcscmp wcsncmp wmemcmp wcslen wcschr wcsrchr wcscpy wcsnlen \
 		wcpcpy wcsncpy wcpncpy wcscat wcsncat wcschrnul wcsspn wcspbrk \
diff --git a/wcsmbs/Versions b/wcsmbs/Versions
index 0b31c1b940..ec28acfb73 100644
--- a/wcsmbs/Versions
+++ b/wcsmbs/Versions
@@ -49,4 +49,7 @@ libc {
     wcstof32; wcstof64; wcstof32x;
     wcstof32_l; wcstof64_l; wcstof32x_l;
   }
+  GLIBC_2.36 {
+    c8rtomb; mbrtoc8;
+  }
 }
diff --git a/wcsmbs/c8rtomb.c b/wcsmbs/c8rtomb.c
new file mode 100644
index 0000000000..8a5ffeab23
--- /dev/null
+++ b/wcsmbs/c8rtomb.c
@@ -0,0 +1,132 @@
+/* UTF-8 to multibyte conversion.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <uchar.h>
+#include <wchar.h>
+
+
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
+
+size_t
+c8rtomb (char *s, char8_t c8, mbstate_t *ps)
+{
+  /* This implementation depends on the converter invoked by wcrtomb not
+     needing to retain state in either the top most bit of ps->__count or
+     in ps->__value between invocations.  This implementation uses the
+     top most bit of ps->__count to indicate that trailing code units are
+     expected and uses ps->__value to store previously seen code units.  */
+
+  wchar_t wc;
+
+  if (ps == NULL)
+    ps = &state;
+
+  if (s == NULL)
+    {
+      /* if 's' is a null pointer, behave as if u8'\0' was passed as 'c8'.  If
+         this occurs for an incomplete code unit sequence, then an error will
+         be reported below.  */
+      c8 = u8""[0];
+    }
+
+  if (! (ps->__count & 0x80000000))
+    {
+      /* Initial state.  */
+      if ((c8 >= 0x80 && c8 <= 0xC1) || c8 >= 0xF5)
+	{
+	  /* An invalid lead code unit.  */
+	  __set_errno (EILSEQ);
+	  return -1;
+	}
+      if (c8 >= 0xC2)
+	{
+	  /* A valid lead code unit.  */
+	  ps->__count |= 0x80000000;
+	  ps->__value.__wchb[0] = c8;
+          ps->__value.__wchb[3] = 1;
+	  return 0;
+	}
+      /* A single byte (ASCII) code unit.  */
+      wc = c8;
+    }
+  else
+    {
+      char8_t cu1 = ps->__value.__wchb[0];
+      if (ps->__value.__wchb[3] == 1)
+	{
+	  /* A single lead code unit was previously seen.  */
+	  if ((c8 < 0x80 || c8 > 0xBF) ||
+               (cu1 == 0xE0 && c8 < 0xA0) ||
+               (cu1 == 0xED && c8 > 0x9F) ||
+               (cu1 == 0xF0 && c8 < 0x90) ||
+               (cu1 == 0xF4 && c8 > 0x8F))
+	    {
+	      /* An invalid second code unit.  */
+	      __set_errno (EILSEQ);
+	      return -1;
+	    }
+	  if (cu1 >= 0xE0)
+	    {
+	      /* A three or four code unit sequence.  */
+	      ps->__value.__wchb[1] = c8;
+	      ++ps->__value.__wchb[3];
+	      return 0;
+	    }
+	  wc = ((cu1 & 0x1F) << 6) +
+	       (c8 & 0x3F);
+	}
+      else
+	{
+	  char8_t cu2 = ps->__value.__wchb[1];
+	  /* A three or four byte code unit sequence.  */
+	  if (c8 < 0x80 || c8 > 0xBF)
+	    {
+	      /* An invalid third or fourth code unit.  */
+	      __set_errno (EILSEQ);
+	      return -1;
+	    }
+	  if (ps->__value.__wchb[3] == 2 && cu1 >= 0xF0)
+	    {
+	      /* A four code unit sequence.  */
+	      ps->__value.__wchb[2] = c8;
+	      ++ps->__value.__wchb[3];
+	      return 0;
+	    }
+	  if (cu1 < 0xF0)
+	    {
+	      wc = ((cu1 & 0x0F) << 12) +
+		   ((cu2 & 0x3F) << 6) +
+		   (c8 & 0x3F);
+	    }
+	  else
+	    {
+	      char8_t cu3 = ps->__value.__wchb[2];
+	      wc = ((cu1 & 0x07) << 18) +
+		   ((cu2 & 0x3F) << 12) +
+		   ((cu3 & 0x3F) << 6) +
+		   (c8 & 0x3F);
+	    }
+	}
+      ps->__count &= 0x7fffffff;
+      ps->__value.__wch = 0;
+    }
+
+  return wcrtomb (s, wc, ps);
+}
diff --git a/wcsmbs/mbrtoc8.c b/wcsmbs/mbrtoc8.c
new file mode 100644
index 0000000000..8ca457088d
--- /dev/null
+++ b/wcsmbs/mbrtoc8.c
@@ -0,0 +1,126 @@
+/* Multibyte to UTF-8 conversion.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <gconv.h>
+#include <uchar.h>
+#include <wcsmbsload.h>
+
+#include <sysdep.h>
+
+#ifndef EILSEQ
+# define EILSEQ EINVAL
+#endif
+
+
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
+
+size_t
+mbrtoc8 (char8_t *pc8, const char *s, size_t n, mbstate_t *ps)
+{
+  /* This implementation depends on the converter invoked by mbrtowc() not
+     needing to retain state in either the top most bit of ps->__count or
+     in ps->__value between invocations.  This implementation uses the
+     top most bit of ps->__count to indicate that trailing code units are
+     yet to be written and uses ps->__value to store those code units.  */
+
+  if (ps == NULL)
+    ps = &state;
+
+  /* If state indicates that trailing code units are yet to be written, write
+     those first regardless of whether 's' is a null pointer.  */
+  if (ps->__count & 0x80000000)
+    {
+      /* ps->__value.__wchb[3] stores the index of the next code unit to
+         write.  Code units are stored in reverse order.  */
+      size_t i = ps->__value.__wchb[3];
+      if (pc8 != NULL)
+	{
+	  *pc8 = ps->__value.__wchb[i];
+	}
+      if (i == 0)
+	{
+	  ps->__count &= 0x7fffffff;
+	  ps->__value.__wch = 0;
+	}
+      else
+	--ps->__value.__wchb[3];
+      return -3;
+    }
+
+  if (s == NULL)
+    {
+      /* if 's' is a null pointer, behave as if a null pointer was passed for
+         'pc8', an empty string was passed for 's', and 1 passed for 'n'.  */
+      pc8 = NULL;
+      s = "";
+      n = 1;
+    }
+
+  wchar_t wc;
+  size_t result;
+
+  result = mbrtowc(&wc, s, n, ps);
+  if (result <= n)
+    {
+      if (wc <= 0x7F)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = wc;
+	}
+      else if (wc <= 0x7FF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xC0 + ((wc >> 6) & 0x1F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 0;
+	  ps->__count |= 0x80000000;
+	}
+      else if (wc <= 0xFFFF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xE0 + ((wc >> 12) & 0x0F);
+	  ps->__value.__wchb[1] = 0x80 + ((wc >> 6) & 0x3F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 1;
+	  ps->__count |= 0x80000000;
+	}
+      else if (wc <= 0x10FFFF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xF0 + ((wc >> 18) & 0x07);
+	  ps->__value.__wchb[2] = 0x80 + ((wc >> 12) & 0x3F);
+	  ps->__value.__wchb[1] = 0x80 + ((wc >> 6) & 0x3F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 2;
+	  ps->__count |= 0x80000000;
+	}
+    }
+  if (result == 0 && wc != 0)
+    {
+      /* mbrtowc() never returns -3.  When a MB sequence converts to multiple
+         WCs, no input is consumed when writing the subsequent WCs resulting
+         in a result of 0 even if a null character wasn't written.  */
+      result = -3;
+    }
+
+  return result;
+}
diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
index 051cdcbeb5..01aaf9c94b 100644
--- a/wcsmbs/uchar.h
+++ b/wcsmbs/uchar.h
@@ -31,6 +31,13 @@
 #include <bits/types.h>
 #include <bits/types/mbstate_t.h>
 
+/* Declare the C2x char8_t typedef in _GNU_SOURCE and C2x modes, but only
+   if the C++ __cpp_char8_t feature test macro is not defined.  */
+#if (defined __USE_GNU || __GLIBC_USE (ISOC2X)) && !defined __cpp_char8_t
+/* Define the 8-bit character type.  */
+typedef unsigned char char8_t;
+#endif
+
 #ifndef __USE_ISOCXX11
 /* Define the 16-bit and 32-bit character types.  */
 typedef __uint_least16_t char16_t;
@@ -40,6 +47,20 @@ typedef __uint_least32_t char32_t;
 
 __BEGIN_DECLS
 
+/* Declare the C2x mbrtoc8() and c8rtomb() functions in _GNU_SOURCE and C2x
+   modes or if the C++ __cpp_char8_t feature test macro is defined.  */
+#if defined __USE_GNU || __GLIBC_USE (ISOC2X) || defined __cpp_char8_t
+/* Write char8_t representation of multibyte character pointed
+   to by S to PC8.  */
+extern size_t mbrtoc8  (char8_t *__restrict __pc8,
+			const char *__restrict __s, size_t __n,
+			mbstate_t *__restrict __p) __THROW;
+
+/* Write multibyte representation of char8_t C8 to S.  */
+extern size_t c8rtomb  (char *__restrict __s, char8_t __c8,
+			mbstate_t *__restrict __ps) __THROW;
+#endif
+
 /* Write char16_t representation of multibyte character pointed
    to by S to PC16.  */
 extern size_t mbrtoc16 (char16_t *__restrict __pc16,

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2021-06-11 16:28     ` Joseph Myers
@ 2021-06-13 15:35       ` Tom Honermann
  0 siblings, 0 replies; 27+ messages in thread
From: Tom Honermann @ 2021-06-13 15:35 UTC (permalink / raw)
  To: Joseph Myers; +Cc: libc-alpha

On 6/11/21 12:28 PM, Joseph Myers wrote:
> On Fri, 11 Jun 2021, Tom Honermann via Libc-alpha wrote:
>
>> 1) Enabling pre-C2x compatibility with C++20.
> Where a feature in a header should be enabled for a particular C++
> version, we can have an internal __GLIBC_USE (CXX20) which is enabled
> based on the value of __cplusplus, just like the existing __USE_ISOCXX11.
> (Though that doesn't make much practical difference until we provide a way
> for C++ library headers to get all the features they need without defining
> _GNU_SOURCE.)
>
> You'd then have
>
> #if defined __USE_GNU || __GLIBC_USE (CXX20)
>
> in uchar.h, with appropriate !defined __cpp_char8_t for defining the
> typedef itself.  And the defined __USE_GNU would become __GLIBC_USE
> (ISOC2X) if the feature is accepted for C2x.

Sounds good for C.

For C++ though, the declarations of mbrtoc8() and c8rtomb() need to be 
aligned with libstdc++ expectations since they are redeclared in the std 
namespace if available.  The corresponding libstdc++ patch 
<https://gcc.gnu.org/pipermail/libstdc++/2021-June/052685.html> probes 
whether these functions are available through an autoconf probe that 
runs g++ -fchar8_t; the redeclarations are then dependent only on 
whether char8_t support is enabled (for C++, the corresponding library 
support is dependent on the core language changes).  Restricting the 
declarations as you suggest would result in compilation errors for 
invocations like g++ -std=c++17 -fchar8_t and g++ -std=c++2x -fchar8_t.  
The char8_t dialect already exists for C++, and I think the glibc 
changes should align with that for C++.  I think it is fine if the new 
functions are declared for modes like g++ -std=gnu++17; there is no need 
to disable them with -fno-char8_t.  I therefore suggest:

#if defined __USE_GNU || /* __GLIBC_USE (ISOC2X) || */ defined __cpp_char8_t

>
>> 2) Enabling conditional code sensitive to the change of type of u8 string
>> literals.
> That might be a reason for a compiler option (I don't think it's a
> sufficient reason, I expect -std=c11 or -Wno-pointer-sign or pointer casts
> to suffice in practice), but it has nothing to do with the use of feature
> test macros in glibc since the library headers don't care at all what the
> type of u8 string literals is (there are no u8 string literals anywhere in
> glibc).
That's fair.  I think Jakub's suggestion on gcc-patches to use 
__CHAR8_TYPE__ to conditionalize sensitive code suffices.
>
>> 3) Avoiding clashes with existing uses of the char8_t identifier in code that
>> may be compiled with _GNU_SOURCE.
> It's a universal feature in glibc that all non-obsolescent,
> non-conflicting features are enabled with _GNU_SOURCE, including features
> from future standard versions - all feature test macros are subsets of
> _GNU_SOURCE, except where the features actually conflict in some way (a
> few cases where a POSIX function has semantics incompatible with a GNU
> function of the same name), and features from future standards with no
> feature test macro support in glibc (e.g. some features proposed for the
> next POSIX version) are also enabled by _GNU_SOURCE.
>
> So char8_t and these functions should be enabled by _GNU_SOURCE,
> regardless of what other options enable them.
>
> Users of _GNU_SOURCE are expected to deal with possible naming conflicts
> with features added to _GNU_SOURCE.  Likewise people building with
> -std=gnu2x / -std=c2x, which would enable these declarations if char8_t
> and these functions are added to C2x, or users of _ISOC2X_SOURCE (which
> isn't expected to be used much).
Ok, great.  I wasn't aware that _GNU_SOURCE was intended to be this 
inconclusive.
>
>> I agree that this is a narrow feature, but I think the feature test macro is
>> beneficial for compatibility reasons.  Assuming the proposal is adopted for
>> C23, some programmers may need to opt-out of the feature by compiling with
>> -fno-char8_t during a migration period; as some C++20 projects have done.
> We don't provide a way to opt out of any other library additions when
> compiling in C2x mode; compiling with -std=c2x or -std=gnu2x or
> -D_GNU_SOURCE unconditionally enables all other C2x additions in headers
> (including e.g. the iszero macro, although the issues seen with that were
> mainly for C++ code and we addressed that by making it a template instead
> of a macro for C++), compiling with e.g. -std=c11 or -std=gnu11 (and not
> using _GNU_SOURCE) is how you opt out of all such additions at the same
> time.  Likewise for previous C standard versions.  And _GNU_SOURCE is the
> universal way to opt in to features that might or might not be in a future
> standard version.  If such a feature has its own TS, we may support the
> __STDC_WANT_* macros from such a TS, but that's not a basis for creating
> our own feature test macro for a handful of new identifiers.

Perfect.

Per this and prior messages, I'll review the patch series as follows:

 1. Remove uses of the _CHAR8_T_SOURCE macro.
 2. Remove the comments added for __GLIBC_USE_ISOC2X,
    __GLIBC_USE_DEPRECATED_GETS, and __GLIBC_USE_DEPRECATED_SCANF.
 3. Remove the __GLIBC_USE_CHAR8_T macro.
 4. Conditionalize the char8_t, mbrtoc8() and c8rtomb() declarations on
    __USE_GNU and __cpp_char8_t (and perhaps __GLIBC_USE (ISOC2X)
    eventually).
 5. Transition the new tests to the support/test-driver.c driver and use
    the support/check.h interfaces.
 6. Correct the copyright statements.
 7. Remove the "contributed by" comments.

If I've forgotten anything, please let me know.

Thank you for the thorough review!

Tom.


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2021-06-11 11:25   ` Tom Honermann
@ 2021-06-11 16:28     ` Joseph Myers
  2021-06-13 15:35       ` Tom Honermann
  0 siblings, 1 reply; 27+ messages in thread
From: Joseph Myers @ 2021-06-11 16:28 UTC (permalink / raw)
  To: Tom Honermann; +Cc: libc-alpha

On Fri, 11 Jun 2021, Tom Honermann via Libc-alpha wrote:

> 1) Enabling pre-C2x compatibility with C++20.

Where a feature in a header should be enabled for a particular C++ 
version, we can have an internal __GLIBC_USE (CXX20) which is enabled 
based on the value of __cplusplus, just like the existing __USE_ISOCXX11.  
(Though that doesn't make much practical difference until we provide a way 
for C++ library headers to get all the features they need without defining 
_GNU_SOURCE.)

You'd then have

#if defined __USE_GNU || __GLIBC_USE (CXX20)

in uchar.h, with appropriate !defined __cpp_char8_t for defining the 
typedef itself.  And the defined __USE_GNU would become __GLIBC_USE 
(ISOC2X) if the feature is accepted for C2x.

> 2) Enabling conditional code sensitive to the change of type of u8 string
> literals.

That might be a reason for a compiler option (I don't think it's a 
sufficient reason, I expect -std=c11 or -Wno-pointer-sign or pointer casts 
to suffice in practice), but it has nothing to do with the use of feature 
test macros in glibc since the library headers don't care at all what the 
type of u8 string literals is (there are no u8 string literals anywhere in 
glibc).

> 3) Avoiding clashes with existing uses of the char8_t identifier in code that
> may be compiled with _GNU_SOURCE.

It's a universal feature in glibc that all non-obsolescent, 
non-conflicting features are enabled with _GNU_SOURCE, including features 
from future standard versions - all feature test macros are subsets of 
_GNU_SOURCE, except where the features actually conflict in some way (a 
few cases where a POSIX function has semantics incompatible with a GNU 
function of the same name), and features from future standards with no 
feature test macro support in glibc (e.g. some features proposed for the 
next POSIX version) are also enabled by _GNU_SOURCE.

So char8_t and these functions should be enabled by _GNU_SOURCE, 
regardless of what other options enable them.

Users of _GNU_SOURCE are expected to deal with possible naming conflicts 
with features added to _GNU_SOURCE.  Likewise people building with 
-std=gnu2x / -std=c2x, which would enable these declarations if char8_t 
and these functions are added to C2x, or users of _ISOC2X_SOURCE (which 
isn't expected to be used much).

> I agree that this is a narrow feature, but I think the feature test macro is
> beneficial for compatibility reasons.  Assuming the proposal is adopted for
> C23, some programmers may need to opt-out of the feature by compiling with
> -fno-char8_t during a migration period; as some C++20 projects have done.

We don't provide a way to opt out of any other library additions when 
compiling in C2x mode; compiling with -std=c2x or -std=gnu2x or 
-D_GNU_SOURCE unconditionally enables all other C2x additions in headers 
(including e.g. the iszero macro, although the issues seen with that were 
mainly for C++ code and we addressed that by making it a template instead 
of a macro for C++), compiling with e.g. -std=c11 or -std=gnu11 (and not 
using _GNU_SOURCE) is how you opt out of all such additions at the same 
time.  Likewise for previous C standard versions.  And _GNU_SOURCE is the 
universal way to opt in to features that might or might not be in a future 
standard version.  If such a feature has its own TS, we may support the 
__STDC_WANT_* macros from such a TS, but that's not a basis for creating 
our own feature test macro for a handful of new identifiers.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t
  2021-06-07 18:53 ` Joseph Myers
@ 2021-06-11 11:25   ` Tom Honermann
  2021-06-11 16:28     ` Joseph Myers
  0 siblings, 1 reply; 27+ messages in thread
From: Tom Honermann @ 2021-06-11 11:25 UTC (permalink / raw)
  To: Joseph Myers; +Cc: libc-alpha

On 6/7/21 2:53 PM, Joseph Myers wrote:
> On Sun, 6 Jun 2021, Tom Honermann via Libc-alpha wrote:
>
>> This patch provides implementations for the mbrtoc8 and c8rtomb functions
>> adopted for C++20 via WG21 P0482R6 [1] and proposed for C2X via WG14 N2653
>> [2].  It also provides the char8_t typedef from WG14 N2653 [2] and introduces
>> a _CHAR8_T_SOURCE feature test macro to opt-in to the new declarations.
> What's the reason for adding _CHAR8_T_SOURCE?  We don't normally have
> feature test macros for such narrow features (_ATFILE_SOURCE is not a good
> example to follow).

Thank you for the review.

There are three motivations for the feature test macro:

1) Enabling pre-C2x compatibility with C++20.

2) Enabling conditional code sensitive to the change of type of u8 
string literals.

3) Avoiding clashes with existing uses of the char8_t identifier in code 
that may be compiled with _GNU_SOURCE.

I agree that this is a narrow feature, but I think the feature test 
macro is beneficial for compatibility reasons.  Assuming the proposal is 
adopted for C23, some programmers may need to opt-out of the feature by 
compiling with -fno-char8_t during a migration period; as some C++20 
projects have done.

>
> Any new feature test macro needs documenting in creature.texi - but I
> think it would be better not to add a new feature test macro in the first
> place.  _GNU_SOURCE is suitable for a proposed-but-not-yet-adopted (or a
> feature in a future standard version for which we don't yet have feature
> test macro support), if in a particular case we get consensus to add the
> feature without it having been accepted for the standard.

Thanks for the pointer to creature.texi; I'll provide an update.

I understand the motivation for avoiding new feature test macros, but I 
think one is warranted in this case.

>
>> Additionally, in features.h, missing comments for the __GLIBC_USE_ISOC2X,
>> __GLIBC_USE_DEPRECATED_GETS, and __GLIBC_USE_DEPRECATED_SCANF macros are
>> added.
> These are covered by the description of __GLIBC_USE (F).  I don't think
> the __GLIBC_USE_* forms should have their own comments, since the version
> calling __GLIBC_USE is what should be tested everywhere in the headers.

Ok, I'll remove them.

I see I also neglected to update the comment for _CHAR8_T_SOURCE to 
reference the current paper number; will fix.

>
>> +/* Copyright (C) 2020 Free Software Foundation, Inc.
> Copyright dates should include 2021.  Each file should have a line before
> the copyright notice describing its contents.
Yes, a copy-and-forgot-to-update issue; will fix.
>
> +   Contributed by Tom Honermann <tom@honermann.net>, 2020.
>
> We don't use "Contributed by" any more in glibc.

Ok, good to know, I'll remove.

Tom.


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb,  char8_t
  2021-06-07  2:08 Tom Honermann
@ 2021-06-07 18:53 ` Joseph Myers
  2021-06-11 11:25   ` Tom Honermann
  0 siblings, 1 reply; 27+ messages in thread
From: Joseph Myers @ 2021-06-07 18:53 UTC (permalink / raw)
  To: Tom Honermann; +Cc: libc-alpha

On Sun, 6 Jun 2021, Tom Honermann via Libc-alpha wrote:

> This patch provides implementations for the mbrtoc8 and c8rtomb functions
> adopted for C++20 via WG21 P0482R6 [1] and proposed for C2X via WG14 N2653
> [2].  It also provides the char8_t typedef from WG14 N2653 [2] and introduces
> a _CHAR8_T_SOURCE feature test macro to opt-in to the new declarations.

What's the reason for adding _CHAR8_T_SOURCE?  We don't normally have 
feature test macros for such narrow features (_ATFILE_SOURCE is not a good 
example to follow).

Any new feature test macro needs documenting in creature.texi - but I 
think it would be better not to add a new feature test macro in the first 
place.  _GNU_SOURCE is suitable for a proposed-but-not-yet-adopted (or a 
feature in a future standard version for which we don't yet have feature 
test macro support), if in a particular case we get consensus to add the 
feature without it having been accepted for the standard.

> Additionally, in features.h, missing comments for the __GLIBC_USE_ISOC2X,
> __GLIBC_USE_DEPRECATED_GETS, and __GLIBC_USE_DEPRECATED_SCANF macros are
> added.

These are covered by the description of __GLIBC_USE (F).  I don't think 
the __GLIBC_USE_* forms should have their own comments, since the version 
calling __GLIBC_USE is what should be tested everywhere in the headers.

> +/* Copyright (C) 2020 Free Software Foundation, Inc.

Copyright dates should include 2021.  Each file should have a line before 
the copyright notice describing its contents.

+   Contributed by Tom Honermann <tom@honermann.net>, 2020.

We don't use "Contributed by" any more in glibc.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb,  char8_t
@ 2021-06-07  2:08 Tom Honermann
  2021-06-07 18:53 ` Joseph Myers
  0 siblings, 1 reply; 27+ messages in thread
From: Tom Honermann @ 2021-06-07  2:08 UTC (permalink / raw)
  To: libc-alpha

[-- Attachment #1: Type: text/plain, Size: 1105 bytes --]

This patch provides implementations for the mbrtoc8 and c8rtomb 
functions adopted for C++20 via WG21 P0482R6 [1] and proposed for C2X 
via WG14 N2653 [2].  It also provides the char8_t typedef from WG14 
N2653 [2] and introduces a _CHAR8_T_SOURCE feature test macro to opt-in 
to the new declarations.

The mbrtoc8 and c8rtomb functions are declared in uchar.h if either the 
C++20 __cpp_char8_t feature test macro or the _CHAR8_T_SOURCE feature 
test macro are defined.

The char8_t typedef is declared in uchar.h if _CHAR8_T_SOURCE is defined 
and __cpp_char8_t is not defined (if __cpp_char8_t is defined, then 
char8_t is a builtin type).

Additionally, in features.h, missing comments for the 
__GLIBC_USE_ISOC2X, __GLIBC_USE_DEPRECATED_GETS, and 
__GLIBC_USE_DEPRECATED_SCANF macros are added.

Tested on Linux x86_64.

Tom.

[1]: WG21 P0482R6
      "char8_t: A type for UTF-8 characters and strings (Revision 6)"
      https://wg21.link/p0482r6

[2]: WG14 N2653
      "char8_t: A type for UTF-8 characters and strings (Revision 1)"
      http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2653.htm


[-- Attachment #2: n2653-2.patch --]
[-- Type: text/x-patch, Size: 39183 bytes --]

commit 9b79320a42146cda02338941606cbf4ee0ca0db8
Author: Tom Honermann <tom@honermann.net>
Date:   Fri Feb 12 22:00:26 2021 -0500

    Implement mbrtoc8(), c8rtomb(), and the char8_t typedef.
    
    This change provides implementations for the mbrtoc8 and c8rtomb
    functions adopted for C++20 via WG21 P0482R6 and proposed for C2X
    via WG14 N2653.  It also provides the char8_t typedef from N2653
    and introduces a _CHAR8_T_SOURCE feature test macro to opt-in to
    the new declarations.
    
    The mbrtoc8 and c8rtomb functions are declared in uchar.h if
    either the C++20 __cpp_char8_t feature test macro or the
    _CHAR8_T_SOURCE feature test macro are defined.
    
    The char8_t typedef is declared in uchar.h if _CHAR8_T_SOURCE is
    defined and __cpp_char8_t is not defined (if __cpp_char8_t is
    defined, then char8_t is a builtin type).
    
    In features.h, missing comments for the __GLIBC_USE_ISOC2X,
    __GLIBC_USE_DEPRECATED_GETS, and __GLIBC_USE_DEPRECATED_SCANF
    macros are added.

diff --git a/NEWS b/NEWS
index 266837bf2d..67793fc324 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,15 @@ Major new features:
 
 * The ISO C2X function timespec_getres has been added.
 
+* The mbrtoc8 and c8rtomb functions are added for implementation of the
+  C++20 P0482R6 and C2X N2653 proposals.  These functions perform conversions
+  between multibyte sequences and the UTF-8 character encoding.  A char8_t
+  typedef is added for the C2X N2653 proposal.  The functions are declared
+  in uchar.h if the C++20 __cpp_char8_t feature test macro or the
+  _CHAR8_T_SOURCE feature test macro is defined.  The char8_t typedef is
+  declared in uchar.h if _CHAR8_T_SOURCE is defined and __cpp_char8_t is
+  not defined.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The function pthread_mutex_consistent_np has been deprecated; programs
diff --git a/include/features.h b/include/features.h
index eb97470afa..9437f0f0b8 100644
--- a/include/features.h
+++ b/include/features.h
@@ -60,6 +60,8 @@
    _REENTRANT, _THREAD_SAFE
 			Obsolete; equivalent to _POSIX_C_SOURCE=199506L.
 
+   _CHAR8_T_SOURCE	Extensions for char8_t as specified in WG14 N2231.
+
    The `-ansi' switch to the GNU C compiler, and standards conformance
    options such as `-std=c99', define __STRICT_ANSI__.  If none of
    these are defined, or if _DEFAULT_SOURCE is defined, the default is
@@ -100,6 +102,12 @@
 			MINSIGSTKSZ and SIGSTKSZ.
    __USE_GNU		Define GNU extensions.
    __USE_FORTIFY_LEVEL	Additional security measures used, according to level.
+   __GLIBC_USE_ISOC2X	Define ISO C2X things.
+   __GLIBC_USE_DEPRECATED_GETS
+			Define deprecated gets()
+   __GLIBC_USE_DEPRECATED_SCANF
+			Define deprecated scanf()
+   __GLIBC_USE_CHAR8_T	Define extensions for char8_t as specified in WG14 N2231.
 
    The macros `__GNU_LIBRARY__', `__GLIBC__', and `__GLIBC_MINOR__' are
    defined by this file unconditionally.  `__GNU_LIBRARY__' is provided
@@ -148,6 +156,7 @@
 #undef	__GLIBC_USE_ISOC2X
 #undef	__GLIBC_USE_DEPRECATED_GETS
 #undef	__GLIBC_USE_DEPRECATED_SCANF
+#undef	__GLIBC_USE_CHAR8_T
 
 /* Suppress kernel-name space pollution unless user expressedly asks
    for it.  */
@@ -457,6 +466,16 @@
 # define __GLIBC_USE_DEPRECATED_SCANF 0
 #endif
 
+/* The char8_t related c8rtomb and mbrtoc8 functions are declared if the
+   C++ __cpp_char8_t feature test macro is defined or if _CHAR8_T_SOURCE
+   is defined.  The char8_t typedef is declared if _CHAR8_T_SOURCE is
+   defined and the C++ __cpp_char8_t feature test macro is not defined.  */
+#if defined _CHAR8_T_SOURCE || defined __cpp_char8_t
+# define __GLIBC_USE_CHAR8_T   1
+#else
+# define __GLIBC_USE_CHAR8_T   0
+#endif
+
 /* Get definitions of __STDC_* predefined macros, if the compiler has
    not preincluded this header automatically.  */
 #include <stdc-predef.h>
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index 49aa809366..f536073108 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2207,7 +2207,9 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __isnanf128 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 _hurd_libc_proc_init F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 timespec_getres F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index d22c7da7ef..54eb6473ff 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2335,6 +2335,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2343,6 +2344,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index cefff3bf36..288ed25ab1 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2427,6 +2427,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2435,6 +2436,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 91a90f8ca4..3ef5eaf40f 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2094,6 +2094,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2102,6 +2103,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 120288d766..5553b89bc1 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -200,6 +200,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -208,6 +209,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index be987da77e..9813f6ca87 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -197,6 +197,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -205,6 +206,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index adb4e15cb8..d457c6e42a 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2278,6 +2278,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2286,6 +2287,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index bd022276e8..23ea3705ba 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2231,6 +2231,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2239,6 +2240,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 9e37e1cb38..39f6611ee0 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2415,6 +2415,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2423,6 +2424,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index b8089b0b0c..4bb6092441 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2267,6 +2267,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2275,6 +2276,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 093854ad85..63a8877c38 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -201,6 +201,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -209,6 +210,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 87554f1468..f3c8644e51 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2358,6 +2358,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2366,6 +2367,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index e9340671c5..5897810a1f 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2329,6 +2329,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2337,6 +2338,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 6ddc0e90cf..7d1672eb0d 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2326,6 +2326,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2334,6 +2335,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 8582c9c371..4a4a43aad7 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2323,6 +2323,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2331,6 +2332,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index b0849bec98..fa33fc92d1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2321,6 +2321,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2329,6 +2330,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 386660a5a1..3dcdfa2b39 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2329,6 +2329,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2337,6 +2338,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 4d05128f21..e4685a7e10 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2323,6 +2323,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2331,6 +2332,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index bd305f440f..3204a54838 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2368,6 +2368,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2376,6 +2377,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index c2665624aa..b0122085c9 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2385,6 +2385,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2393,6 +2394,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 13ef6ef39e..c7e4209cf5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2418,6 +2418,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2426,6 +2427,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index b21072e313..0e14ea72ca 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2232,6 +2232,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2240,6 +2241,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 62af65536c..2ff5fbc8a5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2531,6 +2531,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2539,6 +2540,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index a63aec3379..dbe5fcf2ae 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2096,6 +2096,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2104,6 +2105,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index b52efaf5ee..9b9afda286 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2296,6 +2296,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2304,6 +2305,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index b699dedcc1..1ca55714a6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2383,6 +2383,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2391,6 +2392,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 94209858b1..7348c3aa2a 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2269,6 +2269,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2277,6 +2278,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 0fab90e1e3..279f3388ac 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2238,6 +2238,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2246,6 +2247,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 2f3a64b580..cce9c390da 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2235,6 +2235,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2243,6 +2244,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index e6fe453f50..54e64f4654 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2376,6 +2376,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2384,6 +2385,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 4327cf5eb3..11f9bc8db2 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2288,6 +2288,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2296,6 +2297,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 318a6d50f9..b9cae9f7ab 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2247,6 +2247,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2255,6 +2256,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 0bcf898d4d..cf633eefa4 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2350,6 +2350,7 @@ GLIBC_2.34 __pthread_register_cancel_defer F
 GLIBC_2.34 __pthread_unregister_cancel F
 GLIBC_2.34 __pthread_unregister_cancel_restore F
 GLIBC_2.34 __pthread_unwind_next F
+GLIBC_2.34 c8rtomb F
 GLIBC_2.34 call_once F
 GLIBC_2.34 cnd_broadcast F
 GLIBC_2.34 cnd_destroy F
@@ -2358,6 +2359,7 @@ GLIBC_2.34 cnd_signal F
 GLIBC_2.34 cnd_timedwait F
 GLIBC_2.34 cnd_wait F
 GLIBC_2.34 execveat F
+GLIBC_2.34 mbrtoc8 F
 GLIBC_2.34 mtx_destroy F
 GLIBC_2.34 mtx_init F
 GLIBC_2.34 mtx_lock F
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
index f38eb5cfe1..e0c8acf591 100644
--- a/wcsmbs/Makefile
+++ b/wcsmbs/Makefile
@@ -42,7 +42,7 @@ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
 	    wcsmbsload mbsrtowcs_l \
 	    isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf \
 	    isoc99_swscanf isoc99_vswscanf \
-	    mbrtoc16 c16rtomb mbrtoc32 c32rtomb
+	    mbrtoc8 c8rtomb mbrtoc16 c16rtomb mbrtoc32 c32rtomb
 
 strop-tests :=  wcscmp wcsncmp wmemcmp wcslen wcschr wcsrchr wcscpy wcsnlen \
 		wcpcpy wcsncpy wcpncpy wcscat wcsncat wcschrnul wcsspn wcspbrk \
diff --git a/wcsmbs/Versions b/wcsmbs/Versions
index 0b31c1b940..acf6c3b705 100644
--- a/wcsmbs/Versions
+++ b/wcsmbs/Versions
@@ -49,4 +49,7 @@ libc {
     wcstof32; wcstof64; wcstof32x;
     wcstof32_l; wcstof64_l; wcstof32x_l;
   }
+  GLIBC_2.34 {
+    c8rtomb; mbrtoc8;
+  }
 }
diff --git a/wcsmbs/c8rtomb.c b/wcsmbs/c8rtomb.c
new file mode 100644
index 0000000000..ebb1e73e5c
--- /dev/null
+++ b/wcsmbs/c8rtomb.c
@@ -0,0 +1,137 @@
+/* Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Tom Honermann <tom@honermann.net>, 2020.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/* Ensure that char8_t support is enabled so that the char8_t typedef is
+   declared.  */
+#define _CHAR8_T_SOURCE
+
+#include <features.h>
+#include <errno.h>
+#include <uchar.h>
+#include <wchar.h>
+
+
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
+
+size_t
+c8rtomb (char *s, char8_t c8, mbstate_t *ps)
+{
+  /* This implementation depends on the converter invoked by wcrtomb not
+     needing to retain state in either the top most bit of ps->__count or
+     in ps->__value between invocations.  This implementation uses the
+     top most bit of ps->__count to indicate that trailing code units are
+     expected and uses ps->__value to store previously seen code units.  */
+
+  wchar_t wc;
+
+  if (ps == NULL)
+    ps = &state;
+
+  if (s == NULL)
+    {
+      /* if 's' is a null pointer, behave as if u8'\0' was passed as 'c8'.  If
+         this occurs for an incomplete code unit sequence, then an error will
+         be reported below.  */
+      c8 = u8""[0];
+    }
+
+  if (! (ps->__count & 0x80000000))
+    {
+      /* Initial state.  */
+      if ((c8 >= 0x80 && c8 <= 0xC1) || c8 >= 0xF5)
+	{
+	  /* An invalid lead code unit.  */
+	  __set_errno (EILSEQ);
+	  return -1;
+	}
+      if (c8 >= 0xC2)
+	{
+	  /* A valid lead code unit.  */
+	  ps->__count |= 0x80000000;
+	  ps->__value.__wchb[0] = c8;
+          ps->__value.__wchb[3] = 1;
+	  return 0;
+	}
+      /* A single byte (ASCII) code unit.  */
+      wc = c8;
+    }
+  else
+    {
+      char8_t cu1 = ps->__value.__wchb[0];
+      if (ps->__value.__wchb[3] == 1)
+	{
+	  /* A single lead code unit was previously seen.  */
+	  if ((c8 < 0x80 || c8 > 0xBF) ||
+               (cu1 == 0xE0 && c8 < 0xA0) ||
+               (cu1 == 0xED && c8 > 0x9F) ||
+               (cu1 == 0xF0 && c8 < 0x90) ||
+               (cu1 == 0xF4 && c8 > 0x8F))
+	    {
+	      /* An invalid second code unit.  */
+	      __set_errno (EILSEQ);
+	      return -1;
+	    }
+	  if (cu1 >= 0xE0)
+	    {
+	      /* A three or four code unit sequence.  */
+	      ps->__value.__wchb[1] = c8;
+	      ++ps->__value.__wchb[3];
+	      return 0;
+	    }
+	  wc = ((cu1 & 0x1F) << 6) +
+	       (c8 & 0x3F);
+	}
+      else
+	{
+	  char8_t cu2 = ps->__value.__wchb[1];
+	  /* A three or four byte code unit sequence.  */
+	  if (c8 < 0x80 || c8 > 0xBF)
+	    {
+	      /* An invalid third or fourth code unit.  */
+	      __set_errno (EILSEQ);
+	      return -1;
+	    }
+	  if (ps->__value.__wchb[3] == 2 && cu1 >= 0xF0)
+	    {
+	      /* A four code unit sequence.  */
+	      ps->__value.__wchb[2] = c8;
+	      ++ps->__value.__wchb[3];
+	      return 0;
+	    }
+	  if (cu1 < 0xF0)
+	    {
+	      wc = ((cu1 & 0x0F) << 12) +
+		   ((cu2 & 0x3F) << 6) +
+		   (c8 & 0x3F);
+	    }
+	  else
+	    {
+	      char8_t cu3 = ps->__value.__wchb[2];
+	      wc = ((cu1 & 0x07) << 18) +
+		   ((cu2 & 0x3F) << 12) +
+		   ((cu3 & 0x3F) << 6) +
+		   (c8 & 0x3F);
+	    }
+	}
+      ps->__count &= 0x7fffffff;
+      ps->__value.__wch = 0;
+    }
+
+  return wcrtomb (s, wc, ps);
+}
diff --git a/wcsmbs/mbrtoc8.c b/wcsmbs/mbrtoc8.c
new file mode 100644
index 0000000000..c112216de5
--- /dev/null
+++ b/wcsmbs/mbrtoc8.c
@@ -0,0 +1,131 @@
+/* Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Tom Honermann <tom@honermann.net>, 2020.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/* Ensure that char8_t support is enabled so that the char8_t typedef is
+   declared.  */
+#define _CHAR8_T_SOURCE
+
+#include <features.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <gconv.h>
+#include <uchar.h>
+#include <wcsmbsload.h>
+
+#include <sysdep.h>
+
+#ifndef EILSEQ
+# define EILSEQ EINVAL
+#endif
+
+
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
+
+size_t
+mbrtoc8 (char8_t *pc8, const char *s, size_t n, mbstate_t *ps)
+{
+  /* This implementation depends on the converter invoked by mbrtowc() not
+     needing to retain state in either the top most bit of ps->__count or
+     in ps->__value between invocations.  This implementation uses the
+     top most bit of ps->__count to indicate that trailing code units are
+     yet to be written and uses ps->__value to store those code units.  */
+
+  if (ps == NULL)
+    ps = &state;
+
+  /* If state indicates that trailing code units are yet to be written, write
+     those first regardless of whether 's' is a null pointer.  */
+  if (ps->__count & 0x80000000)
+    {
+      /* ps->__value.__wchb[3] stores the index of the next code unit to
+         write.  Code units are stored in reverse order.  */
+      size_t i = ps->__value.__wchb[3];
+      if (pc8 != NULL)
+	{
+	  *pc8 = ps->__value.__wchb[i];
+	}
+      if (i == 0)
+	{
+	  ps->__count &= 0x7fffffff;
+	  ps->__value.__wch = 0;
+	}
+      else
+	--ps->__value.__wchb[3];
+      return -3;
+    }
+
+  if (s == NULL)
+    {
+      /* if 's' is a null pointer, behave as if a null pointer was passed for
+         'pc8', an empty string was passed for 's', and 1 passed for 'n'.  */
+      pc8 = NULL;
+      s = "";
+      n = 1;
+    }
+
+  wchar_t wc;
+  size_t result;
+
+  result = mbrtowc(&wc, s, n, ps);
+  if (result <= n)
+    {
+      if (wc <= 0x7F)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = wc;
+	}
+      else if (wc <= 0x7FF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xC0 + ((wc >> 6) & 0x1F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 0;
+	  ps->__count |= 0x80000000;
+	}
+      else if (wc <= 0xFFFF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xE0 + ((wc >> 12) & 0x0F);
+	  ps->__value.__wchb[1] = 0x80 + ((wc >> 6) & 0x3F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 1;
+	  ps->__count |= 0x80000000;
+	}
+      else if (wc <= 0x10FFFF)
+	{
+	  if (pc8 != NULL)
+	    *pc8 = 0xF0 + ((wc >> 18) & 0x07);
+	  ps->__value.__wchb[2] = 0x80 + ((wc >> 12) & 0x3F);
+	  ps->__value.__wchb[1] = 0x80 + ((wc >> 6) & 0x3F);
+	  ps->__value.__wchb[0] = 0x80 + (wc & 0x3F);
+	  ps->__value.__wchb[3] = 2;
+	  ps->__count |= 0x80000000;
+	}
+    }
+  if (result == 0 && wc != 0)
+    {
+      /* mbrtowc() never returns -3.  When a MB sequence converts to multiple
+         WCs, no input is consumed when writing the subsequent WCs resulting
+         in a result of 0 even if a null character wasn't written.  */
+      result = -3;
+    }
+
+  return result;
+}
diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
index 6020f66cf6..b23ff1a5ac 100644
--- a/wcsmbs/uchar.h
+++ b/wcsmbs/uchar.h
@@ -31,6 +31,14 @@
 #include <bits/types.h>
 #include <bits/types/mbstate_t.h>
 
+/* Define the char8_t typedef if support is enabled, but only if the C++
+   predefined feature test macro that indicates char8_t is a builtin type
+   is not defined.  */
+#if __GLIBC_USE (CHAR8_T) && !defined __cpp_char8_t
+/* Define the 8-bit character type.  */
+typedef unsigned char char8_t;
+#endif
+
 #ifndef __USE_ISOCXX11
 /* Define the 16-bit and 32-bit character types.  */
 typedef __uint_least16_t char16_t;
@@ -40,6 +48,18 @@ typedef __uint_least32_t char32_t;
 
 __BEGIN_DECLS
 
+#if __GLIBC_USE (CHAR8_T)
+/* Write char8_t representation of multibyte character pointed
+   to by S to PC8.  */
+extern size_t mbrtoc8  (char8_t *__restrict __pc8,
+			const char *__restrict __s, size_t __n,
+			mbstate_t *__restrict __p) __THROW;
+
+/* Write multibyte representation of char8_t C8 to S.  */
+extern size_t c8rtomb  (char *__restrict __s, char8_t __c8,
+			mbstate_t *__restrict __ps) __THROW;
+#endif
+
 /* Write char16_t representation of multibyte character pointed
    to by S to PC16.  */
 extern size_t mbrtoc16 (char16_t *__restrict __pc16,



^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2022-05-18 17:57 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-08  0:39 [PATCH 2/3]: C++20 P0482R6 and C2X N2653: Implement mbrtoc8, c8rtomb, char8_t Tom Honermann
2022-01-11  0:53 ` Joseph Myers
2022-01-11 19:23   ` Tom Honermann
2022-01-20 23:17     ` Tom Honermann
2022-01-21 20:01       ` Adhemerval Zanella
2022-01-22 12:24         ` Tom Honermann
2022-02-16 18:29           ` Joseph Myers
2022-02-16 19:14             ` tom
  -- strict thread matches above, loose matches on Subject: below --
2022-02-27 16:53 Tom Honermann
2022-02-28 23:01 ` Joseph Myers
2022-03-01  3:40   ` Tom Honermann
2022-05-17 15:57     ` Carlos O'Donell
2022-05-17 18:05     ` Adhemerval Zanella
2022-05-17 18:12       ` Joseph Myers
2022-05-17 18:17         ` Adhemerval Zanella
2022-05-17 21:33           ` Florian Weimer
2022-05-18 15:32             ` Tom Honermann
2022-05-18 16:17               ` Adhemerval Zanella
2022-05-18 17:26                 ` Tom Honermann
2022-05-18 17:39                   ` Adhemerval Zanella
2022-05-18 17:40                 ` Florian Weimer
2022-05-18 17:57                   ` Adhemerval Zanella
2021-06-07  2:08 Tom Honermann
2021-06-07 18:53 ` Joseph Myers
2021-06-11 11:25   ` Tom Honermann
2021-06-11 16:28     ` Joseph Myers
2021-06-13 15:35       ` Tom Honermann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).