[libcxx-commits] [libcxx] [libc++][math] Add `constexpr` to `std::fmax()`, `std::fmin()` and `std::fma()` (PR #222953)
Atharva Potdar via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Sep 22 20:05:20 PDT 2026
https://github.com/atharva-potdar updated https://github.com/llvm/llvm-project/pull/222953
>From 25134bbfe67c64517d7eeb9df41f8c00b8f8e748 Mon Sep 17 00:00:00 2001
From: atharva-potdar <atharvapotdar07 at gmail.com>
Date: Fri, 11 Sep 2026 19:21:07 +0530
Subject: [PATCH 1/7] add constexpr for fmax() and fmin()
---
libcxx/include/__math/min_max.h | 16 ++--
libcxx/include/cmath | 12 +--
.../c.math/constexpr-cxx23-clang.pass.cpp | 22 +++---
.../c.math/constexpr-cxx23-gcc.pass.cpp | 8 +-
libcxx/test/std/numerics/c.math/fmax.pass.cpp | 75 +++++++++++++++++++
libcxx/test/std/numerics/c.math/fmin.pass.cpp | 75 +++++++++++++++++++
6 files changed, 179 insertions(+), 29 deletions(-)
create mode 100644 libcxx/test/std/numerics/c.math/fmax.pass.cpp
create mode 100644 libcxx/test/std/numerics/c.math/fmin.pass.cpp
diff --git a/libcxx/include/__math/min_max.h b/libcxx/include/__math/min_max.h
index 1ddbb557d1e8fa..c4257fea5dcc31 100644
--- a/libcxx/include/__math/min_max.h
+++ b/libcxx/include/__math/min_max.h
@@ -25,21 +25,21 @@ namespace __math {
// fmax
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI float fmax(float __x, float __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 float fmax(float __x, float __y) _NOEXCEPT {
return __builtin_fmaxf(__x, __y);
}
template <class = int>
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI double fmax(double __x, double __y) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 double fmax(double __x, double __y) _NOEXCEPT {
return __builtin_fmax(__x, __y);
}
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI long double fmax(long double __x, long double __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 long double fmax(long double __x, long double __y) _NOEXCEPT {
return __builtin_fmaxl(__x, __y);
}
template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __promote_t<_A1, _A2> fmax(_A1 __x, _A2 __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __promote_t<_A1, _A2> fmax(_A1 __x, _A2 __y) _NOEXCEPT {
using __result_type = __promote_t<_A1, _A2>;
static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), "");
return __math::fmax((__result_type)__x, (__result_type)__y);
@@ -47,21 +47,21 @@ template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_ar
// fmin
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI float fmin(float __x, float __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 float fmin(float __x, float __y) _NOEXCEPT {
return __builtin_fminf(__x, __y);
}
template <class = int>
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI double fmin(double __x, double __y) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 double fmin(double __x, double __y) _NOEXCEPT {
return __builtin_fmin(__x, __y);
}
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI long double fmin(long double __x, long double __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 long double fmin(long double __x, long double __y) _NOEXCEPT {
return __builtin_fminl(__x, __y);
}
template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __promote_t<_A1, _A2> fmin(_A1 __x, _A2 __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __promote_t<_A1, _A2> fmin(_A1 __x, _A2 __y) _NOEXCEPT {
using __result_type = __promote_t<_A1, _A2>;
static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), "");
return __math::fmin((__result_type)__x, (__result_type)__y);
diff --git a/libcxx/include/cmath b/libcxx/include/cmath
index c4f4030c2049bb..e1289180a379d7 100644
--- a/libcxx/include/cmath
+++ b/libcxx/include/cmath
@@ -196,13 +196,13 @@ floating_point fma (arithmetic x, arithmetic y, arithmetic z);
float fmaf(float x, float y, float z);
long double fmal(long double x, long double y, long double z);
-floating_point fmax (arithmetic x, arithmetic y);
-float fmaxf(float x, float y);
-long double fmaxl(long double x, long double y);
+floating_point fmax (arithmetic x, arithmetic y); // constexpr since C++23
+float fmaxf(float x, float y); // constexpr since C++23
+long double fmaxl(long double x, long double y); // constexpr since C++23
-floating_point fmin (arithmetic x, arithmetic y);
-float fminf(float x, float y);
-long double fminl(long double x, long double y);
+floating_point fmin (arithmetic x, arithmetic y); // constexpr since C++23
+float fminf(float x, float y); // constexpr since C++23
+long double fminl(long double x, long double y); // constexpr since C++23
double hermite(unsigned n, double x); // C++17
float hermite(unsigned n, float x); // C++17
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 beca4907284adb..95c21eb144bf4b 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
@@ -185,17 +185,17 @@ int main(int, char**) {
ASSERT_NOT_CONSTEXPR_CXX23(std::fdimf(1.0f, 0.0f) == 1.0f);
ASSERT_NOT_CONSTEXPR_CXX23(std::fdiml(1.0L, 0.0L) == 1.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmax(1.0f, 0.0f) == 1.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmax(1.0, 0.0) == 1.0);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmax(1.0L, 0.0L) == 1.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmaxf(1.0f, 0.0f) == 1.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmaxl(1.0L, 0.0L) == 1.0L);
-
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmin(1.0f, 0.0f) == 0.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmin(1.0, 0.0) == 0.0);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmin(1.0L, 0.0L) == 0.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fminf(1.0f, 0.0f) == 0.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fminl(1.0L, 0.0L) == 0.0L);
+ ASSERT_CONSTEXPR_CXX23(std::fmax(1.0f, 0.0f) == 1.0f);
+ ASSERT_CONSTEXPR_CXX23(std::fmax(1.0, 0.0) == 1.0);
+ ASSERT_CONSTEXPR_CXX23(std::fmax(1.0L, 0.0L) == 1.0L);
+ ASSERT_CONSTEXPR_CXX23(std::fmaxf(1.0f, 0.0f) == 1.0f);
+ ASSERT_CONSTEXPR_CXX23(std::fmaxl(1.0L, 0.0L) == 1.0L);
+
+ ASSERT_CONSTEXPR_CXX23(std::fmin(1.0f, 0.0f) == 0.0f);
+ ASSERT_CONSTEXPR_CXX23(std::fmin(1.0, 0.0) == 0.0);
+ ASSERT_CONSTEXPR_CXX23(std::fmin(1.0L, 0.0L) == 0.0L);
+ ASSERT_CONSTEXPR_CXX23(std::fminf(1.0f, 0.0f) == 0.0f);
+ ASSERT_CONSTEXPR_CXX23(std::fminl(1.0L, 0.0L) == 0.0L);
ASSERT_NOT_CONSTEXPR_CXX23(std::fma(1.0f, 1.0f, 1.0f) == 2.0f);
ASSERT_NOT_CONSTEXPR_CXX23(std::fma(1.0, 1.0, 1.0) == 2.0);
diff --git a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp
index 0ae3f5802e21f4..b444d39a7a6cc9 100644
--- a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp
@@ -179,15 +179,15 @@ int main(int, char**) {
ASSERT_CONSTEXPR_CXX23(std::fdimf(1.0f, 0.0f) == 1.0f);
ASSERT_CONSTEXPR_CXX23(std::fdiml(1.0L, 0.0L) == 1.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmax(1.0f, 0.0f) == 1.0f);
+ ASSERT_CONSTEXPR_CXX23(std::fmax(1.0f, 0.0f) == 1.0f);
ASSERT_CONSTEXPR_CXX23(std::fmax(1.0, 0.0) == 1.0);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmax(1.0L, 0.0L) == 1.0L);
+ ASSERT_CONSTEXPR_CXX23(std::fmax(1.0L, 0.0L) == 1.0L);
ASSERT_CONSTEXPR_CXX23(std::fmaxf(1.0f, 0.0f) == 1.0f);
ASSERT_CONSTEXPR_CXX23(std::fmaxl(1.0L, 0.0L) == 1.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmin(1.0f, 0.0f) == 0.0f);
+ ASSERT_CONSTEXPR_CXX23(std::fmin(1.0f, 0.0f) == 0.0f);
ASSERT_CONSTEXPR_CXX23(std::fmin(1.0, 0.0) == 0.0);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmin(1.0L, 0.0L) == 0.0L);
+ ASSERT_CONSTEXPR_CXX23(std::fmin(1.0L, 0.0L) == 0.0L);
ASSERT_CONSTEXPR_CXX23(std::fminf(1.0f, 0.0f) == 0.0f);
ASSERT_CONSTEXPR_CXX23(std::fminl(1.0L, 0.0L) == 0.0L);
diff --git a/libcxx/test/std/numerics/c.math/fmax.pass.cpp b/libcxx/test/std/numerics/c.math/fmax.pass.cpp
new file mode 100644
index 00000000000000..590e40f448e690
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/fmax.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// floating-point-type fmax(floating-point-type x, floating-point-type y); // constexpr since C++23
+
+#include <cassert>
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+struct TestFloat {
+ template <class T>
+ TEST_CONSTEXPR_CXX23 void operator()() const {
+ using lim = std::numeric_limits<T>;
+ TEST_CONSTEXPR_CXX23 T inf = lim::infinity();
+ TEST_CONSTEXPR_CXX23 T nan = lim::quiet_NaN();
+ TEST_CONSTEXPR_CXX23 T s_nan = lim::signaling_NaN();
+
+ assert(std::fmax(T(1), T(2)) == T(2));
+ assert(std::fmax(T(2), T(1)) == T(2));
+ assert(std::fmax(T(-1), T(0)) == T(0));
+
+ assert(std::fmax(inf, T(1)) == inf);
+ assert(std::fmax(T(1), inf) == inf);
+ assert(std::fmax(-inf, T(1)) == T(1));
+ assert(std::fmax(T(1), -inf) == T(1));
+
+ assert(std::fmax(nan, T(1)) == T(1));
+ assert(std::fmax(T(1), nan) == T(1));
+ assert(std::fmax(s_nan, T(1)) == T(1));
+
+ assert(std::isnan(std::fmax(nan, nan)));
+ }
+};
+
+struct TestInt {
+ template <class T>
+ TEST_CONSTEXPR_CXX23 void operator()() const {
+ using lim = std::numeric_limits<T>;
+ TEST_CONSTEXPR_CXX23 T max = lim::max();
+ TEST_CONSTEXPR_CXX23 T low = lim::lowest();
+
+ assert(std::fmax(T(0), T(1)) == T(1));
+ assert(std::fmax(T(1), T(0)) == T(1));
+ assert(std::fmax(low, max) == max);
+
+ if (std::is_signed<T>::value) {
+ assert(std::fmax(T(-1), T(0)) == T(0));
+ assert(std::fmax(low, T(0)) == T(0));
+ }
+ }
+};
+
+TEST_CONSTEXPR_CXX23 bool test() {
+ types::for_each(types::floating_point_types(), TestFloat());
+ types::for_each(types::integral_types(), TestInt());
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 23
+ static_assert(test());
+#endif
+ return 0;
+}
diff --git a/libcxx/test/std/numerics/c.math/fmin.pass.cpp b/libcxx/test/std/numerics/c.math/fmin.pass.cpp
new file mode 100644
index 00000000000000..a2c41bfa940219
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/fmin.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// floating-point-type fmin(floating-point-type x, floating-point-type y); // constexpr since C++23
+
+#include <cassert>
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+struct TestFloat {
+ template <class T>
+ TEST_CONSTEXPR_CXX23 void operator()() const {
+ using lim = std::numeric_limits<T>;
+ TEST_CONSTEXPR_CXX23 T inf = lim::infinity();
+ TEST_CONSTEXPR_CXX23 T nan = lim::quiet_NaN();
+ TEST_CONSTEXPR_CXX23 T s_nan = lim::signaling_NaN();
+
+ assert(std::fmin(T(1), T(2)) == T(1));
+ assert(std::fmin(T(2), T(1)) == T(1));
+ assert(std::fmin(T(-1), T(0)) == T(-1));
+
+ assert(std::fmin(inf, T(1)) == T(1));
+ assert(std::fmin(T(1), inf) == T(1));
+ assert(std::fmin(-inf, T(1)) == -inf);
+ assert(std::fmin(T(1), -inf) == -inf);
+
+ assert(std::fmin(nan, T(1)) == T(1));
+ assert(std::fmin(T(1), nan) == T(1));
+ assert(std::fmin(s_nan, T(1)) == T(1));
+
+ assert(std::isnan(std::fmin(nan, nan)));
+ }
+};
+
+struct TestInt {
+ template <class T>
+ TEST_CONSTEXPR_CXX23 void operator()() const {
+ using lim = std::numeric_limits<T>;
+ TEST_CONSTEXPR_CXX23 T max = lim::max();
+ TEST_CONSTEXPR_CXX23 T low = lim::lowest();
+
+ assert(std::fmin(T(0), T(1)) == T(0));
+ assert(std::fmin(T(1), T(0)) == T(0));
+ assert(std::fmin(low, max) == low);
+
+ if (std::is_signed<T>::value) {
+ assert(std::fmin(T(-1), T(0)) == T(-1));
+ assert(std::fmin(low, T(0)) == T(low));
+ }
+ }
+};
+
+TEST_CONSTEXPR_CXX23 bool test() {
+ types::for_each(types::floating_point_types(), TestFloat());
+ types::for_each(types::integral_types(), TestInt());
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 23
+ static_assert(test());
+#endif
+ return 0;
+}
>From ff7c245d904f95a370df7eefdb7b94f3289e4c4b Mon Sep 17 00:00:00 2001
From: atharva-potdar <atharvapotdar07 at gmail.com>
Date: Fri, 11 Sep 2026 21:37:15 +0530
Subject: [PATCH 2/7] fix: add defensive checks for assert, include; remove
s_nan, low/high from tests
---
libcxx/include/__math/min_max.h | 22 ++++++++++++-------
.../c.math/constexpr-cxx23-clang.pass.cpp | 14 ++++++++++++
libcxx/test/std/numerics/c.math/fmax.pass.cpp | 6 -----
libcxx/test/std/numerics/c.math/fmin.pass.cpp | 6 -----
4 files changed, 28 insertions(+), 20 deletions(-)
diff --git a/libcxx/include/__math/min_max.h b/libcxx/include/__math/min_max.h
index c4257fea5dcc31..eba7c4b76b9519 100644
--- a/libcxx/include/__math/min_max.h
+++ b/libcxx/include/__math/min_max.h
@@ -9,6 +9,12 @@
#ifndef _LIBCPP___MATH_MIN_MAX_H
#define _LIBCPP___MATH_MIN_MAX_H
+#if __has_constexpr_builtin(__builtin_fmax) || defined(_LIBCPP_COMPILER_GCC)
+# define _LIBCPP_CONSTEXPR_FMAX_FMIN _LIBCPP_CONSTEXPR_SINCE_CXX23
+#else
+# define _LIBCPP_CONSTEXPR_FMAX_FMIN
+#endif
+
#include <__config>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_arithmetic.h>
@@ -25,21 +31,21 @@ namespace __math {
// fmax
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 float fmax(float __x, float __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN float fmax(float __x, float __y) _NOEXCEPT {
return __builtin_fmaxf(__x, __y);
}
template <class = int>
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 double fmax(double __x, double __y) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN double fmax(double __x, double __y) _NOEXCEPT {
return __builtin_fmax(__x, __y);
}
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 long double fmax(long double __x, long double __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN long double fmax(long double __x, long double __y) _NOEXCEPT {
return __builtin_fmaxl(__x, __y);
}
template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __promote_t<_A1, _A2> fmax(_A1 __x, _A2 __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN __promote_t<_A1, _A2> fmax(_A1 __x, _A2 __y) _NOEXCEPT {
using __result_type = __promote_t<_A1, _A2>;
static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), "");
return __math::fmax((__result_type)__x, (__result_type)__y);
@@ -47,21 +53,21 @@ template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_ar
// fmin
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 float fmin(float __x, float __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN float fmin(float __x, float __y) _NOEXCEPT {
return __builtin_fminf(__x, __y);
}
template <class = int>
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 double fmin(double __x, double __y) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN double fmin(double __x, double __y) _NOEXCEPT {
return __builtin_fmin(__x, __y);
}
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 long double fmin(long double __x, long double __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN long double fmin(long double __x, long double __y) _NOEXCEPT {
return __builtin_fminl(__x, __y);
}
template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __promote_t<_A1, _A2> fmin(_A1 __x, _A2 __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN __promote_t<_A1, _A2> fmin(_A1 __x, _A2 __y) _NOEXCEPT {
using __result_type = __promote_t<_A1, _A2>;
static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), "");
return __math::fmin((__result_type)__x, (__result_type)__y);
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 95c21eb144bf4b..924ef8f4a0678f 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
@@ -185,6 +185,7 @@ int main(int, char**) {
ASSERT_NOT_CONSTEXPR_CXX23(std::fdimf(1.0f, 0.0f) == 1.0f);
ASSERT_NOT_CONSTEXPR_CXX23(std::fdiml(1.0L, 0.0L) == 1.0L);
+#if __has_constexpr_builtin(__builtin_fmax)
ASSERT_CONSTEXPR_CXX23(std::fmax(1.0f, 0.0f) == 1.0f);
ASSERT_CONSTEXPR_CXX23(std::fmax(1.0, 0.0) == 1.0);
ASSERT_CONSTEXPR_CXX23(std::fmax(1.0L, 0.0L) == 1.0L);
@@ -196,6 +197,19 @@ int main(int, char**) {
ASSERT_CONSTEXPR_CXX23(std::fmin(1.0L, 0.0L) == 0.0L);
ASSERT_CONSTEXPR_CXX23(std::fminf(1.0f, 0.0f) == 0.0f);
ASSERT_CONSTEXPR_CXX23(std::fminl(1.0L, 0.0L) == 0.0L);
+#else
+ ASSERT_NOT_CONSTEXPR_CXX23(std::fmax(1.0f, 0.0f) == 1.0f);
+ ASSERT_NOT_CONSTEXPR_CXX23(std::fmax(1.0, 0.0) == 1.0);
+ ASSERT_NOT_CONSTEXPR_CXX23(std::fmax(1.0L, 0.0L) == 1.0L);
+ ASSERT_NOT_CONSTEXPR_CXX23(std::fmaxf(1.0f, 0.0f) == 1.0f);
+ ASSERT_NOT_CONSTEXPR_CXX23(std::fmaxl(1.0L, 0.0L) == 1.0L);
+
+ ASSERT_NOT_CONSTEXPR_CXX23(std::fmin(1.0f, 0.0f) == 0.0f);
+ ASSERT_NOT_CONSTEXPR_CXX23(std::fmin(1.0, 0.0) == 0.0);
+ ASSERT_NOT_CONSTEXPR_CXX23(std::fmin(1.0L, 0.0L) == 0.0L);
+ ASSERT_NOT_CONSTEXPR_CXX23(std::fminf(1.0f, 0.0f) == 0.0f);
+ ASSERT_NOT_CONSTEXPR_CXX23(std::fminl(1.0L, 0.0L) == 0.0L);
+#endif
ASSERT_NOT_CONSTEXPR_CXX23(std::fma(1.0f, 1.0f, 1.0f) == 2.0f);
ASSERT_NOT_CONSTEXPR_CXX23(std::fma(1.0, 1.0, 1.0) == 2.0);
diff --git a/libcxx/test/std/numerics/c.math/fmax.pass.cpp b/libcxx/test/std/numerics/c.math/fmax.pass.cpp
index 590e40f448e690..69b6cf4c6ed499 100644
--- a/libcxx/test/std/numerics/c.math/fmax.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/fmax.pass.cpp
@@ -22,7 +22,6 @@ struct TestFloat {
using lim = std::numeric_limits<T>;
TEST_CONSTEXPR_CXX23 T inf = lim::infinity();
TEST_CONSTEXPR_CXX23 T nan = lim::quiet_NaN();
- TEST_CONSTEXPR_CXX23 T s_nan = lim::signaling_NaN();
assert(std::fmax(T(1), T(2)) == T(2));
assert(std::fmax(T(2), T(1)) == T(2));
@@ -35,7 +34,6 @@ struct TestFloat {
assert(std::fmax(nan, T(1)) == T(1));
assert(std::fmax(T(1), nan) == T(1));
- assert(std::fmax(s_nan, T(1)) == T(1));
assert(std::isnan(std::fmax(nan, nan)));
}
@@ -45,16 +43,12 @@ struct TestInt {
template <class T>
TEST_CONSTEXPR_CXX23 void operator()() const {
using lim = std::numeric_limits<T>;
- TEST_CONSTEXPR_CXX23 T max = lim::max();
- TEST_CONSTEXPR_CXX23 T low = lim::lowest();
assert(std::fmax(T(0), T(1)) == T(1));
assert(std::fmax(T(1), T(0)) == T(1));
- assert(std::fmax(low, max) == max);
if (std::is_signed<T>::value) {
assert(std::fmax(T(-1), T(0)) == T(0));
- assert(std::fmax(low, T(0)) == T(0));
}
}
};
diff --git a/libcxx/test/std/numerics/c.math/fmin.pass.cpp b/libcxx/test/std/numerics/c.math/fmin.pass.cpp
index a2c41bfa940219..5ffcc479d6d15e 100644
--- a/libcxx/test/std/numerics/c.math/fmin.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/fmin.pass.cpp
@@ -22,7 +22,6 @@ struct TestFloat {
using lim = std::numeric_limits<T>;
TEST_CONSTEXPR_CXX23 T inf = lim::infinity();
TEST_CONSTEXPR_CXX23 T nan = lim::quiet_NaN();
- TEST_CONSTEXPR_CXX23 T s_nan = lim::signaling_NaN();
assert(std::fmin(T(1), T(2)) == T(1));
assert(std::fmin(T(2), T(1)) == T(1));
@@ -35,7 +34,6 @@ struct TestFloat {
assert(std::fmin(nan, T(1)) == T(1));
assert(std::fmin(T(1), nan) == T(1));
- assert(std::fmin(s_nan, T(1)) == T(1));
assert(std::isnan(std::fmin(nan, nan)));
}
@@ -45,16 +43,12 @@ struct TestInt {
template <class T>
TEST_CONSTEXPR_CXX23 void operator()() const {
using lim = std::numeric_limits<T>;
- TEST_CONSTEXPR_CXX23 T max = lim::max();
- TEST_CONSTEXPR_CXX23 T low = lim::lowest();
assert(std::fmin(T(0), T(1)) == T(0));
assert(std::fmin(T(1), T(0)) == T(0));
- assert(std::fmin(low, max) == low);
if (std::is_signed<T>::value) {
assert(std::fmin(T(-1), T(0)) == T(-1));
- assert(std::fmin(low, T(0)) == T(low));
}
}
};
>From 374e86d2c78db7f090849f6e1d3120d0b5092246 Mon Sep 17 00:00:00 2001
From: atharva-potdar <atharvapotdar07 at gmail.com>
Date: Tue, 22 Sep 2026 20:10:17 +0530
Subject: [PATCH 3/7] revert the conditional macros for constexpr on clang
---
libcxx/include/__math/min_max.h | 22 +++++++------------
.../c.math/constexpr-cxx23-clang.pass.cpp | 14 ------------
2 files changed, 8 insertions(+), 28 deletions(-)
diff --git a/libcxx/include/__math/min_max.h b/libcxx/include/__math/min_max.h
index eba7c4b76b9519..c4257fea5dcc31 100644
--- a/libcxx/include/__math/min_max.h
+++ b/libcxx/include/__math/min_max.h
@@ -9,12 +9,6 @@
#ifndef _LIBCPP___MATH_MIN_MAX_H
#define _LIBCPP___MATH_MIN_MAX_H
-#if __has_constexpr_builtin(__builtin_fmax) || defined(_LIBCPP_COMPILER_GCC)
-# define _LIBCPP_CONSTEXPR_FMAX_FMIN _LIBCPP_CONSTEXPR_SINCE_CXX23
-#else
-# define _LIBCPP_CONSTEXPR_FMAX_FMIN
-#endif
-
#include <__config>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_arithmetic.h>
@@ -31,21 +25,21 @@ namespace __math {
// fmax
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN float fmax(float __x, float __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 float fmax(float __x, float __y) _NOEXCEPT {
return __builtin_fmaxf(__x, __y);
}
template <class = int>
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN double fmax(double __x, double __y) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 double fmax(double __x, double __y) _NOEXCEPT {
return __builtin_fmax(__x, __y);
}
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN long double fmax(long double __x, long double __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 long double fmax(long double __x, long double __y) _NOEXCEPT {
return __builtin_fmaxl(__x, __y);
}
template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN __promote_t<_A1, _A2> fmax(_A1 __x, _A2 __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __promote_t<_A1, _A2> fmax(_A1 __x, _A2 __y) _NOEXCEPT {
using __result_type = __promote_t<_A1, _A2>;
static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), "");
return __math::fmax((__result_type)__x, (__result_type)__y);
@@ -53,21 +47,21 @@ template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_ar
// fmin
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN float fmin(float __x, float __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 float fmin(float __x, float __y) _NOEXCEPT {
return __builtin_fminf(__x, __y);
}
template <class = int>
-[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN double fmin(double __x, double __y) _NOEXCEPT {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 double fmin(double __x, double __y) _NOEXCEPT {
return __builtin_fmin(__x, __y);
}
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN long double fmin(long double __x, long double __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 long double fmin(long double __x, long double __y) _NOEXCEPT {
return __builtin_fminl(__x, __y);
}
template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value, int> = 0>
-[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_FMAX_FMIN __promote_t<_A1, _A2> fmin(_A1 __x, _A2 __y) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __promote_t<_A1, _A2> fmin(_A1 __x, _A2 __y) _NOEXCEPT {
using __result_type = __promote_t<_A1, _A2>;
static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), "");
return __math::fmin((__result_type)__x, (__result_type)__y);
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 924ef8f4a0678f..95c21eb144bf4b 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
@@ -185,7 +185,6 @@ int main(int, char**) {
ASSERT_NOT_CONSTEXPR_CXX23(std::fdimf(1.0f, 0.0f) == 1.0f);
ASSERT_NOT_CONSTEXPR_CXX23(std::fdiml(1.0L, 0.0L) == 1.0L);
-#if __has_constexpr_builtin(__builtin_fmax)
ASSERT_CONSTEXPR_CXX23(std::fmax(1.0f, 0.0f) == 1.0f);
ASSERT_CONSTEXPR_CXX23(std::fmax(1.0, 0.0) == 1.0);
ASSERT_CONSTEXPR_CXX23(std::fmax(1.0L, 0.0L) == 1.0L);
@@ -197,19 +196,6 @@ int main(int, char**) {
ASSERT_CONSTEXPR_CXX23(std::fmin(1.0L, 0.0L) == 0.0L);
ASSERT_CONSTEXPR_CXX23(std::fminf(1.0f, 0.0f) == 0.0f);
ASSERT_CONSTEXPR_CXX23(std::fminl(1.0L, 0.0L) == 0.0L);
-#else
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmax(1.0f, 0.0f) == 1.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmax(1.0, 0.0) == 1.0);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmax(1.0L, 0.0L) == 1.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmaxf(1.0f, 0.0f) == 1.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmaxl(1.0L, 0.0L) == 1.0L);
-
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmin(1.0f, 0.0f) == 0.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmin(1.0, 0.0) == 0.0);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmin(1.0L, 0.0L) == 0.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fminf(1.0f, 0.0f) == 0.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fminl(1.0L, 0.0L) == 0.0L);
-#endif
ASSERT_NOT_CONSTEXPR_CXX23(std::fma(1.0f, 1.0f, 1.0f) == 2.0f);
ASSERT_NOT_CONSTEXPR_CXX23(std::fma(1.0, 1.0, 1.0) == 2.0);
>From efb2d3667a4921df774bab7fff8a497294b48814 Mon Sep 17 00:00:00 2001
From: atharva-potdar <atharvapotdar07 at gmail.com>
Date: Tue, 22 Sep 2026 21:13:57 +0530
Subject: [PATCH 4/7] feat: add tests for mixed-type promotions
---
libcxx/test/std/numerics/c.math/fmax.pass.cpp | 9 +++++++++
libcxx/test/std/numerics/c.math/fmin.pass.cpp | 9 +++++++++
2 files changed, 18 insertions(+)
diff --git a/libcxx/test/std/numerics/c.math/fmax.pass.cpp b/libcxx/test/std/numerics/c.math/fmax.pass.cpp
index 69b6cf4c6ed499..a4339cab3c6010 100644
--- a/libcxx/test/std/numerics/c.math/fmax.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/fmax.pass.cpp
@@ -57,6 +57,15 @@ TEST_CONSTEXPR_CXX23 bool test() {
types::for_each(types::floating_point_types(), TestFloat());
types::for_each(types::integral_types(), TestInt());
+ // mixed-type promotions testing
+ {
+ using lim = std::numeric_limits<T>;
+ assert(std::fmax(1, 2.0) == 2.0); // int and double
+ assert(std::fmax(2.0f, 1) == 2.0); // float and int
+ assert(std::fmax(1.0L, 0.0f) == 1.0L); // long double and float
+ assert(std::fmax(lim::quiet_NaN(), 0) == 0); // NaN and int
+ }
+
return true;
}
diff --git a/libcxx/test/std/numerics/c.math/fmin.pass.cpp b/libcxx/test/std/numerics/c.math/fmin.pass.cpp
index 5ffcc479d6d15e..ec6c81dcf85ee9 100644
--- a/libcxx/test/std/numerics/c.math/fmin.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/fmin.pass.cpp
@@ -57,6 +57,15 @@ TEST_CONSTEXPR_CXX23 bool test() {
types::for_each(types::floating_point_types(), TestFloat());
types::for_each(types::integral_types(), TestInt());
+ // mixed-type promotions testing
+ {
+ using lim = std::numeric_limits<T>;
+ assert(std::fmax(1, 2.0) == 1); // int and double
+ assert(std::fmax(2.0f, 1) == 1); // float and int
+ assert(std::fmax(1.0L, 0.0f) == 0.0f); // long double and float
+ assert(std::fmax(lim::quiet_NaN(), 0) == 0); // NaN and int
+ }
+
return true;
}
>From 9e2847257574292018522837cde027686f00c255 Mon Sep 17 00:00:00 2001
From: atharva-potdar <atharvapotdar07 at gmail.com>
Date: Tue, 22 Sep 2026 22:32:31 +0530
Subject: [PATCH 5/7] feat: add constexpr for fma
---
libcxx/include/__math/fma.h | 8 +-
libcxx/include/cmath | 6 +-
.../c.math/constexpr-cxx23-clang.pass.cpp | 10 +--
.../c.math/constexpr-cxx23-gcc.pass.cpp | 4 +-
libcxx/test/std/numerics/c.math/fma.pass.cpp | 78 +++++++++++++++++++
5 files changed, 92 insertions(+), 14 deletions(-)
create mode 100644 libcxx/test/std/numerics/c.math/fma.pass.cpp
diff --git a/libcxx/include/__math/fma.h b/libcxx/include/__math/fma.h
index b972d85b89cb37..24d0138eafcd68 100644
--- a/libcxx/include/__math/fma.h
+++ b/libcxx/include/__math/fma.h
@@ -23,16 +23,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace __math {
-inline _LIBCPP_HIDE_FROM_ABI float fma(float __x, float __y, float __z) _NOEXCEPT {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 float fma(float __x, float __y, float __z) _NOEXCEPT {
return __builtin_fmaf(__x, __y, __z);
}
template <class = int>
-_LIBCPP_HIDE_FROM_ABI double fma(double __x, double __y, double __z) _NOEXCEPT {
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 double fma(double __x, double __y, double __z) _NOEXCEPT {
return __builtin_fma(__x, __y, __z);
}
-inline _LIBCPP_HIDE_FROM_ABI long double fma(long double __x, long double __y, long double __z) _NOEXCEPT {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 long double fma(long double __x, long double __y, long double __z) _NOEXCEPT {
return __builtin_fmal(__x, __y, __z);
}
@@ -40,7 +40,7 @@ template <class _A1,
class _A2,
class _A3,
__enable_if_t<is_arithmetic<_A1>::value && is_arithmetic<_A2>::value && is_arithmetic<_A3>::value, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI __promote_t<_A1, _A2, _A3> fma(_A1 __x, _A2 __y, _A3 __z) _NOEXCEPT {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __promote_t<_A1, _A2, _A3> fma(_A1 __x, _A2 __y, _A3 __z) _NOEXCEPT {
using __result_type = __promote_t<_A1, _A2, _A3>;
static_assert(
!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value && _IsSame<_A3, __result_type>::value),
diff --git a/libcxx/include/cmath b/libcxx/include/cmath
index e1289180a379d7..750503e07d9058 100644
--- a/libcxx/include/cmath
+++ b/libcxx/include/cmath
@@ -192,9 +192,9 @@ floating_point fdim (arithmetic x, arithmetic y);
float fdimf(float x, float y);
long double fdiml(long double x, long double y);
-floating_point fma (arithmetic x, arithmetic y, arithmetic z);
-float fmaf(float x, float y, float z);
-long double fmal(long double x, long double y, long double z);
+floating_point fma (arithmetic x, arithmetic y, arithmetic z); // constexpr since C++23
+float fmaf(float x, float y, float z); // constexpr since C++23
+long double fmal(long double x, long double y, long double z); // constexpr since C++23
floating_point fmax (arithmetic x, arithmetic y); // constexpr since C++23
float fmaxf(float x, float y); // constexpr since C++23
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 95c21eb144bf4b..cbeb64b94f12f5 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
@@ -197,11 +197,11 @@ int main(int, char**) {
ASSERT_CONSTEXPR_CXX23(std::fminf(1.0f, 0.0f) == 0.0f);
ASSERT_CONSTEXPR_CXX23(std::fminl(1.0L, 0.0L) == 0.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fma(1.0f, 1.0f, 1.0f) == 2.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fma(1.0, 1.0, 1.0) == 2.0);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fma(1.0L, 1.0L, 1.0L) == 2.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmaf(1.0f, 1.0f, 1.0f) == 2.0f);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fmal(1.0L, 1.0L, 1.0L) == 2.0L);
+ ASSERT_CONSTEXPR_CXX23(std::fma(1.0f, 1.0f, 1.0f) == 2.0f);
+ ASSERT_CONSTEXPR_CXX23(std::fma(1.0, 1.0, 1.0) == 2.0);
+ ASSERT_CONSTEXPR_CXX23(std::fma(1.0L, 1.0L, 1.0L) == 2.0L);
+ ASSERT_CONSTEXPR_CXX23(std::fmaf(1.0f, 1.0f, 1.0f) == 2.0f);
+ ASSERT_CONSTEXPR_CXX23(std::fmal(1.0L, 1.0L, 1.0L) == 2.0L);
ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0f) == FP_NORMAL);
ASSERT_CONSTEXPR_CXX23(std::fpclassify(-1.0) == FP_NORMAL);
diff --git a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp
index b444d39a7a6cc9..5c909c6cee5673 100644
--- a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp
@@ -191,9 +191,9 @@ int main(int, char**) {
ASSERT_CONSTEXPR_CXX23(std::fminf(1.0f, 0.0f) == 0.0f);
ASSERT_CONSTEXPR_CXX23(std::fminl(1.0L, 0.0L) == 0.0L);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fma(1.0f, 1.0f, 1.0f) == 2.0f);
+ ASSERT_CONSTEXPR_CXX23(std::fma(1.0f, 1.0f, 1.0f) == 2.0f);
ASSERT_CONSTEXPR_CXX23(std::fma(1.0, 1.0, 1.0) == 2.0);
- ASSERT_NOT_CONSTEXPR_CXX23(std::fma(1.0L, 1.0L, 1.0L) == 2.0L);
+ ASSERT_CONSTEXPR_CXX23(std::fma(1.0L, 1.0L, 1.0L) == 2.0L);
ASSERT_CONSTEXPR_CXX23(std::fmaf(1.0f, 1.0f, 1.0f) == 2.0f);
ASSERT_CONSTEXPR_CXX23(std::fmal(1.0L, 1.0L, 1.0L) == 2.0L);
diff --git a/libcxx/test/std/numerics/c.math/fma.pass.cpp b/libcxx/test/std/numerics/c.math/fma.pass.cpp
new file mode 100644
index 00000000000000..e88a4b29916414
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/fma.pass.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// floating-point-type fma(floating-point-type x, floating-point-type y, floating-point-type z); // constexpr since C++23
+
+#include <cassert>
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+struct TestFloat {
+ template <class T>
+ TEST_CONSTEXPR_CXX23 void operator()() const {
+ using lim = std::numeric_limits<T>;
+ TEST_CONSTEXPR_CXX23 T inf = lim::infinity();
+ TEST_CONSTEXPR_CXX23 T nan = lim::quiet_NaN();
+
+ assert(std::fma(T(1), T(1), T(1)) == T(2));
+ assert(std::fma(T(1), T(2), T(3)) == T(5));
+ assert(std::fma(T(-1), T(2), T(2)) == T(0));
+
+ assert(std::fmax(inf, T(1), T(0)) == inf);
+ assert(std::fmax(T(1), inf, T(0)) == inf);
+ assert(std::fmax(-inf, T(1), T(0)) == -inf);
+ assert(std::fmax(T(1), -inf, T(0)) == -inf);
+
+ assert(std::isnan(std::fma(nan, T(1), T(0))));
+ assert(std::isnan(std::fma(T(1), nan, T(0))));
+ assert(std::isnan(std::fma(T(1), T(0), nan)));
+ assert(std::isnan(std::fma(nan, nan, nan)));
+ }
+};
+
+struct TestInt {
+ template <class T>
+ TEST_CONSTEXPR_CXX23 void operator()() const {
+ using lim = std::numeric_limits<T>;
+
+ assert(std::fma(T(0), T(1), T(1)) == T(1));
+ assert(std::fma(T(1), T(2), T(3)) == T(5));
+
+ if (std::is_signed<T>::value) {
+ assert(std::fma(T(-1), T(2), T(3)) == T(1));
+ }
+ }
+};
+
+TEST_CONSTEXPR_CXX23 bool test() {
+ types::for_each(types::floating_point_types(), TestFloat());
+ types::for_each(types::integral_types(), TestInt());
+
+ // mixed-type promotions testing
+ {
+ using lim = std::numeric_limits<T>;
+ assert(std::fma(1, 2.0, 3) == 5.0); // int and double
+ assert(std::fma(2.0f, 1, 1.0f) == 3.0); // float and int
+ assert(std::fma(1.0L, 0.0f, 1) == 1.0L); // long double and float
+ assert(std::isnan(std::fma(lim::quiet_NaN(), 1, 0)))); // NaN and int
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 23
+ static_assert(test());
+#endif
+ return 0;
+}
>From 700cc2e201e05f9d74a4944f332f66d9678955b3 Mon Sep 17 00:00:00 2001
From: atharva-potdar <atharvapotdar07 at gmail.com>
Date: Tue, 22 Sep 2026 23:01:53 +0530
Subject: [PATCH 6/7] fix: change T in test main to double for numeric_limits
---
libcxx/test/std/numerics/c.math/fma.pass.cpp | 2 +-
libcxx/test/std/numerics/c.math/fmax.pass.cpp | 2 +-
libcxx/test/std/numerics/c.math/fmin.pass.cpp | 10 +++++-----
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/fma.pass.cpp b/libcxx/test/std/numerics/c.math/fma.pass.cpp
index e88a4b29916414..caefeb5dbd207f 100644
--- a/libcxx/test/std/numerics/c.math/fma.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/fma.pass.cpp
@@ -59,7 +59,7 @@ TEST_CONSTEXPR_CXX23 bool test() {
// mixed-type promotions testing
{
- using lim = std::numeric_limits<T>;
+ using lim = std::numeric_limits<double>;
assert(std::fma(1, 2.0, 3) == 5.0); // int and double
assert(std::fma(2.0f, 1, 1.0f) == 3.0); // float and int
assert(std::fma(1.0L, 0.0f, 1) == 1.0L); // long double and float
diff --git a/libcxx/test/std/numerics/c.math/fmax.pass.cpp b/libcxx/test/std/numerics/c.math/fmax.pass.cpp
index a4339cab3c6010..4c5b78461f55ac 100644
--- a/libcxx/test/std/numerics/c.math/fmax.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/fmax.pass.cpp
@@ -59,7 +59,7 @@ TEST_CONSTEXPR_CXX23 bool test() {
// mixed-type promotions testing
{
- using lim = std::numeric_limits<T>;
+ using lim = std::numeric_limits<double>;
assert(std::fmax(1, 2.0) == 2.0); // int and double
assert(std::fmax(2.0f, 1) == 2.0); // float and int
assert(std::fmax(1.0L, 0.0f) == 1.0L); // long double and float
diff --git a/libcxx/test/std/numerics/c.math/fmin.pass.cpp b/libcxx/test/std/numerics/c.math/fmin.pass.cpp
index ec6c81dcf85ee9..ba363787e512f2 100644
--- a/libcxx/test/std/numerics/c.math/fmin.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/fmin.pass.cpp
@@ -59,11 +59,11 @@ TEST_CONSTEXPR_CXX23 bool test() {
// mixed-type promotions testing
{
- using lim = std::numeric_limits<T>;
- assert(std::fmax(1, 2.0) == 1); // int and double
- assert(std::fmax(2.0f, 1) == 1); // float and int
- assert(std::fmax(1.0L, 0.0f) == 0.0f); // long double and float
- assert(std::fmax(lim::quiet_NaN(), 0) == 0); // NaN and int
+ using lim = std::numeric_limits<double>;
+ assert(std::fmin(1, 2.0) == 1); // int and double
+ assert(std::fmin(2.0f, 1) == 1); // float and int
+ assert(std::fmin(1.0L, 0.0f) == 0.0f); // long double and float
+ assert(std::fmin(lim::quiet_NaN(), 0) == 0); // NaN and int
}
return true;
>From 49d3c7368b79d971c22e88d6d4a452f666c049f3 Mon Sep 17 00:00:00 2001
From: Atharva Potdar <atharvapotdar07 at gmail.com>
Date: Wed, 23 Sep 2026 08:35:03 +0530
Subject: [PATCH 7/7] fix: replace typo in fma.pass.cpp
---
libcxx/test/std/numerics/c.math/fma.pass.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/fma.pass.cpp b/libcxx/test/std/numerics/c.math/fma.pass.cpp
index caefeb5dbd207f..7bd1a80088ceb5 100644
--- a/libcxx/test/std/numerics/c.math/fma.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/fma.pass.cpp
@@ -27,10 +27,10 @@ struct TestFloat {
assert(std::fma(T(1), T(2), T(3)) == T(5));
assert(std::fma(T(-1), T(2), T(2)) == T(0));
- assert(std::fmax(inf, T(1), T(0)) == inf);
- assert(std::fmax(T(1), inf, T(0)) == inf);
- assert(std::fmax(-inf, T(1), T(0)) == -inf);
- assert(std::fmax(T(1), -inf, T(0)) == -inf);
+ assert(std::fma(inf, T(1), T(0)) == inf);
+ assert(std::fma(T(1), inf, T(0)) == inf);
+ assert(std::fma(-inf, T(1), T(0)) == -inf);
+ assert(std::fma(T(1), -inf, T(0)) == -inf);
assert(std::isnan(std::fma(nan, T(1), T(0))));
assert(std::isnan(std::fma(T(1), nan, T(0))));
More information about the libcxx-commits
mailing list