[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