[libcxx-commits] [libcxx] [zOS] Avoid ambiguous declarations when z/OS libc or wrpper lib adds functionality (PR #133104)

Sean Perry via libcxx-commits libcxx-commits at lists.llvm.org
Wed Mar 26 10:25:41 PDT 2025


https://github.com/perry-ca updated https://github.com/llvm/llvm-project/pull/133104

>From 5b42f60aedba50a3118344054c390c6b618ca336 Mon Sep 17 00:00:00 2001
From: Sean Perry <perry at ca.ibm.com>
Date: Wed, 26 Mar 2025 11:05:45 -0400
Subject: [PATCH 1/4] upstream fixes for z/OS

---
 .../__locale_dir/locale_base_api/ibm.h        | 40 ++++++++++++++-----
 libcxx/include/__thread/support/pthread.h     |  8 +++-
 2 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/libcxx/include/__locale_dir/locale_base_api/ibm.h b/libcxx/include/__locale_dir/locale_base_api/ibm.h
index 1d1d15df9f799..9d51043b7ffdb 100644
--- a/libcxx/include/__locale_dir/locale_base_api/ibm.h
+++ b/libcxx/include/__locale_dir/locale_base_api/ibm.h
@@ -22,31 +22,41 @@
 
 #if defined(__MVS__)
 #  include <wctype.h>
-// POSIX routines
-#  include <__support/xlocale/__posix_l_fallback.h>
 #endif // defined(__MVS__)
 
+_LIBCPP_BEGIN_NAMESPACE_STD
+#ifdef __MVS__
+#define _LIBCPP_CLOC std::__c_locale()
+#ifndef _LIBCPP_LC_GLOBAL_LOCALE
+#define _LIBCPP_LC_GLOBAL_LOCALE ((locale_t) -1)
+#endif
+#else
+extern locale_t __cloc();
+#define _LIBCPP_CLOC std::__cloc()
+#endif
+_LIBCPP_END_NAMESPACE_STD
+
+#ifdef __MVS__
+_LIBCPP_BEGIN_NAMESPACE_STD
+#endif
+
 namespace {
 
 struct __setAndRestore {
-  explicit __setAndRestore(locale_t locale) {
-    if (locale == (locale_t)0) {
-      __cloc   = newlocale(LC_ALL_MASK, "C", /* base */ (locale_t)0);
-      __stored = uselocale(__cloc);
+  explicit __setAndRestore(locale_t __l) {
+    if (__l == (locale_t)0) {
+      __stored = std::uselocale(_LIBCPP_CLOC);
     } else {
-      __stored = uselocale(locale);
+      __stored = std::uselocale(__l);
     }
   }
 
   ~__setAndRestore() {
-    uselocale(__stored);
-    if (__cloc)
-      freelocale(__cloc);
+    std::uselocale(__stored);
   }
 
 private:
   locale_t __stored = (locale_t)0;
-  locale_t __cloc   = (locale_t)0;
 };
 
 } // namespace
@@ -89,7 +99,11 @@ _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 2, 0) int vasprintf(char** strp, const char
   va_list ap_copy;
   // va_copy may not be provided by the C library in C++03 mode.
 #if defined(_LIBCPP_CXX03_LANG) && __has_builtin(__builtin_va_copy)
+#if defined(__MVS__) && !defined(_VARARG_EXT_)
+  __builtin_zos_va_copy(ap_copy, ap);
+#else
   __builtin_va_copy(ap_copy, ap);
+#endif
 #else
   va_copy(ap_copy, ap);
 #endif
@@ -105,4 +119,8 @@ _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 2, 0) int vasprintf(char** strp, const char
   return str_size;
 }
 
+#ifdef __MVS__
+_LIBCPP_END_NAMESPACE_STD
+#endif
+
 #endif // _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_IBM_H
diff --git a/libcxx/include/__thread/support/pthread.h b/libcxx/include/__thread/support/pthread.h
index 14e92079dadfe..f32dbd7f09253 100644
--- a/libcxx/include/__thread/support/pthread.h
+++ b/libcxx/include/__thread/support/pthread.h
@@ -194,9 +194,15 @@ inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_detach(__libcpp_thread_t* __t)
 inline _LIBCPP_HIDE_FROM_ABI void __libcpp_thread_yield() { sched_yield(); }
 
 inline _LIBCPP_HIDE_FROM_ABI void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) {
+#ifdef __MVS__
+  #define __LIBCPP_NS __ibm::
+#else
+  #define __LIBCPP_NS
+#endif
   __libcpp_timespec_t __ts = std::__convert_to_timespec<__libcpp_timespec_t>(__ns);
-  while (nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
+  while (__LIBCPP_NS nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
     ;
+#undef __LIBCPP_NS
 }
 
 //

>From 7832978ffeb3ef56ea2227480bdd205192deb558 Mon Sep 17 00:00:00 2001
From: Sean Perry <perry at ca.ibm.com>
Date: Wed, 26 Mar 2025 11:13:50 -0400
Subject: [PATCH 2/4] make functionlity conform to specs & fix memory leak

---
 libcxx/src/support/ibm/xlocale_zos.cpp | 402 +++++++++++++++++++------
 1 file changed, 302 insertions(+), 100 deletions(-)

diff --git a/libcxx/src/support/ibm/xlocale_zos.cpp b/libcxx/src/support/ibm/xlocale_zos.cpp
index 136999ec0b02f..fa5fb745df88e 100644
--- a/libcxx/src/support/ibm/xlocale_zos.cpp
+++ b/libcxx/src/support/ibm/xlocale_zos.cpp
@@ -6,125 +6,327 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "include/ibm_xlocale.h"
+
 #include <__assert>
-#include <__support/ibm/xlocale.h>
-#include <sstream>
-#include <vector>
+#include <__locale_dir/locale_base_api/ibm.h>
+#include <errno.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
+_LIBCPP_BEGIN_NAMESPACE_STD
 
-locale_t newlocale(int category_mask, const char* locale, locale_t base) {
-  // Maintain current locale name(s) to restore later.
-  std::string current_loc_name(setlocale(LC_ALL, 0));
+#define CategoryList(pair, sep) \
+  pair(LC_COLLATE, lc_collate) sep \
+  pair(LC_CTYPE, lc_ctype) sep \
+  pair(LC_MONETARY, lc_monetary) sep \
+  pair(LC_NUMERIC, lc_numeric) sep \
+  pair(LC_TIME, lc_time) sep \
+  pair(LC_MESSAGES, lc_messages)
+
+// check ids and masks agree
+#define check_ids_and_masks_agree(id, _) \
+  static_assert((1 << id) == id##_MASK, "id and mask do not agree for " #id); \
+  static_assert((1 << id) == _CATMASK(id), "mask does not have expected value for " #id);
+CategoryList(check_ids_and_masks_agree,)
+#undef check_ids_and_masks_agree
+
+// check that LC_ALL_MASK is defined as expected
+#define get_mask(id, _) id##_MASK
+static_assert(LC_ALL_MASK == (CategoryList(get_mask, |)), "LC_ALL_MASK does not have the expected value.  Check that its definition includes all supported categories");
+#undef get_mask
+
+
+// initialize c_locale
+#define init_clocale(id, locale_member) "C",
+static locale_struct c_locale = { LC_ALL_MASK, CategoryList(init_clocale, ) };
+#undef init_clocale
 
-  // Check for errors.
-  if (category_mask == LC_ALL_MASK && setlocale(LC_ALL, locale) == nullptr) {
+static locale_t current_locale = _LIBCPP_LC_GLOBAL_LOCALE;
+
+
+locale_t __c_locale() {
+  return &c_locale;
+}
+
+// locale
+locale_t newlocale(int category_mask, const char* locale, locale_t base) {
+  // start with some basic checks
+  if (! locale) {
     errno = EINVAL;
-    return (locale_t)0;
-  } else {
-    for (int _Cat = 0; _Cat <= _LC_MAX; ++_Cat) {
-      if ((_CATMASK(_Cat) & category_mask) != 0 && setlocale(_Cat, locale) == nullptr) {
-        setlocale(LC_ALL, current_loc_name.c_str());
-        errno = EINVAL;
-        return (locale_t)0;
-      }
-    }
+    return (locale_t) 0;
+  }
+  if (category_mask & ~LC_ALL_MASK) {
+    // then there are bits in category_mask that does not correspond
+    // to a valid category
+    errno = EINVAL;
+    return (locale_t) 0;
   }
 
-  // Create new locale.
-  locale_t newloc = new locale_struct();
+  locale_t  new_loc = new locale_struct;
+  int num_locales_not_found = 0;
+
+  if (base && base != _LIBCPP_LC_GLOBAL_LOCALE)
+    *new_loc = *base;
+
+  auto set_for_category = [&](int id, int mask, std::string &setting) {
+    const char *setting_to_apply = nullptr;
+
+    if (category_mask & mask)
+      setting_to_apply = locale;
+    else if (!base)
+      setting_to_apply = "C";
 
-  if (base) {
-    if (category_mask != LC_ALL_MASK) {
-      // Copy base when it will not be overwritten.
-      memcpy(newloc, base, sizeof(locale_struct));
-      newloc->category_mask = category_mask | base->category_mask;
+    if (setting_to_apply) {
+      // setlocale takes the id, not the mask
+      const char *saved_setting = setlocale(id, nullptr);
+      if (setlocale(id, setting_to_apply)) {
+        // then setting_to_apply is valid for this category
+        // restore the saved setting
+        setlocale(id, saved_setting);
+
+        new_loc->category_mask |= mask;
+        setting = setting_to_apply;
+      } else {
+        // unknown locale for this category
+        num_locales_not_found++;
+      }
     }
-    delete base;
-  } else {
-    newloc->category_mask = category_mask;
+  };
+
+  // now overlay values
+#define Set(id, locale_member) set_for_category(id, id##_MASK, new_loc->locale_member)
+  CategoryList(Set, ;);
+#undef Set
+
+  if (num_locales_not_found != 0) {
+    delete new_loc;
+    errno = ENOENT;
+    new_loc = (locale_t) 0;
   }
 
-  if (category_mask & LC_COLLATE_MASK)
-    newloc->lc_collate = locale;
-  if (category_mask & LC_CTYPE_MASK)
-    newloc->lc_ctype = locale;
-  if (category_mask & LC_MONETARY_MASK)
-    newloc->lc_monetary = locale;
-  if (category_mask & LC_NUMERIC_MASK)
-    newloc->lc_numeric = locale;
-  if (category_mask & LC_TIME_MASK)
-    newloc->lc_time = locale;
-  if (category_mask & LC_MESSAGES_MASK)
-    newloc->lc_messages = locale;
-
-  // Restore current locale.
-  setlocale(LC_ALL, current_loc_name.c_str());
-  return (locale_t)newloc;
-}
-
-void freelocale(locale_t locobj) { delete locobj; }
-
-locale_t uselocale(locale_t newloc) {
-  // Maintain current locale name(s).
-  std::string current_loc_name(setlocale(LC_ALL, 0));
-
-  if (newloc) {
-    // Set locales and check for errors.
-    bool is_error =
-        (newloc->category_mask & LC_COLLATE_MASK && setlocale(LC_COLLATE, newloc->lc_collate.c_str()) == nullptr) ||
-        (newloc->category_mask & LC_CTYPE_MASK && setlocale(LC_CTYPE, newloc->lc_ctype.c_str()) == nullptr) ||
-        (newloc->category_mask & LC_MONETARY_MASK && setlocale(LC_MONETARY, newloc->lc_monetary.c_str()) == nullptr) ||
-        (newloc->category_mask & LC_NUMERIC_MASK && setlocale(LC_NUMERIC, newloc->lc_numeric.c_str()) == nullptr) ||
-        (newloc->category_mask & LC_TIME_MASK && setlocale(LC_TIME, newloc->lc_time.c_str()) == nullptr) ||
-        (newloc->category_mask & LC_MESSAGES_MASK && setlocale(LC_MESSAGES, newloc->lc_messages.c_str()) == nullptr);
-
-    if (is_error) {
-      setlocale(LC_ALL, current_loc_name.c_str());
+  return new_loc;
+}
+
+void freelocale(locale_t locobj) {
+  if (locobj != nullptr && locobj != &c_locale && locobj != _LIBCPP_LC_GLOBAL_LOCALE)
+    delete locobj;
+}
+
+locale_t uselocale(locale_t new_loc) {
+  locale_t prev_loc = current_locale;
+
+  if (new_loc == _LIBCPP_LC_GLOBAL_LOCALE) {
+    current_locale = _LIBCPP_LC_GLOBAL_LOCALE;
+  } else if (new_loc != nullptr) {
+    locale_struct  saved_locale;
+    saved_locale.category_mask = 0;
+
+    auto apply_category = [&](int id, int mask, std::string &setting, std::string &save_setting)-> bool {
+      if (new_loc->category_mask & mask) {
+        const char *old_setting = setlocale(id, setting.c_str());
+        if (old_setting) {
+          // we were able to set for this category.  Save the old setting
+          // in case a subsequent category fails, and we need to restore
+          // all earlier settings.
+          saved_locale.category_mask |= mask;
+          save_setting = old_setting;
+          return true;
+        }
+        return false;
+      }
+      return true;
+    };
+
+#define Apply(id, locale_member) apply_category(id, id##_MASK, new_loc->locale_member, saved_locale. locale_member)
+    bool is_ok = CategoryList(Apply, &&);
+#undef Apply
+
+    if (!is_ok) {
+      auto restore = [&](int id, int mask, std::string &setting) {
+        if (saved_locale.category_mask & mask)
+          setlocale(id, setting.c_str());
+      };
+#define Restore(id, locale_member) restore(id, id##_MASK, saved_locale. locale_member);
+      CategoryList(Restore,);
+#undef Restore
       errno = EINVAL;
-      return (locale_t)0;
+      return nullptr;
     }
+    current_locale = new_loc;
   }
 
-  // Construct and return previous locale.
-  locale_t previous_loc = new locale_struct();
+  return prev_loc;
+}
 
-  // current_loc_name might be a comma-separated locale name list.
-  if (current_loc_name.find(',') != std::string::npos) {
-    // Tokenize locale name list.
-    const char delimiter = ',';
-    std::vector<std::string> tokenized;
-    std::stringstream ss(current_loc_name);
-    std::string s;
+int isdigit_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::isdigit(__c);
+}
 
-    while (std::getline(ss, s, delimiter)) {
-      tokenized.push_back(s);
-    }
+int isxdigit_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::isxdigit(__c);
+}
 
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(tokenized.size() >= _NCAT, "locale-name list is too short");
-
-    previous_loc->lc_collate  = tokenized[LC_COLLATE];
-    previous_loc->lc_ctype    = tokenized[LC_CTYPE];
-    previous_loc->lc_monetary = tokenized[LC_MONETARY];
-    previous_loc->lc_numeric  = tokenized[LC_NUMERIC];
-    previous_loc->lc_time     = tokenized[LC_TIME];
-    // Skip LC_TOD.
-    previous_loc->lc_messages = tokenized[LC_MESSAGES];
-  } else {
-    previous_loc->lc_collate  = current_loc_name;
-    previous_loc->lc_ctype    = current_loc_name;
-    previous_loc->lc_monetary = current_loc_name;
-    previous_loc->lc_numeric  = current_loc_name;
-    previous_loc->lc_time     = current_loc_name;
-    previous_loc->lc_messages = current_loc_name;
-  }
+namespace __ibm {
+int isalnum_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::isalnum(__c);
+}
+
+int isalpha_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::isalpha(__c);
+}
+
+int isblank_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::isblank(__c);
+}
+
+int iscntrl_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iscntrl(__c);
+}
+
+int isgraph_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::isgraph(__c);
+}
+
+int islower_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::islower(__c);
+}
+
+int isprint_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::isprint(__c);
+}
+
+int ispunct_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::ispunct(__c);
+}
+
+int isspace_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::isspace(__c);
+}
+
+int isupper_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::isupper(__c);
+}
+
+int iswalnum_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswalnum(__c);
+}
+
+int iswalpha_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswalpha(__c);
+}
+
+int iswblank_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswblank(__c);
+}
+
+int iswcntrl_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswcntrl(__c);
+}
+
+int iswdigit_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswdigit(__c);
+}
+
+int iswgraph_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswgraph(__c);
+}
+
+int iswlower_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswlower(__c);
+}
+
+int iswprint_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswprint(__c);
+}
+
+int iswpunct_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswpunct(__c);
+}
+
+int iswspace_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswspace(__c);
+}
+
+int iswupper_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswupper(__c);
+}
+
+int iswxdigit_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswxdigit(__c);
+}
+
+int toupper_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::toupper(__c);
+}
+
+int tolower_l(int __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::tolower(__c);
+}
+
+wint_t towupper_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::towupper(__c);
+}
+
+wint_t towlower_l(wint_t __c, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::towlower(__c);
+}
+
+int strcoll_l(const char *__s1, const char *__s2, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::strcoll(__s1, __s2);
+}
+
+size_t strxfrm_l(char *__dest, const char *__src, size_t __n, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::strxfrm(__dest, __src, __n);
+}
+
+size_t strftime_l(char *__s, size_t __max, const char *__format, const struct tm *__tm, 
+                                                  locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::strftime(__s, __max, __format, __tm);
+}
+
+int wcscoll_l(const wchar_t *__ws1, const wchar_t *__ws2, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::wcscoll(__ws1, __ws2);
+}
 
-  previous_loc->category_mask = LC_ALL_MASK;
-  return previous_loc;
+size_t wcsxfrm_l(wchar_t *__dest, const wchar_t *__src, size_t __n, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::wcsxfrm(__dest, __src, __n);
 }
 
-#ifdef __cplusplus
+int iswctype_l(wint_t __c, wctype_t __type, locale_t  __l) {
+  __setAndRestore __newloc(__l);
+  return ::iswctype(__c, __type);
 }
-#endif // __cplusplus
+} // namespace __ibm
+_LIBCPP_END_NAMESPACE_STD

>From 54ef2e1f20376443ca755bf18200141f27f233eb Mon Sep 17 00:00:00 2001
From: Sean Perry <perry at ca.ibm.com>
Date: Wed, 26 Mar 2025 13:23:34 -0400
Subject: [PATCH 3/4] formatting

---
 libcxx/src/support/ibm/xlocale_zos.cpp | 132 ++++++++++++-------------
 1 file changed, 64 insertions(+), 68 deletions(-)

diff --git a/libcxx/src/support/ibm/xlocale_zos.cpp b/libcxx/src/support/ibm/xlocale_zos.cpp
index fa5fb745df88e..c264bff9f45fc 100644
--- a/libcxx/src/support/ibm/xlocale_zos.cpp
+++ b/libcxx/src/support/ibm/xlocale_zos.cpp
@@ -14,61 +14,58 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#define CategoryList(pair, sep) \
-  pair(LC_COLLATE, lc_collate) sep \
-  pair(LC_CTYPE, lc_ctype) sep \
-  pair(LC_MONETARY, lc_monetary) sep \
-  pair(LC_NUMERIC, lc_numeric) sep \
-  pair(LC_TIME, lc_time) sep \
-  pair(LC_MESSAGES, lc_messages)
+#define CategoryList(pair, sep)                                                                                        \
+  pair(LC_COLLATE, lc_collate) sep pair(LC_CTYPE, lc_ctype)                                                            \
+  sep pair(LC_MONETARY, lc_monetary)                                                                                   \
+  sep pair(LC_NUMERIC, lc_numeric)                                                                                     \
+  sep pair(LC_TIME, lc_time)                                                                                           \
+  sep pair(LC_MESSAGES, lc_messages)
 
 // check ids and masks agree
-#define check_ids_and_masks_agree(id, _) \
-  static_assert((1 << id) == id##_MASK, "id and mask do not agree for " #id); \
+#define check_ids_and_masks_agree(id, _)                                                                               \
+  static_assert((1 << id) == id##_MASK, "id and mask do not agree for " #id);                                          \
   static_assert((1 << id) == _CATMASK(id), "mask does not have expected value for " #id);
-CategoryList(check_ids_and_masks_agree,)
+CategoryList(check_ids_and_masks_agree, )
 #undef check_ids_and_masks_agree
 
 // check that LC_ALL_MASK is defined as expected
 #define get_mask(id, _) id##_MASK
-static_assert(LC_ALL_MASK == (CategoryList(get_mask, |)), "LC_ALL_MASK does not have the expected value.  Check that its definition includes all supported categories");
+    static_assert(
+        LC_ALL_MASK == (CategoryList(get_mask, |)),
+        "LC_ALL_MASK does not have the expected value.  Check that its definition includes all supported categories");
 #undef get_mask
 
-
 // initialize c_locale
 #define init_clocale(id, locale_member) "C",
-static locale_struct c_locale = { LC_ALL_MASK, CategoryList(init_clocale, ) };
+static locale_struct c_locale = {LC_ALL_MASK, CategoryList(init_clocale, )};
 #undef init_clocale
 
 static locale_t current_locale = _LIBCPP_LC_GLOBAL_LOCALE;
 
-
-locale_t __c_locale() {
-  return &c_locale;
-}
+locale_t __c_locale() { return &c_locale; }
 
 // locale
 locale_t newlocale(int category_mask, const char* locale, locale_t base) {
   // start with some basic checks
-  if (! locale) {
+  if (!locale) {
     errno = EINVAL;
-    return (locale_t) 0;
+    return (locale_t)0;
   }
   if (category_mask & ~LC_ALL_MASK) {
     // then there are bits in category_mask that does not correspond
     // to a valid category
     errno = EINVAL;
-    return (locale_t) 0;
+    return (locale_t)0;
   }
 
-  locale_t  new_loc = new locale_struct;
+  locale_t new_loc          = new locale_struct;
   int num_locales_not_found = 0;
 
   if (base && base != _LIBCPP_LC_GLOBAL_LOCALE)
     *new_loc = *base;
 
-  auto set_for_category = [&](int id, int mask, std::string &setting) {
-    const char *setting_to_apply = nullptr;
+  auto set_for_category = [&](int id, int mask, std::string& setting) {
+    const char* setting_to_apply = nullptr;
 
     if (category_mask & mask)
       setting_to_apply = locale;
@@ -77,7 +74,7 @@ locale_t newlocale(int category_mask, const char* locale, locale_t base) {
 
     if (setting_to_apply) {
       // setlocale takes the id, not the mask
-      const char *saved_setting = setlocale(id, nullptr);
+      const char* saved_setting = setlocale(id, nullptr);
       if (setlocale(id, setting_to_apply)) {
         // then setting_to_apply is valid for this category
         // restore the saved setting
@@ -99,8 +96,8 @@ locale_t newlocale(int category_mask, const char* locale, locale_t base) {
 
   if (num_locales_not_found != 0) {
     delete new_loc;
-    errno = ENOENT;
-    new_loc = (locale_t) 0;
+    errno   = ENOENT;
+    new_loc = (locale_t)0;
   }
 
   return new_loc;
@@ -117,12 +114,12 @@ locale_t uselocale(locale_t new_loc) {
   if (new_loc == _LIBCPP_LC_GLOBAL_LOCALE) {
     current_locale = _LIBCPP_LC_GLOBAL_LOCALE;
   } else if (new_loc != nullptr) {
-    locale_struct  saved_locale;
+    locale_struct saved_locale;
     saved_locale.category_mask = 0;
 
-    auto apply_category = [&](int id, int mask, std::string &setting, std::string &save_setting)-> bool {
+    auto apply_category = [&](int id, int mask, std::string& setting, std::string& save_setting) -> bool {
       if (new_loc->category_mask & mask) {
-        const char *old_setting = setlocale(id, setting.c_str());
+        const char* old_setting = setlocale(id, setting.c_str());
         if (old_setting) {
           // we were able to set for this category.  Save the old setting
           // in case a subsequent category fails, and we need to restore
@@ -136,17 +133,17 @@ locale_t uselocale(locale_t new_loc) {
       return true;
     };
 
-#define Apply(id, locale_member) apply_category(id, id##_MASK, new_loc->locale_member, saved_locale. locale_member)
+#define Apply(id, locale_member) apply_category(id, id##_MASK, new_loc->locale_member, saved_locale.locale_member)
     bool is_ok = CategoryList(Apply, &&);
 #undef Apply
 
     if (!is_ok) {
-      auto restore = [&](int id, int mask, std::string &setting) {
+      auto restore = [&](int id, int mask, std::string& setting) {
         if (saved_locale.category_mask & mask)
           setlocale(id, setting.c_str());
       };
-#define Restore(id, locale_member) restore(id, id##_MASK, saved_locale. locale_member);
-      CategoryList(Restore,);
+#define Restore(id, locale_member) restore(id, id##_MASK, saved_locale.locale_member);
+      CategoryList(Restore, );
 #undef Restore
       errno = EINVAL;
       return nullptr;
@@ -157,174 +154,173 @@ locale_t uselocale(locale_t new_loc) {
   return prev_loc;
 }
 
-int isdigit_l(int __c, locale_t  __l) {
+int isdigit_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::isdigit(__c);
 }
 
-int isxdigit_l(int __c, locale_t  __l) {
+int isxdigit_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::isxdigit(__c);
 }
 
 namespace __ibm {
-int isalnum_l(int __c, locale_t  __l) {
+int isalnum_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::isalnum(__c);
 }
 
-int isalpha_l(int __c, locale_t  __l) {
+int isalpha_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::isalpha(__c);
 }
 
-int isblank_l(int __c, locale_t  __l) {
+int isblank_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::isblank(__c);
 }
 
-int iscntrl_l(int __c, locale_t  __l) {
+int iscntrl_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iscntrl(__c);
 }
 
-int isgraph_l(int __c, locale_t  __l) {
+int isgraph_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::isgraph(__c);
 }
 
-int islower_l(int __c, locale_t  __l) {
+int islower_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::islower(__c);
 }
 
-int isprint_l(int __c, locale_t  __l) {
+int isprint_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::isprint(__c);
 }
 
-int ispunct_l(int __c, locale_t  __l) {
+int ispunct_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::ispunct(__c);
 }
 
-int isspace_l(int __c, locale_t  __l) {
+int isspace_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::isspace(__c);
 }
 
-int isupper_l(int __c, locale_t  __l) {
+int isupper_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::isupper(__c);
 }
 
-int iswalnum_l(wint_t __c, locale_t  __l) {
+int iswalnum_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswalnum(__c);
 }
 
-int iswalpha_l(wint_t __c, locale_t  __l) {
+int iswalpha_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswalpha(__c);
 }
 
-int iswblank_l(wint_t __c, locale_t  __l) {
+int iswblank_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswblank(__c);
 }
 
-int iswcntrl_l(wint_t __c, locale_t  __l) {
+int iswcntrl_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswcntrl(__c);
 }
 
-int iswdigit_l(wint_t __c, locale_t  __l) {
+int iswdigit_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswdigit(__c);
 }
 
-int iswgraph_l(wint_t __c, locale_t  __l) {
+int iswgraph_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswgraph(__c);
 }
 
-int iswlower_l(wint_t __c, locale_t  __l) {
+int iswlower_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswlower(__c);
 }
 
-int iswprint_l(wint_t __c, locale_t  __l) {
+int iswprint_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswprint(__c);
 }
 
-int iswpunct_l(wint_t __c, locale_t  __l) {
+int iswpunct_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswpunct(__c);
 }
 
-int iswspace_l(wint_t __c, locale_t  __l) {
+int iswspace_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswspace(__c);
 }
 
-int iswupper_l(wint_t __c, locale_t  __l) {
+int iswupper_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswupper(__c);
 }
 
-int iswxdigit_l(wint_t __c, locale_t  __l) {
+int iswxdigit_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswxdigit(__c);
 }
 
-int toupper_l(int __c, locale_t  __l) {
+int toupper_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::toupper(__c);
 }
 
-int tolower_l(int __c, locale_t  __l) {
+int tolower_l(int __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::tolower(__c);
 }
 
-wint_t towupper_l(wint_t __c, locale_t  __l) {
+wint_t towupper_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::towupper(__c);
 }
 
-wint_t towlower_l(wint_t __c, locale_t  __l) {
+wint_t towlower_l(wint_t __c, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::towlower(__c);
 }
 
-int strcoll_l(const char *__s1, const char *__s2, locale_t  __l) {
+int strcoll_l(const char* __s1, const char* __s2, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::strcoll(__s1, __s2);
 }
 
-size_t strxfrm_l(char *__dest, const char *__src, size_t __n, locale_t  __l) {
+size_t strxfrm_l(char* __dest, const char* __src, size_t __n, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::strxfrm(__dest, __src, __n);
 }
 
-size_t strftime_l(char *__s, size_t __max, const char *__format, const struct tm *__tm, 
-                                                  locale_t  __l) {
+size_t strftime_l(char* __s, size_t __max, const char* __format, const struct tm* __tm, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::strftime(__s, __max, __format, __tm);
 }
 
-int wcscoll_l(const wchar_t *__ws1, const wchar_t *__ws2, locale_t  __l) {
+int wcscoll_l(const wchar_t* __ws1, const wchar_t* __ws2, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::wcscoll(__ws1, __ws2);
 }
 
-size_t wcsxfrm_l(wchar_t *__dest, const wchar_t *__src, size_t __n, locale_t  __l) {
+size_t wcsxfrm_l(wchar_t* __dest, const wchar_t* __src, size_t __n, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::wcsxfrm(__dest, __src, __n);
 }
 
-int iswctype_l(wint_t __c, wctype_t __type, locale_t  __l) {
+int iswctype_l(wint_t __c, wctype_t __type, locale_t __l) {
   __setAndRestore __newloc(__l);
   return ::iswctype(__c, __type);
 }

>From e191be630a0a258ec2da486693479c6bf20c07f8 Mon Sep 17 00:00:00 2001
From: Sean Perry <perry at ca.ibm.com>
Date: Wed, 26 Mar 2025 13:25:19 -0400
Subject: [PATCH 4/4] add back in include

---
 libcxx/include/__locale_dir/locale_base_api/ibm.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libcxx/include/__locale_dir/locale_base_api/ibm.h b/libcxx/include/__locale_dir/locale_base_api/ibm.h
index 9d51043b7ffdb..b4cbd134c78ee 100644
--- a/libcxx/include/__locale_dir/locale_base_api/ibm.h
+++ b/libcxx/include/__locale_dir/locale_base_api/ibm.h
@@ -22,6 +22,8 @@
 
 #if defined(__MVS__)
 #  include <wctype.h>
+// POSIX routines
+#  include <__support/xlocale/__posix_l_fallback.h>
 #endif // defined(__MVS__)
 
 _LIBCPP_BEGIN_NAMESPACE_STD



More information about the libcxx-commits mailing list