[libcxx-commits] [libcxx] [libc++][math] Add constexpr for std::abs() and relatives (PR #202985)
via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jun 10 07:05:02 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: pixafera
<details>
<summary>Changes</summary>
Mark `std::abs`, `std::fabs`, `std::labs` and `std::llabs` as constexpr.
Refs [P0533R9](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0533r9.pdf), #<!-- -->105174
Following on the convention established in #<!-- -->98952 for `std::isnan` and `std::isinf`, I used `_LIBCPP_PREFERRED_OVERLOAD` on the overloads that are ambiguous to the underlying C library so that the constexpr C++ functions are now preferred over the C library ones.
---
Full diff: https://github.com/llvm/llvm-project/pull/202985.diff
5 Files Affected:
- (modified) libcxx/include/__math/abs.h (+70-14)
- (modified) libcxx/include/math.h (+2)
- (modified) libcxx/include/stdlib.h (+2)
- (modified) libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp (+13-13)
- (modified) libcxx/test/std/numerics/c.math/abs.pass.cpp (+36)
``````````diff
diff --git a/libcxx/include/__math/abs.h b/libcxx/include/__math/abs.h
index b780159f11ebf..74fc55281916c 100644
--- a/libcxx/include/__math/abs.h
+++ b/libcxx/include/__math/abs.h
@@ -23,43 +23,99 @@ namespace __math {
// fabs
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI float fabs(float __x) _NOEXCEPT { return __builtin_fabsf(__x); }
+[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX23 inline _LIBCPP_HIDE_FROM_ABI float fabs(float __x) _NOEXCEPT { return __builtin_fabsf(__x); }
-template <class = int>
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI double fabs(double __x) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
+#ifdef _LIBCPP_PREFERRED_OVERLOAD
+_LIBCPP_PREFERRED_OVERLOAD
+#endif
+ double
+ fabs(double __x) _NOEXCEPT {
return __builtin_fabs(__x);
}
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI long double fabs(long double __x) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX23 inline _LIBCPP_HIDE_FROM_ABI long double fabs(long double __x) _NOEXCEPT {
return __builtin_fabsl(__x);
}
template <class _A1, __enable_if_t<is_integral<_A1>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI double fabs(_A1 __x) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX23 inline _LIBCPP_HIDE_FROM_ABI double fabs(_A1 __x) _NOEXCEPT {
return __builtin_fabs((double)__x);
}
+// fabsf
+
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
+#ifdef _LIBCPP_PREFERRED_OVERLOAD
+_LIBCPP_PREFERRED_OVERLOAD
+#endif
+ float
+ fabsf(float __x) _NOEXCEPT {
+ return __builtin_fabsf(__x);
+}
+
+// fabsl
+
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
+#ifdef _LIBCPP_PREFERRED_OVERLOAD
+_LIBCPP_PREFERRED_OVERLOAD
+#endif
+ long double
+ fabsl(long double __x) _NOEXCEPT {
+ return __builtin_fabsl(__x);
+}
+
// abs
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inline float abs(float __x) _NOEXCEPT { return __builtin_fabsf(__x); }
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inline double abs(double __x) _NOEXCEPT { return __builtin_fabs(__x); }
+[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline float abs(float __x) _NOEXCEPT { return __builtin_fabsf(__x); }
+[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline double abs(double __x) _NOEXCEPT { return __builtin_fabs(__x); }
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inline long double abs(long double __x) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline long double abs(long double __x) _NOEXCEPT {
return __builtin_fabsl(__x);
}
-template <class = int>
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inline int abs(int __x) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
+#ifdef _LIBCPP_PREFERRED_OVERLOAD
+_LIBCPP_PREFERRED_OVERLOAD
+#endif
+ int
+ abs(int __x) _NOEXCEPT {
return __builtin_abs(__x);
}
-template <class = int>
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inline long abs(long __x) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
+#ifdef _LIBCPP_PREFERRED_OVERLOAD
+_LIBCPP_PREFERRED_OVERLOAD
+#endif
+ long
+ abs(long __x) _NOEXCEPT {
+ return __builtin_labs(__x);
+}
+
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
+#ifdef _LIBCPP_PREFERRED_OVERLOAD
+_LIBCPP_PREFERRED_OVERLOAD
+#endif
+ long long
+ abs(long long __x) _NOEXCEPT {
+ return __builtin_llabs(__x);
+}
+
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
+#ifdef _LIBCPP_PREFERRED_OVERLOAD
+_LIBCPP_PREFERRED_OVERLOAD
+#endif
+ long
+ labs(long __x) _NOEXCEPT {
return __builtin_labs(__x);
}
-template <class = int>
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inline long long abs(long long __x) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
+#ifdef _LIBCPP_PREFERRED_OVERLOAD
+_LIBCPP_PREFERRED_OVERLOAD
+#endif
+ long long
+ llabs(long long __x) _NOEXCEPT {
return __builtin_llabs(__x);
}
diff --git a/libcxx/include/math.h b/libcxx/include/math.h
index 1db61538e995f..23a83e3dcca2e 100644
--- a/libcxx/include/math.h
+++ b/libcxx/include/math.h
@@ -472,6 +472,8 @@ using std::__math::exp;
using std::__math::exp2;
using std::__math::expm1;
using std::__math::fabs;
+using std::__math::fabsf;
+using std::__math::fabsl;
using std::__math::fdim;
using std::__math::floor;
using std::__math::fma;
diff --git a/libcxx/include/stdlib.h b/libcxx/include/stdlib.h
index 8dfdfa416f088..67d667aab2453 100644
--- a/libcxx/include/stdlib.h
+++ b/libcxx/include/stdlib.h
@@ -108,6 +108,8 @@ extern "C++" {
# include <__math/abs.h>
using std::__math::abs;
+using std::__math::labs;
+using std::__math::llabs;
// div
diff --git a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp
index 93865afc5e68b..e9d3604a5e756 100644
--- a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp
@@ -43,15 +43,15 @@ int main(int, char**) {
double DummyDouble;
long double DummyLongDouble;
- ASSERT_NOT_CONSTEXPR_CXX23(std::abs(-1) == 1);
- ASSERT_NOT_CONSTEXPR_CXX23(std::abs(-1L) == 1L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::abs(-1LL) == 1LL);
- ASSERT_NOT_CONSTEXPR_CXX23(std::abs(-1.0f) == 1.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::abs(-1.0) == 1.0);
- ASSERT_NOT_CONSTEXPR_CXX23(std::abs(-1.0L) == 1.0L);
+ ASSERT_CONSTEXPR_CXX23(std::abs(-1) == 1);
+ ASSERT_CONSTEXPR_CXX23(std::abs(-1L) == 1L);
+ ASSERT_CONSTEXPR_CXX23(std::abs(-1LL) == 1LL);
+ ASSERT_CONSTEXPR_CXX23(std::abs(-1.0f) == 1.0f);
+ ASSERT_CONSTEXPR_CXX23(std::abs(-1.0) == 1.0);
+ ASSERT_CONSTEXPR_CXX23(std::abs(-1.0L) == 1.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::labs(-1L) == 1L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::llabs(-1LL) == 1LL);
+ ASSERT_CONSTEXPR_CXX23(std::labs(-1L) == 1L);
+ ASSERT_CONSTEXPR_CXX23(std::llabs(-1LL) == 1LL);
ASSERT_NOT_CONSTEXPR_CXX23(std::div(13, 5).rem == 3);
ASSERT_NOT_CONSTEXPR_CXX23(std::div(13L, 5L).rem == 3L);
@@ -101,11 +101,11 @@ int main(int, char**) {
ASSERT_NOT_CONSTEXPR_CXX23(std::scalblnf(1.0f, 1L) == 2.0f);
ASSERT_NOT_CONSTEXPR_CXX23(std::scalblnl(1.0L, 1L) == 2.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fabs(-1.0f) == 1.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fabs(-1.0) == 1.0);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fabs(-1.0L) == 1.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fabsf(-1.0f) == 1.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fabsl(-1.0L) == 1.0L);
+ ASSERT_CONSTEXPR_CXX23(std::fabs(-1.0f) == 1.0f);
+ ASSERT_CONSTEXPR_CXX23(std::fabs(-1.0) == 1.0);
+ ASSERT_CONSTEXPR_CXX23(std::fabs(-1.0L) == 1.0L);
+ ASSERT_CONSTEXPR_CXX23(std::fabsf(-1.0f) == 1.0f);
+ ASSERT_CONSTEXPR_CXX23(std::fabsl(-1.0L) == 1.0L);
ASSERT_NOT_CONSTEXPR_CXX23(std::ceil(0.0f) == 0.0f);
ASSERT_NOT_CONSTEXPR_CXX23(std::ceil(0.0) == 0.0);
diff --git a/libcxx/test/std/numerics/c.math/abs.pass.cpp b/libcxx/test/std/numerics/c.math/abs.pass.cpp
index 51aee6e986836..482f249dbdcd8 100644
--- a/libcxx/test/std/numerics/c.math/abs.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/abs.pass.cpp
@@ -37,6 +37,19 @@ void test_big() {
assert(std::abs(negative_big_value) == big_value); // make sure it doesn't get casted to a smaller type
}
+template <class Source, class Result>
+constexpr bool test_constexpr_abs() {
+ Source neg_val = -5;
+ Source pos_val = 5;
+ Result res = 5;
+
+ ASSERT_SAME_TYPE(decltype(std::abs(neg_val)), Result);
+
+ assert(std::abs(neg_val) == res);
+ assert(std::abs(pos_val) == res);
+ return true;
+}
+
// The following is helpful to keep in mind:
// 1byte == char <= short <= int <= long <= long long
@@ -68,5 +81,28 @@ int main(int, char**) {
test_big();
+#if TEST_STD_VER > 23
+ // All types less than or equal to and not greater than int are promoted to int.
+ static_assert(test_constexpr_abs<short int, int>());
+ static_assert(test_constexpr_abs<SignedChar, int>());
+ static_assert(test_constexpr_abs<signed char, int>());
+
+ // These three calls have specific overloads:
+ static_assert(test_constexpr_abs<int, int>());
+ static_assert(test_constexpr_abs<long int, long int>());
+ static_assert(test_constexpr_abs<long long int, long long int>());
+
+ // Here there is no guarantee that int is larger than int8_t so we
+ // use a helper type trait to conditional test against int.
+ static_assert(test_constexpr_abs<std::int8_t, correct_size_int<std::int8_t>::type>());
+ static_assert(test_constexpr_abs<std::int16_t, correct_size_int<std::int16_t>::type>());
+ static_assert(test_constexpr_abs<std::int32_t, correct_size_int<std::int32_t>::type>());
+ static_assert(test_constexpr_abs<std::int64_t, correct_size_int<std::int64_t>::type>());
+
+ static_assert(test_constexpr_abs<long double, long double>());
+ static_assert(test_constexpr_abs<double, double>());
+ static_assert(test_constexpr_abs<float, float>());
+#endif
+
return 0;
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/202985
More information about the libcxx-commits
mailing list