aboutsummaryrefslogtreecommitdiff
path: root/libc/src
diff options
context:
space:
mode:
Diffstat (limited to 'libc/src')
-rw-r--r--libc/src/__support/CMakeLists.txt1
-rw-r--r--libc/src/__support/ctype_utils.h24
-rw-r--r--libc/src/__support/integer_to_string.h5
-rw-r--r--libc/src/__support/math/CMakeLists.txt18
-rw-r--r--libc/src/__support/math/exp2m1f16.h180
-rw-r--r--libc/src/__support/wctype_utils.h23
-rw-r--r--libc/src/ctype/CMakeLists.txt23
-rw-r--r--libc/src/ctype/isalnum.cpp7
-rw-r--r--libc/src/ctype/isalnum_l.cpp7
-rw-r--r--libc/src/ctype/isalpha.cpp5
-rw-r--r--libc/src/ctype/isalpha_l.cpp5
-rw-r--r--libc/src/ctype/isdigit.cpp6
-rw-r--r--libc/src/ctype/isdigit_l.cpp6
-rw-r--r--libc/src/ctype/isgraph.cpp5
-rw-r--r--libc/src/ctype/isgraph_l.cpp5
-rw-r--r--libc/src/ctype/islower.cpp7
-rw-r--r--libc/src/ctype/islower_l.cpp7
-rw-r--r--libc/src/ctype/ispunct.cpp5
-rw-r--r--libc/src/ctype/ispunct_l.cpp5
-rw-r--r--libc/src/ctype/isspace.cpp7
-rw-r--r--libc/src/ctype/isspace_l.cpp7
-rw-r--r--libc/src/ctype/isupper.cpp7
-rw-r--r--libc/src/ctype/isupper_l.cpp7
-rw-r--r--libc/src/ctype/isxdigit.cpp7
-rw-r--r--libc/src/ctype/isxdigit_l.cpp7
-rw-r--r--libc/src/ctype/tolower.cpp11
-rw-r--r--libc/src/ctype/tolower_l.cpp9
-rw-r--r--libc/src/ctype/toupper.cpp11
-rw-r--r--libc/src/ctype/toupper_l.cpp9
-rw-r--r--libc/src/fcntl/linux/creat.cpp10
-rw-r--r--libc/src/fcntl/linux/openat.cpp10
-rw-r--r--libc/src/math/generic/CMakeLists.txt14
-rw-r--r--libc/src/math/generic/exp2m1f16.cpp155
-rw-r--r--libc/src/stdio/CMakeLists.txt24
-rw-r--r--libc/src/stdio/asprintf.cpp18
-rw-r--r--libc/src/stdio/baremetal/CMakeLists.txt8
-rw-r--r--libc/src/stdio/baremetal/printf.cpp23
-rw-r--r--libc/src/stdio/baremetal/vprintf.cpp23
-rw-r--r--libc/src/stdio/generic/CMakeLists.txt4
-rw-r--r--libc/src/stdio/generic/fprintf.cpp17
-rw-r--r--libc/src/stdio/generic/printf.cpp17
-rw-r--r--libc/src/stdio/generic/vfprintf.cpp17
-rw-r--r--libc/src/stdio/generic/vprintf.cpp17
-rw-r--r--libc/src/stdio/printf_core/CMakeLists.txt25
-rw-r--r--libc/src/stdio/printf_core/core_structs.h19
-rw-r--r--libc/src/stdio/printf_core/error_mapper.h21
-rw-r--r--libc/src/stdio/printf_core/float_dec_converter_limited.h4
-rw-r--r--libc/src/stdio/printf_core/float_hex_converter.h7
-rw-r--r--libc/src/stdio/printf_core/generic/CMakeLists.txt8
-rw-r--r--libc/src/stdio/printf_core/generic/error_mapper.h49
-rw-r--r--libc/src/stdio/printf_core/linux/CMakeLists.txt8
-rw-r--r--libc/src/stdio/printf_core/linux/error_mapper.h54
-rw-r--r--libc/src/stdio/printf_core/printf_main.h9
-rw-r--r--libc/src/stdio/printf_core/vasprintf_internal.h20
-rw-r--r--libc/src/stdio/printf_core/vfprintf_internal.h41
-rw-r--r--libc/src/stdio/printf_core/write_int_converter.h4
-rw-r--r--libc/src/stdio/printf_core/writer.h8
-rw-r--r--libc/src/stdio/snprintf.cpp19
-rw-r--r--libc/src/stdio/sprintf.cpp18
-rw-r--r--libc/src/stdio/vasprintf.cpp16
-rw-r--r--libc/src/stdio/vsnprintf.cpp19
-rw-r--r--libc/src/stdio/vsprintf.cpp17
-rw-r--r--libc/src/stdlib/CMakeLists.txt6
-rw-r--r--libc/src/stdlib/l64a.cpp6
-rw-r--r--libc/src/stdlib/strfromd.cpp11
-rw-r--r--libc/src/stdlib/strfromf.cpp11
-rw-r--r--libc/src/stdlib/strfroml.cpp11
-rw-r--r--libc/src/string/strcasestr.cpp4
-rw-r--r--libc/src/strings/strcasecmp.cpp4
-rw-r--r--libc/src/strings/strcasecmp_l.cpp4
-rw-r--r--libc/src/strings/strncasecmp.cpp4
-rw-r--r--libc/src/strings/strncasecmp_l.cpp4
-rw-r--r--libc/src/time/strftime_core/strftime_main.h3
-rw-r--r--libc/src/wctype/iswalpha.cpp4
74 files changed, 891 insertions, 330 deletions
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index b7af751..9687470 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -161,6 +161,7 @@ add_header_library(
HDRS
wctype_utils.h
DEPENDS
+ libc.hdr.types.wchar_t
libc.hdr.types.wint_t
)
diff --git a/libc/src/__support/ctype_utils.h b/libc/src/__support/ctype_utils.h
index be0f253..61b7a0a 100644
--- a/libc/src/__support/ctype_utils.h
+++ b/libc/src/__support/ctype_utils.h
@@ -27,7 +27,7 @@ namespace internal {
// as well as a way to support non-ASCII character encodings.
// Similarly, do not change these functions to use case ranges. e.g.
-// bool islower(int ch) {
+// bool islower(char ch) {
// switch(ch) {
// case 'a'...'z':
// return true;
@@ -37,7 +37,7 @@ namespace internal {
// EBCDIC. Technically we could use some smaller ranges, but that's even harder
// to read.
-LIBC_INLINE static constexpr bool islower(int ch) {
+LIBC_INLINE static constexpr bool islower(char ch) {
switch (ch) {
case 'a':
case 'b':
@@ -71,7 +71,7 @@ LIBC_INLINE static constexpr bool islower(int ch) {
}
}
-LIBC_INLINE static constexpr bool isupper(int ch) {
+LIBC_INLINE static constexpr bool isupper(char ch) {
switch (ch) {
case 'A':
case 'B':
@@ -105,7 +105,7 @@ LIBC_INLINE static constexpr bool isupper(int ch) {
}
}
-LIBC_INLINE static constexpr bool isdigit(int ch) {
+LIBC_INLINE static constexpr bool isdigit(char ch) {
switch (ch) {
case '0':
case '1':
@@ -123,7 +123,7 @@ LIBC_INLINE static constexpr bool isdigit(int ch) {
}
}
-LIBC_INLINE static constexpr int tolower(int ch) {
+LIBC_INLINE static constexpr char tolower(char ch) {
switch (ch) {
case 'A':
return 'a';
@@ -182,7 +182,7 @@ LIBC_INLINE static constexpr int tolower(int ch) {
}
}
-LIBC_INLINE static constexpr int toupper(int ch) {
+LIBC_INLINE static constexpr char toupper(char ch) {
switch (ch) {
case 'a':
return 'A';
@@ -241,7 +241,7 @@ LIBC_INLINE static constexpr int toupper(int ch) {
}
}
-LIBC_INLINE static constexpr bool isalpha(int ch) {
+LIBC_INLINE static constexpr bool isalpha(char ch) {
switch (ch) {
case 'a':
case 'b':
@@ -301,7 +301,7 @@ LIBC_INLINE static constexpr bool isalpha(int ch) {
}
}
-LIBC_INLINE static constexpr bool isalnum(int ch) {
+LIBC_INLINE static constexpr bool isalnum(char ch) {
switch (ch) {
case 'a':
case 'b':
@@ -371,7 +371,7 @@ LIBC_INLINE static constexpr bool isalnum(int ch) {
}
}
-LIBC_INLINE static constexpr int b36_char_to_int(int ch) {
+LIBC_INLINE static constexpr int b36_char_to_int(char ch) {
switch (ch) {
case '0':
return 0;
@@ -476,7 +476,7 @@ LIBC_INLINE static constexpr int b36_char_to_int(int ch) {
}
}
-LIBC_INLINE static constexpr int int_to_b36_char(int num) {
+LIBC_INLINE static constexpr char int_to_b36_char(int num) {
// Can't actually use LIBC_ASSERT here because it depends on integer_to_string
// which depends on this.
@@ -559,7 +559,7 @@ LIBC_INLINE static constexpr int int_to_b36_char(int num) {
}
}
-LIBC_INLINE static constexpr bool isspace(int ch) {
+LIBC_INLINE static constexpr bool isspace(char ch) {
switch (ch) {
case ' ':
case '\t':
@@ -574,7 +574,7 @@ LIBC_INLINE static constexpr bool isspace(int ch) {
}
// not yet encoding independent.
-LIBC_INLINE static constexpr bool isgraph(int ch) {
+LIBC_INLINE static constexpr bool isgraph(char ch) {
return 0x20 < ch && ch < 0x7f;
}
diff --git a/libc/src/__support/integer_to_string.h b/libc/src/__support/integer_to_string.h
index 29449bd..5e7369de0 100644
--- a/libc/src/__support/integer_to_string.h
+++ b/libc/src/__support/integer_to_string.h
@@ -378,9 +378,8 @@ template <typename T, typename Fmt = radix::Dec> class IntegerToString {
using UNSIGNED_T = make_integral_or_big_int_unsigned_t<T>;
LIBC_INLINE static char digit_char(uint8_t digit) {
- const int result = internal::int_to_b36_char(digit);
- return static_cast<char>(Fmt::IS_UPPERCASE ? internal::toupper(result)
- : result);
+ const char result = internal::int_to_b36_char(digit);
+ return Fmt::IS_UPPERCASE ? internal::toupper(result) : result;
}
LIBC_INLINE static void
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 6209000..ddc0159 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -770,6 +770,24 @@ add_header_library(
)
add_header_library(
+ exp2m1f16
+ HDRS
+ exp2m1f16.h
+ DEPENDS
+ .expxf16_utils
+ libc.src.__support.common
+ libc.src.__support.FPUtil.cast
+ libc.src.__support.FPUtil.except_value_utils
+ libc.src.__support.FPUtil.fenv_impl
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.multiply_add
+ libc.src.__support.FPUtil.polyeval
+ libc.src.__support.FPUtil.rounding_mode
+ libc.src.__support.macros.optimization
+ libc.src.__support.macros.properties.cpu_features
+)
+
+add_header_library(
exp10
HDRS
exp10.h
diff --git a/libc/src/__support/math/exp2m1f16.h b/libc/src/__support/math/exp2m1f16.h
new file mode 100644
index 0000000..0424af4
--- /dev/null
+++ b/libc/src/__support/math/exp2m1f16.h
@@ -0,0 +1,180 @@
+//===-- Implementation header for exp2m1f16 ----------------------*- 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___SUPPORT_MATH_EXP2M1F16_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2M1F16_H
+
+#include "include/llvm-libc-macros/float16-macros.h"
+
+#ifdef LIBC_TYPES_HAS_FLOAT16
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/PolyEval.h"
+#include "src/__support/FPUtil/cast.h"
+#include "src/__support/FPUtil/except_value_utils.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/macros/properties/cpu_features.h"
+#include "src/__support/math/expxf16_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+LIBC_INLINE static constexpr float16 exp2m1f16(float16 x) {
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ constexpr fputil::ExceptValues<float16, 6> EXP2M1F16_EXCEPTS_LO = {{
+ // (input, RZ output, RU offset, RD offset, RN offset)
+ // x = 0x1.cf4p-13, exp2m1f16(x) = 0x1.41p-13 (RZ)
+ {0x0b3dU, 0x0904U, 1U, 0U, 1U},
+ // x = 0x1.4fcp-12, exp2m1f16(x) = 0x1.d14p-13 (RZ)
+ {0x0d3fU, 0x0b45U, 1U, 0U, 1U},
+ // x = 0x1.63p-11, exp2m1f16(x) = 0x1.ec4p-12 (RZ)
+ {0x118cU, 0x0fb1U, 1U, 0U, 0U},
+ // x = 0x1.6fp-7, exp2m1f16(x) = 0x1.fe8p-8 (RZ)
+ {0x21bcU, 0x1ffaU, 1U, 0U, 1U},
+ // x = -0x1.c6p-10, exp2m1f16(x) = -0x1.3a8p-10 (RZ)
+ {0x9718U, 0x94eaU, 0U, 1U, 0U},
+ // x = -0x1.cfcp-10, exp2m1f16(x) = -0x1.414p-10 (RZ)
+ {0x973fU, 0x9505U, 0U, 1U, 0U},
+ }};
+
+#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT
+ constexpr size_t N_EXP2M1F16_EXCEPTS_HI = 6;
+#else
+ constexpr size_t N_EXP2M1F16_EXCEPTS_HI = 7;
+#endif
+
+ constexpr fputil::ExceptValues<float16, N_EXP2M1F16_EXCEPTS_HI>
+ EXP2M1F16_EXCEPTS_HI = {{
+ // (input, RZ output, RU offset, RD offset, RN offset)
+ // x = 0x1.e58p-3, exp2m1f16(x) = 0x1.6dcp-3 (RZ)
+ {0x3396U, 0x31b7U, 1U, 0U, 0U},
+#ifndef LIBC_TARGET_CPU_HAS_FMA_FLOAT
+ // x = 0x1.2e8p-2, exp2m1f16(x) = 0x1.d14p-3 (RZ)
+ {0x34baU, 0x3345U, 1U, 0U, 0U},
+#endif
+ // x = 0x1.ad8p-2, exp2m1f16(x) = 0x1.598p-2 (RZ)
+ {0x36b6U, 0x3566U, 1U, 0U, 0U},
+#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT
+ // x = 0x1.edcp-2, exp2m1f16(x) = 0x1.964p-2 (RZ)
+ {0x37b7U, 0x3659U, 1U, 0U, 1U},
+#endif
+ // x = -0x1.804p-3, exp2m1f16(x) = -0x1.f34p-4 (RZ)
+ {0xb201U, 0xafcdU, 0U, 1U, 1U},
+ // x = -0x1.f3p-3, exp2m1f16(x) = -0x1.3e4p-3 (RZ)
+ {0xb3ccU, 0xb0f9U, 0U, 1U, 0U},
+ // x = -0x1.294p-1, exp2m1f16(x) = -0x1.53p-2 (RZ)
+ {0xb8a5U, 0xb54cU, 0U, 1U, 1U},
+#ifndef LIBC_TARGET_CPU_HAS_FMA_FLOAT
+ // x = -0x1.a34p-1, exp2m1f16(x) = -0x1.bb4p-2 (RZ)
+ {0xba8dU, 0xb6edU, 0U, 1U, 1U},
+#endif
+ }};
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+ using namespace math::expxf16_internal;
+ using FPBits = fputil::FPBits<float16>;
+ FPBits x_bits(x);
+
+ uint16_t x_u = x_bits.uintval();
+ uint16_t x_abs = x_u & 0x7fffU;
+
+ // When |x| <= 2^(-3), or |x| >= 11, or x is NaN.
+ if (LIBC_UNLIKELY(x_abs <= 0x3000U || x_abs >= 0x4980U)) {
+ // exp2m1(NaN) = NaN
+ if (x_bits.is_nan()) {
+ if (x_bits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
+ return x;
+ }
+
+ // When x >= 16.
+ if (x_u >= 0x4c00 && x_bits.is_pos()) {
+ // exp2m1(+inf) = +inf
+ if (x_bits.is_inf())
+ return FPBits::inf().get_val();
+
+ switch (fputil::quick_get_round()) {
+ case FE_TONEAREST:
+ case FE_UPWARD:
+ fputil::set_errno_if_required(ERANGE);
+ fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
+ return FPBits::inf().get_val();
+ default:
+ return FPBits::max_normal().get_val();
+ }
+ }
+
+ // When x < -11.
+ if (x_u > 0xc980U) {
+ // exp2m1(-inf) = -1
+ if (x_bits.is_inf())
+ return FPBits::one(Sign::NEG).get_val();
+
+ // When -12 < x < -11, round(2^x - 1, HP, RN) = -0x1.ffcp-1.
+ if (x_u < 0xca00U)
+ return fputil::round_result_slightly_down(
+ fputil::cast<float16>(-0x1.ffcp-1));
+
+ // When x <= -12, round(2^x - 1, HP, RN) = -1.
+ switch (fputil::quick_get_round()) {
+ case FE_TONEAREST:
+ case FE_DOWNWARD:
+ return FPBits::one(Sign::NEG).get_val();
+ default:
+ return fputil::cast<float16>(-0x1.ffcp-1);
+ }
+ }
+
+ // When |x| <= 2^(-3).
+ if (x_abs <= 0x3000U) {
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ if (auto r = EXP2M1F16_EXCEPTS_LO.lookup(x_u);
+ LIBC_UNLIKELY(r.has_value()))
+ return r.value();
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+ float xf = x;
+ // Degree-5 minimax polynomial generated by Sollya with the following
+ // commands:
+ // > display = hexadecimal;
+ // > P = fpminimax((2^x - 1)/x, 4, [|SG...|], [-2^-3, 2^-3]);
+ // > x * P;
+ return fputil::cast<float16>(
+ xf * fputil::polyeval(xf, 0x1.62e43p-1f, 0x1.ebfbdep-3f,
+ 0x1.c6af88p-5f, 0x1.3b45d6p-7f,
+ 0x1.641e7cp-10f));
+ }
+ }
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ if (auto r = EXP2M1F16_EXCEPTS_HI.lookup(x_u); LIBC_UNLIKELY(r.has_value()))
+ return r.value();
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+ // exp2(x) = exp2(hi + mid) * exp2(lo)
+ auto [exp2_hi_mid, exp2_lo] = exp2_range_reduction(x);
+ // exp2m1(x) = exp2(hi + mid) * exp2(lo) - 1
+ return fputil::cast<float16>(
+ fputil::multiply_add(exp2_hi_mid, exp2_lo, -1.0f));
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP2M1F16_H
diff --git a/libc/src/__support/wctype_utils.h b/libc/src/__support/wctype_utils.h
index 2ae5ec9..60b6afb 100644
--- a/libc/src/__support/wctype_utils.h
+++ b/libc/src/__support/wctype_utils.h
@@ -9,6 +9,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
#define LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
+#include "hdr/types/wchar_t.h"
#include "hdr/types/wint_t.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/macros/attributes.h" // LIBC_INLINE
@@ -30,7 +31,7 @@ namespace internal {
// Similarly, do not change these fumarks to show your new solution is faster,
// as well as a way to support non-Anctions to use case ranges. e.g.
-// bool iswlower(wint_t ch) {
+// bool iswlower(wchar_t ch) {
// switch(ch) {
// case L'a'...L'z':
// return true;
@@ -40,7 +41,7 @@ namespace internal {
// EBCDIC. Technically we could use some smaller ranges, but that's even harder
// to read.
-LIBC_INLINE static constexpr bool iswlower(wint_t wch) {
+LIBC_INLINE static constexpr bool iswlower(wchar_t wch) {
switch (wch) {
case L'a':
case L'b':
@@ -74,7 +75,7 @@ LIBC_INLINE static constexpr bool iswlower(wint_t wch) {
}
}
-LIBC_INLINE static constexpr bool iswupper(wint_t wch) {
+LIBC_INLINE static constexpr bool iswupper(wchar_t wch) {
switch (wch) {
case L'A':
case L'B':
@@ -108,7 +109,7 @@ LIBC_INLINE static constexpr bool iswupper(wint_t wch) {
}
}
-LIBC_INLINE static constexpr bool iswdigit(wint_t wch) {
+LIBC_INLINE static constexpr bool iswdigit(wchar_t wch) {
switch (wch) {
case L'0':
case L'1':
@@ -126,7 +127,7 @@ LIBC_INLINE static constexpr bool iswdigit(wint_t wch) {
}
}
-LIBC_INLINE static constexpr wint_t towlower(wint_t wch) {
+LIBC_INLINE static constexpr wchar_t towlower(wchar_t wch) {
switch (wch) {
case L'A':
return L'a';
@@ -185,7 +186,7 @@ LIBC_INLINE static constexpr wint_t towlower(wint_t wch) {
}
}
-LIBC_INLINE static constexpr wint_t towupper(wint_t wch) {
+LIBC_INLINE static constexpr wchar_t towupper(wchar_t wch) {
switch (wch) {
case L'a':
return L'A';
@@ -244,7 +245,7 @@ LIBC_INLINE static constexpr wint_t towupper(wint_t wch) {
}
}
-LIBC_INLINE static constexpr bool iswalpha(wint_t wch) {
+LIBC_INLINE static constexpr bool iswalpha(wchar_t wch) {
switch (wch) {
case L'a':
case L'b':
@@ -304,7 +305,7 @@ LIBC_INLINE static constexpr bool iswalpha(wint_t wch) {
}
}
-LIBC_INLINE static constexpr bool iswalnum(wint_t wch) {
+LIBC_INLINE static constexpr bool iswalnum(wchar_t wch) {
switch (wch) {
case L'a':
case L'b':
@@ -374,7 +375,7 @@ LIBC_INLINE static constexpr bool iswalnum(wint_t wch) {
}
}
-LIBC_INLINE static constexpr int b36_wchar_to_int(wint_t wch) {
+LIBC_INLINE static constexpr int b36_wchar_to_int(wchar_t wch) {
switch (wch) {
case L'0':
return 0;
@@ -479,7 +480,7 @@ LIBC_INLINE static constexpr int b36_wchar_to_int(wint_t wch) {
}
}
-LIBC_INLINE static constexpr wint_t int_to_b36_wchar(int num) {
+LIBC_INLINE static constexpr wchar_t int_to_b36_wchar(int num) {
// Can't actually use LIBC_ASSERT here because it depends on integer_to_string
// which depends on this.
@@ -562,7 +563,7 @@ LIBC_INLINE static constexpr wint_t int_to_b36_wchar(int num) {
}
}
-LIBC_INLINE static constexpr bool iswspace(wint_t wch) {
+LIBC_INLINE static constexpr bool iswspace(wchar_t wch) {
switch (wch) {
case L' ':
case L'\t':
diff --git a/libc/src/ctype/CMakeLists.txt b/libc/src/ctype/CMakeLists.txt
index 8830c1b..68e982b 100644
--- a/libc/src/ctype/CMakeLists.txt
+++ b/libc/src/ctype/CMakeLists.txt
@@ -6,6 +6,7 @@ add_entrypoint_object(
isalnum.h
DEPENDS
libc.include.ctype
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
)
@@ -16,6 +17,7 @@ add_entrypoint_object(
HDRS
isalpha.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
)
@@ -50,6 +52,7 @@ add_entrypoint_object(
HDRS
isdigit.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
)
@@ -60,6 +63,7 @@ add_entrypoint_object(
HDRS
isgraph.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
)
@@ -70,6 +74,7 @@ add_entrypoint_object(
HDRS
islower.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
)
@@ -88,6 +93,7 @@ add_entrypoint_object(
HDRS
ispunct.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
)
@@ -97,6 +103,9 @@ add_entrypoint_object(
isspace.cpp
HDRS
isspace.h
+ DEPENDS
+ libc.src.__support.CPP.limits
+ libc.src.__support.ctype_utils
)
add_entrypoint_object(
@@ -106,6 +115,7 @@ add_entrypoint_object(
HDRS
isupper.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
)
@@ -116,6 +126,7 @@ add_entrypoint_object(
HDRS
isxdigit.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
)
@@ -126,6 +137,7 @@ add_entrypoint_object(
HDRS
tolower.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
)
@@ -144,6 +156,7 @@ add_entrypoint_object(
HDRS
toupper.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
)
@@ -160,6 +173,7 @@ add_entrypoint_object(
isalnum_l.h
DEPENDS
libc.include.ctype
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
libc.hdr.types.locale_t
)
@@ -171,6 +185,7 @@ add_entrypoint_object(
HDRS
isalpha_l.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
libc.hdr.types.locale_t
)
@@ -202,6 +217,7 @@ add_entrypoint_object(
HDRS
isdigit_l.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
libc.hdr.types.locale_t
)
@@ -224,6 +240,7 @@ add_entrypoint_object(
HDRS
islower_l.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
libc.hdr.types.locale_t
)
@@ -257,6 +274,8 @@ add_entrypoint_object(
isspace_l.h
DEPENDS
libc.hdr.types.locale_t
+ libc.src.__support.CPP.limits
+ libc.src.__support.ctype_utils
)
add_entrypoint_object(
@@ -266,6 +285,7 @@ add_entrypoint_object(
HDRS
isupper_l.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
libc.hdr.types.locale_t
)
@@ -277,6 +297,7 @@ add_entrypoint_object(
HDRS
isxdigit_l.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
libc.hdr.types.locale_t
)
@@ -288,6 +309,7 @@ add_entrypoint_object(
HDRS
tolower_l.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
libc.hdr.types.locale_t
)
@@ -299,6 +321,7 @@ add_entrypoint_object(
HDRS
toupper_l.h
DEPENDS
+ libc.src.__support.CPP.limits
libc.src.__support.ctype_utils
libc.hdr.types.locale_t
)
diff --git a/libc/src/ctype/isalnum.cpp b/libc/src/ctype/isalnum.cpp
index 54a3e35..102b5e7 100644
--- a/libc/src/ctype/isalnum.cpp
+++ b/libc/src/ctype/isalnum.cpp
@@ -7,15 +7,18 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/isalnum.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isalnum, (int c)) {
- return static_cast<int>(internal::isalnum(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::isalnum(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isalnum_l.cpp b/libc/src/ctype/isalnum_l.cpp
index 671d9b75..173e1c1 100644
--- a/libc/src/ctype/isalnum_l.cpp
+++ b/libc/src/ctype/isalnum_l.cpp
@@ -7,15 +7,18 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/isalnum_l.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isalnum_l, (int c, locale_t)) {
- return static_cast<int>(internal::isalnum(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::isalnum(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isalpha.cpp b/libc/src/ctype/isalpha.cpp
index 78b26f6..7c874bf 100644
--- a/libc/src/ctype/isalpha.cpp
+++ b/libc/src/ctype/isalpha.cpp
@@ -8,6 +8,7 @@
#include "src/ctype/isalpha.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
@@ -15,7 +16,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isalpha, (int c)) {
- return static_cast<int>(internal::isalpha(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::isalpha(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isalpha_l.cpp b/libc/src/ctype/isalpha_l.cpp
index 0619d97..982bcc5 100644
--- a/libc/src/ctype/isalpha_l.cpp
+++ b/libc/src/ctype/isalpha_l.cpp
@@ -8,6 +8,7 @@
#include "src/ctype/isalpha_l.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
@@ -15,7 +16,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isalpha_l, (int c, locale_t)) {
- return static_cast<int>(internal::isalpha(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::isalpha(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isdigit.cpp b/libc/src/ctype/isdigit.cpp
index 1f71194..43553c7 100644
--- a/libc/src/ctype/isdigit.cpp
+++ b/libc/src/ctype/isdigit.cpp
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/isdigit.h"
+
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
@@ -14,7 +16,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isdigit, (int c)) {
- return static_cast<int>(internal::isdigit(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::isdigit(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isdigit_l.cpp b/libc/src/ctype/isdigit_l.cpp
index ca981362..40b5618 100644
--- a/libc/src/ctype/isdigit_l.cpp
+++ b/libc/src/ctype/isdigit_l.cpp
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/isdigit_l.h"
+
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
@@ -14,7 +16,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isdigit_l, (int c, locale_t)) {
- return static_cast<int>(internal::isdigit(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::isdigit(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isgraph.cpp b/libc/src/ctype/isgraph.cpp
index 74bb2e7..b9308ec 100644
--- a/libc/src/ctype/isgraph.cpp
+++ b/libc/src/ctype/isgraph.cpp
@@ -8,6 +8,7 @@
#include "src/ctype/isgraph.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
@@ -15,7 +16,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isgraph, (int c)) {
- return static_cast<int>(internal::isgraph(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::isgraph(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isgraph_l.cpp b/libc/src/ctype/isgraph_l.cpp
index cbef6df1..dddcb9b 100644
--- a/libc/src/ctype/isgraph_l.cpp
+++ b/libc/src/ctype/isgraph_l.cpp
@@ -8,6 +8,7 @@
#include "src/ctype/isgraph_l.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
@@ -15,7 +16,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isgraph_l, (int c, locale_t)) {
- return static_cast<int>(internal::isgraph(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::isgraph(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/islower.cpp b/libc/src/ctype/islower.cpp
index 831aad3..920bfc1 100644
--- a/libc/src/ctype/islower.cpp
+++ b/libc/src/ctype/islower.cpp
@@ -7,15 +7,18 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/islower.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, islower, (int c)) {
- return static_cast<int>(internal::islower(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::islower(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/islower_l.cpp b/libc/src/ctype/islower_l.cpp
index b9be6ac..da97026 100644
--- a/libc/src/ctype/islower_l.cpp
+++ b/libc/src/ctype/islower_l.cpp
@@ -7,15 +7,18 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/islower_l.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, islower_l, (int c, locale_t)) {
- return static_cast<int>(internal::islower(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::islower(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/ispunct.cpp b/libc/src/ctype/ispunct.cpp
index 0635294..4950036 100644
--- a/libc/src/ctype/ispunct.cpp
+++ b/libc/src/ctype/ispunct.cpp
@@ -8,6 +8,7 @@
#include "src/ctype/ispunct.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
@@ -15,7 +16,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, ispunct, (int c)) {
- const unsigned ch = static_cast<unsigned>(c);
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ const char ch = static_cast<char>(c);
return static_cast<int>(!internal::isalnum(ch) && internal::isgraph(ch));
}
diff --git a/libc/src/ctype/ispunct_l.cpp b/libc/src/ctype/ispunct_l.cpp
index e825fbe..79cd47b 100644
--- a/libc/src/ctype/ispunct_l.cpp
+++ b/libc/src/ctype/ispunct_l.cpp
@@ -8,6 +8,7 @@
#include "src/ctype/ispunct_l.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
@@ -15,7 +16,9 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, ispunct_l, (int c, locale_t)) {
- const unsigned ch = static_cast<unsigned>(c);
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ const char ch = static_cast<char>(c);
return static_cast<int>(!internal::isalnum(ch) && internal::isgraph(ch));
}
diff --git a/libc/src/ctype/isspace.cpp b/libc/src/ctype/isspace.cpp
index 005bf46..998dbf2 100644
--- a/libc/src/ctype/isspace.cpp
+++ b/libc/src/ctype/isspace.cpp
@@ -7,15 +7,18 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/isspace.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isspace, (int c)) {
- return static_cast<int>(internal::isspace(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::isspace(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isspace_l.cpp b/libc/src/ctype/isspace_l.cpp
index 5c46dd6..e407653 100644
--- a/libc/src/ctype/isspace_l.cpp
+++ b/libc/src/ctype/isspace_l.cpp
@@ -7,15 +7,18 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/isspace_l.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isspace_l, (int c, locale_t)) {
- return static_cast<int>(internal::isspace(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::isspace(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isupper.cpp b/libc/src/ctype/isupper.cpp
index 965fa33..c5c3dbd 100644
--- a/libc/src/ctype/isupper.cpp
+++ b/libc/src/ctype/isupper.cpp
@@ -7,15 +7,18 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/isupper.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isupper, (int c)) {
- return static_cast<int>(internal::isupper(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::isupper(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isupper_l.cpp b/libc/src/ctype/isupper_l.cpp
index 3589902..44ed9da 100644
--- a/libc/src/ctype/isupper_l.cpp
+++ b/libc/src/ctype/isupper_l.cpp
@@ -7,15 +7,18 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/isupper_l.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isupper_l, (int c, locale_t)) {
- return static_cast<int>(internal::isupper(static_cast<unsigned>(c)));
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ return static_cast<int>(internal::isupper(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isxdigit.cpp b/libc/src/ctype/isxdigit.cpp
index 81f645c..1b2e717 100644
--- a/libc/src/ctype/isxdigit.cpp
+++ b/libc/src/ctype/isxdigit.cpp
@@ -7,15 +7,18 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/isxdigit.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isxdigit, (int c)) {
- const unsigned ch = static_cast<unsigned>(c);
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ const char ch = static_cast<char>(c);
return static_cast<int>(internal::isalnum(ch) &&
internal::b36_char_to_int(ch) < 16);
}
diff --git a/libc/src/ctype/isxdigit_l.cpp b/libc/src/ctype/isxdigit_l.cpp
index eddfd20..e615047 100644
--- a/libc/src/ctype/isxdigit_l.cpp
+++ b/libc/src/ctype/isxdigit_l.cpp
@@ -7,15 +7,18 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/isxdigit_l.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, isxdigit_l, (int c, locale_t)) {
- const unsigned ch = static_cast<unsigned>(c);
+ if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
+ return 0;
+ const char ch = static_cast<char>(c);
return static_cast<int>(internal::isalnum(ch) &&
internal::b36_char_to_int(ch) < 16);
}
diff --git a/libc/src/ctype/tolower.cpp b/libc/src/ctype/tolower.cpp
index 3ecad7b..b45c5f2 100644
--- a/libc/src/ctype/tolower.cpp
+++ b/libc/src/ctype/tolower.cpp
@@ -7,13 +7,20 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/tolower.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
-LLVM_LIBC_FUNCTION(int, tolower, (int c)) { return internal::tolower(c); }
+LLVM_LIBC_FUNCTION(int, tolower, (int c)) {
+ if (c < cpp::numeric_limits<char>::min() ||
+ c > cpp::numeric_limits<char>::max()) {
+ return c;
+ }
+ return static_cast<int>(internal::tolower(static_cast<char>(c)));
+}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/tolower_l.cpp b/libc/src/ctype/tolower_l.cpp
index 7ccf316..049e46a 100644
--- a/libc/src/ctype/tolower_l.cpp
+++ b/libc/src/ctype/tolower_l.cpp
@@ -7,15 +7,20 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/tolower_l.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, tolower_l, (int c, locale_t)) {
- return internal::tolower(c);
+ if (c < cpp::numeric_limits<char>::min() ||
+ c > cpp::numeric_limits<char>::max()) {
+ return c;
+ }
+ return static_cast<int>(internal::tolower(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/toupper.cpp b/libc/src/ctype/toupper.cpp
index 1e1e8fc..0e38723 100644
--- a/libc/src/ctype/toupper.cpp
+++ b/libc/src/ctype/toupper.cpp
@@ -7,13 +7,20 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/toupper.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
-LLVM_LIBC_FUNCTION(int, toupper, (int c)) { return internal::toupper(c); }
+LLVM_LIBC_FUNCTION(int, toupper, (int c)) {
+ if (c < cpp::numeric_limits<char>::min() ||
+ c > cpp::numeric_limits<char>::max()) {
+ return c;
+ }
+ return static_cast<int>(internal::toupper(static_cast<char>(c)));
+}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/toupper_l.cpp b/libc/src/ctype/toupper_l.cpp
index a435ca1..d1dff262 100644
--- a/libc/src/ctype/toupper_l.cpp
+++ b/libc/src/ctype/toupper_l.cpp
@@ -7,15 +7,20 @@
//===----------------------------------------------------------------------===//
#include "src/ctype/toupper_l.h"
-#include "src/__support/ctype_utils.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, toupper_l, (int c, locale_t)) {
- return internal::toupper(c);
+ if (c < cpp::numeric_limits<char>::min() ||
+ c > cpp::numeric_limits<char>::max()) {
+ return c;
+ }
+ return static_cast<int>(internal::toupper(static_cast<char>(c)));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/fcntl/linux/creat.cpp b/libc/src/fcntl/linux/creat.cpp
index 71412a8e..e74cef2 100644
--- a/libc/src/fcntl/linux/creat.cpp
+++ b/libc/src/fcntl/linux/creat.cpp
@@ -27,11 +27,11 @@ LLVM_LIBC_FUNCTION(int, creat, (const char *path, int mode_flags)) {
SYS_openat, AT_FDCWD, path, O_CREAT | O_WRONLY | O_TRUNC, mode_flags);
#endif
- if (fd > 0)
- return fd;
-
- libc_errno = -fd;
- return -1;
+ if (fd < 0) {
+ libc_errno = -fd;
+ return -1;
+ }
+ return fd;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/fcntl/linux/openat.cpp b/libc/src/fcntl/linux/openat.cpp
index b47ad1f..b80abe5 100644
--- a/libc/src/fcntl/linux/openat.cpp
+++ b/libc/src/fcntl/linux/openat.cpp
@@ -32,11 +32,11 @@ LLVM_LIBC_FUNCTION(int, openat, (int dfd, const char *path, int flags, ...)) {
int fd = LIBC_NAMESPACE::syscall_impl<int>(SYS_openat, dfd, path, flags,
mode_flags);
- if (fd > 0)
- return fd;
-
- libc_errno = -fd;
- return -1;
+ if (fd < 0) {
+ libc_errno = -fd;
+ return -1;
+ }
+ return fd;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index c048a64..e713005 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -1498,19 +1498,7 @@ add_entrypoint_object(
HDRS
../exp2m1f16.h
DEPENDS
- libc.hdr.errno_macros
- libc.hdr.fenv_macros
- libc.src.__support.common
- libc.src.__support.FPUtil.cast
- libc.src.__support.FPUtil.except_value_utils
- libc.src.__support.FPUtil.fenv_impl
- libc.src.__support.FPUtil.fp_bits
- libc.src.__support.FPUtil.multiply_add
- libc.src.__support.FPUtil.polyeval
- libc.src.__support.FPUtil.rounding_mode
- libc.src.__support.macros.optimization
- libc.src.__support.macros.properties.cpu_features
- libc.src.__support.math.expxf16_utils
+ libc.src.__support.math.exp2m1f16
)
add_entrypoint_object(
diff --git a/libc/src/math/generic/exp2m1f16.cpp b/libc/src/math/generic/exp2m1f16.cpp
index ce0cc60..497a288 100644
--- a/libc/src/math/generic/exp2m1f16.cpp
+++ b/libc/src/math/generic/exp2m1f16.cpp
@@ -7,163 +7,12 @@
//===----------------------------------------------------------------------===//
#include "src/math/exp2m1f16.h"
-#include "hdr/errno_macros.h"
-#include "hdr/fenv_macros.h"
-#include "src/__support/FPUtil/FEnvImpl.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/PolyEval.h"
-#include "src/__support/FPUtil/cast.h"
-#include "src/__support/FPUtil/except_value_utils.h"
-#include "src/__support/FPUtil/multiply_add.h"
-#include "src/__support/FPUtil/rounding_mode.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h"
-#include "src/__support/macros/properties/cpu_features.h"
-#include "src/__support/math/expxf16_utils.h"
+#include "src/__support/math/exp2m1f16.h"
namespace LIBC_NAMESPACE_DECL {
-#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-static constexpr fputil::ExceptValues<float16, 6> EXP2M1F16_EXCEPTS_LO = {{
- // (input, RZ output, RU offset, RD offset, RN offset)
- // x = 0x1.cf4p-13, exp2m1f16(x) = 0x1.41p-13 (RZ)
- {0x0b3dU, 0x0904U, 1U, 0U, 1U},
- // x = 0x1.4fcp-12, exp2m1f16(x) = 0x1.d14p-13 (RZ)
- {0x0d3fU, 0x0b45U, 1U, 0U, 1U},
- // x = 0x1.63p-11, exp2m1f16(x) = 0x1.ec4p-12 (RZ)
- {0x118cU, 0x0fb1U, 1U, 0U, 0U},
- // x = 0x1.6fp-7, exp2m1f16(x) = 0x1.fe8p-8 (RZ)
- {0x21bcU, 0x1ffaU, 1U, 0U, 1U},
- // x = -0x1.c6p-10, exp2m1f16(x) = -0x1.3a8p-10 (RZ)
- {0x9718U, 0x94eaU, 0U, 1U, 0U},
- // x = -0x1.cfcp-10, exp2m1f16(x) = -0x1.414p-10 (RZ)
- {0x973fU, 0x9505U, 0U, 1U, 0U},
-}};
-
-#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT
-static constexpr size_t N_EXP2M1F16_EXCEPTS_HI = 6;
-#else
-static constexpr size_t N_EXP2M1F16_EXCEPTS_HI = 7;
-#endif
-
-static constexpr fputil::ExceptValues<float16, N_EXP2M1F16_EXCEPTS_HI>
- EXP2M1F16_EXCEPTS_HI = {{
- // (input, RZ output, RU offset, RD offset, RN offset)
- // x = 0x1.e58p-3, exp2m1f16(x) = 0x1.6dcp-3 (RZ)
- {0x3396U, 0x31b7U, 1U, 0U, 0U},
-#ifndef LIBC_TARGET_CPU_HAS_FMA_FLOAT
- // x = 0x1.2e8p-2, exp2m1f16(x) = 0x1.d14p-3 (RZ)
- {0x34baU, 0x3345U, 1U, 0U, 0U},
-#endif
- // x = 0x1.ad8p-2, exp2m1f16(x) = 0x1.598p-2 (RZ)
- {0x36b6U, 0x3566U, 1U, 0U, 0U},
-#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT
- // x = 0x1.edcp-2, exp2m1f16(x) = 0x1.964p-2 (RZ)
- {0x37b7U, 0x3659U, 1U, 0U, 1U},
-#endif
- // x = -0x1.804p-3, exp2m1f16(x) = -0x1.f34p-4 (RZ)
- {0xb201U, 0xafcdU, 0U, 1U, 1U},
- // x = -0x1.f3p-3, exp2m1f16(x) = -0x1.3e4p-3 (RZ)
- {0xb3ccU, 0xb0f9U, 0U, 1U, 0U},
- // x = -0x1.294p-1, exp2m1f16(x) = -0x1.53p-2 (RZ)
- {0xb8a5U, 0xb54cU, 0U, 1U, 1U},
-#ifndef LIBC_TARGET_CPU_HAS_FMA_FLOAT
- // x = -0x1.a34p-1, exp2m1f16(x) = -0x1.bb4p-2 (RZ)
- {0xba8dU, 0xb6edU, 0U, 1U, 1U},
-#endif
- }};
-#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-
LLVM_LIBC_FUNCTION(float16, exp2m1f16, (float16 x)) {
- using namespace math::expxf16_internal;
- using FPBits = fputil::FPBits<float16>;
- FPBits x_bits(x);
-
- uint16_t x_u = x_bits.uintval();
- uint16_t x_abs = x_u & 0x7fffU;
-
- // When |x| <= 2^(-3), or |x| >= 11, or x is NaN.
- if (LIBC_UNLIKELY(x_abs <= 0x3000U || x_abs >= 0x4980U)) {
- // exp2m1(NaN) = NaN
- if (x_bits.is_nan()) {
- if (x_bits.is_signaling_nan()) {
- fputil::raise_except_if_required(FE_INVALID);
- return FPBits::quiet_nan().get_val();
- }
-
- return x;
- }
-
- // When x >= 16.
- if (x_u >= 0x4c00 && x_bits.is_pos()) {
- // exp2m1(+inf) = +inf
- if (x_bits.is_inf())
- return FPBits::inf().get_val();
-
- switch (fputil::quick_get_round()) {
- case FE_TONEAREST:
- case FE_UPWARD:
- fputil::set_errno_if_required(ERANGE);
- fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
- return FPBits::inf().get_val();
- default:
- return FPBits::max_normal().get_val();
- }
- }
-
- // When x < -11.
- if (x_u > 0xc980U) {
- // exp2m1(-inf) = -1
- if (x_bits.is_inf())
- return FPBits::one(Sign::NEG).get_val();
-
- // When -12 < x < -11, round(2^x - 1, HP, RN) = -0x1.ffcp-1.
- if (x_u < 0xca00U)
- return fputil::round_result_slightly_down(
- fputil::cast<float16>(-0x1.ffcp-1));
-
- // When x <= -12, round(2^x - 1, HP, RN) = -1.
- switch (fputil::quick_get_round()) {
- case FE_TONEAREST:
- case FE_DOWNWARD:
- return FPBits::one(Sign::NEG).get_val();
- default:
- return fputil::cast<float16>(-0x1.ffcp-1);
- }
- }
-
- // When |x| <= 2^(-3).
- if (x_abs <= 0x3000U) {
-#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- if (auto r = EXP2M1F16_EXCEPTS_LO.lookup(x_u);
- LIBC_UNLIKELY(r.has_value()))
- return r.value();
-#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-
- float xf = x;
- // Degree-5 minimax polynomial generated by Sollya with the following
- // commands:
- // > display = hexadecimal;
- // > P = fpminimax((2^x - 1)/x, 4, [|SG...|], [-2^-3, 2^-3]);
- // > x * P;
- return fputil::cast<float16>(
- xf * fputil::polyeval(xf, 0x1.62e43p-1f, 0x1.ebfbdep-3f,
- 0x1.c6af88p-5f, 0x1.3b45d6p-7f,
- 0x1.641e7cp-10f));
- }
- }
-
-#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- if (auto r = EXP2M1F16_EXCEPTS_HI.lookup(x_u); LIBC_UNLIKELY(r.has_value()))
- return r.value();
-#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-
- // exp2(x) = exp2(hi + mid) * exp2(lo)
- auto [exp2_hi_mid, exp2_lo] = exp2_range_reduction(x);
- // exp2m1(x) = exp2(hi + mid) * exp2(lo) - 1
- return fputil::cast<float16>(
- fputil::multiply_add(exp2_hi_mid, exp2_lo, -1.0f));
+ return math::exp2m1f16(x);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index b0a6ef1..c75c8b1 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -125,6 +125,10 @@ add_entrypoint_object(
DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
@@ -136,6 +140,10 @@ add_entrypoint_object(
DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
@@ -146,6 +154,10 @@ add_entrypoint_object(
asprintf.h
DEPENDS
libc.src.stdio.printf_core.vasprintf_internal
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
@@ -157,6 +169,10 @@ add_entrypoint_object(
DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
@@ -168,6 +184,10 @@ add_entrypoint_object(
DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
@@ -178,6 +198,10 @@ add_entrypoint_object(
vasprintf.h
DEPENDS
libc.src.stdio.printf_core.vasprintf_internal
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_subdirectory(printf_core)
diff --git a/libc/src/stdio/asprintf.cpp b/libc/src/stdio/asprintf.cpp
index f8cfb74..0991dfc 100644
--- a/libc/src/stdio/asprintf.cpp
+++ b/libc/src/stdio/asprintf.cpp
@@ -7,8 +7,12 @@
//===----------------------------------------------------------------------===//
#include "src/stdio/asprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/arg_list.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/vasprintf_internal.h"
namespace LIBC_NAMESPACE_DECL {
@@ -22,8 +26,18 @@ LLVM_LIBC_FUNCTION(int, asprintf,
// and pointer semantics, as well as handling
// destruction automatically.
va_end(vlist);
- int ret = printf_core::vasprintf_internal(buffer, format, args);
- return ret;
+ auto ret_val = printf_core::vasprintf_internal(buffer, format, args);
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt
index 548938f..bfeff0e 100644
--- a/libc/src/stdio/baremetal/CMakeLists.txt
+++ b/libc/src/stdio/baremetal/CMakeLists.txt
@@ -29,8 +29,12 @@ add_entrypoint_object(
DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.stdio.printf_core.core_structs
libc.src.__support.arg_list
libc.src.__support.OSUtil.osutil
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
@@ -87,8 +91,12 @@ add_entrypoint_object(
DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
+ libc.src.stdio.printf_core.error_mapper
+ libc.src.stdio.printf_core.core_structs
libc.src.__support.arg_list
libc.src.__support.OSUtil.osutil
+ libc.src.__support.libc_errno
+ libc.src.__support.CPP.limits
)
add_entrypoint_object(
diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp
index 7253c65..5a9b19f 100644
--- a/libc/src/stdio/baremetal/printf.cpp
+++ b/libc/src/stdio/baremetal/printf.cpp
@@ -7,10 +7,13 @@
//===----------------------------------------------------------------------===//
#include "src/stdio/printf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/OSUtil/io.h"
#include "src/__support/arg_list.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/printf_main.h"
#include "src/stdio/printf_core/writer.h"
@@ -42,13 +45,25 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) {
buffer, BUFF_SIZE, &stdout_write_hook, nullptr);
printf_core::Writer<printf_core::WriteMode::FLUSH_TO_STREAM> writer(wb);
- int retval = printf_core::printf_main(&writer, format, args);
+ auto retval = printf_core::printf_main(&writer, format, args);
+ if (!retval.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(retval.error());
+ return -1;
+ }
int flushval = wb.overflow_write("");
- if (flushval != printf_core::WRITE_OK)
- retval = flushval;
+ if (flushval != printf_core::WRITE_OK) {
+ libc_errno = printf_core::internal_error_to_errno(-flushval);
+ return -1;
+ }
- return retval;
+ if (retval.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(retval.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp
index ab02533..c172b36 100644
--- a/libc/src/stdio/baremetal/vprintf.cpp
+++ b/libc/src/stdio/baremetal/vprintf.cpp
@@ -7,10 +7,13 @@
//===----------------------------------------------------------------------===//
#include "src/stdio/vprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/OSUtil/io.h"
#include "src/__support/arg_list.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/printf_main.h"
#include "src/stdio/printf_core/writer.h"
@@ -40,13 +43,25 @@ LLVM_LIBC_FUNCTION(int, vprintf,
buffer, BUFF_SIZE, &stdout_write_hook, nullptr);
printf_core::Writer<printf_core::WriteMode::FLUSH_TO_STREAM> writer(wb);
- int retval = printf_core::printf_main(&writer, format, args);
+ auto retval = printf_core::printf_main(&writer, format, args);
+ if (!retval.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(retval.error());
+ return -1;
+ }
int flushval = wb.overflow_write("");
- if (flushval != printf_core::WRITE_OK)
- retval = flushval;
+ if (flushval != printf_core::WRITE_OK) {
+ libc_errno = printf_core::internal_error_to_errno(-flushval);
+ return -1;
+ }
- return retval;
+ if (retval.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(retval.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/generic/CMakeLists.txt b/libc/src/stdio/generic/CMakeLists.txt
index 6361822..71055ed 100644
--- a/libc/src/stdio/generic/CMakeLists.txt
+++ b/libc/src/stdio/generic/CMakeLists.txt
@@ -393,7 +393,11 @@ add_generic_entrypoint_object(
list(APPEND fprintf_deps
libc.hdr.types.FILE
libc.src.__support.arg_list
+ libc.src.__support.CPP.limits
+ libc.src.__support.libc_errno
libc.src.stdio.printf_core.vfprintf_internal
+ libc.src.stdio.printf_core.core_structs
+ libc.src.stdio.printf_core.error_mapper
)
if(LLVM_LIBC_FULL_BUILD)
diff --git a/libc/src/stdio/generic/fprintf.cpp b/libc/src/stdio/generic/fprintf.cpp
index 087aead..b2033901 100644
--- a/libc/src/stdio/generic/fprintf.cpp
+++ b/libc/src/stdio/generic/fprintf.cpp
@@ -8,9 +8,12 @@
#include "src/stdio/fprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/File/file.h"
#include "src/__support/arg_list.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/vfprintf_internal.h"
#include "hdr/types/FILE.h"
@@ -27,8 +30,18 @@ LLVM_LIBC_FUNCTION(int, fprintf,
// and pointer semantics, as well as handling
// destruction automatically.
va_end(vlist);
- int ret_val = printf_core::vfprintf_internal(stream, format, args);
- return ret_val;
+ auto ret_val = printf_core::vfprintf_internal(stream, format, args);
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/generic/printf.cpp b/libc/src/stdio/generic/printf.cpp
index bb7c7c8..8d159d5 100644
--- a/libc/src/stdio/generic/printf.cpp
+++ b/libc/src/stdio/generic/printf.cpp
@@ -8,9 +8,12 @@
#include "src/stdio/printf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/File/file.h"
#include "src/__support/arg_list.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/vfprintf_internal.h"
#include "hdr/types/FILE.h"
@@ -31,9 +34,19 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) {
// and pointer semantics, as well as handling
// destruction automatically.
va_end(vlist);
- int ret_val = printf_core::vfprintf_internal(
+ auto ret_val = printf_core::vfprintf_internal(
reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args);
- return ret_val;
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/generic/vfprintf.cpp b/libc/src/stdio/generic/vfprintf.cpp
index 01f4265..a26f082 100644
--- a/libc/src/stdio/generic/vfprintf.cpp
+++ b/libc/src/stdio/generic/vfprintf.cpp
@@ -8,9 +8,12 @@
#include "src/stdio/vfprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/File/file.h"
#include "src/__support/arg_list.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/vfprintf_internal.h"
#include "hdr/types/FILE.h"
@@ -24,8 +27,18 @@ LLVM_LIBC_FUNCTION(int, vfprintf,
internal::ArgList args(vlist); // This holder class allows for easier copying
// and pointer semantics, as well as handling
// destruction automatically.
- int ret_val = printf_core::vfprintf_internal(stream, format, args);
- return ret_val;
+ auto ret_val = printf_core::vfprintf_internal(stream, format, args);
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/generic/vprintf.cpp b/libc/src/stdio/generic/vprintf.cpp
index 08d7151..ae216021 100644
--- a/libc/src/stdio/generic/vprintf.cpp
+++ b/libc/src/stdio/generic/vprintf.cpp
@@ -8,9 +8,12 @@
#include "src/stdio/vprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/File/file.h"
#include "src/__support/arg_list.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/vfprintf_internal.h"
#include "hdr/types/FILE.h"
@@ -29,9 +32,19 @@ LLVM_LIBC_FUNCTION(int, vprintf,
internal::ArgList args(vlist); // This holder class allows for easier copying
// and pointer semantics, as well as handling
// destruction automatically.
- int ret_val = printf_core::vfprintf_internal(
+ auto ret_val = printf_core::vfprintf_internal(
reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args);
- return ret_val;
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt
index ee66145..624129b 100644
--- a/libc/src/stdio/printf_core/CMakeLists.txt
+++ b/libc/src/stdio/printf_core/CMakeLists.txt
@@ -32,6 +32,17 @@ if(printf_config_copts)
list(PREPEND printf_config_copts "COMPILE_OPTIONS")
endif()
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+ add_subdirectory(${LIBC_TARGET_OS})
+else()
+ add_subdirectory(generic)
+endif()
+
+set(target_error_mapper libc.src.stdio.printf_core.${LIBC_TARGET_OS}.error_mapper)
+if(NOT TARGET ${target_error_mapper})
+ set(target_error_mapper libc.src.stdio.printf_core.generic.error_mapper)
+endif()
+
add_header_library(
printf_config
HDRS
@@ -47,6 +58,7 @@ add_header_library(
libc.include.inttypes
libc.src.__support.CPP.string_view
libc.src.__support.FPUtil.fp_bits
+ libc.hdr.errno_macros
)
add_header_library(
@@ -125,6 +137,7 @@ add_header_library(
.writer
.core_structs
libc.src.__support.arg_list
+ libc.src.__support.error_or
)
add_header_library(
@@ -136,10 +149,20 @@ add_header_library(
libc.hdr.func.free
libc.hdr.func.realloc
libc.src.__support.arg_list
+ libc.src.__support.error_or
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
)
+add_header_library(
+ error_mapper
+ HDRS
+ error_mapper.h
+ DEPENDS
+ ${target_error_mapper}
+ libc.src.__support.macros.properties.architectures
+)
+
if(NOT (TARGET libc.src.__support.File.file) AND LLVM_LIBC_FULL_BUILD)
# Not all platforms have a file implementation. If file is unvailable, and a
# full build is requested, then we must skip all file based printf sections.
@@ -152,8 +175,10 @@ add_header_library(
vfprintf_internal.h
DEPENDS
libc.src.__support.File.file
+ libc.src.__support.error_or
libc.src.__support.arg_list
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.writer
${use_system_file}
)
+
diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h
index e27f77b6..0d41f22 100644
--- a/libc/src/stdio/printf_core/core_structs.h
+++ b/libc/src/stdio/printf_core/core_structs.h
@@ -132,14 +132,17 @@ template <typename T> LIBC_INLINE constexpr TypeDesc type_desc_from_type() {
// This is the value to be returned by conversions when no error has occurred.
constexpr int WRITE_OK = 0;
-// These are the printf return values for when an error has occurred. They are
-// all negative, and should be distinct.
-constexpr int FILE_WRITE_ERROR = -1;
-constexpr int FILE_STATUS_ERROR = -2;
-constexpr int NULLPTR_WRITE_ERROR = -3;
-constexpr int INT_CONVERSION_ERROR = -4;
-constexpr int FIXED_POINT_CONVERSION_ERROR = -5;
-constexpr int ALLOCATION_ERROR = -6;
+// These are the error return values used by the printf engine when an
+// error has occurred. They are all large negative, distinct values starting
+// from -1000 to not overlap with system errors.
+constexpr int FILE_WRITE_ERROR = -1001;
+constexpr int FILE_STATUS_ERROR = -1002;
+constexpr int NULLPTR_WRITE_ERROR = -1003;
+constexpr int INT_CONVERSION_ERROR = -1004;
+constexpr int FIXED_POINT_CONVERSION_ERROR = -1005;
+constexpr int ALLOCATION_ERROR = -1006;
+constexpr int OVERFLOW_ERROR = -1007;
+
} // namespace printf_core
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/printf_core/error_mapper.h b/libc/src/stdio/printf_core/error_mapper.h
new file mode 100644
index 0000000..2303093
--- /dev/null
+++ b/libc/src/stdio/printf_core/error_mapper.h
@@ -0,0 +1,21 @@
+//===-- Error mapper for printf ---------------------------------*- 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_STDIO_PRINTF_CORE_ERROR_MAPPER_H
+#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_ERROR_MAPPER_H
+
+#include "src/__support/macros/properties/architectures.h"
+
+// Maps internal errors to the available errnos on the platform.
+#if defined(__linux__)
+#include "linux/error_mapper.h"
+#else
+#include "generic/error_mapper.h"
+#endif
+
+#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_ERROR_MAPPER_H
diff --git a/libc/src/stdio/printf_core/float_dec_converter_limited.h b/libc/src/stdio/printf_core/float_dec_converter_limited.h
index 9cdc135..0f85d0a 100644
--- a/libc/src/stdio/printf_core/float_dec_converter_limited.h
+++ b/libc/src/stdio/printf_core/float_dec_converter_limited.h
@@ -363,8 +363,8 @@ DigitsOutput decimal_digits(DigitsInput input, int precision, bool e_mode) {
// we made it from and doing the decimal conversion all over again.)
for (size_t i = output.ndigits; i-- > 0;) {
if (output.digits[i] != '9') {
- output.digits[i] = static_cast<char>(internal::int_to_b36_char(
- internal::b36_char_to_int(output.digits[i]) + 1));
+ output.digits[i] = internal::int_to_b36_char(
+ internal::b36_char_to_int(output.digits[i]) + 1);
break;
} else {
output.digits[i] = '0';
diff --git a/libc/src/stdio/printf_core/float_hex_converter.h b/libc/src/stdio/printf_core/float_hex_converter.h
index 16592e7..9b57f1d 100644
--- a/libc/src/stdio/printf_core/float_hex_converter.h
+++ b/libc/src/stdio/printf_core/float_hex_converter.h
@@ -137,9 +137,9 @@ LIBC_INLINE int convert_float_hex_exp(Writer<write_mode> *writer,
size_t first_non_zero = 1;
for (; mant_cur > 0; --mant_cur, mantissa >>= 4) {
char mant_mod_16 = static_cast<char>(mantissa % 16);
- char new_digit = static_cast<char>(internal::int_to_b36_char(mant_mod_16));
+ char new_digit = internal::int_to_b36_char(mant_mod_16);
if (internal::isupper(to_conv.conv_name))
- new_digit = static_cast<char>(internal::toupper(new_digit));
+ new_digit = internal::toupper(new_digit);
mant_buffer[mant_cur - 1] = new_digit;
if (new_digit != '0' && first_non_zero < mant_cur)
first_non_zero = mant_cur;
@@ -167,8 +167,7 @@ LIBC_INLINE int convert_float_hex_exp(Writer<write_mode> *writer,
size_t exp_cur = EXP_LEN;
for (; exponent > 0; --exp_cur, exponent /= 10) {
- exp_buffer[exp_cur - 1] =
- static_cast<char>(internal::int_to_b36_char(exponent % 10));
+ exp_buffer[exp_cur - 1] = internal::int_to_b36_char(exponent % 10);
}
if (exp_cur == EXP_LEN) { // if nothing else was written, write a 0.
exp_buffer[EXP_LEN - 1] = '0';
diff --git a/libc/src/stdio/printf_core/generic/CMakeLists.txt b/libc/src/stdio/printf_core/generic/CMakeLists.txt
new file mode 100644
index 0000000..2f0143d
--- /dev/null
+++ b/libc/src/stdio/printf_core/generic/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_header_library(
+ error_mapper
+ HDRS
+ error_mapper.h
+ DEPENDS
+ libc.src.stdio.printf_core.core_structs
+ libc.hdr.errno_macros
+)
diff --git a/libc/src/stdio/printf_core/generic/error_mapper.h b/libc/src/stdio/printf_core/generic/error_mapper.h
new file mode 100644
index 0000000..d8cdd2c
--- /dev/null
+++ b/libc/src/stdio/printf_core/generic/error_mapper.h
@@ -0,0 +1,49 @@
+//===-- Generic implementation of error mapper ------------------*- 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_STDIO_PRINTF_CORE_GENERIC_ERROR_MAPPER_H
+#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_GENERIC_ERROR_MAPPER_H
+
+#include "hdr/errno_macros.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace printf_core {
+
+LIBC_INLINE static int internal_error_to_errno(int internal_error) {
+ // System error occured, return error as is.
+ if (internal_error < 1001 && internal_error > 0) {
+ return internal_error;
+ }
+
+ // Map internal error to the available C standard errnos.
+ switch (-internal_error) {
+ case WRITE_OK:
+ return 0;
+ case FILE_WRITE_ERROR:
+ case FILE_STATUS_ERROR:
+ case NULLPTR_WRITE_ERROR:
+ case ALLOCATION_ERROR:
+ return EDOM;
+ case INT_CONVERSION_ERROR:
+ case FIXED_POINT_CONVERSION_ERROR:
+ case OVERFLOW_ERROR:
+ return ERANGE;
+ default:
+ LIBC_ASSERT(
+ false &&
+ "Invalid internal printf error code passed to internal_error_to_errno");
+ return EDOM;
+ }
+}
+
+} // namespace printf_core
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_GENERIC_ERROR_MAPPER_H
diff --git a/libc/src/stdio/printf_core/linux/CMakeLists.txt b/libc/src/stdio/printf_core/linux/CMakeLists.txt
new file mode 100644
index 0000000..2f0143d
--- /dev/null
+++ b/libc/src/stdio/printf_core/linux/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_header_library(
+ error_mapper
+ HDRS
+ error_mapper.h
+ DEPENDS
+ libc.src.stdio.printf_core.core_structs
+ libc.hdr.errno_macros
+)
diff --git a/libc/src/stdio/printf_core/linux/error_mapper.h b/libc/src/stdio/printf_core/linux/error_mapper.h
new file mode 100644
index 0000000..3c2fe66
--- /dev/null
+++ b/libc/src/stdio/printf_core/linux/error_mapper.h
@@ -0,0 +1,54 @@
+//===-- Linux implementation of error mapper --------------------*- 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_STDIO_PRINTF_CORE_LINUX_ERROR_MAPPER_H
+#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_LINUX_ERROR_MAPPER_H
+
+#include "hdr/errno_macros.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace printf_core {
+
+LIBC_INLINE static int internal_error_to_errno(int internal_error) {
+ // System error occured, return error as is.
+ if (internal_error < 1001 && internal_error > 0) {
+ return internal_error;
+ }
+
+ // Map internal error to POSIX errnos.
+ switch (-internal_error) {
+ case WRITE_OK:
+ return 0;
+ case FILE_WRITE_ERROR:
+ return EIO;
+ case FILE_STATUS_ERROR:
+ return EIO;
+ case NULLPTR_WRITE_ERROR:
+ return EINVAL;
+ case INT_CONVERSION_ERROR:
+ return ERANGE;
+ case FIXED_POINT_CONVERSION_ERROR:
+ return EINVAL;
+ case ALLOCATION_ERROR:
+ return ENOMEM;
+ case OVERFLOW_ERROR:
+ return EOVERFLOW;
+ default:
+ LIBC_ASSERT(
+ false &&
+ "Invalid internal printf error code passed to internal_error_to_errno");
+ return EINVAL;
+ }
+}
+
+} // namespace printf_core
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_LINUX_ERROR_MAPPER_H
diff --git a/libc/src/stdio/printf_core/printf_main.h b/libc/src/stdio/printf_core/printf_main.h
index 57f2985..1c7a723 100644
--- a/libc/src/stdio/printf_core/printf_main.h
+++ b/libc/src/stdio/printf_core/printf_main.h
@@ -10,6 +10,7 @@
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PRINTF_MAIN_H
#include "src/__support/arg_list.h"
+#include "src/__support/error_or.h"
#include "src/__support/macros/config.h"
#include "src/stdio/printf_core/converter.h"
#include "src/stdio/printf_core/core_structs.h"
@@ -22,8 +23,9 @@ namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
template <WriteMode write_mode>
-int printf_main(Writer<write_mode> *writer, const char *__restrict str,
- internal::ArgList &args) {
+ErrorOr<size_t> printf_main(Writer<write_mode> *writer,
+ const char *__restrict str,
+ internal::ArgList &args) {
Parser<internal::ArgList> parser(str, args);
int result = 0;
for (FormatSection cur_section = parser.get_next_section();
@@ -33,9 +35,8 @@ int printf_main(Writer<write_mode> *writer, const char *__restrict str,
result = convert(writer, cur_section);
else
result = writer->write(cur_section.raw_string);
-
if (result < 0)
- return result;
+ return Error(-result);
}
return writer->get_chars_written();
diff --git a/libc/src/stdio/printf_core/vasprintf_internal.h b/libc/src/stdio/printf_core/vasprintf_internal.h
index 283d8df28..41df17b 100644
--- a/libc/src/stdio/printf_core/vasprintf_internal.h
+++ b/libc/src/stdio/printf_core/vasprintf_internal.h
@@ -10,6 +10,7 @@
#include "hdr/func/malloc.h"
#include "hdr/func/realloc.h"
#include "src/__support/arg_list.h"
+#include "src/__support/error_or.h"
#include "src/stdio/printf_core/core_structs.h"
#include "src/stdio/printf_core/printf_main.h"
#include "src/stdio/printf_core/writer.h"
@@ -29,7 +30,7 @@ LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str, void *target) {
if (new_buff == nullptr) {
if (wb->buff != wb->init_buff)
free(wb->buff);
- return printf_core::ALLOCATION_ERROR;
+ return ALLOCATION_ERROR;
}
if (isBuffOnStack)
inline_memcpy(new_buff, wb->buff, wb->buff_cur);
@@ -42,27 +43,28 @@ LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str, void *target) {
constexpr size_t DEFAULT_BUFFER_SIZE = 200;
-LIBC_INLINE int vasprintf_internal(char **ret, const char *__restrict format,
- internal::ArgList args) {
+LIBC_INLINE ErrorOr<size_t> vasprintf_internal(char **ret,
+ const char *__restrict format,
+ internal::ArgList args) {
char init_buff_on_stack[DEFAULT_BUFFER_SIZE];
printf_core::WriteBuffer<Mode<WriteMode::RESIZE_AND_FILL_BUFF>::value> wb(
init_buff_on_stack, DEFAULT_BUFFER_SIZE, resize_overflow_hook);
printf_core::Writer writer(wb);
auto ret_val = printf_core::printf_main(&writer, format, args);
- if (ret_val < 0) {
+ if (!ret_val.has_value()) {
*ret = nullptr;
- return -1;
+ return ret_val;
}
if (wb.buff == init_buff_on_stack) {
- *ret = static_cast<char *>(malloc(ret_val + 1));
+ *ret = static_cast<char *>(malloc(ret_val.value() + 1));
if (ret == nullptr)
- return printf_core::ALLOCATION_ERROR;
- inline_memcpy(*ret, wb.buff, ret_val);
+ return Error(ALLOCATION_ERROR);
+ inline_memcpy(*ret, wb.buff, ret_val.value());
} else {
*ret = wb.buff;
}
- (*ret)[ret_val] = '\0';
+ (*ret)[ret_val.value()] = '\0';
return ret_val;
}
} // namespace printf_core
diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h
index 630de9d..564441d3 100644
--- a/libc/src/stdio/printf_core/vfprintf_internal.h
+++ b/libc/src/stdio/printf_core/vfprintf_internal.h
@@ -11,6 +11,7 @@
#include "src/__support/File/file.h"
#include "src/__support/arg_list.h"
+#include "src/__support/error_or.h"
#include "src/__support/macros/attributes.h" // For LIBC_INLINE
#include "src/__support/macros/config.h"
#include "src/stdio/printf_core/core_structs.h"
@@ -35,8 +36,8 @@ LIBC_INLINE void funlockfile(FILE *f) {
reinterpret_cast<LIBC_NAMESPACE::File *>(f)->unlock();
}
-LIBC_INLINE size_t fwrite_unlocked(const void *ptr, size_t size, size_t nmemb,
- FILE *f) {
+LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size,
+ size_t nmemb, FILE *f) {
return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->write_unlocked(
ptr, size * nmemb);
}
@@ -47,9 +48,11 @@ LIBC_INLINE void flockfile(::FILE *f) { ::flockfile(f); }
LIBC_INLINE void funlockfile(::FILE *f) { ::funlockfile(f); }
-LIBC_INLINE size_t fwrite_unlocked(const void *ptr, size_t size, size_t nmemb,
- ::FILE *f) {
- return ::fwrite_unlocked(ptr, size, nmemb, f);
+LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size,
+ size_t nmemb, ::FILE *f) {
+ // Need to use system errno in this case, as system write will set this errno
+ // which we need to propagate back into our code.
+ return {::fwrite_unlocked(ptr, size, nmemb, f), errno};
}
#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
} // namespace internal
@@ -60,26 +63,38 @@ LIBC_INLINE int file_write_hook(cpp::string_view new_str, void *fp) {
::FILE *target_file = reinterpret_cast<::FILE *>(fp);
// Write new_str to the target file. The logic preventing a zero-length write
// is in the writer, so we don't check here.
- size_t written = internal::fwrite_unlocked(new_str.data(), sizeof(char),
- new_str.size(), target_file);
- if (written != new_str.size() || internal::ferror_unlocked(target_file))
+ auto write_result = internal::fwrite_unlocked(new_str.data(), sizeof(char),
+ new_str.size(), target_file);
+ // Propagate actual system error in FileIOResult.
+ if (write_result.has_error())
+ return -write_result.error;
+
+ // In case short write occured or error was not set on FileIOResult for some
+ // reason.
+ if (write_result.value != new_str.size() ||
+ internal::ferror_unlocked(target_file))
return FILE_WRITE_ERROR;
+
return WRITE_OK;
}
-LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream,
- const char *__restrict format,
- internal::ArgList &args) {
+LIBC_INLINE ErrorOr<size_t> vfprintf_internal(::FILE *__restrict stream,
+ const char *__restrict format,
+ internal::ArgList &args) {
constexpr size_t BUFF_SIZE = 1024;
char buffer[BUFF_SIZE];
printf_core::WriteBuffer<Mode<WriteMode::FLUSH_TO_STREAM>::value> wb(
buffer, BUFF_SIZE, &file_write_hook, reinterpret_cast<void *>(stream));
Writer writer(wb);
internal::flockfile(stream);
- int retval = printf_main(&writer, format, args);
+ auto retval = printf_main(&writer, format, args);
+ if (!retval.has_value()) {
+ internal::funlockfile(stream);
+ return retval;
+ }
int flushval = wb.overflow_write("");
if (flushval != WRITE_OK)
- retval = flushval;
+ retval = Error(-flushval);
internal::funlockfile(stream);
return retval;
}
diff --git a/libc/src/stdio/printf_core/write_int_converter.h b/libc/src/stdio/printf_core/write_int_converter.h
index efcff27..04b2bef 100644
--- a/libc/src/stdio/printf_core/write_int_converter.h
+++ b/libc/src/stdio/printf_core/write_int_converter.h
@@ -29,11 +29,11 @@ LIBC_INLINE int convert_write_int(Writer<write_mode> *writer,
return NULLPTR_WRITE_ERROR;
#endif // LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS
- int written = writer->get_chars_written();
+ size_t written = writer->get_chars_written();
switch (to_conv.length_modifier) {
case LengthModifier::none:
- *reinterpret_cast<int *>(to_conv.conv_val_ptr) = written;
+ *reinterpret_cast<int *>(to_conv.conv_val_ptr) = static_cast<int>(written);
break;
case LengthModifier::l:
*reinterpret_cast<long *>(to_conv.conv_val_ptr) = written;
diff --git a/libc/src/stdio/printf_core/writer.h b/libc/src/stdio/printf_core/writer.h
index 1d4734a..9de108e 100644
--- a/libc/src/stdio/printf_core/writer.h
+++ b/libc/src/stdio/printf_core/writer.h
@@ -127,7 +127,7 @@ template <WriteMode write_mode> struct WriteBuffer {
template <WriteMode write_mode> class Writer final {
WriteBuffer<write_mode> &wb;
- int chars_written = 0;
+ size_t chars_written = 0;
LIBC_INLINE int pad(char new_char, size_t length) {
// First, fill as much of the buffer as possible with the padding char.
@@ -161,7 +161,7 @@ public:
// Takes a string, copies it into the buffer if there is space, else passes it
// to the overflow mechanism to be handled separately.
LIBC_INLINE int write(cpp::string_view new_string) {
- chars_written += static_cast<int>(new_string.size());
+ chars_written += new_string.size();
if (LIBC_LIKELY(wb.buff_cur + new_string.size() <= wb.buff_len)) {
inline_memcpy(wb.buff + wb.buff_cur, new_string.data(),
new_string.size());
@@ -175,7 +175,7 @@ public:
// if there is space, else calls pad which will loop and call the overflow
// mechanism on a secondary buffer.
LIBC_INLINE int write(char new_char, size_t length) {
- chars_written += static_cast<int>(length);
+ chars_written += length;
if (LIBC_LIKELY(wb.buff_cur + length <= wb.buff_len)) {
inline_memset(wb.buff + wb.buff_cur, static_cast<unsigned char>(new_char),
@@ -199,7 +199,7 @@ public:
return wb.overflow_write(char_string_view);
}
- LIBC_INLINE int get_chars_written() { return chars_written; }
+ LIBC_INLINE size_t get_chars_written() { return chars_written; }
};
// Class-template auto deduction helpers.
diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp
index c894086..d95195f 100644
--- a/libc/src/stdio/snprintf.cpp
+++ b/libc/src/stdio/snprintf.cpp
@@ -8,8 +8,12 @@
#include "src/stdio/snprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/arg_list.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/printf_main.h"
#include "src/stdio/printf_core/writer.h"
@@ -32,10 +36,21 @@ LLVM_LIBC_FUNCTION(int, snprintf,
wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
printf_core::Writer writer(wb);
- int ret_val = printf_core::printf_main(&writer, format, args);
+ auto ret_val = printf_core::printf_main(&writer, format, args);
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
wb.buff[wb.buff_cur] = '\0';
- return ret_val;
+
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp
index 7be97d3..2a9b6ea 100644
--- a/libc/src/stdio/sprintf.cpp
+++ b/libc/src/stdio/sprintf.cpp
@@ -10,7 +10,10 @@
#include "src/__support/CPP/limits.h"
#include "src/__support/arg_list.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/printf_main.h"
#include "src/stdio/printf_core/writer.h"
@@ -33,9 +36,20 @@ LLVM_LIBC_FUNCTION(int, sprintf,
wb(buffer, cpp::numeric_limits<size_t>::max());
printf_core::Writer writer(wb);
- int ret_val = printf_core::printf_main(&writer, format, args);
+ auto ret_val = printf_core::printf_main(&writer, format, args);
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
wb.buff[wb.buff_cur] = '\0';
- return ret_val;
+
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/vasprintf.cpp b/libc/src/stdio/vasprintf.cpp
index 4a44d4a..bd77cd88 100644
--- a/libc/src/stdio/vasprintf.cpp
+++ b/libc/src/stdio/vasprintf.cpp
@@ -7,7 +7,11 @@
//===----------------------------------------------------------------------===//
#include "src/stdio/vasprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/arg_list.h"
+#include "src/__support/libc_errno.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/vasprintf_internal.h"
namespace LIBC_NAMESPACE_DECL {
@@ -18,7 +22,17 @@ LLVM_LIBC_FUNCTION(int, vasprintf,
internal::ArgList args(vlist); // This holder class allows for easier copying
// and pointer semantics, as well as handling
// destruction automatically.
- return printf_core::vasprintf_internal(ret, format, args);
+ auto ret_val = printf_core::vasprintf_internal(ret, format, args);
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp
index b07a249..5d93636 100644
--- a/libc/src/stdio/vsnprintf.cpp
+++ b/libc/src/stdio/vsnprintf.cpp
@@ -8,8 +8,12 @@
#include "src/stdio/vsnprintf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/arg_list.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/printf_main.h"
#include "src/stdio/printf_core/writer.h"
@@ -29,10 +33,21 @@ LLVM_LIBC_FUNCTION(int, vsnprintf,
wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
printf_core::Writer writer(wb);
- int ret_val = printf_core::printf_main(&writer, format, args);
+ auto ret_val = printf_core::printf_main(&writer, format, args);
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
wb.buff[wb.buff_cur] = '\0';
- return ret_val;
+
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp
index 26d497b..f9cf811 100644
--- a/libc/src/stdio/vsprintf.cpp
+++ b/libc/src/stdio/vsprintf.cpp
@@ -10,7 +10,10 @@
#include "src/__support/CPP/limits.h"
#include "src/__support/arg_list.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdio/printf_core/printf_main.h"
#include "src/stdio/printf_core/writer.h"
@@ -30,9 +33,19 @@ LLVM_LIBC_FUNCTION(int, vsprintf,
wb(buffer, cpp::numeric_limits<size_t>::max());
printf_core::Writer writer(wb);
- int ret_val = printf_core::printf_main(&writer, format, args);
+ auto ret_val = printf_core::printf_main(&writer, format, args);
+ if (!ret_val.has_value()) {
+ libc_errno = printf_core::internal_error_to_errno(ret_val.error());
+ return -1;
+ }
wb.buff[wb.buff_cur] = '\0';
- return ret_val;
+
+ if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+ return static_cast<int>(ret_val.value());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index c464f82..1ccdcc8 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -73,6 +73,8 @@ add_entrypoint_object(
strfromf.h
DEPENDS
.str_from_util
+ libc.src.__support.CPP.limits
+ libc.src.stdio.printf_core.error_mapper
)
add_entrypoint_object(
@@ -83,6 +85,8 @@ add_entrypoint_object(
strfromd.h
DEPENDS
.str_from_util
+ libc.src.__support.CPP.limits
+ libc.src.stdio.printf_core.error_mapper
)
add_entrypoint_object(
@@ -93,6 +97,8 @@ add_entrypoint_object(
strfroml.h
DEPENDS
.str_from_util
+ libc.src.__support.CPP.limits
+ libc.src.stdio.printf_core.error_mapper
)
add_header_library(
diff --git a/libc/src/stdlib/l64a.cpp b/libc/src/stdlib/l64a.cpp
index d59e65e..d8fe8ef 100644
--- a/libc/src/stdlib/l64a.cpp
+++ b/libc/src/stdlib/l64a.cpp
@@ -32,15 +32,13 @@ constexpr static char b64_int_to_char(uint32_t num) {
if (num == 1)
return '/';
if (num < 38)
- return static_cast<char>(
- internal::toupper(internal::int_to_b36_char(num - 2)));
+ return internal::toupper(internal::int_to_b36_char(num - 2));
// this tolower is technically unnecessary, but it provides safety if we
// change the default behavior of int_to_b36_char. Also the compiler
// completely elides it so there's no performance penalty, see:
// https://godbolt.org/z/o5ennv7fc
- return static_cast<char>(
- internal::tolower(internal::int_to_b36_char(num - 2 - 26)));
+ return internal::tolower(internal::int_to_b36_char(num - 2 - 26));
}
// This function takes a long and converts the low 32 bits of it into at most 6
diff --git a/libc/src/stdlib/strfromd.cpp b/libc/src/stdlib/strfromd.cpp
index f51e6d4..71e257f 100644
--- a/libc/src/stdlib/strfromd.cpp
+++ b/libc/src/stdlib/strfromd.cpp
@@ -7,7 +7,10 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strfromd.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdlib/str_from_util.h"
namespace LIBC_NAMESPACE_DECL {
@@ -36,7 +39,13 @@ LLVM_LIBC_FUNCTION(int, strfromd,
if (n > 0)
wb.buff[wb.buff_cur] = '\0';
- return writer.get_chars_written();
+ if (writer.get_chars_written() >
+ static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+ return static_cast<int>(writer.get_chars_written());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strfromf.cpp b/libc/src/stdlib/strfromf.cpp
index 14dbfdb..65f242b 100644
--- a/libc/src/stdlib/strfromf.cpp
+++ b/libc/src/stdlib/strfromf.cpp
@@ -7,7 +7,10 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strfromf.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdlib/str_from_util.h"
namespace LIBC_NAMESPACE_DECL {
@@ -36,7 +39,13 @@ LLVM_LIBC_FUNCTION(int, strfromf,
if (n > 0)
wb.buff[wb.buff_cur] = '\0';
- return writer.get_chars_written();
+ if (writer.get_chars_written() >
+ static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+ return static_cast<int>(writer.get_chars_written());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strfroml.cpp b/libc/src/stdlib/strfroml.cpp
index 12f22a8..31668a0 100644
--- a/libc/src/stdlib/strfroml.cpp
+++ b/libc/src/stdlib/strfroml.cpp
@@ -7,7 +7,10 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strfroml.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/error_mapper.h"
#include "src/stdlib/str_from_util.h"
namespace LIBC_NAMESPACE_DECL {
@@ -41,7 +44,13 @@ LLVM_LIBC_FUNCTION(int, strfroml,
if (n > 0)
wb.buff[wb.buff_cur] = '\0';
- return writer.get_chars_written();
+ if (writer.get_chars_written() >
+ static_cast<size_t>(cpp::numeric_limits<int>::max())) {
+ libc_errno =
+ printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR);
+ return -1;
+ }
+ return static_cast<int>(writer.get_chars_written());
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/string/strcasestr.cpp b/libc/src/string/strcasestr.cpp
index de8e4be..575d6be 100644
--- a/libc/src/string/strcasestr.cpp
+++ b/libc/src/string/strcasestr.cpp
@@ -21,8 +21,8 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(char *, strcasestr,
(const char *haystack, const char *needle)) {
auto case_cmp = [](char a, char b) {
- return LIBC_NAMESPACE::internal::tolower(a) -
- LIBC_NAMESPACE::internal::tolower(b);
+ return static_cast<int>(LIBC_NAMESPACE::internal::tolower(a)) -
+ static_cast<int>(LIBC_NAMESPACE::internal::tolower(b));
};
LIBC_CRASH_ON_NULLPTR(haystack);
diff --git a/libc/src/strings/strcasecmp.cpp b/libc/src/strings/strcasecmp.cpp
index 4bbe290..4518647 100644
--- a/libc/src/strings/strcasecmp.cpp
+++ b/libc/src/strings/strcasecmp.cpp
@@ -17,8 +17,8 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, strcasecmp, (const char *left, const char *right)) {
auto case_cmp = [](char a, char b) {
- return LIBC_NAMESPACE::internal::tolower(a) -
- LIBC_NAMESPACE::internal::tolower(b);
+ return static_cast<int>(LIBC_NAMESPACE::internal::tolower(a)) -
+ static_cast<int>(LIBC_NAMESPACE::internal::tolower(b));
};
return inline_strcmp(left, right, case_cmp);
}
diff --git a/libc/src/strings/strcasecmp_l.cpp b/libc/src/strings/strcasecmp_l.cpp
index 95117cb..d77f956 100644
--- a/libc/src/strings/strcasecmp_l.cpp
+++ b/libc/src/strings/strcasecmp_l.cpp
@@ -18,8 +18,8 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, strcasecmp_l,
(const char *left, const char *right, locale_t)) {
auto case_cmp = [](char a, char b) {
- return LIBC_NAMESPACE::internal::tolower(a) -
- LIBC_NAMESPACE::internal::tolower(b);
+ return static_cast<int>(LIBC_NAMESPACE::internal::tolower(a)) -
+ static_cast<int>(LIBC_NAMESPACE::internal::tolower(b));
};
return inline_strcmp(left, right, case_cmp);
}
diff --git a/libc/src/strings/strncasecmp.cpp b/libc/src/strings/strncasecmp.cpp
index 9c2f0ab..a592649 100644
--- a/libc/src/strings/strncasecmp.cpp
+++ b/libc/src/strings/strncasecmp.cpp
@@ -18,8 +18,8 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, strncasecmp,
(const char *left, const char *right, size_t n)) {
auto case_cmp = [](char a, char b) {
- return LIBC_NAMESPACE::internal::tolower(a) -
- LIBC_NAMESPACE::internal::tolower(b);
+ return static_cast<int>(LIBC_NAMESPACE::internal::tolower(a)) -
+ static_cast<int>(LIBC_NAMESPACE::internal::tolower(b));
};
return inline_strncmp(left, right, n, case_cmp);
}
diff --git a/libc/src/strings/strncasecmp_l.cpp b/libc/src/strings/strncasecmp_l.cpp
index 91ac7e5..a828f60 100644
--- a/libc/src/strings/strncasecmp_l.cpp
+++ b/libc/src/strings/strncasecmp_l.cpp
@@ -18,8 +18,8 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, strncasecmp_l,
(const char *left, const char *right, size_t n, locale_t)) {
auto case_cmp = [](char a, char b) {
- return LIBC_NAMESPACE::internal::tolower(a) -
- LIBC_NAMESPACE::internal::tolower(b);
+ return static_cast<int>(LIBC_NAMESPACE::internal::tolower(a)) -
+ static_cast<int>(LIBC_NAMESPACE::internal::tolower(b));
};
return inline_strncmp(left, right, n, case_cmp);
}
diff --git a/libc/src/time/strftime_core/strftime_main.h b/libc/src/time/strftime_core/strftime_main.h
index c7e5906..2b136d8 100644
--- a/libc/src/time/strftime_core/strftime_main.h
+++ b/libc/src/time/strftime_core/strftime_main.h
@@ -36,7 +36,8 @@ int strftime_main(printf_core::Writer<write_mode> *writer,
return result;
}
- return writer->get_chars_written();
+ // TODO: Use ErrorOr<size_t>
+ return static_cast<int>(writer->get_chars_written());
}
} // namespace strftime_core
diff --git a/libc/src/wctype/iswalpha.cpp b/libc/src/wctype/iswalpha.cpp
index 09f55d3..e151363 100644
--- a/libc/src/wctype/iswalpha.cpp
+++ b/libc/src/wctype/iswalpha.cpp
@@ -14,6 +14,8 @@
namespace LIBC_NAMESPACE_DECL {
-LLVM_LIBC_FUNCTION(int, iswalpha, (wint_t c)) { return internal::iswalpha(c); }
+LLVM_LIBC_FUNCTION(int, iswalpha, (wint_t c)) {
+ return internal::iswalpha(static_cast<wchar_t>(c));
+}
} // namespace LIBC_NAMESPACE_DECL