On Mon, 05 Jan 2026 at 18:46 -0800, Keith Packard wrote:
Existing toolchain builds rely on the similarity between picolibc and
newlib when building libstdc++ and use --with-newlib.

Switch to the picolibc 16-bit _ctype_wide array which provides
separate values for ctype_base::blank and ctype_base::space.

This fixes a bug where libstdc++ was including '\f', '\n', '\r' and
'\v' in the set of 'blank' chars. Afterwards, only ' ' and '\t' are in
this set, as specified by C++ 11.

Signed-off-by: Keith Packard <[email protected]>
---
libstdc++-v3/acinclude.m4                     |   4 +
libstdc++-v3/config/os/picolibc/ctype_base.h  |  61 ++++++++++
.../os/picolibc/ctype_configure_char.cc       | 105 ++++++++++++++++++
.../config/os/picolibc/ctype_inline.h         |  74 ++++++++++++
libstdc++-v3/config/os/picolibc/os_defines.h  |  61 ++++++++++
libstdc++-v3/configure.ac                     |  62 +++++++++++
6 files changed, 367 insertions(+)
create mode 100644 libstdc++-v3/config/os/picolibc/ctype_base.h
create mode 100644 libstdc++-v3/config/os/picolibc/ctype_configure_char.cc
create mode 100644 libstdc++-v3/config/os/picolibc/ctype_inline.h
create mode 100644 libstdc++-v3/config/os/picolibc/os_defines.h

diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 103515c000f..1eb575d3202 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -81,6 +81,10 @@ AC_DEFUN([GLIBCXX_CONFIGURE], [
    AC_HELP_STRING([--with-newlib],
                   [assume newlib as a system C library]))

+  AC_ARG_WITH([picolibc],
+    AC_HELP_STRING([--with-picolibc],
+                  [assume picolibc as a system C library]))
+
  # Will set LN_S to either 'ln -s', 'ln', or 'cp -p' (if linking isn't
  # available).  Uncomment the next line to force a particular method.
  AC_PROG_LN_S
diff --git a/libstdc++-v3/config/os/picolibc/ctype_base.h 
b/libstdc++-v3/config/os/picolibc/ctype_base.h
new file mode 100644
index 00000000000..0d73c74387f
--- /dev/null
+++ b/libstdc++-v3/config/os/picolibc/ctype_base.h
@@ -0,0 +1,61 @@
+// Locale support -*- C++ -*-
+
+// Copyright (C) 2000-2026 Free Software Foundation, Inc.

Are the copyright dates correct? Was this file based on an existing
one? (If so, copying the dates from the original file is fine.)

Same question to all files with dates earlier than 2026.

+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This 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 General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+//
+// ISO C++ 14882: 22.1  Locales
+//
+
+// Information as gleaned from /usr/include/ctype.h
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  /// @brief  Base class for ctype.
+  struct ctype_base
+  {
+    // Non-standard typedefs.
+    typedef const int*                 __to_type;
+
+    // NB: Offsets into ctype<char>::_M_table force a particular size
+    // on the mask type. Because of this, we don't use an enum.
+    typedef short              mask;
+    static const mask upper            = mask (__CTYPE_UPPER);
+    static const mask lower    = mask (__CTYPE_LOWER);
+    static const mask alpha    = mask (__CTYPE_UPPER | __CTYPE_LOWER);
+    static const mask digit    = mask (__CTYPE_DIGIT);
+    static const mask xdigit   = mask (__CTYPE_HEX | __CTYPE_DIGIT);
+    static const mask space    = mask (__CTYPE_SPACE);
+    static const mask print    = mask (__CTYPE_PUNCT | __CTYPE_UPPER | 
__CTYPE_LOWER | __CTYPE_DIGIT | __CTYPE_BLANK);
+    static const mask graph    = mask (__CTYPE_PUNCT | __CTYPE_UPPER | 
__CTYPE_LOWER | __CTYPE_DIGIT);
+    static const mask cntrl    = mask (__CTYPE_CNTRL);
+    static const mask punct    = mask (__CTYPE_PUNCT);
+    static const mask alnum    = mask (__CTYPE_UPPER | __CTYPE_LOWER | 
__CTYPE_DIGIT);
+#if __cplusplus >= 201103L
+    static const mask blank    = mask (__CTYPE_BLANK | __CTYPE_TAB);
+#endif
+  };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
diff --git a/libstdc++-v3/config/os/picolibc/ctype_configure_char.cc 
b/libstdc++-v3/config/os/picolibc/ctype_configure_char.cc
new file mode 100644
index 00000000000..74370d4be49
--- /dev/null
+++ b/libstdc++-v3/config/os/picolibc/ctype_configure_char.cc
@@ -0,0 +1,105 @@
+// Locale support -*- C++ -*-
+
+// Copyright (C) 2011-2026 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This 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 General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file ctype_configure_char.cc */
+
+//
+// ISO C++ 14882: 22.1  Locales
+//
+
+#include <locale>
+#include <cstdlib>
+#include <cstring>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+// Information as gleaned from /usr/include/ctype.h
+
+  const ctype_base::mask*
+  ctype<char>::classic_table() throw()
+  { return _ctype_wide + 1; }
+
+  ctype<char>::ctype(__c_locale, const mask* __table, bool __del,
+                    size_t __refs)
+  : facet(__refs), _M_del(__table != 0 && __del),
+  _M_toupper(NULL), _M_tolower(NULL),
+  _M_table(__table ? __table : classic_table())
+  {
+    memset(_M_widen, 0, sizeof(_M_widen));
+    _M_widen_ok = 0;
+    memset(_M_narrow, 0, sizeof(_M_narrow));
+    _M_narrow_ok = 0;
+  }
+
+  ctype<char>::ctype(const mask* __table, bool __del, size_t __refs)
+  : facet(__refs), _M_del(__table != 0 && __del),
+  _M_toupper(NULL), _M_tolower(NULL),
+  _M_table(__table ? __table : classic_table())
+  {
+    memset(_M_widen, 0, sizeof(_M_widen));
+    _M_widen_ok = 0;
+    memset(_M_narrow, 0, sizeof(_M_narrow));
+    _M_narrow_ok = 0;
+  }
+
+  char
+  ctype<char>::do_toupper(char __c) const
+  {
+    int __x = __c;
+    return (this->is(ctype_base::lower, __c) ? (__x - 'a' + 'A') : __x);
+  }
+
+  const char*
+  ctype<char>::do_toupper(char* __low, const char* __high) const
+  {
+    while (__low < __high)
+      {
+       *__low = this->do_toupper(*__low);
+       ++__low;
+      }
+    return __high;
+  }
+
+  char
+  ctype<char>::do_tolower(char __c) const
+  {
+    int __x = __c;
+    return (this->is(ctype_base::upper, __c) ? (__x - 'A' + 'a') : __x);
+  }
+
+  const char*
+  ctype<char>::do_tolower(char* __low, const char* __high) const
+  {
+    while (__low < __high)
+      {
+       *__low = this->do_tolower(*__low);
+       ++__low;
+      }
+    return __high;
+  }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
diff --git a/libstdc++-v3/config/os/picolibc/ctype_inline.h 
b/libstdc++-v3/config/os/picolibc/ctype_inline.h
new file mode 100644
index 00000000000..950983800e7
--- /dev/null
+++ b/libstdc++-v3/config/os/picolibc/ctype_inline.h
@@ -0,0 +1,74 @@
+// Locale support -*- C++ -*-
+
+// Copyright (C) 2000-2026 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This 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 General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/ctype_inline.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{locale}
+ */
+
+//
+// ISO C++ 14882: 22.1  Locales
+//
+
+// ctype bits to be inlined go here. Non-inlinable (ie virtual do_*)
+// functions go in ctype.cc
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  bool
+  ctype<char>::
+  is(mask __m, char __c) const
+  { return _M_table[static_cast<unsigned char>(__c)] & __m; }
+
+  const char*
+  ctype<char>::
+  is(const char* __low, const char* __high, mask* __vec) const
+  {
+    while (__low < __high)
+      *__vec++ = _M_table[static_cast<unsigned char>(*__low++)];
+    return __high;
+  }
+
+  const char*
+  ctype<char>::
+  scan_is(mask __m, const char* __low, const char* __high) const
+  {
+    while (__low < __high && !this->is(__m, *__low))
+      ++__low;
+    return __low;
+  }
+
+  const char*
+  ctype<char>::
+  scan_not(mask __m, const char* __low, const char* __high) const
+  {
+    while (__low < __high && this->is(__m, *__low) != 0)
+      ++__low;
+    return __low;
+  }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
diff --git a/libstdc++-v3/config/os/picolibc/os_defines.h 
b/libstdc++-v3/config/os/picolibc/os_defines.h
new file mode 100644
index 00000000000..fa180715d9e
--- /dev/null
+++ b/libstdc++-v3/config/os/picolibc/os_defines.h
@@ -0,0 +1,61 @@
+// Specific definitions for newlib  -*- C++ -*-

s/newlib/picolibc/

+
+// Copyright (C) 2000-2026 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This 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 General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/os_defines.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{iosfwd}
+ */
+
+#ifndef _GLIBCXX_OS_DEFINES
+#define _GLIBCXX_OS_DEFINES 1
+
+// System-specific #define, typedefs, corrections, etc, go here.  This
+// file will come before all others.
+
+#ifdef __CYGWIN__

I don't think any of this cygwin-specific content is relevant to
picolibc, right? So this should be am empty file (and doesn't need to
be copyright 2000-2026, just 2026).



+#define _GLIBCXX_GTHREAD_USE_WEAK 0

This is the only one which might be relevant for your target, should
this be defined to 0? If it should (or if it's not relevant because
your target doesn't support gthreads anyway) you could just use
os_include_dir=os/generic in configure.ac and not bother to add a
custom os/picolibc/os_defines.h file at all.


+
+#if defined (_GLIBCXX_DLL)
+#define _GLIBCXX_PSEUDO_VISIBILITY_default __attribute__ ((__dllimport__))
+#else
+#define _GLIBCXX_PSEUDO_VISIBILITY_default
+#endif
+#define _GLIBCXX_PSEUDO_VISIBILITY_hidden
+
+#define _GLIBCXX_PSEUDO_VISIBILITY(V) _GLIBCXX_PSEUDO_VISIBILITY_ ## V
+
+// See libstdc++/20806.
+#define _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM 1
+
+// Enable use of GetModuleHandleEx (requires Windows XP/2003) in
+// __cxa_thread_atexit to prevent modules from being unloaded before
+// their dtors are called
+#define _GLIBCXX_THREAD_ATEXIT_WIN32 1
+
+// See libstdc++/69506
+#define _GLIBCXX_USE_WEAK_REF 0
+
+#endif
+
+#endif
diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index 339e7bb17a4..cd038ee85ac 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -100,6 +100,7 @@ GLIBCXX_CONFIGURE

# Libtool setup.
if test "x${with_newlib}" != "xyes" &&
+    test "x${with_picolibc}" != "xyes" &&
    test "x${with_avrlibc}" != "xyes" &&
    test "x$with_headers" != "xno"; then
  AC_LIBTOOL_DLOPEN
@@ -428,6 +429,67 @@ dnl # rather than hardcoding that information.
        glibcxx_cv_mkdir=yes
        ;;
    esac
+  elif test "x${with_picolibc}" = "xyes"; then
+    os_include_dir="os/picolibc"
+    AC_DEFINE(HAVE_HYPOT)
+
+    # GLIBCXX_CHECK_STDLIB_SUPPORT
+    AC_DEFINE(HAVE_STRTOF)
+
+    AC_DEFINE(HAVE_ACOSF)
+    AC_DEFINE(HAVE_ASINF)
+    AC_DEFINE(HAVE_ATAN2F)
+    AC_DEFINE(HAVE_ATANF)
+    AC_DEFINE(HAVE_CEILF)
+    AC_DEFINE(HAVE_COSF)
+    AC_DEFINE(HAVE_COSHF)
+    AC_DEFINE(HAVE_EXPF)
+    AC_DEFINE(HAVE_FABSF)
+    AC_DEFINE(HAVE_FLOORF)
+    AC_DEFINE(HAVE_FMODF)
+    AC_DEFINE(HAVE_FREXPF)
+    AC_DEFINE(HAVE_HYPOTF)
+    AC_DEFINE(HAVE_LDEXPF)
+    AC_DEFINE(HAVE_LOG10F)
+    AC_DEFINE(HAVE_LOGF)
+    AC_DEFINE(HAVE_MODFF)
+    AC_DEFINE(HAVE_POWF)
+    AC_DEFINE(HAVE_SINF)
+    AC_DEFINE(HAVE_SINHF)
+    AC_DEFINE(HAVE_SQRTF)
+    AC_DEFINE(HAVE_TANF)
+    AC_DEFINE(HAVE_TANHF)
+
+    # Support for iconv in picolibc is configurable.
+    AC_TRY_COMPILE([#include <picolibc.h>], [
+      #ifndef _ICONV_ENABLED
+      #error
+      #endif], [ac_picolibc_iconv_enabled=yes], [ac_picolibc_iconv_enabled=no])
+    if test "$ac_picolibc_iconv_enabled" = yes; then
+      AC_DEFINE(HAVE_ICONV)
+    fi
+
+    AC_DEFINE(HAVE_MEMALIGN)
+
+    # Check for TLS
+    AC_TRY_COMPILE([#include <picolibc.h>], [
+      #ifndef __THREAD_LOCAL_STORAGE
+      #error
+      #endif], [ac_picolibc_tls_enabled=yes], [ac_picolibc_tls_enabled=no])
+    if test "$ac_picolibc_tls_enabled" = yes; then
+      AC_DEFINE(HAVE_TLS)
+    fi
+
+    AC_DEFINE(HAVE_ALIGNED_ALLOC)
+    AC_DEFINE(HAVE_AT_QUICK_EXIT)
+    AC_DEFINE(HAVE_LINK)
+    AC_DEFINE(HAVE_SYS_STAT_H)
+    AC_DEFINE(HAVE_SYS_TYPES_H)
+    AC_DEFINE(HAVE_SETENV)
+    AC_DEFINE(HAVE_STRERROR_L)
+    AC_DEFINE(HAVE_S_ISREG)
+    AC_DEFINE(HAVE_UNISTD_H)
+
  elif test "x$with_headers" != "xno"; then
    GLIBCXX_CROSSCONFIG
  fi
--
2.51.0



Reply via email to