Skip to content

[libc] Implement locale variants for 'stdlib.h' functions #105718

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 29, 2024

Conversation

jhuber6
Copy link
Contributor

@jhuber6 jhuber6 commented Aug 22, 2024

Summary:
This provides the _l variants for the stdlib.h functions. These are
just copies of the same entrypoint and don't do anything with the locale
information.

Summary:
This provides the `_l` variants for the `stdlib.h` functions. These are
just copies of the same entrypoint and don't do anything with the locale
information.
@llvmbot
Copy link
Member

llvmbot commented Aug 22, 2024

@llvm/pr-subscribers-libc

Author: Joseph Huber (jhuber6)

Changes

Summary:
This provides the _l variants for the stdlib.h functions. These are
just copies of the same entrypoint and don't do anything with the locale
information.


Patch is 22.61 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/105718.diff

21 Files Affected:

  • (modified) libc/config/gpu/entrypoints.txt (+7)
  • (modified) libc/config/linux/x86_64/entrypoints.txt (+9)
  • (modified) libc/include/llvm-libc-macros/stdlib-macros.h (+5)
  • (modified) libc/include/stdlib.h.def (+1)
  • (modified) libc/newhdrgen/yaml/stdlib.yaml (+60)
  • (modified) libc/spec/stdc.td (+8)
  • (modified) libc/src/stdlib/CMakeLists.txt (+77)
  • (added) libc/src/stdlib/strtod_l.cpp (+30)
  • (added) libc/src/stdlib/strtod_l.h (+22)
  • (added) libc/src/stdlib/strtof_l.cpp (+30)
  • (added) libc/src/stdlib/strtof_l.h (+22)
  • (added) libc/src/stdlib/strtol_l.cpp (+30)
  • (added) libc/src/stdlib/strtol_l.h (+22)
  • (added) libc/src/stdlib/strtold_l.cpp (+30)
  • (added) libc/src/stdlib/strtold_l.h (+22)
  • (added) libc/src/stdlib/strtoll_l.cpp (+30)
  • (added) libc/src/stdlib/strtoll_l.h (+22)
  • (added) libc/src/stdlib/strtoul_l.cpp (+30)
  • (added) libc/src/stdlib/strtoul_l.h (+22)
  • (added) libc/src/stdlib/strtoull_l.cpp (+30)
  • (added) libc/src/stdlib/strtoull_l.h (+23)
diff --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt
index 7b869902074d8e..36b46c49e68974 100644
--- a/libc/config/gpu/entrypoints.txt
+++ b/libc/config/gpu/entrypoints.txt
@@ -173,12 +173,19 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.rand
     libc.src.stdlib.srand
     libc.src.stdlib.strtod
+    libc.src.stdlib.strtod_l
     libc.src.stdlib.strtof
+    libc.src.stdlib.strtof_l
     libc.src.stdlib.strtol
+    libc.src.stdlib.strtol_l
     libc.src.stdlib.strtold
+    libc.src.stdlib.strtold_l
     libc.src.stdlib.strtoll
+    libc.src.stdlib.strtoll_l
     libc.src.stdlib.strtoul
+    libc.src.stdlib.strtoul_l
     libc.src.stdlib.strtoull
+    libc.src.stdlib.strtoull_l
     libc.src.stdlib.at_quick_exit
     libc.src.stdlib.quick_exit
     libc.src.stdlib.getenv
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index bac1e3cfa85da7..8b714e56b5a453 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -798,6 +798,15 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.ctype.tolower_l
     libc.src.ctype.toupper_l
 
+    # stdlib.h entrypoints
+    libc.src.stdlib.strtod_l
+    libc.src.stdlib.strtof_l
+    libc.src.stdlib.strtol_l
+    libc.src.stdlib.strtold_l
+    libc.src.stdlib.strtoll_l
+    libc.src.stdlib.strtoul_l
+    libc.src.stdlib.strtoull_l
+
     # assert.h entrypoints
     libc.src.assert.__assert_fail
 
diff --git a/libc/include/llvm-libc-macros/stdlib-macros.h b/libc/include/llvm-libc-macros/stdlib-macros.h
index 5fcbfef97b3285..2565c76be3c55c 100644
--- a/libc/include/llvm-libc-macros/stdlib-macros.h
+++ b/libc/include/llvm-libc-macros/stdlib-macros.h
@@ -17,6 +17,11 @@
 #define EXIT_SUCCESS 0
 #define EXIT_FAILURE 1
 
+#ifndef MB_CUR_MAX
+// We only support the "C" locale right now, so this is a constant byte.
+#define MB_CUR_MAX 1
+#endif // MB_CUR_MAX
+
 #define RAND_MAX 2147483647
 
 #endif // LLVM_LIBC_MACROS_STDLIB_MACROS_H
diff --git a/libc/include/stdlib.h.def b/libc/include/stdlib.h.def
index d523f7a53024aa..01b0e1a2395a29 100644
--- a/libc/include/stdlib.h.def
+++ b/libc/include/stdlib.h.def
@@ -10,6 +10,7 @@
 #define LLVM_LIBC_STDLIB_H
 
 #include "__llvm-libc-common.h"
+#include "llvm-libc-types/locale_t.h"
 #include "llvm-libc-macros/stdlib-macros.h"
 
 %%public_api()
diff --git a/libc/newhdrgen/yaml/stdlib.yaml b/libc/newhdrgen/yaml/stdlib.yaml
index 081da5391c3a52..5da49b8a89101c 100644
--- a/libc/newhdrgen/yaml/stdlib.yaml
+++ b/libc/newhdrgen/yaml/stdlib.yaml
@@ -273,3 +273,63 @@ functions:
       - type: const char *__restrict
       - type: char **__restrict
       - type: int
+  - name: strtod_l
+    standards:
+      - stdc
+    return_type: double
+    arguments:
+      - type: const char *__restrict
+      - type: char **__restrict
+      - type: locale_t
+  - name: strtof_l
+    standards:
+      - stdc
+    return_type: float
+    arguments:
+      - type: const char *__restrict
+      - type: char **__restrict
+      - type: locale_t
+  - name: strtol_l
+    standards:
+      - stdc
+    return_type: long
+    arguments:
+      - type: const char *__restrict
+      - type: char **__restrict
+      - type: int
+      - type: locale_t
+  - name: strtold_l
+    standards:
+      - stdc
+    return_type: long double
+    arguments:
+      - type: const char *__restrict
+      - type: char **__restrict
+      - type: locale_t
+  - name: strtoll_l
+    standards:
+      - stdc
+    return_type: long long
+    arguments:
+      - type: const char *__restrict
+      - type: char **__restrict
+      - type: int
+      - type: locale_t
+  - name: strtoul_l
+    standards:
+      - stdc
+    return_type: unsigned long
+    arguments:
+      - type: const char *__restrict
+      - type: char **__restrict
+      - type: int
+      - type: locale_t
+  - name: strtoull_l
+    standards:
+      - stdc
+    return_type: unsigned long long
+    arguments:
+      - type: const char *__restrict
+      - type: char **__restrict
+      - type: int
+      - type: locale_t
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 6d8be9f8e4016d..92919fcdb6214b 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -1295,6 +1295,14 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"strtoul", RetValSpec<UnsignedLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,
           FunctionSpec<"strtoull", RetValSpec<UnsignedLongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,
 
+          FunctionSpec<"strtof", RetValSpec<FloatType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<LocaleT>]>,
+          FunctionSpec<"strtod", RetValSpec<DoubleType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<LocaleT>]>,
+          FunctionSpec<"strtold", RetValSpec<LongDoubleType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<LocaleT>]>,
+          FunctionSpec<"strtol", RetValSpec<LongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleT>]>,
+          FunctionSpec<"strtoll", RetValSpec<LongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleT>]>,
+          FunctionSpec<"strtoul", RetValSpec<UnsignedLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleT>]>,
+          FunctionSpec<"strtoull", RetValSpec<UnsignedLongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleT>]>,
+
           FunctionSpec<"malloc", RetValSpec<VoidPtr>, [ArgSpec<SizeTType>]>,
           FunctionSpec<"calloc", RetValSpec<VoidPtr>, [ArgSpec<SizeTType>, ArgSpec<SizeTType>]>,
           FunctionSpec<"realloc", RetValSpec<VoidPtr>, [ArgSpec<VoidPtr>, ArgSpec<SizeTType>]>,
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index ce12e66cf3e57f..7fc68cb35e8489 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -428,6 +428,83 @@ if(NOT LLVM_LIBC_FULL_BUILD)
   return()
 endif()
 
+add_entrypoint_object(
+  strtof_l
+  SRCS
+    strtof_l.cpp
+  HDRS
+    strtof_l.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.src.__support.str_to_float
+)
+
+add_entrypoint_object(
+  strtod_l
+  SRCS
+    strtod_l.cpp
+  HDRS
+    strtod_l.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.src.__support.str_to_float
+)
+
+add_entrypoint_object(
+  strtold_l
+  SRCS
+    strtold_l.cpp
+  HDRS
+    strtold_l.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.src.__support.str_to_float
+)
+
+add_entrypoint_object(
+  strtol_l
+  SRCS
+    strtol_l.cpp
+  HDRS
+    strtol_l.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.src.__support.str_to_integer
+)
+
+add_entrypoint_object(
+  strtoll_l
+  SRCS
+    strtoll_l.cpp
+  HDRS
+    strtoll_l.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.src.__support.str_to_integer
+)
+
+add_entrypoint_object(
+  strtoul_l
+  SRCS
+    strtoul_l.cpp
+  HDRS
+    strtoul_l.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.src.__support.str_to_integer
+)
+
+add_entrypoint_object(
+  strtoull_l
+  SRCS
+    strtoull_l.cpp
+  HDRS
+    strtoull_l.h
+  DEPENDS
+    libc.src.errno.errno
+    libc.src.__support.str_to_integer
+)
+
 if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
   add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
 endif()
diff --git a/libc/src/stdlib/strtod_l.cpp b/libc/src/stdlib/strtod_l.cpp
new file mode 100644
index 00000000000000..247314398315b0
--- /dev/null
+++ b/libc/src/stdlib/strtod_l.cpp
@@ -0,0 +1,30 @@
+//===-- Implementation of strtod_l ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtod_l.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/str_to_float.h"
+#include "src/errno/libc_errno.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(double, strtod_l,
+                   (const char *__restrict str, char **__restrict str_end,
+                    locale_t)) {
+  auto result = internal::strtofloatingpoint<double>(str);
+  if (result.has_error())
+    libc_errno = result.error;
+
+  if (str_end != nullptr)
+    *str_end = const_cast<char *>(str + result.parsed_len);
+
+  return result.value;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtod_l.h b/libc/src/stdlib/strtod_l.h
new file mode 100644
index 00000000000000..06a8c893af2896
--- /dev/null
+++ b/libc/src/stdlib/strtod_l.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for strtod_l ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOD_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOD_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+double strtod_l(const char *__restrict str, char **__restrict str_end,
+                locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOD_L_H
diff --git a/libc/src/stdlib/strtof_l.cpp b/libc/src/stdlib/strtof_l.cpp
new file mode 100644
index 00000000000000..d54efa66e0846c
--- /dev/null
+++ b/libc/src/stdlib/strtof_l.cpp
@@ -0,0 +1,30 @@
+//===-- Implementation of strtof_l ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtof_l.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/str_to_float.h"
+#include "src/errno/libc_errno.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(float, strtof_l,
+                   (const char *__restrict str, char **__restrict str_end,
+                    locale_t)) {
+  auto result = internal::strtofloatingpoint<float>(str);
+  if (result.has_error())
+    libc_errno = result.error;
+
+  if (str_end != nullptr)
+    *str_end = const_cast<char *>(str + result.parsed_len);
+
+  return result.value;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtof_l.h b/libc/src/stdlib/strtof_l.h
new file mode 100644
index 00000000000000..de629e3f36d458
--- /dev/null
+++ b/libc/src/stdlib/strtof_l.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for strtof_l ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOF_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOF_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float strtof_l(const char *__restrict str, char **__restrict str_end,
+               locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOF_L_H
diff --git a/libc/src/stdlib/strtol_l.cpp b/libc/src/stdlib/strtol_l.cpp
new file mode 100644
index 00000000000000..f94aff1a0d7b2a
--- /dev/null
+++ b/libc/src/stdlib/strtol_l.cpp
@@ -0,0 +1,30 @@
+//===-- Implementation of strtol_l ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtol_l.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/str_to_integer.h"
+#include "src/errno/libc_errno.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(long, strtol_l,
+                   (const char *__restrict str, char **__restrict str_end,
+                    int base, locale_t)) {
+  auto result = internal::strtointeger<long>(str, base);
+  if (result.has_error())
+    libc_errno = result.error;
+
+  if (str_end != nullptr)
+    *str_end = const_cast<char *>(str + result.parsed_len);
+
+  return result;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtol_l.h b/libc/src/stdlib/strtol_l.h
new file mode 100644
index 00000000000000..9f8c8553654d78
--- /dev/null
+++ b/libc/src/stdlib/strtol_l.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for strtol_l ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOL_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOL_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+long strtol_l(const char *__restrict str, char **__restrict str_end, int base,
+              locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOL_L_H
diff --git a/libc/src/stdlib/strtold_l.cpp b/libc/src/stdlib/strtold_l.cpp
new file mode 100644
index 00000000000000..d0c57f50246b5c
--- /dev/null
+++ b/libc/src/stdlib/strtold_l.cpp
@@ -0,0 +1,30 @@
+//===-- Implementation of strtold_l ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtold_l.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/str_to_float.h"
+#include "src/errno/libc_errno.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(long double, strtold_l,
+                   (const char *__restrict str, char **__restrict str_end,
+                    locale_t)) {
+  auto result = internal::strtofloatingpoint<long double>(str);
+  if (result.has_error())
+    libc_errno = result.error;
+
+  if (str_end != nullptr)
+    *str_end = const_cast<char *>(str + result.parsed_len);
+
+  return result.value;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtold_l.h b/libc/src/stdlib/strtold_l.h
new file mode 100644
index 00000000000000..d694ce279b6e39
--- /dev/null
+++ b/libc/src/stdlib/strtold_l.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for strtold_l ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOLD_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOLD_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+long double strtold_l(const char *__restrict str, char **__restrict str_end,
+                      locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOLD_L_H
diff --git a/libc/src/stdlib/strtoll_l.cpp b/libc/src/stdlib/strtoll_l.cpp
new file mode 100644
index 00000000000000..e82971d59c48d3
--- /dev/null
+++ b/libc/src/stdlib/strtoll_l.cpp
@@ -0,0 +1,30 @@
+//===-- Implementation of strtoll_l ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtoll_l.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/str_to_integer.h"
+#include "src/errno/libc_errno.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(long long, strtoll_l,
+                   (const char *__restrict str, char **__restrict str_end,
+                    int base, locale_t)) {
+  auto result = internal::strtointeger<long long>(str, base);
+  if (result.has_error())
+    libc_errno = result.error;
+
+  if (str_end != nullptr)
+    *str_end = const_cast<char *>(str + result.parsed_len);
+
+  return result;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoll_l.h b/libc/src/stdlib/strtoll_l.h
new file mode 100644
index 00000000000000..461fedb3df485d
--- /dev/null
+++ b/libc/src/stdlib/strtoll_l.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for strtoll_l ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOLL_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOLL_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+long long strtoll_l(const char *__restrict str, char **__restrict str_end,
+                    int base, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOLL_L_H
diff --git a/libc/src/stdlib/strtoul_l.cpp b/libc/src/stdlib/strtoul_l.cpp
new file mode 100644
index 00000000000000..74fce00a0ac3c4
--- /dev/null
+++ b/libc/src/stdlib/strtoul_l.cpp
@@ -0,0 +1,30 @@
+//===-- Implementation of strtoul_l ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtoul_l.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/str_to_integer.h"
+#include "src/errno/libc_errno.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(unsigned long, strtoul_l,
+                   (const char *__restrict str, char **__restrict str_end,
+                    int base, locale_t)) {
+  auto result = internal::strtointeger<unsigned long>(str, base);
+  if (result.has_error())
+    libc_errno = result.error;
+
+  if (str_end != nullptr)
+    *str_end = const_cast<char *>(str + result.parsed_len);
+
+  return result;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoul_l.h b/libc/src/stdlib/strtoul_l.h
new file mode 100644
index 00000000000000..7c9f53a8acb31c
--- /dev/null
+++ b/libc/src/stdlib/strtoul_l.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for strtoul_l ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOUL_L_H
+#define LLVM_LIBC_SRC_STDLIB_...
[truncated]

@@ -17,6 +17,11 @@
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1

#ifndef MB_CUR_MAX
// We only support the "C" locale right now, so this is a constant byte.
#define MB_CUR_MAX 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this going to be stable? I remember we ran into issues with MB_LEN_MAX. Also should this be moved to limits-macros.h to be in the same place as MB_LEN_MAX?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, in a real implementation this would be non-constant. And I don't think so, this is specifically mentioned in the standard as being provided by stdlib.h

       The <stdlib.h> header shall define the following macro which shall
       expand to a positive integer expression with type size_t:

       {MB_CUR_MAX}
                   Maximum number of bytes in a character specified by the
                   current locale (category LC_CTYPE).

       In the POSIX locale the value of {MB_CUR_MAX} shall be 1.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me then

@jhuber6 jhuber6 merged commit a871051 into llvm:main Aug 29, 2024
9 checks passed
@jhuber6 jhuber6 deleted the stdlib branch August 29, 2024 19:20
@Prabhuk
Copy link
Contributor

Prabhuk commented Aug 30, 2024

We are starting to see failures in our builders and I suspect this patch could be the reason. I am looking into it further.

Log file: https://logs.chromium.org/logs/fuchsia/buildbucket/cr-buildbucket/8738242099202573585/+/u/clang/build/stdout

FAILED: libcxx/src/CMakeFiles/cxx_static.dir/string.cpp.obj 
/b/s/w/ir/x/w/llvm_build/./bin/clang++ --target=armv6m-none-eabi -D_DEBUG -D_FILE_OFFSET_BITS=64 -D_GLIBCXX_ASSERTIONS -D_LARGEFILE_SOURCE -D_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_LINK_PTHREAD_LIB -D_LIBCPP_LINK_RT_LIB -D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src -I/b/s/w/ir/x/w/llvm_build/tools/clang/stage2-bins/include/armv6m-unknown-none-eabi/c++/v1 -I/b/s/w/ir/x/w/llvm_build/tools/clang/stage2-bins/include/c++/v1 -isystem /b/s/w/ir/x/w/llvm_build/tools/clang/stage2-bins/include/armv6m-unknown-none-eabi -resource-dir=/b/s/w/ir/x/w/llvm_build/tools/clang/stage2-bins/./lib/clang/20 --target=armv6m-none-eabi -mthumb -Wno-atomic-alignment "-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)" "-Dfprintf(stream, format, ...)=printf(format)" "-Dtimeval=struct timeval{int tv_sec; int tv_usec;}" "-Dgettimeofday(tv, tz)" -D_LIBCPP_PRINT=1 -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -ffunction-sections -fdata-sections -ffile-prefix-map=/b/s/w/ir/x/w/llvm_build/tools/clang/stage2-bins/runtimes/runtimes-armv6m-none-eabi-bins=../../../../../../llvm-llvm-project -ffile-prefix-map=/b/s/w/ir/x/w/llvm-llvm-project/= -no-canonical-prefixes -Os -DNDEBUG -std=c++2b -UNDEBUG -faligned-allocation -nostdinc++ -fvisibility-inlines-hidden -fvisibility=hidden -fsized-deallocation -Wall -Wextra -Wnewline-eof -Wshadow -Wwrite-strings -Wno-unused-parameter -Wno-long-long -Werror=return-type -Wextra-semi -Wundef -Wunused-template -Wformat-nonliteral -Wno-user-defined-literals -Wno-covered-switch-default -Wno-suggest-override -Wno-error -fno-exceptions -fno-rtti -nostdlibinc -MD -MT libcxx/src/CMakeFiles/cxx_static.dir/string.cpp.obj -MF libcxx/src/CMakeFiles/cxx_static.dir/string.cpp.obj.d -o libcxx/src/CMakeFiles/cxx_static.dir/string.cpp.obj -c /b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:74:76: error: too few arguments to function call, expected 4, have 3
   74 |   V r                                                     = f(p, &ptr, base);
      |                                                             ~              ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:92:12: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_integer_helper<long, std::string, long (*)(const char *, char **, int, __locale_t *) noexcept>' requested here
   92 |   long r = as_integer_helper<long>(func, s, idx, base, strtol);
      |            ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:74:76: error: too few arguments to function call, expected 4, have 3
   74 |   V r                                                     = f(p, &ptr, base);
      |                                                             ~              ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:105:10: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_integer_helper<unsigned long, std::string, unsigned long (*)(const char *, char **, int, __locale_t *) noexcept>' requested here
  105 |   return as_integer_helper<unsigned long>(func, s, idx, base, strtoul);
      |          ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:74:76: error: too few arguments to function call, expected 4, have 3
   74 |   V r                                                     = f(p, &ptr, base);
      |                                                             ~              ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:110:10: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_integer_helper<long long, std::string, long long (*)(const char *, char **, int, __locale_t *) noexcept>' requested here
  110 |   return as_integer_helper<long long>(func, s, idx, base, strtoll);
      |          ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:74:76: error: too few arguments to function call, expected 4, have 3
   74 |   V r                                                     = f(p, &ptr, base);
      |                                                             ~              ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:115:10: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_integer_helper<unsigned long long, std::string, unsigned long long (*)(const char *, char **, int, __locale_t *) noexcept>' requested here
  115 |   return as_integer_helper<unsigned long long>(func, s, idx, base, strtoull);
      |          ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:158:70: error: too few arguments to function call, expected 3, have 2
  158 |   V r                                                     = f(p, &ptr);
      |                                                             ~        ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:174:10: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_float_helper<float, std::string, float (*)(const char *, char **, __locale_t *) noexcept>' requested here
  174 |   return as_float_helper<float>(func, s, idx, strtof);
      |          ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:158:70: error: too few arguments to function call, expected 3, have 2
  158 |   V r                                                     = f(p, &ptr);
      |                                                             ~        ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:179:10: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_float_helper<double, std::string, double (*)(const char *, char **, __locale_t *) noexcept>' requested here
  179 |   return as_float_helper<double>(func, s, idx, strtod);
      |          ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:158:70: error: too few arguments to function call, expected 3, have 2
  158 |   V r                                                     = f(p, &ptr);
      |                                                             ~        ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:184:10: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_float_helper<long double, std::string, long double (*)(const char *, char **, __locale_t *) noexcept>' requested here
  184 |   return as_float_helper<long double>(func, s, idx, strtold);
      |          ^
7 errors generated.

@jhuber6
Copy link
Contributor Author

jhuber6 commented Aug 30, 2024

We are starting to see failures in our builders and I suspect this patch could be the reason. I am looking into it further.

Log file: https://logs.chromium.org/logs/fuchsia/buildbucket/cr-buildbucket/8738242099202573585/+/u/clang/build/stdout

FAILED: libcxx/src/CMakeFiles/cxx_static.dir/string.cpp.obj 
/b/s/w/ir/x/w/llvm_build/./bin/clang++ --target=armv6m-none-eabi -D_DEBUG -D_FILE_OFFSET_BITS=64 -D_GLIBCXX_ASSERTIONS -D_LARGEFILE_SOURCE -D_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_LINK_PTHREAD_LIB -D_LIBCPP_LINK_RT_LIB -D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src -I/b/s/w/ir/x/w/llvm_build/tools/clang/stage2-bins/include/armv6m-unknown-none-eabi/c++/v1 -I/b/s/w/ir/x/w/llvm_build/tools/clang/stage2-bins/include/c++/v1 -isystem /b/s/w/ir/x/w/llvm_build/tools/clang/stage2-bins/include/armv6m-unknown-none-eabi -resource-dir=/b/s/w/ir/x/w/llvm_build/tools/clang/stage2-bins/./lib/clang/20 --target=armv6m-none-eabi -mthumb -Wno-atomic-alignment "-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)" "-Dfprintf(stream, format, ...)=printf(format)" "-Dtimeval=struct timeval{int tv_sec; int tv_usec;}" "-Dgettimeofday(tv, tz)" -D_LIBCPP_PRINT=1 -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -ffunction-sections -fdata-sections -ffile-prefix-map=/b/s/w/ir/x/w/llvm_build/tools/clang/stage2-bins/runtimes/runtimes-armv6m-none-eabi-bins=../../../../../../llvm-llvm-project -ffile-prefix-map=/b/s/w/ir/x/w/llvm-llvm-project/= -no-canonical-prefixes -Os -DNDEBUG -std=c++2b -UNDEBUG -faligned-allocation -nostdinc++ -fvisibility-inlines-hidden -fvisibility=hidden -fsized-deallocation -Wall -Wextra -Wnewline-eof -Wshadow -Wwrite-strings -Wno-unused-parameter -Wno-long-long -Werror=return-type -Wextra-semi -Wundef -Wunused-template -Wformat-nonliteral -Wno-user-defined-literals -Wno-covered-switch-default -Wno-suggest-override -Wno-error -fno-exceptions -fno-rtti -nostdlibinc -MD -MT libcxx/src/CMakeFiles/cxx_static.dir/string.cpp.obj -MF libcxx/src/CMakeFiles/cxx_static.dir/string.cpp.obj.d -o libcxx/src/CMakeFiles/cxx_static.dir/string.cpp.obj -c /b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:74:76: error: too few arguments to function call, expected 4, have 3
   74 |   V r                                                     = f(p, &ptr, base);
      |                                                             ~              ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:92:12: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_integer_helper<long, std::string, long (*)(const char *, char **, int, __locale_t *) noexcept>' requested here
   92 |   long r = as_integer_helper<long>(func, s, idx, base, strtol);
      |            ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:74:76: error: too few arguments to function call, expected 4, have 3
   74 |   V r                                                     = f(p, &ptr, base);
      |                                                             ~              ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:105:10: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_integer_helper<unsigned long, std::string, unsigned long (*)(const char *, char **, int, __locale_t *) noexcept>' requested here
  105 |   return as_integer_helper<unsigned long>(func, s, idx, base, strtoul);
      |          ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:74:76: error: too few arguments to function call, expected 4, have 3
   74 |   V r                                                     = f(p, &ptr, base);
      |                                                             ~              ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:110:10: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_integer_helper<long long, std::string, long long (*)(const char *, char **, int, __locale_t *) noexcept>' requested here
  110 |   return as_integer_helper<long long>(func, s, idx, base, strtoll);
      |          ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:74:76: error: too few arguments to function call, expected 4, have 3
   74 |   V r                                                     = f(p, &ptr, base);
      |                                                             ~              ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:115:10: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_integer_helper<unsigned long long, std::string, unsigned long long (*)(const char *, char **, int, __locale_t *) noexcept>' requested here
  115 |   return as_integer_helper<unsigned long long>(func, s, idx, base, strtoull);
      |          ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:158:70: error: too few arguments to function call, expected 3, have 2
  158 |   V r                                                     = f(p, &ptr);
      |                                                             ~        ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:174:10: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_float_helper<float, std::string, float (*)(const char *, char **, __locale_t *) noexcept>' requested here
  174 |   return as_float_helper<float>(func, s, idx, strtof);
      |          ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:158:70: error: too few arguments to function call, expected 3, have 2
  158 |   V r                                                     = f(p, &ptr);
      |                                                             ~        ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:179:10: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_float_helper<double, std::string, double (*)(const char *, char **, __locale_t *) noexcept>' requested here
  179 |   return as_float_helper<double>(func, s, idx, strtod);
      |          ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:158:70: error: too few arguments to function call, expected 3, have 2
  158 |   V r                                                     = f(p, &ptr);
      |                                                             ~        ^
/b/s/w/ir/x/w/llvm-llvm-project/libcxx/src/string.cpp:184:10: note: in instantiation of function template specialization 'std::__2::(anonymous namespace)::as_float_helper<long double, std::string, long double (*)(const char *, char **, __locale_t *) noexcept>' requested here
  184 |   return as_float_helper<long double>(func, s, idx, strtold);
      |          ^
7 errors generated.

Does this bot build libcxx on top of libc? I have a similar config and don't notice anything off for the GPU case at least. Maybe there's a conflicting definition somewhere? All this did was add definitions into the header, but I don't see anything that's obviously locale related in the errors.

petrhosek added a commit to petrhosek/llvm-project that referenced this pull request Aug 30, 2024
@petrhosek
Copy link
Member

@jhuber6 I reproduced this locally and I see the following declarations in the generated stdlib.h:

double strtod(const char *__restrict, char * *__restrict, locale_t) __NOEXCEPT;
float strtof(const char *__restrict, char * *__restrict, locale_t) __NOEXCEPT;
long strtol(const char *__restrict, char * *__restrict, int, locale_t) __NOEXCEPT;
long double strtold(const char *__restrict, char * *__restrict, locale_t) __NOEXCEPT;
long long strtoll(const char *__restrict, char * *__restrict, int, locale_t) __NOEXCEPT;
unsigned long strtoul(const char *__restrict, char * *__restrict, int, locale_t) __NOEXCEPT;
unsigned long long strtoull(const char *__restrict, char * *__restrict, int, locale_t) __NOEXCEPT;

#106806 is the fix.

petrhosek added a commit that referenced this pull request Aug 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants