[libcxx-commits] [libcxx] [libc++] std::abs support for _BitInt(N) and __int128 (PR #196532)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jun 16 00:12:06 PDT 2026
================
@@ -0,0 +1,122 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// std::abs for _BitInt(N) and __int128 -- libc++ extension over the standard
+// abs(int / long / long long) overloads. The new template covers signed
+// integer types not handled by the existing builtin overloads, gated on
+// __is_signed_integer_v plus a sizeof(_Tp) >= sizeof(int) check that keeps
+// shorter standard types on the integer-promotion path.
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <cassert>
+#include <cstdlib>
+#include <type_traits>
+
+#include "test_macros.h"
+
+// Pin down the sizeof gate: narrow signed types still resolve to abs(int) via
+// integer promotion, and the new template stays out of their overload set.
+// Detection probes the template path specifically (the type of std::abs(t) is
+// the unpromoted T only for the new overload).
+template <class T>
+constexpr bool unpromoted_abs = std::is_same<decltype(std::abs(T(0))), T>::value;
+static_assert(!unpromoted_abs<signed char>);
+static_assert(!unpromoted_abs<short>);
+
+#if TEST_HAS_EXTENSION(bit_int)
+// _BitInt(N) narrower than int does not promote and the new template's sizeof
+// gate excludes it, so abs is not callable. Probe via SFINAE.
+template <class T, class = void>
+constexpr bool has_abs = false;
+template <class T>
+constexpr bool has_abs<T, decltype((void)std::abs(T(0)))> = true;
+static_assert(!has_abs<signed _BitInt(7)>);
+static_assert(!has_abs<signed _BitInt(16)>);
+static_assert(!has_abs<signed _BitInt(31)>);
+static_assert(has_abs<signed _BitInt(32)>);
+
+template <int N>
+void test_signed_bitint() {
+ using T = signed _BitInt(N);
+ ASSERT_SAME_TYPE(decltype(std::abs(T(0))), T);
+ assert(std::abs(T(0)) == T(0));
+ assert(std::abs(T(1)) == T(1));
+ assert(std::abs(T(42)) == T(42));
+ assert(std::abs(T(-1)) == T(1));
+ assert(std::abs(T(-42)) == T(42));
+
+ // Boundary cases. T_MAX has no overflow (identity). T_MIN + 1 negates to
+ // T_MAX, which is the largest negative value abs handles cleanly. T_MIN
+ // itself is intentionally not tested: -T_MIN overflows in signed
+ // arithmetic, which is undefined behaviour. The same caveat applies to
+ // std::abs(int) with INT_MIN.
+ T t_max = static_cast<T>(~static_cast<unsigned _BitInt(N)>(0) >> 1);
+ T t_min_plus1 = -t_max; // == T_MIN + 1
+ assert(std::abs(t_max) == t_max);
+ assert(std::abs(t_min_plus1) == t_max);
+}
+#endif
+
+int main(int, char**) {
+#if TEST_HAS_EXTENSION(bit_int)
----------------
philnik777 wrote:
Please fix this.
https://github.com/llvm/llvm-project/pull/196532
More information about the libcxx-commits
mailing list