[libcxx] [llvm] [libc++][math][c++17] P0226R1 - Mathematical Special Functions: infra + `std::assoc_laguerre` (PR #205649)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 12 14:04:55 PDT 2026
https://github.com/PaulXiCao updated https://github.com/llvm/llvm-project/pull/205649
>From 7555447d01b3e6bd5127f4ffbfaeeb223cf9ea81 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 23 Jun 2026 20:52:48 +0200
Subject: [PATCH 01/72] link against Boost.Math
---
libcxx/CMakeLists.txt | 8 ++++++++
libcxx/src/CMakeLists.txt | 2 ++
2 files changed, 10 insertions(+)
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 845240d1b894c..845042f15495f 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -899,6 +899,14 @@ add_custom_target(cxx-test-depends
COMMENT "Build dependencies required to run the libc++ test suite.")
add_subdirectory(include)
+
+# Header-only Boost.Math (INTERFACE target `boost_math`). Lives outside the
+# libcxx source tree, so a binary dir must be supplied.
+add_subdirectory(
+ ${LLVM_THIRD_PARTY_DIR}/boost-math
+ ${LIBCXX_BINARY_DIR}/third-party/boost-math
+ EXCLUDE_FROM_ALL)
+
add_subdirectory(src)
add_subdirectory(utils)
add_subdirectory(modules)
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index de7817ad69f26..c882446596a3e 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -176,6 +176,7 @@ add_library(cxx_shared SHARED ${LIBCXX_SOURCES} ${LIBCXX_HEADERS})
target_include_directories(cxx_shared PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(cxx_shared PUBLIC cxx-headers runtimes-libc-shared
PRIVATE ${LIBCXX_LIBRARIES}
+ PRIVATE boost_math
PRIVATE llvm-libc-common-utilities)
set_target_properties(cxx_shared
PROPERTIES
@@ -263,6 +264,7 @@ add_library(cxx_static STATIC ${LIBCXX_SOURCES} ${LIBCXX_HEADERS})
target_include_directories(cxx_static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(cxx_static PUBLIC cxx-headers runtimes-libc-static
PRIVATE ${LIBCXX_LIBRARIES}
+ PRIVATE boost_math
PRIVATE libcxx-abi-static
PRIVATE llvm-libc-common-utilities)
set_target_properties(cxx_static
>From fe89c404516cfea93ab67939b48a15c74213cd59 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 23 Jun 2026 20:53:37 +0200
Subject: [PATCH 02/72] add empty src/mathematical_special_functions.cpp
---
libcxx/src/CMakeLists.txt | 1 +
libcxx/src/mathematical_special_functions.cpp | 17 +++++++++++++++++
2 files changed, 18 insertions(+)
create mode 100644 libcxx/src/mathematical_special_functions.cpp
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index c882446596a3e..d2168decbfdba 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -29,6 +29,7 @@ set(LIBCXX_SOURCES
include/ryu/ryu.h
include/to_chars_floating_point.h
include/from_chars_floating_point.h
+ mathematical_special_functions.cpp
memory.cpp
memory_resource.cpp
new_handler.cpp
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
new file mode 100644
index 0000000000000..db07d61f89319
--- /dev/null
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -0,0 +1,17 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <__config>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+
+namespace {}
+
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
>From 7fbc20f4bea5a80fdebfb22eadee50cb90698b46 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 23 Jun 2026 21:06:04 +0200
Subject: [PATCH 03/72] add simple test for std::assoc_laguerref (fails atm)
---
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
new file mode 100644
index 0000000000000..1a12c8f81a16c
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Missing powl
+// XFAIL: LLVM-LIBC-FIXME
+
+// REQUIRES: std-at-least-c++17
+
+// <cmath>
+//
+// [sf.cmath.assoc.laguerre], associated Laguerre polynomials
+// floating-point-type assoc_laguerre(unsigned n, unsigned m, floating-point-type x);
+// float assoc_laguerref(unsigned n, unsigned m, float x);
+// long double assoc_laguerrel(unsigned n, unsigned m, long double x);
+
+#include <cmath>
+
+int main(int, char**) {
+ std::assoc_laguerref(0, 0, 0.0f);
+
+ return 0;
+}
>From c7e11e92b9c70fe1f319a8f959ce1c11cbbfa9cc Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 23 Jun 2026 21:52:09 +0200
Subject: [PATCH 04/72] handling MATH_ERRNO, MATH_ERREXCEPT via __sf_result
---
libcxx/include/__math/special_functions.h | 25 +++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 6b217852e2f8c..86b3ac9cb665e 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -15,7 +15,10 @@
#include <__math/traits.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_integral.h>
+#include <cerrno>
+#include <cfenv>
#include <limits>
+#include <math.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -25,6 +28,28 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 17
+namespace __math {
+template <class _Tp>
+struct __sf_result {
+ bool __domain_error;
+ _Tp __ret;
+
+ operator _Tp() const {
+# if math_errhandling & MATH_ERRNO
+ if (__domain_error)
+ errno = EDOM;
+# endif
+
+# if math_errhandling & MATH_ERREXCEPT
+ if (__domain_error)
+ feraiseexcept(FE_INVALID);
+# endif
+
+ return __ret;
+ }
+};
+} // namespace __math
+
template <class _Real>
_LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) {
// The Hermite polynomial H_n(x).
>From 23081681878b007cb50f1ed115ec316fa956b4cf Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 23 Jun 2026 22:00:10 +0200
Subject: [PATCH 05/72] impl assoc_laguerref
---
libcxx/include/__math/special_functions.h | 9 +++++
libcxx/src/mathematical_special_functions.cpp | 37 ++++++++++++++++++-
2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 86b3ac9cb665e..d0d6e56507e85 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -25,6 +25,7 @@
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
#if _LIBCPP_STD_VER >= 17
@@ -48,8 +49,15 @@ struct __sf_result {
return __ret;
}
};
+
+_LIBCPP_EXPORTED_FROM_ABI __sf_result<float> __assoc_laguerre(unsigned int, unsigned int, float) noexcept;
+
} // namespace __math
+inline _LIBCPP_HIDE_FROM_ABI float assoc_laguerref(unsigned int __n, unsigned int __m, float __x) noexcept {
+ return __math::__assoc_laguerre(__n, __m, __x);
+}
+
template <class _Real>
_LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) {
// The Hermite polynomial H_n(x).
@@ -104,6 +112,7 @@ _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) {
#endif // _LIBCPP_STD_VER >= 17
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___MATH_SPECIAL_FUNCTIONS_H
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index db07d61f89319..e18e9c5f2797c 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -7,11 +7,46 @@
//===----------------------------------------------------------------------===//
#include <__config>
+#include <boost/math/special_functions.hpp>
+#include <cmath>
+#include <optional>
+#include <type_traits>
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
-namespace {}
+namespace __math {
+namespace {
+template <class _Ret>
+optional<_Ret> __check_nan() {
+ return nullopt;
+}
+
+template <class _Ret, class _Arg, class... _Args>
+optional<_Ret> __check_nan(_Arg __arg, _Args... __args) {
+ if constexpr (is_floating_point_v<_Arg>)
+ if (isnan(__arg))
+ return __arg;
+ return __check_nan<_Ret>(__args...);
+}
+
+template <class Func, class... _Args, class _Ret = std::invoke_result_t<Func, _Args...>>
+__sf_result<_Ret> invoke_boost_math(Func f, _Args... __args) {
+ if (auto __maybe_nan = __check_nan<_Ret>(__args...); __maybe_nan.has_value())
+ return {.__domain_error = false, .__ret = *__maybe_nan};
+
+ try {
+ return {.__domain_error = false, .__ret = f(__args...)};
+ } catch (...) {
+ return {.__domain_error = true, .__ret = numeric_limits<_Ret>::quiet_NaN()};
+ }
+}
+} // namespace
+
+__sf_result<float> __assoc_laguerre(unsigned int __n, unsigned int __m, float __x) noexcept {
+ return invoke_boost_math([&](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
+}
+} // namespace __math
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
>From adb174a0e9d29b172b17bc9e0d781db0dff15d5c Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 23 Jun 2026 22:34:12 +0200
Subject: [PATCH 06/72] test assoc_laguerref
---
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index 1a12c8f81a16c..fe92daa501c6f 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -6,22 +6,18 @@
//
//===----------------------------------------------------------------------===//
-// Missing powl
-// XFAIL: LLVM-LIBC-FIXME
-
// REQUIRES: std-at-least-c++17
// <cmath>
//
// [sf.cmath.assoc.laguerre], associated Laguerre polynomials
-// floating-point-type assoc_laguerre(unsigned n, unsigned m, floating-point-type x);
// float assoc_laguerref(unsigned n, unsigned m, float x);
-// long double assoc_laguerrel(unsigned n, unsigned m, long double x);
+#include <cassert>
#include <cmath>
-int main(int, char**) {
- std::assoc_laguerref(0, 0, 0.0f);
-
- return 0;
+int main() {
+ // Single value tested against known solution.
+ // Note, underlying Boost.Math is itself well-tested.
+ assert(std::abs(std::assoc_laguerref(2, 10, 0.5f) - 60.125f) < 0.001f);
}
>From b7bc1fb6247235ce62066d70a30c13608a8672fc Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 26 Jun 2026 18:26:00 +0200
Subject: [PATCH 07/72] test: common.h
---
.../std/numerics/c.math/sf.cmath/common.h | 65 +++++++++++++++++++
1 file changed, 65 insertions(+)
create mode 100644 libcxx/test/std/numerics/c.math/sf.cmath/common.h
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/common.h b/libcxx/test/std/numerics/c.math/sf.cmath/common.h
new file mode 100644
index 0000000000000..867e6af6f6914
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/common.h
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_SF_CMATH_COMMON_H
+#define TEST_SF_CMATH_COMMON_H
+
+#include <cassert>
+#include <cerrno>
+#include <cmath>
+#include <math.h>
+#include <cfenv>
+
+// std::type_identity is C++20 (we need to support C++17 here)
+template <class T>
+struct type_identity {
+ typedef T type;
+};
+template <class T>
+using type_identity_t = typename type_identity<T>::type;
+
+template <class T>
+bool between(type_identity_t<T> lower, T value, type_identity_t<T> upper) {
+ return lower < value && value < upper;
+}
+
+template <class Func>
+void check_no_domain_error(Func f) {
+#if math_errhandling & MATH_ERRNO
+ errno = EACCES;
+#endif
+#if math_errhandling & MATH_ERREXCEPT
+ std::feclearexcept(FE_INVALID);
+#endif
+ f();
+#if math_errhandling & MATH_ERRNO
+ assert(errno == EACCES);
+#endif
+#if math_errhandling & MATH_ERREXCEPT
+ assert(!std::fetestexcept(FE_INVALID));
+#endif
+}
+
+template <class Func>
+void check_domain_error(Func f) {
+#if math_errhandling & MATH_ERRNO
+ errno = EACCES;
+#endif
+#if math_errhandling & MATH_ERREXCEPT
+ std::feclearexcept(FE_INVALID);
+#endif
+ f();
+#if math_errhandling & MATH_ERRNO
+ assert(errno == EDOM);
+#endif
+#if math_errhandling & MATH_ERREXCEPT
+ assert(std::fetestexcept(FE_INVALID));
+#endif
+}
+
+#endif // TEST_SF_CMATH_COMMON_H
>From a47f9e902e5c427c84115f4af119eedf8778e182 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 26 Jun 2026 18:26:59 +0200
Subject: [PATCH 08/72] more testing of assoc_laguerref: values, types, domain
error
---
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 36 +++++++++++++++++--
1 file changed, 33 insertions(+), 3 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index fe92daa501c6f..eb747efb4c1c6 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -14,10 +14,40 @@
// float assoc_laguerref(unsigned n, unsigned m, float x);
#include <cassert>
+#include <cerrno>
+#include <cfenv>
#include <cmath>
+#include "common.h"
+#include "type_algorithms.h"
+
+struct TestFloatingPoint {
+ template <class T>
+ void operator()() const {
+ assert(between(0.99f, std::assoc_laguerref(0, 0, T(0.)), 1.01f));
+
+ assert(between(0.99f, std::assoc_laguerref(1, 1, T(1.)), 1.01f));
+
+ assert(between(-0.01f, std::assoc_laguerref(2, 2, T(2.)), 0.01f));
+
+ assert(std::abs(std::assoc_laguerref(2, 10, 0.5f) - 60.125f) < 0.001f);
+
+ static_assert(std::is_same_v<decltype(std::assoc_laguerref(0, 0, T(0.))), float>);
+
+ check_no_domain_error([] { (void)std::assoc_laguerref(0, 0, std::numeric_limits<T>::quiet_NaN()); });
+ }
+};
+
+struct TestIntegral {
+ template <class T>
+ void operator()() const {
+ assert(between(0.99f, std::assoc_laguerref(0, 0, T(0.)), 1.01f));
+
+ static_assert(std::is_same_v<decltype(std::assoc_laguerref(0, 0, T(0.))), float>);
+ }
+};
+
int main() {
- // Single value tested against known solution.
- // Note, underlying Boost.Math is itself well-tested.
- assert(std::abs(std::assoc_laguerref(2, 10, 0.5f) - 60.125f) < 0.001f);
+ types::for_each(types::floating_point_types{}, TestFloatingPoint{});
+ types::for_each(types::integral_types{}, TestIntegral{});
}
>From f8a3b1d891405ff6ab04bfc7a7d615ca2cd54a56 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 26 Jun 2026 23:15:40 +0200
Subject: [PATCH 09/72] silence boost_math warnings by marking it as `SYSTEM`
lib
---
third-party/boost-math/CMakeLists.txt | 2 +-
third-party/update_boost_math.sh | 13 +++++++++++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/third-party/boost-math/CMakeLists.txt b/third-party/boost-math/CMakeLists.txt
index a1f6011d95e55..0de1fa2ec01ed 100644
--- a/third-party/boost-math/CMakeLists.txt
+++ b/third-party/boost-math/CMakeLists.txt
@@ -11,7 +11,7 @@ add_library(boost_math INTERFACE)
add_library(Boost::math ALIAS boost_math)
-target_include_directories(boost_math INTERFACE include)
+target_include_directories(boost_math SYSTEM INTERFACE include)
if(NOT CMAKE_VERSION VERSION_LESS "3.19")
file(GLOB_RECURSE headers include/*.hpp)
target_sources(boost_math PRIVATE ${headers})
diff --git a/third-party/update_boost_math.sh b/third-party/update_boost_math.sh
index 96cd73ed8c304..27d8816b7cb12 100755
--- a/third-party/update_boost_math.sh
+++ b/third-party/update_boost_math.sh
@@ -27,3 +27,16 @@ echo "****************************************"
echo "Subsetting Boost.Math ${VERSION}"
echo "****************************************"
rm -rf ${SCRIPT_DIR}/boost-math/{.circleci,.drone,.github,build,config,doc,example,meta,reporting,src,test,tools}
+
+echo "****************************************"
+echo "Patching Boost.Math ${VERSION} for libc++"
+echo "****************************************"
+# Mark boost_math include dir as SYSTEM so libc++ consumers don't surface warnings from vendored boost-math code (e.g.
+# -Wdeprecated-redundant-constexpr-static-def). Upstream keeps these for pre-C++17 compat.
+sed -i 's|target_include_directories(boost_math INTERFACE include)|target_include_directories(boost_math SYSTEM INTERFACE include)|' \
+ ${SCRIPT_DIR}/boost-math/CMakeLists.txt
+
+# Verify the patch landed -- fail loudly if upstream renamed the target.
+grep -q 'target_include_directories(boost_math SYSTEM INTERFACE include)' \
+ ${SCRIPT_DIR}/boost-math/CMakeLists.txt \
+ || { echo "ERROR: SYSTEM include patch failed -- upstream CMakeLists.txt structure changed"; exit 1; }
>From 17c19c5c87c5adf5618686cbf1cac445d4bfbfda Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 26 Jun 2026 23:24:39 +0200
Subject: [PATCH 10/72] add nodiscard test for assoc_laguerref
---
.../c.math/sf.cmath/nodiscard.verify.cpp | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..7928ebf50681a
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// Check that functions are marked [[nodiscard]]
+
+#include <cmath>
+
+void test() {
+ // clang-format off
+ // assoc_laguerre
+ std::assoc_laguerref(0, 0, 0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ // clang-format on
+}
>From 0a7cf75eca52eab4c5d98b4f323f05fbf0187a9c Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 26 Jun 2026 23:27:41 +0200
Subject: [PATCH 11/72] add nodiscard to assoc_laguerref
---
libcxx/include/__math/special_functions.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index d0d6e56507e85..dee70bec45cd8 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -54,7 +54,8 @@ _LIBCPP_EXPORTED_FROM_ABI __sf_result<float> __assoc_laguerre(unsigned int, unsi
} // namespace __math
-inline _LIBCPP_HIDE_FROM_ABI float assoc_laguerref(unsigned int __n, unsigned int __m, float __x) noexcept {
+[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI float
+assoc_laguerref(unsigned int __n, unsigned int __m, float __x) noexcept {
return __math::__assoc_laguerre(__n, __m, __x);
}
>From ddfb2c1563bf465cd912f226abe221488a67b0df Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Fri, 26 Jun 2026 23:50:00 +0200
Subject: [PATCH 12/72] insert grouping for assoc_laguerre functions
---
libcxx/include/__math/special_functions.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index dee70bec45cd8..3100860ec8c70 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -49,9 +49,11 @@ struct __sf_result {
return __ret;
}
};
+} // namespace __math
+// assoc_laguerre
+namespace __math {
_LIBCPP_EXPORTED_FROM_ABI __sf_result<float> __assoc_laguerre(unsigned int, unsigned int, float) noexcept;
-
} // namespace __math
[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI float
>From 39b98428ea2cf592234512ac3762348f3594087c Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 27 Jun 2026 00:09:27 +0200
Subject: [PATCH 13/72] insert grouping for hermite functions
---
libcxx/include/__math/special_functions.h | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 3100860ec8c70..b8ec0785a3b2b 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -26,7 +26,6 @@
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
-
#if _LIBCPP_STD_VER >= 17
namespace __math {
@@ -61,6 +60,14 @@ assoc_laguerref(unsigned int __n, unsigned int __m, float __x) noexcept {
return __math::__assoc_laguerre(__n, __m, __x);
}
+#endif // _LIBCPP_STD_VER >= 17
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+// hermite
+_LIBCPP_BEGIN_NAMESPACE_STD
+#if _LIBCPP_STD_VER >= 17
+
template <class _Real>
_LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) {
// The Hermite polynomial H_n(x).
@@ -114,8 +121,5 @@ _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) {
}
#endif // _LIBCPP_STD_VER >= 17
-
-_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
-
#endif // _LIBCPP___MATH_SPECIAL_FUNCTIONS_H
>From 145ce5f04732b8f5800f9013411d11ffe97c215f Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 27 Jun 2026 00:10:16 +0200
Subject: [PATCH 14/72] add missing ABI annotation
---
libcxx/include/__math/special_functions.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index b8ec0785a3b2b..e11dc97fd46d4 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -34,7 +34,7 @@ struct __sf_result {
bool __domain_error;
_Tp __ret;
- operator _Tp() const {
+ _LIBCPP_HIDE_FROM_ABI operator _Tp() const {
# if math_errhandling & MATH_ERRNO
if (__domain_error)
errno = EDOM;
>From 2328d31c7918995c6895836c69e1371250675427 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 27 Jun 2026 10:16:15 +0200
Subject: [PATCH 15/72] TU: guard by C++ >= 17
---
libcxx/src/mathematical_special_functions.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index e18e9c5f2797c..102acb37e50bc 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -14,6 +14,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+#if _LIBCPP_STD_VER >= 17
namespace __math {
namespace {
@@ -48,5 +49,6 @@ __sf_result<float> __assoc_laguerre(unsigned int __n, unsigned int __m, float __
}
} // namespace __math
+#endif
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
>From 7b60948e6eb6cb5b9ccea95e76bb02865d314871 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 27 Jun 2026 10:18:02 +0200
Subject: [PATCH 16/72] TU: qualify std:: functions
---
libcxx/src/mathematical_special_functions.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index 102acb37e50bc..03a90cd3bd982 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -19,14 +19,14 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
namespace __math {
namespace {
template <class _Ret>
-optional<_Ret> __check_nan() {
- return nullopt;
+std::optional<_Ret> __check_nan() {
+ return std::nullopt;
}
template <class _Ret, class _Arg, class... _Args>
-optional<_Ret> __check_nan(_Arg __arg, _Args... __args) {
- if constexpr (is_floating_point_v<_Arg>)
- if (isnan(__arg))
+std::optional<_Ret> __check_nan(_Arg __arg, _Args... __args) {
+ if constexpr (std::is_floating_point_v<_Arg>)
+ if (std::isnan(__arg))
return __arg;
return __check_nan<_Ret>(__args...);
}
@@ -39,7 +39,7 @@ __sf_result<_Ret> invoke_boost_math(Func f, _Args... __args) {
try {
return {.__domain_error = false, .__ret = f(__args...)};
} catch (...) {
- return {.__domain_error = true, .__ret = numeric_limits<_Ret>::quiet_NaN()};
+ return {.__domain_error = true, .__ret = std::numeric_limits<_Ret>::quiet_NaN()};
}
}
} // namespace
>From a0f3426cd940ef45a441b4e610efaebf8f3e6655 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 27 Jun 2026 10:18:46 +0200
Subject: [PATCH 17/72] TU: add missing __uglify
---
libcxx/src/mathematical_special_functions.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index 03a90cd3bd982..fdca91bf5a8b4 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -31,13 +31,13 @@ std::optional<_Ret> __check_nan(_Arg __arg, _Args... __args) {
return __check_nan<_Ret>(__args...);
}
-template <class Func, class... _Args, class _Ret = std::invoke_result_t<Func, _Args...>>
-__sf_result<_Ret> invoke_boost_math(Func f, _Args... __args) {
+template <class _Func, class... _Args, class _Ret = std::invoke_result_t<_Func, _Args...>>
+__sf_result<_Ret> __invoke_boost_math(_Func __f, _Args... __args) {
if (auto __maybe_nan = __check_nan<_Ret>(__args...); __maybe_nan.has_value())
return {.__domain_error = false, .__ret = *__maybe_nan};
try {
- return {.__domain_error = false, .__ret = f(__args...)};
+ return {.__domain_error = false, .__ret = __f(__args...)};
} catch (...) {
return {.__domain_error = true, .__ret = std::numeric_limits<_Ret>::quiet_NaN()};
}
@@ -45,7 +45,7 @@ __sf_result<_Ret> invoke_boost_math(Func f, _Args... __args) {
} // namespace
__sf_result<float> __assoc_laguerre(unsigned int __n, unsigned int __m, float __x) noexcept {
- return invoke_boost_math([&](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
+ return __invoke_boost_math([&](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
}
} // namespace __math
>From 745c9d9aa7dfc246593851286f70e6494148c0d4 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 27 Jun 2026 10:28:07 +0200
Subject: [PATCH 18/72] TU: add missing headers
---
libcxx/src/mathematical_special_functions.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index fdca91bf5a8b4..9a106c763c776 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -7,8 +7,10 @@
//===----------------------------------------------------------------------===//
#include <__config>
+#include <__math/special_functions.h>
#include <boost/math/special_functions.hpp>
#include <cmath>
+#include <limits>
#include <optional>
#include <type_traits>
>From 372f1054b2aa081808ed07b6182a6b8f2e4a21e3 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 27 Jun 2026 10:28:42 +0200
Subject: [PATCH 19/72] TU: remove C++20 designated initializers
---
libcxx/src/mathematical_special_functions.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index 9a106c763c776..23d9216d777d2 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -36,12 +36,12 @@ std::optional<_Ret> __check_nan(_Arg __arg, _Args... __args) {
template <class _Func, class... _Args, class _Ret = std::invoke_result_t<_Func, _Args...>>
__sf_result<_Ret> __invoke_boost_math(_Func __f, _Args... __args) {
if (auto __maybe_nan = __check_nan<_Ret>(__args...); __maybe_nan.has_value())
- return {.__domain_error = false, .__ret = *__maybe_nan};
+ return {false, *__maybe_nan};
try {
- return {.__domain_error = false, .__ret = __f(__args...)};
+ return {false, __f(__args...)};
} catch (...) {
- return {.__domain_error = true, .__ret = std::numeric_limits<_Ret>::quiet_NaN()};
+ return {true, std::numeric_limits<_Ret>::quiet_NaN()};
}
}
} // namespace
>From 4e32fcc443bdd93c388e69aad76c0b08d7335d9d Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 27 Jun 2026 10:28:51 +0200
Subject: [PATCH 20/72] TU: cleanup
---
libcxx/src/mathematical_special_functions.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index 23d9216d777d2..cf88cbef159fa 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -47,7 +47,7 @@ __sf_result<_Ret> __invoke_boost_math(_Func __f, _Args... __args) {
} // namespace
__sf_result<float> __assoc_laguerre(unsigned int __n, unsigned int __m, float __x) noexcept {
- return __invoke_boost_math([&](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
+ return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
}
} // namespace __math
>From 299419630480cc7ba0fd7c026a14c8797b461aa0 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 27 Jun 2026 11:21:18 +0200
Subject: [PATCH 21/72] break cyclic header deps: move errno logic into TU
---
libcxx/include/__math/special_functions.h | 34 +------------------
libcxx/src/mathematical_special_functions.cpp | 21 ++++++++----
2 files changed, 15 insertions(+), 40 deletions(-)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index e11dc97fd46d4..89c75cfc04585 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -15,10 +15,7 @@
#include <__math/traits.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_integral.h>
-#include <cerrno>
-#include <cfenv>
#include <limits>
-#include <math.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -28,37 +25,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
#if _LIBCPP_STD_VER >= 17
-namespace __math {
-template <class _Tp>
-struct __sf_result {
- bool __domain_error;
- _Tp __ret;
-
- _LIBCPP_HIDE_FROM_ABI operator _Tp() const {
-# if math_errhandling & MATH_ERRNO
- if (__domain_error)
- errno = EDOM;
-# endif
-
-# if math_errhandling & MATH_ERREXCEPT
- if (__domain_error)
- feraiseexcept(FE_INVALID);
-# endif
-
- return __ret;
- }
-};
-} // namespace __math
-
// assoc_laguerre
-namespace __math {
-_LIBCPP_EXPORTED_FROM_ABI __sf_result<float> __assoc_laguerre(unsigned int, unsigned int, float) noexcept;
-} // namespace __math
-
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI float
-assoc_laguerref(unsigned int __n, unsigned int __m, float __x) noexcept {
- return __math::__assoc_laguerre(__n, __m, __x);
-}
+[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI float assoc_laguerref(unsigned int __n, unsigned int __m, float __x) noexcept;
#endif // _LIBCPP_STD_VER >= 17
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index cf88cbef159fa..daab723b8f2e3 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -9,8 +9,11 @@
#include <__config>
#include <__math/special_functions.h>
#include <boost/math/special_functions.hpp>
+#include <cerrno>
+#include <cfenv>
#include <cmath>
#include <limits>
+#include <math.h>
#include <optional>
#include <type_traits>
@@ -18,7 +21,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
#if _LIBCPP_STD_VER >= 17
-namespace __math {
namespace {
template <class _Ret>
std::optional<_Ret> __check_nan() {
@@ -34,22 +36,27 @@ std::optional<_Ret> __check_nan(_Arg __arg, _Args... __args) {
}
template <class _Func, class... _Args, class _Ret = std::invoke_result_t<_Func, _Args...>>
-__sf_result<_Ret> __invoke_boost_math(_Func __f, _Args... __args) {
+_Ret __invoke_boost_math(_Func __f, _Args... __args) {
if (auto __maybe_nan = __check_nan<_Ret>(__args...); __maybe_nan.has_value())
- return {false, *__maybe_nan};
+ return *__maybe_nan;
try {
- return {false, __f(__args...)};
+ return __f(__args...);
} catch (...) {
- return {true, std::numeric_limits<_Ret>::quiet_NaN()};
+# if math_errhandling & MATH_ERRNO
+ errno = EDOM;
+# endif
+# if math_errhandling & MATH_ERREXCEPT
+ feraiseexcept(FE_INVALID);
+# endif
+ return std::numeric_limits<_Ret>::quiet_NaN();
}
}
} // namespace
-__sf_result<float> __assoc_laguerre(unsigned int __n, unsigned int __m, float __x) noexcept {
+float assoc_laguerref(unsigned int __n, unsigned int __m, float __x) noexcept {
return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
}
-} // namespace __math
#endif
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
>From f2580f1f2e853e83db75462c95558cbfeef6508c Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 27 Jun 2026 11:29:35 +0200
Subject: [PATCH 22/72] TU: cleanups
---
libcxx/src/mathematical_special_functions.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index daab723b8f2e3..420e0a1e71cb0 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -13,7 +13,6 @@
#include <cfenv>
#include <cmath>
#include <limits>
-#include <math.h>
#include <optional>
#include <type_traits>
@@ -47,7 +46,7 @@ _Ret __invoke_boost_math(_Func __f, _Args... __args) {
errno = EDOM;
# endif
# if math_errhandling & MATH_ERREXCEPT
- feraiseexcept(FE_INVALID);
+ std::feraiseexcept(FE_INVALID);
# endif
return std::numeric_limits<_Ret>::quiet_NaN();
}
>From 80f81ae52610bc7accc38605524fdbf872004e4f Mon Sep 17 00:00:00 2001
From: Paul <a at a.a>
Date: Sun, 28 Jun 2026 16:31:15 +0200
Subject: [PATCH 23/72] use boost errno_on_error policy instead of exceptions
---
libcxx/src/mathematical_special_functions.cpp | 44 +++++++++++++++----
1 file changed, 35 insertions(+), 9 deletions(-)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index 420e0a1e71cb0..f8fea7ff1b70e 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -8,19 +8,31 @@
#include <__config>
#include <__math/special_functions.h>
-#include <boost/math/special_functions.hpp>
#include <cerrno>
#include <cfenv>
#include <cmath>
-#include <limits>
#include <optional>
#include <type_traits>
+#define BOOST_MATH_NO_EXCEPTIONS
+#include <boost/math/special_functions.hpp>
+
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
#if _LIBCPP_STD_VER >= 17
namespace {
+// Error policy for all Boost.Math calls: report domain/pole/overflow/evaluation
+// errors via errno (errno_on_error) instead of throwing. Boost sets errno to
+// EDOM (domain/pole/evaluation) or ERANGE (overflow) and returns NaN/inf. The
+// remaining categories (underflow/denorm/indeterminate) default to ignore.
+namespace __bmp = boost::math::policies;
+using __policy =
+ __bmp::policy<__bmp::domain_error<__bmp::errno_on_error>,
+ __bmp::pole_error<__bmp::errno_on_error>,
+ __bmp::overflow_error<__bmp::errno_on_error>,
+ __bmp::evaluation_error<__bmp::errno_on_error>>;
+
template <class _Ret>
std::optional<_Ret> __check_nan() {
return std::nullopt;
@@ -34,22 +46,36 @@ std::optional<_Ret> __check_nan(_Arg __arg, _Args... __args) {
return __check_nan<_Ret>(__args...);
}
+// Shared back-end for the C++17 mathematical special functions ([sf.cmath]).
+// Boost.Math is the compute kernel; this wrapper enforces the standard's
+// error-reporting rules ([sf.cmath.general]):
+// 1. NaN argument -> return NaN, do NOT report a domain error (the
+// __check_nan pre-filter below).
+// 2. domain/range error -> report per <cmath> math_errhandling: errno = EDOM
+// (domain/pole) or ERANGE (overflow), done by Boost's errno_on_error
+// policy; and, when MATH_ERREXCEPT is set, raise the matching <cfenv>
+// exception (done here, since Boost never touches <cfenv>).
+// Promotion: Boost's default promote_float=true computes float inputs in double
+// and rounds once -- more accurate and overflow-resistant, matching the
+// existing std::hermite(float) approach. We keep it.
template <class _Func, class... _Args, class _Ret = std::invoke_result_t<_Func, _Args...>>
_Ret __invoke_boost_math(_Func __f, _Args... __args) {
if (auto __maybe_nan = __check_nan<_Ret>(__args...); __maybe_nan.has_value())
return *__maybe_nan;
- try {
- return __f(__args...);
- } catch (...) {
-# if math_errhandling & MATH_ERRNO
- errno = EDOM;
+# if math_errhandling & MATH_ERREXCEPT
+ errno = 0;
# endif
+ _Ret __ret = __f(__args..., __policy{});
+ // Boost set errno via the policy; mirror it onto <cfenv>:
+ // EDOM (domain/pole) -> FE_INVALID, ERANGE (overflow) -> FE_OVERFLOW.
# if math_errhandling & MATH_ERREXCEPT
+ if (errno == EDOM)
std::feraiseexcept(FE_INVALID);
+ else if (errno == ERANGE)
+ std::feraiseexcept(FE_OVERFLOW);
# endif
- return std::numeric_limits<_Ret>::quiet_NaN();
- }
+ return __ret;
}
} // namespace
>From 2c13b0df2188c488e3f2fe235ba22569419e0e5b Mon Sep 17 00:00:00 2001
From: Paul <a at a.a>
Date: Sun, 28 Jun 2026 16:44:35 +0200
Subject: [PATCH 24/72] TU: remove fenv support.
---
libcxx/src/mathematical_special_functions.cpp | 25 +++++--------------
1 file changed, 6 insertions(+), 19 deletions(-)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index f8fea7ff1b70e..3c0af96fb0c19 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -8,8 +8,6 @@
#include <__config>
#include <__math/special_functions.h>
-#include <cerrno>
-#include <cfenv>
#include <cmath>
#include <optional>
#include <type_traits>
@@ -51,10 +49,11 @@ std::optional<_Ret> __check_nan(_Arg __arg, _Args... __args) {
// error-reporting rules ([sf.cmath.general]):
// 1. NaN argument -> return NaN, do NOT report a domain error (the
// __check_nan pre-filter below).
-// 2. domain/range error -> report per <cmath> math_errhandling: errno = EDOM
-// (domain/pole) or ERANGE (overflow), done by Boost's errno_on_error
-// policy; and, when MATH_ERREXCEPT is set, raise the matching <cfenv>
-// exception (done here, since Boost never touches <cfenv>).
+// 2. domain/range error -> reported via errno only: Boost's errno_on_error
+// policy sets errno = EDOM (domain/pole/evaluation) or ERANGE (overflow).
+// The <cfenv> floating-point-exception side of math_errhandling
+// (MATH_ERREXCEPT) is intentionally not mirrored, matching the shipped
+// std::hermite and libstdc++'s special-function implementations.
// Promotion: Boost's default promote_float=true computes float inputs in double
// and rounds once -- more accurate and overflow-resistant, matching the
// existing std::hermite(float) approach. We keep it.
@@ -63,19 +62,7 @@ _Ret __invoke_boost_math(_Func __f, _Args... __args) {
if (auto __maybe_nan = __check_nan<_Ret>(__args...); __maybe_nan.has_value())
return *__maybe_nan;
-# if math_errhandling & MATH_ERREXCEPT
- errno = 0;
-# endif
- _Ret __ret = __f(__args..., __policy{});
- // Boost set errno via the policy; mirror it onto <cfenv>:
- // EDOM (domain/pole) -> FE_INVALID, ERANGE (overflow) -> FE_OVERFLOW.
-# if math_errhandling & MATH_ERREXCEPT
- if (errno == EDOM)
- std::feraiseexcept(FE_INVALID);
- else if (errno == ERANGE)
- std::feraiseexcept(FE_OVERFLOW);
-# endif
- return __ret;
+ return __f(__args..., __policy{});
}
} // namespace
>From 580076b2ffe777b1f00d844091f88ebd03820402 Mon Sep 17 00:00:00 2001
From: Paul <a at a.a>
Date: Sun, 28 Jun 2026 17:24:36 +0200
Subject: [PATCH 25/72] test: add more tests; fix header includes
---
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index eb747efb4c1c6..079751321f3b9 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -14,11 +14,11 @@
// float assoc_laguerref(unsigned n, unsigned m, float x);
#include <cassert>
-#include <cerrno>
-#include <cfenv>
#include <cmath>
+#include <limits>
#include "common.h"
+#include "test_macros.h"
#include "type_algorithms.h"
struct TestFloatingPoint {
@@ -32,9 +32,19 @@ struct TestFloatingPoint {
assert(std::abs(std::assoc_laguerref(2, 10, 0.5f) - 60.125f) < 0.001f);
+ // m == 0 reduces to the ordinary Laguerre polynomial: L_2(2) = (4 - 8 + 2) / 2 = -1.
+ assert(between(-1.01f, std::assoc_laguerref(2, 0, T(2.)), -0.99f));
+
static_assert(std::is_same_v<decltype(std::assoc_laguerref(0, 0, T(0.))), float>);
+ // noexcept is a libc++ extension here ([sf.cmath] does not mandate it), so use the libc++-only assertion.
+ LIBCPP_ASSERT_NOEXCEPT(std::assoc_laguerref(0, 0, T(0.)));
+
check_no_domain_error([] { (void)std::assoc_laguerref(0, 0, std::numeric_limits<T>::quiet_NaN()); });
+
+ // The associated Laguerre polynomials are defined for all real x: a negative
+ // argument is in-domain and must not report a domain error. L_1^0(-1) = 1 - x = 2.
+ check_no_domain_error([] { assert(between(1.99f, std::assoc_laguerref(1, 0, -1.f), 2.01f)); });
}
};
>From 2a6dfd4ae296d0f89e1ea5bc953d7d5f8f536ca9 Mon Sep 17 00:00:00 2001
From: Paul <a at a.a>
Date: Sun, 28 Jun 2026 17:53:16 +0200
Subject: [PATCH 26/72] test: add noexcept.compile.pass test
---
.../c.math/sf.cmath/noexcept.compile.pass.cpp | 20 +++++++++++++++++++
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 3 ---
2 files changed, 20 insertions(+), 3 deletions(-)
create mode 100644 libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
new file mode 100644
index 0000000000000..9994e6a018f8d
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// Check that functions are marked noexcept
+
+#include <cmath>
+
+#include "test_macros.h"
+
+void test() {
+ // assoc_laguerre
+ ASSERT_NOEXCEPT(std::assoc_laguerref(0, 0, 0.0f));
+}
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index 079751321f3b9..068ca81e04b83 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -37,9 +37,6 @@ struct TestFloatingPoint {
static_assert(std::is_same_v<decltype(std::assoc_laguerref(0, 0, T(0.))), float>);
- // noexcept is a libc++ extension here ([sf.cmath] does not mandate it), so use the libc++-only assertion.
- LIBCPP_ASSERT_NOEXCEPT(std::assoc_laguerref(0, 0, T(0.)));
-
check_no_domain_error([] { (void)std::assoc_laguerref(0, 0, std::numeric_limits<T>::quiet_NaN()); });
// The associated Laguerre polynomials are defined for all real x: a negative
>From 7b8204c6a252f2971f288212096aee6641c14d82 Mon Sep 17 00:00:00 2001
From: Paul <a at a.a>
Date: Sun, 28 Jun 2026 17:55:16 +0200
Subject: [PATCH 27/72] test: cleanup
---
.../test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
index 7928ebf50681a..a4c471e4b3168 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
@@ -15,6 +15,6 @@
void test() {
// clang-format off
// assoc_laguerre
- std::assoc_laguerref(0, 0, 0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerref(0, 0, 0.0f); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
// clang-format on
}
>From 82d264a4bc5a0a1f6d4c932b97b4a74c11957fac Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 28 Jun 2026 23:37:36 +0200
Subject: [PATCH 28/72] test: remove fenv support
---
libcxx/test/std/numerics/c.math/sf.cmath/common.h | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/common.h b/libcxx/test/std/numerics/c.math/sf.cmath/common.h
index 867e6af6f6914..723422bf7038d 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/common.h
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/common.h
@@ -12,8 +12,6 @@
#include <cassert>
#include <cerrno>
#include <cmath>
-#include <math.h>
-#include <cfenv>
// std::type_identity is C++20 (we need to support C++17 here)
template <class T>
@@ -32,34 +30,22 @@ template <class Func>
void check_no_domain_error(Func f) {
#if math_errhandling & MATH_ERRNO
errno = EACCES;
-#endif
-#if math_errhandling & MATH_ERREXCEPT
- std::feclearexcept(FE_INVALID);
#endif
f();
#if math_errhandling & MATH_ERRNO
assert(errno == EACCES);
#endif
-#if math_errhandling & MATH_ERREXCEPT
- assert(!std::fetestexcept(FE_INVALID));
-#endif
}
template <class Func>
void check_domain_error(Func f) {
#if math_errhandling & MATH_ERRNO
errno = EACCES;
-#endif
-#if math_errhandling & MATH_ERREXCEPT
- std::feclearexcept(FE_INVALID);
#endif
f();
#if math_errhandling & MATH_ERRNO
assert(errno == EDOM);
#endif
-#if math_errhandling & MATH_ERREXCEPT
- assert(std::fetestexcept(FE_INVALID));
-#endif
}
#endif // TEST_SF_CMATH_COMMON_H
>From 6b65307f26de7474c6b3f6789c8bd49e9b9787d7 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 28 Jun 2026 23:37:54 +0200
Subject: [PATCH 29/72] test: cleanups + more NaN tests
---
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 28 ++++++++++---------
1 file changed, 15 insertions(+), 13 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index 068ca81e04b83..fffbb72557a5a 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -18,30 +18,32 @@
#include <limits>
#include "common.h"
-#include "test_macros.h"
#include "type_algorithms.h"
struct TestFloatingPoint {
template <class T>
void operator()() const {
+ // sample value testing
assert(between(0.99f, std::assoc_laguerref(0, 0, T(0.)), 1.01f));
-
assert(between(0.99f, std::assoc_laguerref(1, 1, T(1.)), 1.01f));
-
- assert(between(-0.01f, std::assoc_laguerref(2, 2, T(2.)), 0.01f));
-
- assert(std::abs(std::assoc_laguerref(2, 10, 0.5f) - 60.125f) < 0.001f);
-
- // m == 0 reduces to the ordinary Laguerre polynomial: L_2(2) = (4 - 8 + 2) / 2 = -1.
assert(between(-1.01f, std::assoc_laguerref(2, 0, T(2.)), -0.99f));
+ assert(between(-0.01f, std::assoc_laguerref(2, 2, T(2.)), 0.01f));
+ assert(between(60.124f, std::assoc_laguerref(2, 10, T(0.5)), 60.126f));
+ // return type: float
static_assert(std::is_same_v<decltype(std::assoc_laguerref(0, 0, T(0.))), float>);
- check_no_domain_error([] { (void)std::assoc_laguerref(0, 0, std::numeric_limits<T>::quiet_NaN()); });
-
- // The associated Laguerre polynomials are defined for all real x: a negative
- // argument is in-domain and must not report a domain error. L_1^0(-1) = 1 - x = 2.
- check_no_domain_error([] { assert(between(1.99f, std::assoc_laguerref(1, 0, -1.f), 2.01f)); });
+ // NaN input -> NaN output (w/o domain error)
+ auto check_nan = [](T nan) {
+ check_no_domain_error([nan] { assert(std::isnan(std::assoc_laguerref(0, 0, nan))); });
+ };
+ if (std::numeric_limits<T>::has_quiet_NaN)
+ check_nan(std::numeric_limits<T>::quiet_NaN());
+ if (std::numeric_limits<T>::has_signaling_NaN)
+ check_nan(std::numeric_limits<T>::signaling_NaN());
+
+ // negative x: no domain error
+ check_no_domain_error([] { assert(between(1.99f, std::assoc_laguerref(1, 0, T(-1)), 2.01f)); });
}
};
>From ddd4eef0a09edb02e8e486fb587bf5e64d538b65 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 00:00:33 +0200
Subject: [PATCH 30/72] impl assoc_laguerrel
---
libcxx/include/__math/special_functions.h | 1 +
libcxx/src/mathematical_special_functions.cpp | 5 +++++
2 files changed, 6 insertions(+)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 89c75cfc04585..0cfd484955b15 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -27,6 +27,7 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
// assoc_laguerre
[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI float assoc_laguerref(unsigned int __n, unsigned int __m, float __x) noexcept;
+[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI long double assoc_laguerrel(unsigned int __n, unsigned int __m, long double __x) noexcept;
#endif // _LIBCPP_STD_VER >= 17
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index 3c0af96fb0c19..980af019748db 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -66,10 +66,15 @@ _Ret __invoke_boost_math(_Func __f, _Args... __args) {
}
} // namespace
+// assoc_laguerre
float assoc_laguerref(unsigned int __n, unsigned int __m, float __x) noexcept {
return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
}
+long double assoc_laguerrel(unsigned int __n, unsigned int __m, long double __x) noexcept {
+ return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
+}
+
#endif
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
>From a35b978e0601bea7a9accf072c175a4c8b182c97 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 00:23:48 +0200
Subject: [PATCH 31/72] test: assoc_laguerrel
---
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 78 ++++++++-----------
1 file changed, 34 insertions(+), 44 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index fffbb72557a5a..0a9abaf2f4f24 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -9,54 +9,44 @@
// REQUIRES: std-at-least-c++17
// <cmath>
-//
-// [sf.cmath.assoc.laguerre], associated Laguerre polynomials
-// float assoc_laguerref(unsigned n, unsigned m, float x);
+
+// float assoc_laguerref(unsigned n, unsigned m, float x);
+// long double assoc_laguerrel(unsigned n, unsigned m, long double x);
#include <cassert>
#include <cmath>
#include <limits>
#include "common.h"
-#include "type_algorithms.h"
-
-struct TestFloatingPoint {
- template <class T>
- void operator()() const {
- // sample value testing
- assert(between(0.99f, std::assoc_laguerref(0, 0, T(0.)), 1.01f));
- assert(between(0.99f, std::assoc_laguerref(1, 1, T(1.)), 1.01f));
- assert(between(-1.01f, std::assoc_laguerref(2, 0, T(2.)), -0.99f));
- assert(between(-0.01f, std::assoc_laguerref(2, 2, T(2.)), 0.01f));
- assert(between(60.124f, std::assoc_laguerref(2, 10, T(0.5)), 60.126f));
-
- // return type: float
- static_assert(std::is_same_v<decltype(std::assoc_laguerref(0, 0, T(0.))), float>);
-
- // NaN input -> NaN output (w/o domain error)
- auto check_nan = [](T nan) {
- check_no_domain_error([nan] { assert(std::isnan(std::assoc_laguerref(0, 0, nan))); });
- };
- if (std::numeric_limits<T>::has_quiet_NaN)
- check_nan(std::numeric_limits<T>::quiet_NaN());
- if (std::numeric_limits<T>::has_signaling_NaN)
- check_nan(std::numeric_limits<T>::signaling_NaN());
-
- // negative x: no domain error
- check_no_domain_error([] { assert(between(1.99f, std::assoc_laguerref(1, 0, T(-1)), 2.01f)); });
- }
-};
-
-struct TestIntegral {
- template <class T>
- void operator()() const {
- assert(between(0.99f, std::assoc_laguerref(0, 0, T(0.)), 1.01f));
-
- static_assert(std::is_same_v<decltype(std::assoc_laguerref(0, 0, T(0.))), float>);
- }
-};
-
-int main() {
- types::for_each(types::floating_point_types{}, TestFloatingPoint{});
- types::for_each(types::integral_types{}, TestIntegral{});
+
+// Each suffixed overload is fixed to a single floating-point type, so it is
+// tested directly with that type. The unsuffixed std::assoc_laguerre overloads
+// (and the integer-argument overload) are not implemented yet.
+template <class T, class Func>
+void test(Func assoc_laguerre) {
+ // sample values
+ assert(between(0.99, assoc_laguerre(0, 0, T(0)), 1.01));
+ assert(between(0.99, assoc_laguerre(1, 1, T(1)), 1.01));
+ assert(between(-1.01, assoc_laguerre(2, 0, T(2)), -0.99));
+ assert(between(-0.01, assoc_laguerre(2, 2, T(2)), 0.01));
+ assert(between(60.124, assoc_laguerre(2, 10, T(0.5)), 60.126));
+
+ static_assert(std::is_same_v<decltype(assoc_laguerre(0, 0, T(0))), T>);
+
+ // NaN argument -> NaN result, without a domain error ([sf.cmath.general]/1).
+ auto test_nan = [&](T nan) { check_no_domain_error([&] { assert(std::isnan(assoc_laguerre(0, 0, nan))); }); };
+ if (std::numeric_limits<T>::has_quiet_NaN)
+ test_nan(std::numeric_limits<T>::quiet_NaN());
+ if (std::numeric_limits<T>::has_signaling_NaN)
+ test_nan(std::numeric_limits<T>::signaling_NaN());
+
+ // A negative argument is in the domain (no domain error).
+ check_no_domain_error([&] { assert(between(1.99, assoc_laguerre(1, 0, T(-1)), 2.01)); });
}
+
+int main(int, char**) {
+ test<float>([](unsigned __n, unsigned __m, float __x) { return std::assoc_laguerref(__n, __m, __x); });
+ test<long double>([](unsigned __n, unsigned __m, long double __x) { return std::assoc_laguerrel(__n, __m, __x); });
+
+ return 0;
+}
\ No newline at end of file
>From 96e8004c4a6f41343f1257898d04efbbd01f6457 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 21:43:26 +0200
Subject: [PATCH 32/72] re-introduce __math::__assoc_laguerre -> only ABI
export internal API
---
libcxx/include/__math/special_functions.h | 16 ++++++++++++++--
libcxx/src/mathematical_special_functions.cpp | 7 +++++--
2 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 0cfd484955b15..62ae09594bea3 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -11,6 +11,7 @@
#define _LIBCPP___MATH_SPECIAL_FUNCTIONS_H
#include <__config>
+#include <__configuration/attributes.h>
#include <__math/copysign.h>
#include <__math/traits.h>
#include <__type_traits/enable_if.h>
@@ -26,8 +27,19 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
#if _LIBCPP_STD_VER >= 17
// assoc_laguerre
-[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI float assoc_laguerref(unsigned int __n, unsigned int __m, float __x) noexcept;
-[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI long double assoc_laguerrel(unsigned int __n, unsigned int __m, long double __x) noexcept;
+namespace __math {
+[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI float __assoc_laguerre(unsigned, unsigned, float) noexcept;
+[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI long double __assoc_laguerre(unsigned, unsigned, long double) noexcept;
+} // namespace __math
+
+[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI float assoc_laguerref(unsigned __n, unsigned __m, float __x) noexcept {
+ return __math::__assoc_laguerre(__n, __m, __x);
+}
+
+[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI long double
+assoc_laguerrel(unsigned __n, unsigned __m, long double __x) noexcept {
+ return __math::__assoc_laguerre(__n, __m, __x);
+}
#endif // _LIBCPP_STD_VER >= 17
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index 980af019748db..ed8109c7e482c 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -19,6 +19,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
#if _LIBCPP_STD_VER >= 17
+namespace __math {
namespace {
// Error policy for all Boost.Math calls: report domain/pole/overflow/evaluation
// errors via errno (errno_on_error) instead of throwing. Boost sets errno to
@@ -67,14 +68,16 @@ _Ret __invoke_boost_math(_Func __f, _Args... __args) {
} // namespace
// assoc_laguerre
-float assoc_laguerref(unsigned int __n, unsigned int __m, float __x) noexcept {
+float __assoc_laguerre(unsigned __n, unsigned __m, float __x) noexcept {
return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
}
-long double assoc_laguerrel(unsigned int __n, unsigned int __m, long double __x) noexcept {
+long double __assoc_laguerre(unsigned __n, unsigned __m, long double __x) noexcept {
return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
}
+} // namespace __math
+
#endif
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
>From 34d62b1da4598efb45c79363654566b9ca6677aa Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 21:43:57 +0200
Subject: [PATCH 33/72] add exported ABI symbols to abilist
---
...-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist | 2 ++
...nux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist | 2 ++
...werpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist | 2 ++
...rpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist | 2 ++
...-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist | 2 ++
...nux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist | 2 ++
...known-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist | 2 ++
...own-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist | 4 +++-
...n-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist | 2 ++
9 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 74283373d1b65..7889109825e10 100644
--- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1700,6 +1700,8 @@
{'is_defined': True, 'name': '__ZNSt3__15wcoutE', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__itoa8__u64toaEyPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index 291149608c9c7..3e139e30496a6 100644
--- a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1338,6 +1338,8 @@
{'is_defined': True, 'name': '_ZNSt6__ndk16__clocEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u64toaEyPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index da6d608af462c..304817ba0cffb 100644
--- a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -686,6 +686,8 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEyPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12steady_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12system_clock11from_time_tEi', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12system_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 6ee31613d5320..d5e37635fa511 100644
--- a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -686,6 +686,8 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12steady_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12system_clock11from_time_tEl', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12system_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 92a37db24ac5f..a59b72d695b55 100644
--- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1690,6 +1690,8 @@
{'is_defined': True, 'name': '__ZNSt3__15wcoutE', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__itoa8__u64toaEyPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index 7b09d3dd3f75c..abef314dc14f4 100644
--- a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1338,6 +1338,8 @@
{'is_defined': True, 'name': '_ZNSt6__ndk16__clocEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u64toaEmPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
index 725ed669fb561..86bc3dec5bd34 100644
--- a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1350,6 +1350,8 @@
{'is_defined': True, 'name': '_ZNSt3__15wcoutE', 'size': 160, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
index 717d4c9bee726..11330e7eaf442 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1349,6 +1349,8 @@
{'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -2030,4 +2032,4 @@
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD0Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}
\ No newline at end of file
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
index 45db143b4cf4a..460bd21a2fecf 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
@@ -1320,6 +1320,8 @@
{'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
>From 7e1ed83abf9818cb95663ed9077215f102873666 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 22:10:37 +0200
Subject: [PATCH 34/72] impl std::assoc_laguerre(double)
---
libcxx/include/__math/special_functions.h | 6 ++++++
libcxx/src/mathematical_special_functions.cpp | 4 ++++
2 files changed, 10 insertions(+)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 782e441562c00..8fd363919e5cc 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -30,6 +30,7 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
// assoc_laguerre
namespace __math {
[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI float __assoc_laguerre(unsigned, unsigned, float) noexcept;
+[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI double __assoc_laguerre(unsigned, unsigned, double) noexcept;
[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI long double __assoc_laguerre(unsigned, unsigned, long double) noexcept;
} // namespace __math
@@ -37,6 +38,11 @@ namespace __math {
return __math::__assoc_laguerre(__n, __m, __x);
}
+template <class = int>
+_LIBCPP_HIDE_FROM_ABI double assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
+ return __math::__assoc_laguerre(__n, __m, __x);
+}
+
[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI long double
assoc_laguerrel(unsigned __n, unsigned __m, long double __x) noexcept {
return __math::__assoc_laguerre(__n, __m, __x);
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index ed8109c7e482c..0f6e3a850ad73 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -72,6 +72,10 @@ float __assoc_laguerre(unsigned __n, unsigned __m, float __x) noexcept {
return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
}
+double __assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
+ return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
+}
+
long double __assoc_laguerre(unsigned __n, unsigned __m, long double __x) noexcept {
return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
}
>From 8b1f5f6ded44a8cbd009c03310faa645d320bb97 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 22:20:15 +0200
Subject: [PATCH 35/72] fixup impl std::assoc_laguerre(double)
---
libcxx/include/__math/special_functions.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 8fd363919e5cc..b48b9ffdb129c 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -39,7 +39,7 @@ namespace __math {
}
template <class = int>
-_LIBCPP_HIDE_FROM_ABI double assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI double assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
return __math::__assoc_laguerre(__n, __m, __x);
}
>From fbbd70784b3e8bc65aa5e3b18870d936ea438e2e Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 22:43:07 +0200
Subject: [PATCH 36/72] fixup: assoc_laguerre(dbl)
---
libcxx/include/__math/special_functions.h | 3 +--
.../std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp | 6 +++---
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index b48b9ffdb129c..20268dd1bd7d6 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -38,8 +38,7 @@ namespace __math {
return __math::__assoc_laguerre(__n, __m, __x);
}
-template <class = int>
-[[nodiscard]] _LIBCPP_HIDE_FROM_ABI double assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
+[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI double assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
return __math::__assoc_laguerre(__n, __m, __x);
}
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index 0a9abaf2f4f24..b9223f6d66a2c 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -19,9 +19,9 @@
#include "common.h"
-// Each suffixed overload is fixed to a single floating-point type, so it is
-// tested directly with that type. The unsuffixed std::assoc_laguerre overloads
-// (and the integer-argument overload) are not implemented yet.
+// Each overload is fixed to a single floating-point type, so it is tested
+// directly with that type. The integer-argument overload
+// (assoc_laguerre(unsigned, unsigned, Integer) -> double) is not implemented yet.
template <class T, class Func>
void test(Func assoc_laguerre) {
// sample values
>From 7f5e5515ad7c1e551ff1b7cecf57772211f3b376 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 22:12:00 +0200
Subject: [PATCH 37/72] test: general cleanups
---
.../std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index b9223f6d66a2c..d446e017494c4 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -45,8 +45,8 @@ void test(Func assoc_laguerre) {
}
int main(int, char**) {
- test<float>([](unsigned __n, unsigned __m, float __x) { return std::assoc_laguerref(__n, __m, __x); });
- test<long double>([](unsigned __n, unsigned __m, long double __x) { return std::assoc_laguerrel(__n, __m, __x); });
+ test<float>([](unsigned n, unsigned m, float x) { return std::assoc_laguerref(n, m, x); });
+ test<long double>([](unsigned n, unsigned m, long double x) { return std::assoc_laguerrel(n, m, x); });
return 0;
-}
\ No newline at end of file
+}
>From 340ed9ca7b9f543fd3ffa8110f29863dc7fcef4f Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 22:14:47 +0200
Subject: [PATCH 38/72] test: std::assoc_laguerre(double)
---
.../test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index d446e017494c4..9c2bc2026a348 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -10,6 +10,7 @@
// <cmath>
+// double assoc_laguerre(unsigned n, unsigned m, double x);
// float assoc_laguerref(unsigned n, unsigned m, float x);
// long double assoc_laguerrel(unsigned n, unsigned m, long double x);
@@ -45,6 +46,8 @@ void test(Func assoc_laguerre) {
}
int main(int, char**) {
+ test<double>([](unsigned n, unsigned m, double x) { return std::assoc_laguerre(n, m, x); });
+
test<float>([](unsigned n, unsigned m, float x) { return std::assoc_laguerref(n, m, x); });
test<long double>([](unsigned n, unsigned m, long double x) { return std::assoc_laguerrel(n, m, x); });
>From 589d01b5fce70f06068b3304556145bc1c284ebe Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 22:20:51 +0200
Subject: [PATCH 39/72] test: nodiscard/noexcept for assoc_laguerre(double),
assoc_laguerrel
---
.../test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp | 3 +++
.../libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp | 3 +++
2 files changed, 6 insertions(+)
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
index a4c471e4b3168..8b8826d03de01 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
@@ -15,6 +15,9 @@
void test() {
// clang-format off
// assoc_laguerre
+ std::assoc_laguerre(0, 0, 0.0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
std::assoc_laguerref(0, 0, 0.0f); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerrel(0, 0, 0.0l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
// clang-format on
}
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
index 9994e6a018f8d..70984fc0c83bf 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
@@ -16,5 +16,8 @@
void test() {
// assoc_laguerre
+ ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0));
+
ASSERT_NOEXCEPT(std::assoc_laguerref(0, 0, 0.0f));
+ ASSERT_NOEXCEPT(std::assoc_laguerrel(0, 0, 0.0l));
}
>From db297e6b6a155fdd5ea0bb4978f5e267c14a773e Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 22:42:41 +0200
Subject: [PATCH 40/72] add ABI symbol to abilist for assoc_laguerre(double)
---
...m64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
...-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
.../powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
...owerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
..._64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
...-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
...-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
...nknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
...nown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist | 1 +
9 files changed, 9 insertions(+)
diff --git a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 6ab143c0113f3..9f70dd6550fc7 100644
--- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1701,6 +1701,7 @@
{'is_defined': True, 'name': '__ZNSt3__15wcoutE', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__itoa8__u64toaEyPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index 08d42d44e4827..4152a583ec5a3 100644
--- a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1339,6 +1339,7 @@
{'is_defined': True, 'name': '_ZNSt6__ndk16__clocEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u64toaEyPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 98fd189eaa3f7..861750f606c77 100644
--- a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -687,6 +687,7 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEyPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12steady_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 9e1db57fc315b..347d9f9f23d70 100644
--- a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -687,6 +687,7 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12steady_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index a59b72d695b55..cd3f3e4fda9a2 100644
--- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1690,6 +1690,7 @@
{'is_defined': True, 'name': '__ZNSt3__15wcoutE', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__itoa8__u64toaEyPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index 61bd10d997a1b..421f4839f762e 100644
--- a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1339,6 +1339,7 @@
{'is_defined': True, 'name': '_ZNSt6__ndk16__clocEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u64toaEmPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
index 286ad56406ee2..d59e224c42922 100644
--- a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1351,6 +1351,7 @@
{'is_defined': True, 'name': '_ZNSt3__15wcoutE', 'size': 160, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
index 9fd2edf63e6ef..d2b084bace550 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1350,6 +1350,7 @@
{'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
index 51c27fea37ce9..7e57931398e85 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
@@ -1321,6 +1321,7 @@
{'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
>From e8984b706592b5b2ff08bdd19020330498423157 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 23:12:02 +0200
Subject: [PATCH 41/72] impl assoc_laguerre(Int)
---
libcxx/include/__math/special_functions.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 20268dd1bd7d6..5021e5a54b634 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -47,6 +47,11 @@ assoc_laguerrel(unsigned __n, unsigned __m, long double __x) noexcept {
return __math::__assoc_laguerre(__n, __m, __x);
}
+template <class _Int, std::enable_if_t<std::is_integral_v<_Int>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI double assoc_laguerre(unsigned __n, unsigned __m, _Int __x) noexcept {
+ return __math::__assoc_laguerre(__n, __m, static_cast<double>(__x));
+}
+
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
// hermite
>From c8c5eb6a2040040b6a5c67c42128172a4c5661a8 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 23:18:00 +0200
Subject: [PATCH 42/72] test: nodiscard/except assoc_laguerre(Int)
---
.../numerics/c.math/sf.cmath/nodiscard.verify.cpp | 1 +
.../numerics/c.math/sf.cmath/noexcept.compile.pass.cpp | 10 ++++++++++
2 files changed, 11 insertions(+)
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
index 8b8826d03de01..b83070f4f984d 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
@@ -16,6 +16,7 @@ void test() {
// clang-format off
// assoc_laguerre
std::assoc_laguerre(0, 0, 0.0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerre(0, 0, 0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::assoc_laguerref(0, 0, 0.0f); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::assoc_laguerrel(0, 0, 0.0l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
index 70984fc0c83bf..cca9c1e924a8c 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
@@ -13,6 +13,14 @@
#include <cmath>
#include "test_macros.h"
+#include "type_algorithms.h"
+
+struct TestIntegral {
+ template <class T>
+ void operator()() const {
+ ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, T{}));
+ }
+};
void test() {
// assoc_laguerre
@@ -20,4 +28,6 @@ void test() {
ASSERT_NOEXCEPT(std::assoc_laguerref(0, 0, 0.0f));
ASSERT_NOEXCEPT(std::assoc_laguerrel(0, 0, 0.0l));
+
+ types::for_each(types::integral_types{}, TestIntegral{});
}
>From 5946b7d3c07ea7f4dc898e9750313838fd3a99a8 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 29 Jun 2026 23:19:29 +0200
Subject: [PATCH 43/72] wip: test: assoc_laguerre(Int)
---
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 48 ++++++++++++-------
1 file changed, 32 insertions(+), 16 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index 9c2bc2026a348..b39e20fe6288a 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -17,39 +17,55 @@
#include <cassert>
#include <cmath>
#include <limits>
+#include <type_traits>
#include "common.h"
+#include "type_algorithms.h"
// Each overload is fixed to a single floating-point type, so it is tested
// directly with that type. The integer-argument overload
// (assoc_laguerre(unsigned, unsigned, Integer) -> double) is not implemented yet.
-template <class T, class Func>
+template <class ExpectedFuncRet, class FuncArgX, class Func>
void test(Func assoc_laguerre) {
// sample values
- assert(between(0.99, assoc_laguerre(0, 0, T(0)), 1.01));
- assert(between(0.99, assoc_laguerre(1, 1, T(1)), 1.01));
- assert(between(-1.01, assoc_laguerre(2, 0, T(2)), -0.99));
- assert(between(-0.01, assoc_laguerre(2, 2, T(2)), 0.01));
- assert(between(60.124, assoc_laguerre(2, 10, T(0.5)), 60.126));
+ assert(between(0.99, assoc_laguerre(0, 0, FuncArgX(0)), 1.01));
+ assert(between(0.99, assoc_laguerre(1, 1, FuncArgX(1)), 1.01));
+ assert(between(-1.01, assoc_laguerre(2, 0, FuncArgX(2)), -0.99));
+ assert(between(-0.01, assoc_laguerre(2, 2, FuncArgX(2)), 0.01));
+ if constexpr (std::is_floating_point_v<FuncArgX>)
+ assert(between(60.124, assoc_laguerre(2, 10, FuncArgX(0.5)), 60.126));
- static_assert(std::is_same_v<decltype(assoc_laguerre(0, 0, T(0))), T>);
+ static_assert(std::is_same_v<decltype(assoc_laguerre(0, 0, FuncArgX(0))), ExpectedFuncRet>);
// NaN argument -> NaN result, without a domain error ([sf.cmath.general]/1).
- auto test_nan = [&](T nan) { check_no_domain_error([&] { assert(std::isnan(assoc_laguerre(0, 0, nan))); }); };
- if (std::numeric_limits<T>::has_quiet_NaN)
- test_nan(std::numeric_limits<T>::quiet_NaN());
- if (std::numeric_limits<T>::has_signaling_NaN)
- test_nan(std::numeric_limits<T>::signaling_NaN());
+ if constexpr (std::is_floating_point_v<FuncArgX>) {
+ auto test_nan = [&](FuncArgX nan) {
+ check_no_domain_error([&] { assert(std::isnan(assoc_laguerre(0, 0, nan))); });
+ };
+ if (std::numeric_limits<FuncArgX>::has_quiet_NaN)
+ test_nan(std::numeric_limits<FuncArgX>::quiet_NaN());
+ if (std::numeric_limits<FuncArgX>::has_signaling_NaN)
+ test_nan(std::numeric_limits<FuncArgX>::signaling_NaN());
+ }
// A negative argument is in the domain (no domain error).
- check_no_domain_error([&] { assert(between(1.99, assoc_laguerre(1, 0, T(-1)), 2.01)); });
+ check_no_domain_error([&] { assert(between(1.99, assoc_laguerre(1, 0, FuncArgX(-1)), 2.01)); });
}
+struct TestIntegral {
+ template <class Int>
+ void operator()() const {
+ test<double, Int>([](unsigned n, unsigned m, Int x) { return std::assoc_laguerre(n, m, x); });
+ }
+};
+
int main(int, char**) {
- test<double>([](unsigned n, unsigned m, double x) { return std::assoc_laguerre(n, m, x); });
+ test<double, double>([](unsigned n, unsigned m, double x) { return std::assoc_laguerre(n, m, x); });
+
+ test<float, float>([](unsigned n, unsigned m, float x) { return std::assoc_laguerref(n, m, x); });
+ test<long double, long double>([](unsigned n, unsigned m, long double x) { return std::assoc_laguerrel(n, m, x); });
- test<float>([](unsigned n, unsigned m, float x) { return std::assoc_laguerref(n, m, x); });
- test<long double>([](unsigned n, unsigned m, long double x) { return std::assoc_laguerrel(n, m, x); });
+ // types::for_each(types::integral_types{}, TestIntegral{}); WIP
return 0;
}
>From 619773ba99f60f0d799ca98488fa71cc246e2c47 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 30 Jun 2026 17:48:09 +0200
Subject: [PATCH 44/72] fix gcc build: gcc defines __STDCPP_FLOATXX_T__ even
though we dont ship <stdfloat> yet -> breaks Boost
---
libcxx/src/mathematical_special_functions.cpp | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index 0f6e3a850ad73..b8e14967740f1 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -12,6 +12,22 @@
#include <optional>
#include <type_traits>
+// GCC defines __STDCPP_FLOATnn_T__ whenever the _Floatnn extended types exist at the
+// language level, independent of the standard library. libc++ currently ships no
+// <stdfloat>, so std::floatnn_t is never declared -- but Boost.Math keys its
+// std::floatnn_t overloads off these macros and would reference the missing types.
+// Suppress those overloads while <stdfloat> is unavailable. The __has_include guard is
+// the same condition Boost uses to include <stdfloat>, so this workaround disables itself
+// automatically once libc++ provides the header (the overloads then light up on their own
+// -- no manual re-enable needed here).
+#if !__has_include(<stdfloat>)
+# undef __STDCPP_FLOAT16_T__
+# undef __STDCPP_FLOAT32_T__
+# undef __STDCPP_FLOAT64_T__
+# undef __STDCPP_FLOAT128_T__
+# undef __STDCPP_BFLOAT16_T__
+#endif
+
#define BOOST_MATH_NO_EXCEPTIONS
#include <boost/math/special_functions.hpp>
>From 3c8e6c21dca99ac9b83fe264c70255710d20c21f Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 30 Jun 2026 18:01:47 +0200
Subject: [PATCH 45/72] fix android abilist
---
...linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index 421f4839f762e..08b901a94f394 100644
--- a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1340,8 +1340,8 @@
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u64toaEmPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjg', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
>From e4c48175cfc00429e93c92a30aa81e67201f4866 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 30 Jun 2026 18:02:21 +0200
Subject: [PATCH 46/72] fix boost math thread support
---
libcxx/src/mathematical_special_functions.cpp | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index b8e14967740f1..c37811bdf52ea 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -28,6 +28,14 @@
# undef __STDCPP_BFLOAT16_T__
#endif
+// Boost.Math detects thread support via __has_include(<thread>/<mutex>/...), but libc++
+// ships those headers even when threads are disabled (_LIBCPP_HAS_THREADS == 0), so the
+// detection wrongly enables std::mutex use and breaks on no-thread targets (e.g. picolibc).
+// Tell Boost there are no threads; lazy-init tables don't need locking without threads.
+#if !_LIBCPP_HAS_THREADS
+# define BOOST_MATH_DISABLE_THREADS
+#endif
+
#define BOOST_MATH_NO_EXCEPTIONS
#include <boost/math/special_functions.hpp>
>From 60635ce92abd69cad3a5161a78a5a2f55281d9b8 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 30 Jun 2026 21:47:33 +0200
Subject: [PATCH 47/72] test: fix apple's math_errhandling usage. runtime not
macro constant
---
.../std/numerics/c.math/sf.cmath/common.h | 23 +++++++++----------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/common.h b/libcxx/test/std/numerics/c.math/sf.cmath/common.h
index 723422bf7038d..ca6de9ea868bd 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/common.h
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/common.h
@@ -26,26 +26,25 @@ bool between(type_identity_t<T> lower, T value, type_identity_t<T> upper) {
return lower < value && value < upper;
}
+// Note: math_errhandling must be queried with a runtime `if`, not `#if`. On Apple
+// platforms it is defined as a function call (__math_errhandling()), so it is not a
+// preprocessor constant and would break `#if` under -Wundef.
template <class Func>
void check_no_domain_error(Func f) {
-#if math_errhandling & MATH_ERRNO
- errno = EACCES;
-#endif
+ if (math_errhandling & MATH_ERRNO)
+ errno = EACCES;
f();
-#if math_errhandling & MATH_ERRNO
- assert(errno == EACCES);
-#endif
+ if (math_errhandling & MATH_ERRNO)
+ assert(errno == EACCES);
}
template <class Func>
void check_domain_error(Func f) {
-#if math_errhandling & MATH_ERRNO
- errno = EACCES;
-#endif
+ if (math_errhandling & MATH_ERRNO)
+ errno = EACCES;
f();
-#if math_errhandling & MATH_ERRNO
- assert(errno == EDOM);
-#endif
+ if (math_errhandling & MATH_ERRNO)
+ assert(errno == EDOM);
}
#endif // TEST_SF_CMATH_COMMON_H
>From 8201618481b60722093b07eff23b8bcb3b274e05 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 30 Jun 2026 22:16:59 +0200
Subject: [PATCH 48/72] minimze boost includes
---
libcxx/src/mathematical_special_functions.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index c37811bdf52ea..dc046b3a845df 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -37,7 +37,7 @@
#endif
#define BOOST_MATH_NO_EXCEPTIONS
-#include <boost/math/special_functions.hpp>
+#include <boost/math/special_functions/laguerre.hpp>
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
>From 4d11bdbe96fca5653a71146ff3fea197180f13ef Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 30 Jun 2026 22:22:46 +0200
Subject: [PATCH 49/72] patch boost: make it compilable w/o localization
support
---
third-party/boost-math-libcxx.patch | 47 +++++++++++++++++++++++++++++
third-party/update_boost_math.sh | 10 ++++++
2 files changed, 57 insertions(+)
create mode 100644 third-party/boost-math-libcxx.patch
diff --git a/third-party/boost-math-libcxx.patch b/third-party/boost-math-libcxx.patch
new file mode 100644
index 0000000000000..f7692a7e54b67
--- /dev/null
+++ b/third-party/boost-math-libcxx.patch
@@ -0,0 +1,47 @@
+# Local libc++ patch for the vendored Boost.Math snapshot.
+#
+# Boost.Math only uses <sstream>/<iomanip> and detail::prec_format to build the
+# what() text of the exceptions it throws. That machinery sits OUTSIDE Boost's own
+# `#ifndef BOOST_MATH_NO_EXCEPTIONS` guard (unlike the adjacent <stdexcept> /
+# throw_exception.hpp includes), so it is compiled even when exceptions are disabled.
+# libc++ builds the Math Special Functions back-end with BOOST_MATH_NO_EXCEPTIONS,
+# and on configurations without localization (e.g. -DLIBCXX_ENABLE_LOCALIZATION=OFF)
+# libc++ ships no functional <sstream>, so prec_format fails to compile.
+#
+# This patch guards the iostream-only message formatting under BOOST_MATH_NO_EXCEPTIONS.
+# Reported upstream: https://github.com/boostorg/math/issues (see PR description).
+# Re-applied by update_boost_math.sh after each snapshot refresh; drop once upstream.
+diff --git a/boost-math/include/boost/math/policies/error_handling.hpp b/boost-math/include/boost/math/policies/error_handling.hpp
+index d7ba694564ba..da167171f650 100644
+--- a/boost-math/include/boost/math/policies/error_handling.hpp
++++ b/boost-math/include/boost/math/policies/error_handling.hpp
+@@ -26,9 +26,9 @@
+ #include <complex>
+ #include <cstdint>
+ #include <cstring>
++#ifndef BOOST_MATH_NO_EXCEPTIONS
+ #include <iomanip>
+ #include <sstream>
+-#ifndef BOOST_MATH_NO_EXCEPTIONS
+ #include <stdexcept>
+ #endif
+ #include <string>
+@@ -95,6 +95,10 @@ T user_indeterminate_result_error(const char* function, const char* message, con
+ namespace detail
+ {
+
++// prec_format is only used to build exception what() messages, so it is gated on
++// exceptions being enabled. It relies on <sstream>, which is unavailable in some
++// standard-library configurations (e.g. libc++ built without localization).
++#ifndef BOOST_MATH_NO_EXCEPTIONS
+ template <class T>
+ inline std::string prec_format(const T& val)
+ {
+@@ -125,6 +129,7 @@ inline std::string prec_format<std::float128_t>(const std::float128_t& val)
+ }
+
+ #endif
++#endif // BOOST_MATH_NO_EXCEPTIONS
+
+ inline void replace_all_in_string(std::string& result, const char* what, const char* with)
+ {
diff --git a/third-party/update_boost_math.sh b/third-party/update_boost_math.sh
index 27d8816b7cb12..a4276cdb74028 100755
--- a/third-party/update_boost_math.sh
+++ b/third-party/update_boost_math.sh
@@ -40,3 +40,13 @@ sed -i 's|target_include_directories(boost_math INTERFACE include)|target_includ
grep -q 'target_include_directories(boost_math SYSTEM INTERFACE include)' \
${SCRIPT_DIR}/boost-math/CMakeLists.txt \
|| { echo "ERROR: SYSTEM include patch failed -- upstream CMakeLists.txt structure changed"; exit 1; }
+
+# Guard Boost.Math's iostream-only exception-message formatting (prec_format / <sstream>)
+# under BOOST_MATH_NO_EXCEPTIONS, so the no-exceptions back-end builds without <sstream>.
+# Needed for libc++ configurations without localization. Drop once fixed upstream.
+patch -p1 -d ${SCRIPT_DIR} < ${SCRIPT_DIR}/boost-math-libcxx.patch
+
+# Verify the patch landed -- fail loudly if upstream restructured error_handling.hpp.
+grep -q 'prec_format is only used to build exception' \
+ ${SCRIPT_DIR}/boost-math/include/boost/math/policies/error_handling.hpp \
+ || { echo "ERROR: no-exceptions iostream patch failed -- upstream error_handling.hpp structure changed"; exit 1; }
>From 276df4abe72a9ba6d4979d5922b466445aa406b9 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 30 Jun 2026 22:32:27 +0200
Subject: [PATCH 50/72] apply boost patch
---
.../include/boost/math/policies/error_handling.hpp | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/third-party/boost-math/include/boost/math/policies/error_handling.hpp b/third-party/boost-math/include/boost/math/policies/error_handling.hpp
index d7ba694564ba4..da167171f650d 100644
--- a/third-party/boost-math/include/boost/math/policies/error_handling.hpp
+++ b/third-party/boost-math/include/boost/math/policies/error_handling.hpp
@@ -26,9 +26,9 @@
#include <complex>
#include <cstdint>
#include <cstring>
+#ifndef BOOST_MATH_NO_EXCEPTIONS
#include <iomanip>
#include <sstream>
-#ifndef BOOST_MATH_NO_EXCEPTIONS
#include <stdexcept>
#endif
#include <string>
@@ -95,6 +95,10 @@ T user_indeterminate_result_error(const char* function, const char* message, con
namespace detail
{
+// prec_format is only used to build exception what() messages, so it is gated on
+// exceptions being enabled. It relies on <sstream>, which is unavailable in some
+// standard-library configurations (e.g. libc++ built without localization).
+#ifndef BOOST_MATH_NO_EXCEPTIONS
template <class T>
inline std::string prec_format(const T& val)
{
@@ -125,6 +129,7 @@ inline std::string prec_format<std::float128_t>(const std::float128_t& val)
}
#endif
+#endif // BOOST_MATH_NO_EXCEPTIONS
inline void replace_all_in_string(std::string& result, const char* what, const char* with)
{
>From 6bbed03306814ee7a45418ba8e01e619852d7d94 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 30 Jun 2026 22:53:16 +0200
Subject: [PATCH 51/72] doc: add boost issue
---
third-party/boost-math-libcxx.patch | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/third-party/boost-math-libcxx.patch b/third-party/boost-math-libcxx.patch
index f7692a7e54b67..8593b077a2db2 100644
--- a/third-party/boost-math-libcxx.patch
+++ b/third-party/boost-math-libcxx.patch
@@ -9,7 +9,7 @@
# libc++ ships no functional <sstream>, so prec_format fails to compile.
#
# This patch guards the iostream-only message formatting under BOOST_MATH_NO_EXCEPTIONS.
-# Reported upstream: https://github.com/boostorg/math/issues (see PR description).
+# Reported upstream: https://github.com/boostorg/math/issues/1412
# Re-applied by update_boost_math.sh after each snapshot refresh; drop once upstream.
diff --git a/boost-math/include/boost/math/policies/error_handling.hpp b/boost-math/include/boost/math/policies/error_handling.hpp
index d7ba694564ba..da167171f650 100644
>From 441f2f0089823971d515573e8f8074fddd2e32a1 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 4 Jul 2026 08:34:54 +0200
Subject: [PATCH 52/72] guard via
_LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS
---
libcxx/include/__configuration/availability.h | 5 +++++
libcxx/include/__math/special_functions.h | 20 ++++++++++++-------
.../c.math/sf.cmath/nodiscard.verify.cpp | 4 ++++
.../c.math/sf.cmath/noexcept.compile.pass.cpp | 4 ++++
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 4 ++++
.../libcxx/test/features/availability.py | 8 ++++++++
6 files changed, 38 insertions(+), 7 deletions(-)
diff --git a/libcxx/include/__configuration/availability.h b/libcxx/include/__configuration/availability.h
index 735af5d431cb1..72eb50721338f 100644
--- a/libcxx/include/__configuration/availability.h
+++ b/libcxx/include/__configuration/availability.h
@@ -271,6 +271,11 @@
#define _LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_20
#define _LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_20_ATTRIBUTE
+// This controls the availability of the C++17 mathematical special functions
+// ([sf.cmath]). Their implementation lives in the built library (backed by Boost.Math).
+#define _LIBCPP_AVAILABILITY_HAS_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_23
+#define _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_23_ATTRIBUTE
+
// This controls the availability of the C++20 time zone database.
// The parser code is built in the library.
#define _LIBCPP_AVAILABILITY_HAS_TZDB _LIBCPP_INTRODUCED_IN_LLVM_19
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 5021e5a54b634..546600b72bce0 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -29,26 +29,32 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
// assoc_laguerre
namespace __math {
-[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI float __assoc_laguerre(unsigned, unsigned, float) noexcept;
-[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI double __assoc_laguerre(unsigned, unsigned, double) noexcept;
-[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI long double __assoc_laguerre(unsigned, unsigned, long double) noexcept;
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_EXPORTED_FROM_ABI float
+__assoc_laguerre(unsigned, unsigned, float) noexcept;
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_EXPORTED_FROM_ABI double
+__assoc_laguerre(unsigned, unsigned, double) noexcept;
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_EXPORTED_FROM_ABI long double
+__assoc_laguerre(unsigned, unsigned, long double) noexcept;
} // namespace __math
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI float assoc_laguerref(unsigned __n, unsigned __m, float __x) noexcept {
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI float
+assoc_laguerref(unsigned __n, unsigned __m, float __x) noexcept {
return __math::__assoc_laguerre(__n, __m, __x);
}
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI double assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI double
+assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
return __math::__assoc_laguerre(__n, __m, __x);
}
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI long double
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI long double
assoc_laguerrel(unsigned __n, unsigned __m, long double __x) noexcept {
return __math::__assoc_laguerre(__n, __m, __x);
}
template <class _Int, std::enable_if_t<std::is_integral_v<_Int>, int> = 0>
-[[nodiscard]] _LIBCPP_HIDE_FROM_ABI double assoc_laguerre(unsigned __n, unsigned __m, _Int __x) noexcept {
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_HIDE_FROM_ABI double
+assoc_laguerre(unsigned __n, unsigned __m, _Int __x) noexcept {
return __math::__assoc_laguerre(__n, __m, static_cast<double>(__x));
}
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
index b83070f4f984d..598311f20917d 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
@@ -8,6 +8,10 @@
// REQUIRES: std-at-least-c++17
+// The functions carry availability markup, so referencing them fails to compile against a
+// back-deployment target whose libc++ predates them.
+// XFAIL: availability-mathematical_special_functions-missing
+
// Check that functions are marked [[nodiscard]]
#include <cmath>
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
index cca9c1e924a8c..8f9dd87c0ee87 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
@@ -8,6 +8,10 @@
// REQUIRES: std-at-least-c++17
+// The functions carry availability markup, so referencing them fails to compile against a
+// back-deployment target whose libc++ predates them.
+// XFAIL: availability-mathematical_special_functions-missing
+
// Check that functions are marked noexcept
#include <cmath>
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index b39e20fe6288a..91a7c4a3d2047 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -8,6 +8,10 @@
// REQUIRES: std-at-least-c++17
+// These functions are implemented in the built library, so a program using them fails to
+// load against a back-deployment target whose libc++ predates them.
+// XFAIL: availability-mathematical_special_functions-missing
+
// <cmath>
// double assoc_laguerre(unsigned n, unsigned m, double x);
diff --git a/libcxx/utils/libcxx/test/features/availability.py b/libcxx/utils/libcxx/test/features/availability.py
index c0f2a3d4cdc88..7bb1add0e9e9c 100644
--- a/libcxx/utils/libcxx/test/features/availability.py
+++ b/libcxx/utils/libcxx/test/features/availability.py
@@ -211,4 +211,12 @@
cfg.available_features,
),
),
+ # Tests that require the C++17 mathematical special functions in the built library
+ Feature(
+ name="availability-mathematical_special_functions-missing",
+ when=lambda cfg: BooleanExpression.evaluate(
+ "!libcpp-has-no-availability-markup && (stdlib=apple-libc++ && !_target-has-llvm-23)",
+ cfg.available_features,
+ ),
+ ),
]
>From c63f3e0b04b37c5dcd6294473878de37d612a0f7 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 4 Jul 2026 13:31:20 +0200
Subject: [PATCH 53/72] cleanup header includes
---
libcxx/include/__math/special_functions.h | 1 -
libcxx/src/mathematical_special_functions.cpp | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 546600b72bce0..9721430ee0c64 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -11,7 +11,6 @@
#define _LIBCPP___MATH_SPECIAL_FUNCTIONS_H
#include <__config>
-#include <__configuration/attributes.h>
#include <__math/copysign.h>
#include <__math/traits.h>
#include <__type_traits/enable_if.h>
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index dc046b3a845df..e9f655d56aa69 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -37,6 +37,7 @@
#endif
#define BOOST_MATH_NO_EXCEPTIONS
+#include <boost/math/policies/policy.hpp>
#include <boost/math/special_functions/laguerre.hpp>
_LIBCPP_BEGIN_NAMESPACE_STD
>From 8afb315b5746d25b2c2f915d91fffa49b41720f8 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 4 Jul 2026 14:02:44 +0200
Subject: [PATCH 54/72] test: add integral tests; refactor
---
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 72 +++++++++----------
1 file changed, 36 insertions(+), 36 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index 91a7c4a3d2047..7561cb27b6020 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -14,62 +14,62 @@
// <cmath>
-// double assoc_laguerre(unsigned n, unsigned m, double x);
-// float assoc_laguerref(unsigned n, unsigned m, float x);
-// long double assoc_laguerrel(unsigned n, unsigned m, long double x);
+// floating-point-type assoc_laguerre( unsigned n, unsigned m, floating-point-type x);
+// float assoc_laguerref(unsigned n, unsigned m, float x );
+// long double assoc_laguerrel(unsigned n, unsigned m, long double x );
#include <cassert>
#include <cmath>
+#include <initializer_list>
#include <limits>
#include <type_traits>
#include "common.h"
#include "type_algorithms.h"
-// Each overload is fixed to a single floating-point type, so it is tested
-// directly with that type. The integer-argument overload
-// (assoc_laguerre(unsigned, unsigned, Integer) -> double) is not implemented yet.
-template <class ExpectedFuncRet, class FuncArgX, class Func>
-void test(Func assoc_laguerre) {
- // sample values
- assert(between(0.99, assoc_laguerre(0, 0, FuncArgX(0)), 1.01));
- assert(between(0.99, assoc_laguerre(1, 1, FuncArgX(1)), 1.01));
- assert(between(-1.01, assoc_laguerre(2, 0, FuncArgX(2)), -0.99));
- assert(between(-0.01, assoc_laguerre(2, 2, FuncArgX(2)), 0.01));
- if constexpr (std::is_floating_point_v<FuncArgX>)
- assert(between(60.124, assoc_laguerre(2, 10, FuncArgX(0.5)), 60.126));
+// Tests a fixed-precision overload (assoc_laguerre / assoc_laguerref / assoc_laguerrel),
+// whose argument and return type are both `Float`.
+template <class Float, class Func>
+void test_floating_point(Func assoc_laguerre) {
+ // return type is the argument type
+ static_assert(std::is_same_v<decltype(assoc_laguerre(0, 0, Float(0))), Float>);
- static_assert(std::is_same_v<decltype(assoc_laguerre(0, 0, FuncArgX(0))), ExpectedFuncRet>);
+ // sample values
+ assert(between(0.99, assoc_laguerre(0, 0, Float(0)), 1.01));
+ assert(between(0.99, assoc_laguerre(1, 1, Float(1)), 1.01));
+ assert(between(-1.01, assoc_laguerre(2, 0, Float(2)), -0.99));
+ assert(between(-0.01, assoc_laguerre(2, 2, Float(2)), 0.01));
+ assert(between(60.124, assoc_laguerre(2, 10, Float(0.5)), 60.126));
- // NaN argument -> NaN result, without a domain error ([sf.cmath.general]/1).
- if constexpr (std::is_floating_point_v<FuncArgX>) {
- auto test_nan = [&](FuncArgX nan) {
- check_no_domain_error([&] { assert(std::isnan(assoc_laguerre(0, 0, nan))); });
- };
- if (std::numeric_limits<FuncArgX>::has_quiet_NaN)
- test_nan(std::numeric_limits<FuncArgX>::quiet_NaN());
- if (std::numeric_limits<FuncArgX>::has_signaling_NaN)
- test_nan(std::numeric_limits<FuncArgX>::signaling_NaN());
- }
+ // a negative argument is in the domain (no domain error)
+ check_no_domain_error([&] { assert(between(1.99, assoc_laguerre(1, 0, Float(-1)), 2.01)); });
- // A negative argument is in the domain (no domain error).
- check_no_domain_error([&] { assert(between(1.99, assoc_laguerre(1, 0, FuncArgX(-1)), 2.01)); });
+ // NaN argument -> NaN result, without a domain error ([sf.cmath.general]/1)
+ auto test_nan = [&](Float nan) { check_no_domain_error([&] { assert(std::isnan(assoc_laguerre(0, 0, nan))); }); };
+ if (std::numeric_limits<Float>::has_quiet_NaN)
+ test_nan(std::numeric_limits<Float>::quiet_NaN());
+ if (std::numeric_limits<Float>::has_signaling_NaN)
+ test_nan(std::numeric_limits<Float>::signaling_NaN());
}
-struct TestIntegral {
- template <class Int>
+// Tests the integer-argument overload: it promotes the argument to double and returns double.
+struct TestInteger {
+ template <class Integer>
void operator()() const {
- test<double, Int>([](unsigned n, unsigned m, Int x) { return std::assoc_laguerre(n, m, x); });
+ static_assert(std::is_same_v<decltype(std::assoc_laguerre(0u, 0u, Integer(0))), double>);
+
+ // same result as the double overload with the argument cast to double
+ for (Integer x : {Integer(0), Integer(1), Integer(2)})
+ assert(std::assoc_laguerre(2, 0, x) == std::assoc_laguerre(2, 0, static_cast<double>(x)));
}
};
int main(int, char**) {
- test<double, double>([](unsigned n, unsigned m, double x) { return std::assoc_laguerre(n, m, x); });
-
- test<float, float>([](unsigned n, unsigned m, float x) { return std::assoc_laguerref(n, m, x); });
- test<long double, long double>([](unsigned n, unsigned m, long double x) { return std::assoc_laguerrel(n, m, x); });
+ test_floating_point<float>([](unsigned n, unsigned m, float x) { return std::assoc_laguerref(n, m, x); });
+ test_floating_point<double>([](unsigned n, unsigned m, double x) { return std::assoc_laguerre(n, m, x); });
+ test_floating_point<long double>([](unsigned n, unsigned m, long double x) { return std::assoc_laguerrel(n, m, x); });
- // types::for_each(types::integral_types{}, TestIntegral{}); WIP
+ types::for_each(types::integral_types{}, TestInteger{});
return 0;
}
>From 7236c0aa7861a04227195f8fa88d0f7efde7267c Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 4 Jul 2026 14:21:17 +0200
Subject: [PATCH 55/72] impl assoc_laguerre(float/long double) + tests
---
libcxx/include/__math/special_functions.h | 14 ++++++++++++--
.../numerics/c.math/sf.cmath/nodiscard.verify.cpp | 6 ++++--
.../c.math/sf.cmath/noexcept.compile.pass.cpp | 13 +++----------
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 2 ++
4 files changed, 21 insertions(+), 14 deletions(-)
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 9721430ee0c64..8bb805d721b5f 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -37,7 +37,7 @@ __assoc_laguerre(unsigned, unsigned, long double) noexcept;
} // namespace __math
[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI float
-assoc_laguerref(unsigned __n, unsigned __m, float __x) noexcept {
+assoc_laguerre(unsigned __n, unsigned __m, float __x) noexcept {
return __math::__assoc_laguerre(__n, __m, __x);
}
@@ -47,7 +47,7 @@ assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
}
[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI long double
-assoc_laguerrel(unsigned __n, unsigned __m, long double __x) noexcept {
+assoc_laguerre(unsigned __n, unsigned __m, long double __x) noexcept {
return __math::__assoc_laguerre(__n, __m, __x);
}
@@ -57,6 +57,16 @@ assoc_laguerre(unsigned __n, unsigned __m, _Int __x) noexcept {
return __math::__assoc_laguerre(__n, __m, static_cast<double>(__x));
}
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI float
+assoc_laguerref(unsigned __n, unsigned __m, float __x) noexcept {
+ return __math::__assoc_laguerre(__n, __m, __x);
+}
+
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI long double
+assoc_laguerrel(unsigned __n, unsigned __m, long double __x) noexcept {
+ return __math::__assoc_laguerre(__n, __m, __x);
+}
+
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
// hermite
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
index 598311f20917d..4729dbd23c58e 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
@@ -19,8 +19,10 @@
void test() {
// clang-format off
// assoc_laguerre
- std::assoc_laguerre(0, 0, 0.0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::assoc_laguerre(0, 0, 0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerre(0, 0, 0.0f); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerre(0, 0, 0.0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerre(0, 0, 0.0l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerre(0, 0, 0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::assoc_laguerref(0, 0, 0.0f); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::assoc_laguerrel(0, 0, 0.0l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
index 8f9dd87c0ee87..b9993ab6500a7 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
@@ -17,21 +17,14 @@
#include <cmath>
#include "test_macros.h"
-#include "type_algorithms.h"
-
-struct TestIntegral {
- template <class T>
- void operator()() const {
- ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, T{}));
- }
-};
void test() {
// assoc_laguerre
+ ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0f));
ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0));
+ ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0l));
+ ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0));
ASSERT_NOEXCEPT(std::assoc_laguerref(0, 0, 0.0f));
ASSERT_NOEXCEPT(std::assoc_laguerrel(0, 0, 0.0l));
-
- types::for_each(types::integral_types{}, TestIntegral{});
}
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index 7561cb27b6020..a0dca3cf5ce14 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -66,8 +66,10 @@ struct TestInteger {
int main(int, char**) {
test_floating_point<float>([](unsigned n, unsigned m, float x) { return std::assoc_laguerref(n, m, x); });
+ test_floating_point<float>([](unsigned n, unsigned m, float x) { return std::assoc_laguerre(n, m, x); });
test_floating_point<double>([](unsigned n, unsigned m, double x) { return std::assoc_laguerre(n, m, x); });
test_floating_point<long double>([](unsigned n, unsigned m, long double x) { return std::assoc_laguerrel(n, m, x); });
+ test_floating_point<long double>([](unsigned n, unsigned m, long double x) { return std::assoc_laguerre(n, m, x); });
types::for_each(types::integral_types{}, TestInteger{});
>From 743cc59817c20cb989c244ba6ad9588586777993 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 4 Jul 2026 22:59:48 +0200
Subject: [PATCH 56/72] test: if constexpr on NaN support
---
.../std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index a0dca3cf5ce14..dbd8a5d24eaee 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -45,10 +45,12 @@ void test_floating_point(Func assoc_laguerre) {
check_no_domain_error([&] { assert(between(1.99, assoc_laguerre(1, 0, Float(-1)), 2.01)); });
// NaN argument -> NaN result, without a domain error ([sf.cmath.general]/1)
- auto test_nan = [&](Float nan) { check_no_domain_error([&] { assert(std::isnan(assoc_laguerre(0, 0, nan))); }); };
- if (std::numeric_limits<Float>::has_quiet_NaN)
+ [[maybe_unused]] auto test_nan = [&](Float nan) {
+ check_no_domain_error([&] { assert(std::isnan(assoc_laguerre(0, 0, nan))); });
+ };
+ if constexpr (std::numeric_limits<Float>::has_quiet_NaN)
test_nan(std::numeric_limits<Float>::quiet_NaN());
- if (std::numeric_limits<Float>::has_signaling_NaN)
+ if constexpr (std::numeric_limits<Float>::has_signaling_NaN)
test_nan(std::numeric_limits<Float>::signaling_NaN());
}
>From 4745005a1a88853ea9af7d9ce8c4525e5004f9d0 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 25 Aug 2026 22:19:54 +0200
Subject: [PATCH 57/72] report domain and range errors for assoc_laguerre
[sf.cmath.general]/1.1 makes an argument outside the domain stated in a
function's Returns: element a domain error, and [cmath.syn]/1 imports C
7.12.1 for how one is reported: errno = EDOM plus FE_INVALID, and
errno = ERANGE plus FE_OVERFLOW for a range error from overflow. Boost
only ever sets errno, so raise the flags here.
Both channels are used unconditionally: math_errhandling describes the
caller's translation unit, which these out-of-line definitions cannot
see, so a caller built with -fno-math-errno or -ffast-math must still
get both.
assoc_laguerre specifics: x >= 0 is the domain, so a negative x (-inf
included) is a domain error. x == +inf is in the domain and its value
follows the leading term (-1)^n x^n / n! -- answered directly because
Boost's recurrence forms inf - inf for n >= 3. A non-finite result from
finite arguments is an overflow; Boost's recurrence can produce either
an infinity or, two steps later, inf - inf == NaN, and past the largest
root the sign is again the leading term's.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
libcxx/src/mathematical_special_functions.cpp | 121 ++++++++++++------
.../c.math/sf.cmath/assoc_laguerre.pass.cpp | 29 ++++-
.../std/numerics/c.math/sf.cmath/common.h | 39 ++++++
3 files changed, 151 insertions(+), 38 deletions(-)
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index 2d43f25dc4914..6c597561344b1 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -6,11 +6,12 @@
//
//===----------------------------------------------------------------------===//
-#include <__config>
#include <__cmath/special_functions.h>
+#include <__config>
+#include <cerrno>
+#include <cfenv>
#include <cmath>
-#include <optional>
-#include <type_traits>
+#include <limits>
// GCC defines __STDCPP_FLOATnn_T__ whenever the _Floatnn extended types exist at the
// language level, independent of the standard library. libc++ currently ships no
@@ -45,6 +46,16 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
#if _LIBCPP_STD_VER >= 17
namespace __math {
+
+// Boost.Math computes; the per-function wrappers below add the standard's error rules.
+// Notes that apply to all of them:
+// - underflow is left alone: C 7.12.1/5 makes both the ERANGE and the flag
+// implementation-defined there, and Boost's underflow policy defaults to ignore.
+// - C 7.12.1/1 ("as if a single operation") is not implemented: intermediate flags from
+// Boost's recurrences leak into the caller's environment.
+// - promotion: Boost's default promote_float=true computes float inputs in double and
+// rounds once -- more accurate and overflow-resistant, matching the existing
+// std::hermite(float) approach. We keep it.
namespace {
// Error policy for all Boost.Math calls: report domain/pole/overflow/evaluation
// errors via errno (errno_on_error) instead of throwing. Boost sets errno to
@@ -57,52 +68,90 @@ using __policy =
__bmp::overflow_error<__bmp::errno_on_error>,
__bmp::evaluation_error<__bmp::errno_on_error>>;
+// Reports a domain error and returns the value libc++ hands back for one.
+//
+// C 7.12.1/2, imported by [cmath.syn]/1: errno acquires EDOM when math_errhandling &
+// MATH_ERRNO, "invalid" is raised when math_errhandling & MATH_ERREXCEPT, and the
+// returned value is implementation-defined. Both channels are used unconditionally
+// because math_errhandling describes the caller's translation unit, which this
+// out-of-line definition cannot see. FE_INVALID is optional -- picolibc without
+// hardware floating point does not define it.
template <class _Ret>
-std::optional<_Ret> __check_nan() {
- return std::nullopt;
+_Ret __report_domain_error() {
+ errno = EDOM;
+# ifdef FE_INVALID
+ std::feraiseexcept(FE_INVALID);
+# endif
+ return std::numeric_limits<_Ret>::quiet_NaN();
}
-template <class _Ret, class _Arg, class... _Args>
-std::optional<_Ret> __check_nan(_Arg __arg, _Args... __args) {
- if constexpr (std::is_floating_point_v<_Arg>)
- if (std::isnan(__arg))
- return __arg;
- return __check_nan<_Ret>(__args...);
-}
-
-// Shared back-end for the C++17 mathematical special functions ([sf.cmath]).
-// Boost.Math is the compute kernel; this wrapper enforces the standard's
-// error-reporting rules ([sf.cmath.general]):
-// 1. NaN argument -> return NaN, do NOT report a domain error (the
-// __check_nan pre-filter below).
-// 2. domain/range error -> reported via errno only: Boost's errno_on_error
-// policy sets errno = EDOM (domain/pole/evaluation) or ERANGE (overflow).
-// The <cfenv> floating-point-exception side of math_errhandling
-// (MATH_ERREXCEPT) is intentionally not mirrored, matching the shipped
-// std::hermite and libstdc++'s special-function implementations.
-// Promotion: Boost's default promote_float=true computes float inputs in double
-// and rounds once -- more accurate and overflow-resistant, matching the
-// existing std::hermite(float) approach. We keep it.
-template <class _Func, class... _Args, class _Ret = std::invoke_result_t<_Func, _Args...>>
-_Ret __invoke_boost_math(_Func __f, _Args... __args) {
- if (auto __maybe_nan = __check_nan<_Ret>(__args...); __maybe_nan.has_value())
- return *__maybe_nan;
-
- return __f(__args..., __policy{});
+// Reports a range error from overflow and returns __value, which the caller supplies as
+// the correctly signed HUGE_VAL (an infinity on IEEE 754 targets), per C 7.12.1/4. No
+// Boost policy raises floating-point exceptions, so the flag is ours to raise; Boost's
+// own overflow detection sets ERANGE too, and the two channels have to agree. A pole would
+// want FE_DIVBYZERO instead, and Boost's policies cannot tell the two apart (both map to
+// ERANGE) -- none of the functions implemented so far has one.
+template <class _Ret>
+_Ret __report_overflow(_Ret __value) {
+ errno = ERANGE;
+# ifdef FE_OVERFLOW
+ std::feraiseexcept(FE_OVERFLOW);
+# endif
+ return __value;
}
} // namespace
// assoc_laguerre
-float __assoc_laguerre(unsigned __n, unsigned __m, float __x) noexcept {
- return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
+namespace {
+template <class _Real>
+_Real __assoc_laguerre_impl(unsigned __n, unsigned __m, _Real __x) {
+ // [sf.cmath.general]/1: a NaN argument returns a NaN and reports no domain error. It is
+ // returned unchanged, so a signaling NaN stays signaling. IEEE 754 would raise "invalid"
+ // for it -- and the comparisons below can too, since the relational operators may signal
+ // for unordered operands (C 7.12.14) -- which [sf.cmath] neither requires nor forbids
+ // for a NaN argument. Quiet NaNs, the case that matters, reach neither.
+ if (std::isnan(__x))
+ return __x;
+
+ // [sf.cmath.assoc.laguerre] Returns: states the domain as x >= 0, so a negative
+ // argument -- -inf included ([sf.cmath.general]/2) -- is a domain error
+ // ([sf.cmath.general]/1.1). Boost evaluates such an argument happily, so the check has
+ // to live here.
+ if (__x < 0)
+ return __report_domain_error<_Real>();
+
+ // x == +inf is in the domain. The leading term of L^m_n is (-1)^n x^n / n!, so the value
+ // there is 1 for n == 0 and (-1)^n * inf otherwise. That is not a range error: the
+ // mathematical result is itself infinite. Answered here because Boost's recurrence is
+ // not infinity-safe (it forms inf - inf for n >= 3) and its narrowing cast reports a
+ // spurious ERANGE for an infinite value.
+ if (std::isinf(__x))
+ return __n == 0 ? _Real(1) : (__n % 2 == 0 ? __x : -__x);
+
+ _Real __result = boost::math::laguerre(__n, __m, __x, __policy{});
+
+ // A non-finite result from finite arguments is a range error from overflow (C 7.12.1/4).
+ // Boost runs the recurrence in the result type, so a value on the way to L^m_n that does
+ // not fit becomes an infinity and, two steps further, inf - inf == NaN. Past its largest
+ // root L^m_n has the sign of its leading term, so both cases are overflowed values with
+ // a known sign rather than undefined ones.
+ if (!std::isfinite(__result)) {
+ _Real __inf = std::numeric_limits<_Real>::infinity();
+ return __report_overflow(__n % 2 == 0 ? __inf : -__inf);
+ }
+
+ return __result;
}
+} // namespace
+
+float __assoc_laguerre(unsigned __n, unsigned __m, float __x) noexcept { return __assoc_laguerre_impl(__n, __m, __x); }
double __assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
- return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
+ return __assoc_laguerre_impl(__n, __m, __x);
}
long double __assoc_laguerre(unsigned __n, unsigned __m, long double __x) noexcept {
- return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
+ return __assoc_laguerre_impl(__n, __m, __x);
}
} // namespace __math
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index dbd8a5d24eaee..b7c59db249810 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -41,8 +41,33 @@ void test_floating_point(Func assoc_laguerre) {
assert(between(-0.01, assoc_laguerre(2, 2, Float(2)), 0.01));
assert(between(60.124, assoc_laguerre(2, 10, Float(0.5)), 60.126));
- // a negative argument is in the domain (no domain error)
- check_no_domain_error([&] { assert(between(1.99, assoc_laguerre(1, 0, Float(-1)), 2.01)); });
+ // [sf.cmath.assoc.laguerre] Returns: states the domain as x >= 0, so a negative
+ // argument is a domain error ([sf.cmath.general]/1.1)
+ check_domain_error([&] { assoc_laguerre(1, 0, Float(-1)); });
+
+ // [sf.cmath.general]/2 leaves both infinities in the domain unless the Returns:
+ // element excludes them, and x >= 0 excludes -inf but not +inf. The leading term of
+ // L^m_n is (-1)^n x^n / n!, so L^m_n(+inf) is 1 for n == 0 and (-1)^n * inf otherwise.
+ if constexpr (std::numeric_limits<Float>::has_infinity) {
+ const Float inf = std::numeric_limits<Float>::infinity();
+
+ check_domain_error([&] { assoc_laguerre(1, 0, -inf); });
+
+ check_no_domain_error([&] { assert(assoc_laguerre(0, 0, inf) == Float(1)); });
+ check_no_domain_error([&] { assert(assoc_laguerre(1, 0, inf) == -inf); });
+ check_no_domain_error([&] { assert(assoc_laguerre(2, 0, inf) == inf); });
+ check_no_domain_error([&] { assert(assoc_laguerre(3, 5, inf) == -inf); });
+
+ // An infinity produced from finite arguments is a range error, not a domain error:
+ // errno == ERANGE and the value is +-HUGE_VAL, again with the sign of the leading
+ // term (C 7.12.1/4).
+ const Float max = std::numeric_limits<Float>::max();
+
+ check_range_error([&] { assert(assoc_laguerre(2, 0, max) == inf); });
+ check_range_error([&] { assert(assoc_laguerre(3, 0, max) == -inf); });
+ check_range_error([&] { assert(assoc_laguerre(4, 1, max) == inf); });
+ check_range_error([&] { assert(assoc_laguerre(5, 1, max) == -inf); });
+ }
// NaN argument -> NaN result, without a domain error ([sf.cmath.general]/1)
[[maybe_unused]] auto test_nan = [&](Float nan) {
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/common.h b/libcxx/test/std/numerics/c.math/sf.cmath/common.h
index ca6de9ea868bd..5d0d5f3a49eb9 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/common.h
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/common.h
@@ -11,6 +11,7 @@
#include <cassert>
#include <cerrno>
+#include <cfenv>
#include <cmath>
// std::type_identity is C++20 (we need to support C++17 here)
@@ -26,9 +27,18 @@ bool between(type_identity_t<T> lower, T value, type_identity_t<T> upper) {
return lower < value && value < upper;
}
+// C 7.12.1/2 and /4, imported by [cmath.syn]/1: a domain error sets errno to EDOM and
+// raises "invalid", a range error from overflow sets errno to ERANGE and raises
+// "overflow" -- each channel only when math_errhandling advertises it.
+//
// Note: math_errhandling must be queried with a runtime `if`, not `#if`. On Apple
// platforms it is defined as a function call (__math_errhandling()), so it is not a
// preprocessor constant and would break `#if` under -Wundef.
+//
+// The FE_* macros are optional (picolibc without hardware floating point does not define
+// them), so every use is guarded. The flag is only asserted for the error cases: an
+// error-free call may still raise "inexact" or "overflow" from an intermediate step, and
+// a signaling NaN argument may raise "invalid" from a comparison.
template <class Func>
void check_no_domain_error(Func f) {
if (math_errhandling & MATH_ERRNO)
@@ -42,9 +52,38 @@ template <class Func>
void check_domain_error(Func f) {
if (math_errhandling & MATH_ERRNO)
errno = EACCES;
+#ifdef FE_INVALID
+ if (math_errhandling & MATH_ERREXCEPT)
+ std::feclearexcept(FE_INVALID);
+#endif
+
f();
+
if (math_errhandling & MATH_ERRNO)
assert(errno == EDOM);
+#ifdef FE_INVALID
+ if (math_errhandling & MATH_ERREXCEPT)
+ assert(std::fetestexcept(FE_INVALID) != 0);
+#endif
+}
+
+template <class Func>
+void check_range_error(Func f) {
+ if (math_errhandling & MATH_ERRNO)
+ errno = EACCES;
+#ifdef FE_OVERFLOW
+ if (math_errhandling & MATH_ERREXCEPT)
+ std::feclearexcept(FE_OVERFLOW);
+#endif
+
+ f();
+
+ if (math_errhandling & MATH_ERRNO)
+ assert(errno == ERANGE);
+#ifdef FE_OVERFLOW
+ if (math_errhandling & MATH_ERREXCEPT)
+ assert(std::fetestexcept(FE_OVERFLOW) != 0);
+#endif
}
#endif // TEST_SF_CMATH_COMMON_H
>From 0857945b9d96f2d5c8c05abdfcfa7c9fd596c70d Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 25 Aug 2026 22:19:55 +0200
Subject: [PATCH 58/72] test error reporting under math-related compile flags
The reporting is unconditional by design, so pin it down where
math_errhandling changes: glibc drops it to MATH_ERREXCEPT under
-fno-math-errno and to 0 under -ffast-math. Three lit variants share one
body; -ffast-math implies -ffinite-math-only, which folds isnan and
comparisons against infinities, so only the channels are checked there.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
...aguerre.error_reporting.fast_math.pass.cpp | 30 ++++++
...rre.error_reporting.no_math_errno.pass.cpp | 29 +++++
.../assoc_laguerre.error_reporting.pass.cpp | 26 +++++
.../c.math/sf.cmath/error_reporting.h | 102 ++++++++++++++++++
4 files changed, 187 insertions(+)
create mode 100644 libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.fast_math.pass.cpp
create mode 100644 libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.no_math_errno.pass.cpp
create mode 100644 libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.pass.cpp
create mode 100644 libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.fast_math.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.fast_math.pass.cpp
new file mode 100644
index 0000000000000..7cad4f012e4a9
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.fast_math.pass.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// These functions are implemented in the built library, so a program using them fails to
+// load against a back-deployment target whose libc++ predates them.
+// XFAIL: availability-mathematical_special_functions-missing
+
+// ADDITIONAL_COMPILE_FLAGS: -ffast-math
+
+// Same as assoc_laguerre.error_reporting.pass.cpp, but compiled with -ffast-math, which
+// makes glibc define math_errhandling as 0. Both channels must still be reported by the
+// library. -ffinite-math-only makes the value assertions unusable, so error_reporting.h
+// drops them here. See error_reporting.h.
+
+#include <cmath>
+
+#include "error_reporting.h"
+
+int main(int, char**) {
+ test_error_reporting();
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.no_math_errno.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.no_math_errno.pass.cpp
new file mode 100644
index 0000000000000..eb128abac1689
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.no_math_errno.pass.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// These functions are implemented in the built library, so a program using them fails to
+// load against a back-deployment target whose libc++ predates them.
+// XFAIL: availability-mathematical_special_functions-missing
+
+// ADDITIONAL_COMPILE_FLAGS: -fno-math-errno
+
+// Same as assoc_laguerre.error_reporting.pass.cpp, but compiled with -fno-math-errno,
+// which makes glibc define math_errhandling as MATH_ERREXCEPT alone. The library still
+// has to set errno: it cannot see the caller's flags. See error_reporting.h.
+
+#include <cmath>
+
+#include "error_reporting.h"
+
+int main(int, char**) {
+ test_error_reporting();
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.pass.cpp
new file mode 100644
index 0000000000000..5c8443ad7a458
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.pass.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// These functions are implemented in the built library, so a program using them fails to
+// load against a back-deployment target whose libc++ predates them.
+// XFAIL: availability-mathematical_special_functions-missing
+
+// Implementation-defined half of the error reporting for std::assoc_laguerre, with the
+// default math flags. See error_reporting.h.
+
+#include <cmath>
+
+#include "error_reporting.h"
+
+int main(int, char**) {
+ test_error_reporting();
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h b/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h
new file mode 100644
index 0000000000000..5ac06d51dca5b
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Shared body for the assoc_laguerre error-reporting tests, which run it under several
+// math-related compile flags.
+//
+// C 7.12.1/2 and /4, imported by [cmath.syn]/1, tie the reporting channel to
+// math_errhandling and leave the value returned on a domain error implementation-defined.
+// libc++ returns a quiet NaN and reports on *both* channels unconditionally, because
+// math_errhandling describes the caller's translation unit while these functions are
+// defined out of line in the built library: a caller compiled with -fno-math-errno (glibc
+// then defines math_errhandling as MATH_ERREXCEPT) or with -ffast-math (math_errhandling
+// becomes 0) must still see errno and the flags set. That is what these tests pin down,
+// so the assertions here are deliberately not guarded on math_errhandling.
+
+#ifndef TEST_LIBCXX_SF_CMATH_ERROR_REPORTING_H
+#define TEST_LIBCXX_SF_CMATH_ERROR_REPORTING_H
+
+#include <cassert>
+#include <cerrno>
+#include <cfenv>
+#include <cmath>
+#include <limits>
+
+// -ffast-math implies -ffinite-math-only, which lets the compiler fold isnan and a
+// comparison against an infinity to a constant. Only the reporting channels are checked
+// there; the returned values are covered by the test in test/std.
+#ifdef __FAST_MATH__
+# define TEST_SF_CHECK_VALUES 0
+#else
+# define TEST_SF_CHECK_VALUES 1
+#endif
+
+// The FE_* macros are optional (picolibc without hardware floating point does not define
+// them), so every use is guarded.
+template <class Func, class Float>
+void test_domain_error(Func assoc_laguerre, Float x) {
+ errno = 0;
+#ifdef FE_INVALID
+ std::feclearexcept(FE_INVALID);
+#endif
+
+ [[maybe_unused]] Float result = assoc_laguerre(1, 0, x);
+
+ assert(errno == EDOM);
+#ifdef FE_INVALID
+ assert(std::fetestexcept(FE_INVALID) != 0);
+#endif
+#if TEST_SF_CHECK_VALUES
+ assert(std::isnan(result));
+#endif
+}
+
+template <class Func, class Float>
+void test_range_error(Func assoc_laguerre, Float x) {
+ errno = 0;
+#ifdef FE_OVERFLOW
+ std::feclearexcept(FE_OVERFLOW);
+#endif
+
+ // L^0_2(x) = 1 - 2x + x^2/2 does not fit for an x near the largest finite value
+ [[maybe_unused]] Float result = assoc_laguerre(2, 0, x);
+
+ assert(errno == ERANGE);
+#ifdef FE_OVERFLOW
+ assert(std::fetestexcept(FE_OVERFLOW) != 0);
+#endif
+#if TEST_SF_CHECK_VALUES
+ assert(result == std::numeric_limits<Float>::infinity());
+#endif
+}
+
+inline void test_error_reporting() {
+ auto laguerre_f = [](unsigned n, unsigned m, float x) { return std::assoc_laguerref(n, m, x); };
+ auto laguerre = [](unsigned n, unsigned m, double x) { return std::assoc_laguerre(n, m, x); };
+ auto laguerre_l = [](unsigned n, unsigned m, long double x) { return std::assoc_laguerrel(n, m, x); };
+ auto laguerre_ff = [](unsigned n, unsigned m, float x) { return std::assoc_laguerre(n, m, x); };
+ auto laguerre_ll = [](unsigned n, unsigned m, long double x) { return std::assoc_laguerre(n, m, x); };
+
+ test_domain_error(laguerre_f, -1.0f);
+ test_domain_error(laguerre_ff, -1.0f);
+ test_domain_error(laguerre, -1.0);
+ test_domain_error(laguerre_l, -1.0L);
+ test_domain_error(laguerre_ll, -1.0L);
+
+ // -inf is outside the x >= 0 domain too ([sf.cmath.general]/2)
+ if (std::numeric_limits<double>::has_infinity)
+ test_domain_error(laguerre, -std::numeric_limits<double>::infinity());
+
+ test_range_error(laguerre_f, std::numeric_limits<float>::max());
+ test_range_error(laguerre_ff, std::numeric_limits<float>::max());
+ test_range_error(laguerre, std::numeric_limits<double>::max());
+ test_range_error(laguerre_l, std::numeric_limits<long double>::max());
+ test_range_error(laguerre_ll, std::numeric_limits<long double>::max());
+}
+
+#endif // TEST_LIBCXX_SF_CMATH_ERROR_REPORTING_H
>From 8dce1510d5ef464bbf8adb0a06262f2a6947fbf6 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 25 Aug 2026 22:33:34 +0200
Subject: [PATCH 59/72] rename the dylib namespace from __math to __cmath
__math/ and __cmath/ are split by which public header has to expose the
name: __math/ holds the C functions <math.h> also provides, in
std::__math::, re-exported to global scope by math.h; __cmath/ holds the
<cmath>-only additions. 8d47bda9cd1a moved this header out of __math/
precisely because these were the only functions there that were not in
the __math namespace -- declaring them in __math:: from __cmath/ was the
mirror image of the same inconsistency.
std::__cmath:: also stops the two from reading alike at the point of
use: special_functions.h calls both __math::isnan and, one line later,
its own helpers.
The three mangled names change with it, so all 9 libcxx/lib/abi lists
move: _ZNSt3__16__math16__assoc_laguerreEjjf becomes
_ZNSt3__17__cmath16__assoc_laguerreEjjf. Kept in generate_abi_list.py's
sort order (the pre-existing bad_array_new_length inversions are
untouched). No released symbol is affected -- these are new on this
branch.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
libcxx/include/__cmath/special_functions.h | 16 ++++++++--------
....libcxxabi.v1.stable.exceptions.nonew.abilist | 6 +++---
....libcxxabi.v1.stable.exceptions.nonew.abilist | 6 +++---
....libcxxabi.v1.stable.exceptions.nonew.abilist | 6 +++---
....libcxxabi.v1.stable.exceptions.nonew.abilist | 6 +++---
....libcxxabi.v1.stable.exceptions.nonew.abilist | 6 +++---
....libcxxabi.v1.stable.exceptions.nonew.abilist | 6 +++---
....libcxxabi.v1.stable.exceptions.nonew.abilist | 6 +++---
....libcxxabi.v1.stable.exceptions.nonew.abilist | 6 +++---
...ibcxxabi.v1.stable.noexceptions.nonew.abilist | 6 +++---
libcxx/src/mathematical_special_functions.cpp | 4 ++--
11 files changed, 37 insertions(+), 37 deletions(-)
diff --git a/libcxx/include/__cmath/special_functions.h b/libcxx/include/__cmath/special_functions.h
index 17c4ba90cc0b7..ce1bdbc916639 100644
--- a/libcxx/include/__cmath/special_functions.h
+++ b/libcxx/include/__cmath/special_functions.h
@@ -27,44 +27,44 @@ _LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
// assoc_laguerre
-namespace __math {
+namespace __cmath {
[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_EXPORTED_FROM_ABI float
__assoc_laguerre(unsigned, unsigned, float) noexcept;
[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_EXPORTED_FROM_ABI double
__assoc_laguerre(unsigned, unsigned, double) noexcept;
[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_EXPORTED_FROM_ABI long double
__assoc_laguerre(unsigned, unsigned, long double) noexcept;
-} // namespace __math
+} // namespace __cmath
[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI float
assoc_laguerre(unsigned __n, unsigned __m, float __x) noexcept {
- return __math::__assoc_laguerre(__n, __m, __x);
+ return __cmath::__assoc_laguerre(__n, __m, __x);
}
[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI double
assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
- return __math::__assoc_laguerre(__n, __m, __x);
+ return __cmath::__assoc_laguerre(__n, __m, __x);
}
[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI long double
assoc_laguerre(unsigned __n, unsigned __m, long double __x) noexcept {
- return __math::__assoc_laguerre(__n, __m, __x);
+ return __cmath::__assoc_laguerre(__n, __m, __x);
}
template <class _Int, std::enable_if_t<std::is_integral_v<_Int>, int> = 0>
[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_HIDE_FROM_ABI double
assoc_laguerre(unsigned __n, unsigned __m, _Int __x) noexcept {
- return __math::__assoc_laguerre(__n, __m, static_cast<double>(__x));
+ return __cmath::__assoc_laguerre(__n, __m, static_cast<double>(__x));
}
[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI float
assoc_laguerref(unsigned __n, unsigned __m, float __x) noexcept {
- return __math::__assoc_laguerre(__n, __m, __x);
+ return __cmath::__assoc_laguerre(__n, __m, __x);
}
[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI long double
assoc_laguerrel(unsigned __n, unsigned __m, long double __x) noexcept {
- return __math::__assoc_laguerre(__n, __m, __x);
+ return __cmath::__assoc_laguerre(__n, __m, __x);
}
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
diff --git a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 629c34e5f3c72..0b35fefe2cd81 100644
--- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1701,9 +1701,6 @@
{'is_defined': True, 'name': '__ZNSt3__15wcoutE', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__itoa8__u64toaEyPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1772,6 +1769,9 @@
{'is_defined': True, 'name': '__ZNSt3__16thread6detachEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16threadD1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__17__cmath16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__17codecvtIDiDu11__mbstate_tE2idE', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZNSt3__17codecvtIDiDu11__mbstate_tED0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__17codecvtIDiDu11__mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index 2761e2a92ab58..ceed6e413dd2c 100644
--- a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1339,9 +1339,6 @@
{'is_defined': True, 'name': '_ZNSt6__ndk16__clocEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u64toaEyPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1410,6 +1407,9 @@
{'is_defined': True, 'name': '_ZNSt6__ndk16thread6detachEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16threadD1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cmath16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk17codecvtIDiDu9mbstate_tE2idE', 'size': 8, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZNSt6__ndk17codecvtIDiDu9mbstate_tED0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk17codecvtIDiDu9mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 1ec9665f78ffc..2c022fd452fa9 100644
--- a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -687,9 +687,6 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEyPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12steady_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12system_clock11from_time_tEi', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12system_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
@@ -741,6 +738,9 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16thread6detachEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16threadD1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16threadD2Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjd', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjje', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjf', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDuPcE2idE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDuPcED0Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDuPcED1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 7761e33ff97d0..f90d482858f09 100644
--- a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -687,9 +687,6 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12steady_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12system_clock11from_time_tEl', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12system_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
@@ -741,6 +738,9 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16thread6detachEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16threadD1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16threadD2Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjd', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjje', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjf', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDuPcE2idE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDuPcED0Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDuPcED1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 63a56a4a8f367..a387fd331f81d 100644
--- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1690,9 +1690,6 @@
{'is_defined': True, 'name': '__ZNSt3__15wcoutE', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__itoa8__u64toaEyPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1761,6 +1758,9 @@
{'is_defined': True, 'name': '__ZNSt3__16thread6detachEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16threadD1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__17__cmath16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__17codecvtIDiDu11__mbstate_tE2idE', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZNSt3__17codecvtIDiDu11__mbstate_tED0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__17codecvtIDiDu11__mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index 75936b3f0f102..5a20b6fde0d34 100644
--- a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1339,9 +1339,6 @@
{'is_defined': True, 'name': '_ZNSt6__ndk16__clocEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u64toaEmPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjg', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1410,6 +1407,9 @@
{'is_defined': True, 'name': '_ZNSt6__ndk16thread6detachEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16threadD1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cmath16__assoc_laguerreEjjg', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk17codecvtIDiDu9mbstate_tE2idE', 'size': 16, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZNSt6__ndk17codecvtIDiDu9mbstate_tED0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt6__ndk17codecvtIDiDu9mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
index ba4ce0e65c354..506771d2fbcb3 100644
--- a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1351,9 +1351,6 @@
{'is_defined': True, 'name': '_ZNSt3__15wcoutE', 'size': 160, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1422,6 +1419,9 @@
{'is_defined': True, 'name': '_ZNSt3__16thread6detachEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16threadD1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tE2idE', 'size': 16, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
index 425b2f367013e..fcb1a3bef89c9 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1350,9 +1350,6 @@
{'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1421,6 +1418,9 @@
{'is_defined': True, 'name': '_ZNSt3__16thread6detachEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16threadD1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tE2idE', 'size': 16, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
index ebea1ab30439d..89367962fb850 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
@@ -1321,9 +1321,6 @@
{'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1392,6 +1389,9 @@
{'is_defined': True, 'name': '_ZNSt3__16thread6detachEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16threadD1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tE2idE', 'size': 16, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index 6c597561344b1..fb606538acbcf 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -45,7 +45,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
#if _LIBCPP_STD_VER >= 17
-namespace __math {
+namespace __cmath {
// Boost.Math computes; the per-function wrappers below add the standard's error rules.
// Notes that apply to all of them:
@@ -154,7 +154,7 @@ long double __assoc_laguerre(unsigned __n, unsigned __m, long double __x) noexce
return __assoc_laguerre_impl(__n, __m, __x);
}
-} // namespace __math
+} // namespace __cmath
#endif
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
>From 108b926d492b06bd9c4747dc8d3a164be1d27b0e Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 25 Aug 2026 22:44:15 +0200
Subject: [PATCH 60/72] add the LLVM 24 availability tier and mark the special
functions with it
LLVM 23 has branched: cmake/Modules/LLVMVersion.cmake says
LLVM_VERSION_MAJOR 24 and libcxx/docs/ReleaseNotes.rst points at
ReleaseNotes/24.rst, so anything landing on main now ships in 24. Saying
_LIBCPP_INTRODUCED_IN_LLVM_23 told back-deployment targets the symbols
exist in a release that does not contain them.
_LIBCPP_INTRODUCED_IN_LLVM_24 did not exist -- 23 was the newest, added
by the <text_encoding> PR (#141312) -- so add the tier the same way:
available unconditionally when vendor annotations are off, and on Apple
a "TODO: Fill this in" placeholder that is 0 plus
__attribute__((unavailable)) until an OS release is synchronized to
LLVM 24, matching what LLVM 22 and 23 still look like there.
On the lit side, _target-has-llvm-24 takes over the "TBD" and
_target-has-llvm-23 chains off it, mirroring how 22 chains off 23. Both
still evaluate false, so no feature changes state; what changes is that
using-built-library-before-llvm-24, which the loop already generates and
libcxx/test/libcxx/input.output/iostream.objects/sync_with_stdio.buffer_type.pass.cpp
already uses, now resolves against a feature that exists.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
libcxx/include/__configuration/availability.h | 12 ++++++++++--
libcxx/utils/libcxx/test/features/availability.py | 11 +++++++++--
2 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/__configuration/availability.h b/libcxx/include/__configuration/availability.h
index 9430f4976d23d..ff3c413922516 100644
--- a/libcxx/include/__configuration/availability.h
+++ b/libcxx/include/__configuration/availability.h
@@ -39,6 +39,9 @@
// in all versions of the library are available.
#if !_LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS
+# define _LIBCPP_INTRODUCED_IN_LLVM_24 1
+# define _LIBCPP_INTRODUCED_IN_LLVM_24_ATTRIBUTE /* nothing */
+
# define _LIBCPP_INTRODUCED_IN_LLVM_23 1
# define _LIBCPP_INTRODUCED_IN_LLVM_23_ATTRIBUTE /* nothing */
@@ -73,6 +76,11 @@
// clang-format off
+// LLVM 24
+// TODO: Fill this in
+# define _LIBCPP_INTRODUCED_IN_LLVM_24 0
+# define _LIBCPP_INTRODUCED_IN_LLVM_24_ATTRIBUTE __attribute__((unavailable))
+
// LLVM 23
// TODO: Fill this in
# define _LIBCPP_INTRODUCED_IN_LLVM_23 0
@@ -275,8 +283,8 @@
// This controls the availability of the C++17 mathematical special functions
// ([sf.cmath]). Their implementation lives in the built library (backed by Boost.Math).
-#define _LIBCPP_AVAILABILITY_HAS_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_23
-#define _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_23_ATTRIBUTE
+#define _LIBCPP_AVAILABILITY_HAS_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_24
+#define _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_24_ATTRIBUTE
// This controls the availability of the C++20 time zone database.
// The parser code is built in the library.
diff --git a/libcxx/utils/libcxx/test/features/availability.py b/libcxx/utils/libcxx/test/features/availability.py
index d2c655e61ed9f..4d75ac15371b0 100644
--- a/libcxx/utils/libcxx/test/features/availability.py
+++ b/libcxx/utils/libcxx/test/features/availability.py
@@ -13,12 +13,19 @@
# Those are used for backdeployment features below, do not use directly in tests.
features = [
Feature(
- name="_target-has-llvm-23",
+ name="_target-has-llvm-24",
when=lambda cfg: BooleanExpression.evaluate(
"TBD",
cfg.available_features,
),
),
+ Feature(
+ name="_target-has-llvm-23",
+ when=lambda cfg: BooleanExpression.evaluate(
+ "_target-has-llvm-24",
+ cfg.available_features,
+ ),
+ ),
Feature(
name="_target-has-llvm-22",
when=lambda cfg: BooleanExpression.evaluate(
@@ -215,7 +222,7 @@
Feature(
name="availability-mathematical_special_functions-missing",
when=lambda cfg: BooleanExpression.evaluate(
- "!libcpp-has-no-availability-markup && (stdlib=apple-libc++ && !_target-has-llvm-23)",
+ "!libcpp-has-no-availability-markup && (stdlib=apple-libc++ && !_target-has-llvm-24)",
cfg.available_features,
),
),
>From fe37eeffd60ff2941e1774b8ac2285740c735c08 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 25 Aug 2026 22:52:40 +0200
Subject: [PATCH 61/72] nodiscard tests: use `// expected-warning at +1` style
---
.../c.math/sf.cmath/nodiscard.verify.cpp | 21 +++++++++++--------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
index 4729dbd23c58e..60d34199d745e 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
@@ -17,14 +17,17 @@
#include <cmath>
void test() {
- // clang-format off
// assoc_laguerre
- std::assoc_laguerre(0, 0, 0.0f); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::assoc_laguerre(0, 0, 0.0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::assoc_laguerre(0, 0, 0.0l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::assoc_laguerre(0, 0, 0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-
- std::assoc_laguerref(0, 0, 0.0f); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- std::assoc_laguerrel(0, 0, 0.0l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- // clang-format on
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerre(0, 0, 0.0f);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerre(0, 0, 0.0);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerre(0, 0, 0.0l);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerre(0, 0, 0);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerref(0, 0, 0.0f);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::assoc_laguerrel(0, 0, 0.0l);
}
>From d9ba8075ad051745e9578e68a36605f43d7a8450 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 25 Aug 2026 22:54:34 +0200
Subject: [PATCH 62/72] noexcept tests: inline ASSERT_NOEXCEPT macro
---
.../c.math/sf.cmath/noexcept.compile.pass.cpp | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
index b9993ab6500a7..a537712879323 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
@@ -16,15 +16,12 @@
#include <cmath>
-#include "test_macros.h"
-
void test() {
// assoc_laguerre
- ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0f));
- ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0));
- ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0l));
- ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0));
-
- ASSERT_NOEXCEPT(std::assoc_laguerref(0, 0, 0.0f));
- ASSERT_NOEXCEPT(std::assoc_laguerrel(0, 0, 0.0l));
+ static_assert(noexcept(std::assoc_laguerre(0, 0, 0.0f)));
+ static_assert(noexcept(std::assoc_laguerre(0, 0, 0.0)));
+ static_assert(noexcept(std::assoc_laguerre(0, 0, 0.0l)));
+ static_assert(noexcept(std::assoc_laguerre(0, 0, 0)));
+ static_assert(noexcept(std::assoc_laguerref(0, 0, 0.0f)));
+ static_assert(noexcept(std::assoc_laguerrel(0, 0, 0.0l)));
}
>From baa587977c31ce6f7e6c2200efc059590bf364b2 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Wed, 26 Aug 2026 23:16:33 +0200
Subject: [PATCH 63/72] link libm when it holds feraiseexcept
The mathematical special functions call feraiseexcept to report floating-point
exceptions, and on most Unix platforms that symbol lives in libm. libc++ has
never needed libm before, so it is not on the link line: cxx_shared links with
-nostdlib++ -Wl,-z,defs, where an unresolved symbol is a hard error. Clang's
driver adds -lm to every C++ link and hid this; the generic-gcc CI job, whose
driver does not, failed with
ld: mathematical_special_functions.cpp.o: undefined reference to `feraiseexcept'
Probe for the library and put it on the link line next to libatomic.
The probe is a check_cxx_source_compiles rather than a check_library_exists,
because config-ix puts -nostdlib++ in CMAKE_REQUIRED_FLAGS. That is a C++ driver
option and check_library_exists compiles C, so on a GCC toolchain the C driver
rejects it and the check answers NO for any library -- LIBCXX_HAS_ATOMIC_LIB
included, which is a pre-existing instance of the same problem.
It includes <fenv.h> rather than <cfenv> because libc++'s <cfenv> is <fenv.h>
plus a `using ::feraiseexcept`, so the two name one declaration and one symbol,
and the C header is the one that exists while the C++ headers are still the
libc++ being built.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
libcxx/CMakeLists.txt | 4 ++++
libcxx/cmake/config-ix.cmake | 25 +++++++++++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 6fb440aa46bb4..f933e60e165b4 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -736,6 +736,10 @@ function(cxx_link_system_libraries target)
target_link_libraries(${target} PRIVATE atomic)
endif()
+ if (LIBCXX_HAS_M_LIB)
+ target_link_libraries(${target} PRIVATE m)
+ endif()
+
if (MINGW)
target_link_libraries(${target} PRIVATE "${MINGW_LIBRARIES}")
endif()
diff --git a/libcxx/cmake/config-ix.cmake b/libcxx/cmake/config-ix.cmake
index 270d80575adcf..aeab5ae10370b 100644
--- a/libcxx/cmake/config-ix.cmake
+++ b/libcxx/cmake/config-ix.cmake
@@ -5,6 +5,7 @@ include(LLVMCheckCompilerLinkerFlag)
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
include(CheckCSourceCompiles)
+include(CheckCXXSourceCompiles)
# The compiler driver may be implicitly trying to link against libunwind.
# This is normally ok (libcxx relies on an unwinder), but if libunwind is
@@ -131,3 +132,27 @@ else()
check_library_exists(rt clock_gettime "" LIBCXX_HAS_RT_LIB)
check_library_exists(atomic __atomic_fetch_add_8 "" LIBCXX_HAS_ATOMIC_LIB)
endif()
+
+# The library calls feraiseexcept to report floating-point exceptions from the mathematical
+# special functions. On most Unix platforms that symbol lives in libm, which the library has
+# never needed before, so libm is not on the link line yet. Windows keeps it in the CRT and
+# Apple in libSystem, and neither has a separate libm to link.
+#
+# This is a C++ check rather than a check_library_exists, because CMAKE_REQUIRED_FLAGS holds
+# -nostdlib++ above: that is a C++ driver option, and check_library_exists compiles C, so on
+# a GCC toolchain the C driver rejects it and the check answers NO for any library.
+#
+# <fenv.h> rather than <cfenv>, because libc++'s <cfenv> is <fenv.h> plus a
+# `using ::feraiseexcept` -- the same declaration and the same symbol -- and the C header is
+# the one that exists while the C++ headers are still the libc++ being built.
+if((WIN32 AND NOT MINGW) OR APPLE)
+ set(LIBCXX_HAS_M_LIB NO)
+else()
+ cmake_push_check_state()
+ list(APPEND CMAKE_REQUIRED_LIBRARIES m)
+ check_cxx_source_compiles("
+#include <fenv.h>
+int main() { return feraiseexcept(0); }
+" LIBCXX_HAS_M_LIB)
+ cmake_pop_check_state()
+endif()
>From 4036f9d38dbdd0747e010a0c2c2ef07eee5399ac Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Wed, 26 Aug 2026 23:33:23 +0200
Subject: [PATCH 64/72] build-at-commit: check out third-party/boost-math
libcxx/CMakeLists.txt add_subdirectory()s the vendored Boost.Math
unconditionally, but build-at-commit git-archives a fixed list of directories and
that one is not on it, so configuring the checkout fails:
CMake Error at .../libcxx/CMakeLists.txt:930 (add_subdirectory):
add_subdirectory given source ".../runtimes/../third-party/boost-math"
which is not an existing directory.
This is what the test-tools CI job hits. Commits predating the vendoring stay
buildable: the list is filtered through exists_in_commit before the archive, so a
directory that does not exist at the requested commit is simply dropped.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
libcxx/utils/build-at-commit | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/utils/build-at-commit b/libcxx/utils/build-at-commit
index 2b741e3501a5d..3cab78e05147d 100755
--- a/libcxx/utils/build-at-commit
+++ b/libcxx/utils/build-at-commit
@@ -18,6 +18,7 @@ LIBCXX_REQUIRED_DIRECTORIES = [
'runtimes',
'cmake',
'third-party/benchmark',
+ 'third-party/boost-math',
'libc'
]
>From 295afb4f93bce5211c596512410eeb2fff236980 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Wed, 26 Aug 2026 23:50:04 +0200
Subject: [PATCH 65/72] fast_math test: silence -Wnan-infinity-disabled, drop
the -inf argument
The -ffast-math variant did not compile. -ffinite-math-only makes any use of an
infinity or a NaN undefined behavior, and -Wnan-infinity-disabled reports every
such use; the test suite compiles libc++'s headers as non-system headers
(-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER), so the uses inside <limits> and <cmath>
reach the test TU, where -Werror turns them into errors:
__cmath/special_functions.h:101:19: error: use of infinity is undefined
behavior due to the currently enabled floating-point options
[-Werror,-Wnan-infinity-disabled]
Fourteen of the fifteen sites are in the headers -- numeric_limits<T>::infinity()
itself, the isnan/isinf/isfinite implementations, the unrelated std::__hermite --
and none of them runs from this test, so -Wno-nan-infinity-disabled is the only
way to have a -ffast-math test of anything in <cmath> at all.
The fifteenth was the test body passing -infinity() as a domain-error argument,
which is a real reliance on a value the compiler is licensed to assume never
occurs. Drop it here rather than hide it: it stays covered by the other two
variants and by the test in test/std.
Dropping it needs the preprocessor. `if constexpr` cannot do it -- has_infinity
is true wherever this matters, so nothing would be discarded, and a discarded
substatement in a non-templated entity is still fully analyzed, so it warns
either way.
The variant still does its job: math_errhandling 0 cannot be had without
-ffinite-math-only, since glibc keys it on __FAST_MATH__ and clang defines that
only when finite-math-only is on too. With finite arguments it still pins that
both channels are reported when the caller sees math_errhandling == 0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
...aguerre.error_reporting.fast_math.pass.cpp | 14 ++++++++---
.../c.math/sf.cmath/error_reporting.h | 23 +++++++++++++------
2 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.fast_math.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.fast_math.pass.cpp
index 7cad4f012e4a9..c7c1ccd8c15ce 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.fast_math.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.fast_math.pass.cpp
@@ -12,12 +12,20 @@
// load against a back-deployment target whose libc++ predates them.
// XFAIL: availability-mathematical_special_functions-missing
-// ADDITIONAL_COMPILE_FLAGS: -ffast-math
+// ADDITIONAL_COMPILE_FLAGS: -ffast-math -Wno-nan-infinity-disabled
// Same as assoc_laguerre.error_reporting.pass.cpp, but compiled with -ffast-math, which
// makes glibc define math_errhandling as 0. Both channels must still be reported by the
-// library. -ffinite-math-only makes the value assertions unusable, so error_reporting.h
-// drops them here. See error_reporting.h.
+// library.
+//
+// math_errhandling 0 cannot be had without -ffinite-math-only: glibc keys it on
+// __FAST_MATH__, which clang defines only when finite-math-only is on as well. So
+// error_reporting.h drops the value assertions and the infinite argument here, and
+// -Wnan-infinity-disabled has to be silenced -- it fires inside <limits> and <cmath>
+// themselves (numeric_limits<T>::infinity(), the isnan/isinf/isfinite implementations, the
+// unrelated std::__hermite), which reach this TU because the test suite compiles libc++'s
+// headers as non-system headers. None of those sites runs from here; the test body itself no
+// longer uses an infinity. See error_reporting.h.
#include <cmath>
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h b/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h
index 5ac06d51dca5b..73d53a77d71b1 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h
@@ -27,13 +27,20 @@
#include <cmath>
#include <limits>
-// -ffast-math implies -ffinite-math-only, which lets the compiler fold isnan and a
-// comparison against an infinity to a constant. Only the reporting channels are checked
-// there; the returned values are covered by the test in test/std.
+// -ffast-math implies -ffinite-math-only, which makes any use of an infinity or a NaN
+// undefined behavior and lets the compiler fold isnan and a comparison against an infinity
+// to a constant. Under it this body checks only the reporting channels, and only with finite
+// arguments: the returned values and the -inf argument are dropped. Both stay covered by the
+// other two variants of this test and by the test in test/std.
+//
+// The guard has to be a #if. `if constexpr` would not do: has_infinity is true wherever this
+// matters, so nothing is discarded, and a discarded substatement in a non-templated entity is
+// still fully analyzed ([stmt.if]/2 scopes non-instantiation to templates), so it warns
+// either way. Only the preprocessor removes the tokens from translation.
#ifdef __FAST_MATH__
-# define TEST_SF_CHECK_VALUES 0
+# define TEST_SF_FINITE_MATH_ONLY 1
#else
-# define TEST_SF_CHECK_VALUES 1
+# define TEST_SF_FINITE_MATH_ONLY 0
#endif
// The FE_* macros are optional (picolibc without hardware floating point does not define
@@ -51,7 +58,7 @@ void test_domain_error(Func assoc_laguerre, Float x) {
#ifdef FE_INVALID
assert(std::fetestexcept(FE_INVALID) != 0);
#endif
-#if TEST_SF_CHECK_VALUES
+#if !TEST_SF_FINITE_MATH_ONLY
assert(std::isnan(result));
#endif
}
@@ -70,7 +77,7 @@ void test_range_error(Func assoc_laguerre, Float x) {
#ifdef FE_OVERFLOW
assert(std::fetestexcept(FE_OVERFLOW) != 0);
#endif
-#if TEST_SF_CHECK_VALUES
+#if !TEST_SF_FINITE_MATH_ONLY
assert(result == std::numeric_limits<Float>::infinity());
#endif
}
@@ -88,9 +95,11 @@ inline void test_error_reporting() {
test_domain_error(laguerre_l, -1.0L);
test_domain_error(laguerre_ll, -1.0L);
+#if !TEST_SF_FINITE_MATH_ONLY
// -inf is outside the x >= 0 domain too ([sf.cmath.general]/2)
if (std::numeric_limits<double>::has_infinity)
test_domain_error(laguerre, -std::numeric_limits<double>::infinity());
+#endif
test_range_error(laguerre_f, std::numeric_limits<float>::max());
test_range_error(laguerre_ff, std::numeric_limits<float>::max());
>From 902f459858c84159852200a0d17a66e05f36c98c Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Wed, 26 Aug 2026 23:51:03 +0200
Subject: [PATCH 66/72] error_reporting.h: use if constexpr for the
has_infinity guard
has_infinity is a compile-time property of the type, and every other
numeric_limits guard in these tests spells it that way -- hermite.pass.cpp lines
228, 309 and 318, and assoc_laguerre.pass.cpp lines 51 and 76. This was the only
plain runtime if left.
No behavioral difference here: the call site is a non-templated function on a
fixed double, so nothing is discarded either way. Consistency only.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
.../libcxx/numerics/c.math/sf.cmath/error_reporting.h | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h b/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h
index 73d53a77d71b1..4b0a0e15f66b9 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h
@@ -33,10 +33,11 @@
// arguments: the returned values and the -inf argument are dropped. Both stay covered by the
// other two variants of this test and by the test in test/std.
//
-// The guard has to be a #if. `if constexpr` would not do: has_infinity is true wherever this
-// matters, so nothing is discarded, and a discarded substatement in a non-templated entity is
-// still fully analyzed ([stmt.if]/2 scopes non-instantiation to templates), so it warns
-// either way. Only the preprocessor removes the tokens from translation.
+// The guard has to be a #if, not the `if constexpr` used for has_infinity below: an
+// `if constexpr (__FAST_MATH__ ? false : true)` would discard nothing where it matters, and a
+// discarded substatement in a non-templated entity is still fully analyzed ([stmt.if]/2
+// scopes non-instantiation to templates), so the use of an infinity would be diagnosed either
+// way. Only the preprocessor removes the tokens from translation.
#ifdef __FAST_MATH__
# define TEST_SF_FINITE_MATH_ONLY 1
#else
@@ -97,7 +98,7 @@ inline void test_error_reporting() {
#if !TEST_SF_FINITE_MATH_ONLY
// -inf is outside the x >= 0 domain too ([sf.cmath.general]/2)
- if (std::numeric_limits<double>::has_infinity)
+ if constexpr (std::numeric_limits<double>::has_infinity)
test_domain_error(laguerre, -std::numeric_limits<double>::infinity());
#endif
>From 3e2a4adaf02e06a83947615bef8c748aac4b09ca Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Wed, 26 Aug 2026 23:57:53 +0200
Subject: [PATCH 67/72] export assoc_laguerre from the std module
The [sf.cmath] block in modules/std/cmath.inc sat entirely behind `#if 0`, so
<cmath> exported three names the std module partition did not, which module_std
reports as:
--- t.tmp.cmath.module
+++ t.tmp.cmath.include
+using ::std::assoc_laguerre;
+using ::std::assoc_laguerref;
+using ::std::assoc_laguerrel;
Move the guard below the [sf.cmath.assoc.laguerre] declarations, leaving the
other 20 functions behind it. No _LIBCPP_USING_IF_EXISTS, matching the
[sf.cmath.hermite] block below.
modules/std.compat/cmath.inc needs no counterpart: [sf.cmath] names are the
exception to <math.h> placing everything in the global namespace, so it has
nothing to export there.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
libcxx/modules/std/cmath.inc | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libcxx/modules/std/cmath.inc b/libcxx/modules/std/cmath.inc
index fe8ac773c9d1c..212986bfabd04 100644
--- a/libcxx/modules/std/cmath.inc
+++ b/libcxx/modules/std/cmath.inc
@@ -263,12 +263,13 @@ export namespace std {
using std::signbit _LIBCPP_USING_IF_EXISTS;
// [sf.cmath], mathematical special functions
-#if 0
+
// [sf.cmath.assoc.laguerre], associated Laguerre polynomials
using std::assoc_laguerre;
using std::assoc_laguerref;
using std::assoc_laguerrel;
+#if 0
// [sf.cmath.assoc.legendre], associated Legendre functions
using std::assoc_legendre;
using std::assoc_legendref;
>From 33e724e87d42d5e8a895079272db3832ec386657 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Thu, 27 Aug 2026 00:03:44 +0200
Subject: [PATCH 68/72] add a release note for assoc_laguerre and the libm
dependency
Implemented Papers gets P0226R1 with a parenthetical naming what is implemented,
matching how the other two partially implemented papers are listed:
- P2255R2: A type trait to detect reference binding to temporary
(implemented the type traits only) (Github ...)
- P3372R3: constexpr containers and adaptors (Github ...) (forward_list, list,
priority_queue, flat_map, and flat_set are implemented)
The parenthetical names hermite as well, which has been implemented since
LLVM 19, so the entry describes the state of the paper rather than only this
release's delta.
Build System Changes gets the libm link, which distro packagers and anyone
linking libc++ by hand care about.
docs/Status/Cxx17Papers.csv is left alone. It marks P0226R1 |In Progress| behind
#99939; Styles.rst defines both that marker and |Partial| but documents no
distinction, and switching between them is a maintainer's call, not a
prerequisite for this PR.
ABI Affecting Changes is also left alone: every entry in 20.rst through 23.rst is
a layout or behavior change to an entity that already existed, and no release
note has ever listed a symbol addition there.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
libcxx/docs/ReleaseNotes/24.rst | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/libcxx/docs/ReleaseNotes/24.rst b/libcxx/docs/ReleaseNotes/24.rst
index e55fee2bc8a8c..59476cb313b04 100644
--- a/libcxx/docs/ReleaseNotes/24.rst
+++ b/libcxx/docs/ReleaseNotes/24.rst
@@ -47,6 +47,7 @@ Implemented Papers
- P3961R1: Less double indirection in ``function_ref`` (RU-220) (`Github <https://llvm.org/PR189606>`__)
- P1901R2: Enabling the Use of ``weak_ptr`` as Keys in Unordered Associative Containers (`Github <https://llvm.org/PR105372>`__)
- P0528R3: The Curious Case of Padding Bits, Featuring Atomic Compare-and-Exchange (`Github <https://llvm.org/PR76180>`__)
+- P0226R1: Mathematical Special Functions for C++17 (`Github <https://github.com/llvm/llvm-project/issues/99939>`__) (``assoc_laguerre`` and ``hermite`` are implemented)
Improvements and New Features
-----------------------------
@@ -89,3 +90,7 @@ ABI Affecting Changes
Build System Changes
--------------------
+
+- On platforms where ``feraiseexcept`` lives in libm, libc++ now links against it, since the mathematical special
+ functions use it to report the floating-point exception half of a domain or range error. ``libc++.so`` gains a
+ dependency on libm there. Windows and Apple are unaffected: the symbol is in the CRT and in libSystem respectively.
>From 8856bc1b0bc356a1277756925689fb37c170e084 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Thu, 27 Aug 2026 00:17:56 +0200
Subject: [PATCH 69/72] list assoc_laguerre in the <cmath> and test synopses
The <cmath> synopsis block had no entry for it. Added in the alphabetical
position the second group uses, between asinh and atanh, with all six public
signatures, which is exactly what __cmath/special_functions.h declares.
Concrete types rather than the floating-point-type placeholder: that spelling
comes from P1467R9 (C++23), which libc++ has not implemented -- its row in
Cxx23Papers.csv has an empty status -- and every entry in this synopsis, hermite
included, uses double/float/long double. The // C++17 marker follows hermite too.
The template <class Integer> overload is listed because it exists
(special_functions.h:54) and because hermite lists its counterpart. It is what
makes std::assoc_laguerre(0, 0, 0) compile in the nodiscard and noexcept tests;
without it an int argument would be ambiguous between the three floating-point
overloads.
The synopsis in test/std/.../assoc_laguerre.pass.cpp had both problems, and is
where the placeholder spelling in the first draft of the <cmath> entry came from.
It now lists the same six signatures, formatted like hermite.pass.cpp. The
integer overload was already exercised there by TestInteger, just not listed.
Renamed the header's _Int to _Integer as well, matching hermite 65 lines below
and the spelling both synopses now use.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
libcxx/include/__cmath/special_functions.h | 4 ++--
libcxx/include/cmath | 8 ++++++++
.../numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp | 10 +++++++---
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/libcxx/include/__cmath/special_functions.h b/libcxx/include/__cmath/special_functions.h
index ce1bdbc916639..b1bba2a2f65dc 100644
--- a/libcxx/include/__cmath/special_functions.h
+++ b/libcxx/include/__cmath/special_functions.h
@@ -51,9 +51,9 @@ assoc_laguerre(unsigned __n, unsigned __m, long double __x) noexcept {
return __cmath::__assoc_laguerre(__n, __m, __x);
}
-template <class _Int, std::enable_if_t<std::is_integral_v<_Int>, int> = 0>
+template <class _Integer, std::enable_if_t<std::is_integral_v<_Integer>, int> = 0>
[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_HIDE_FROM_ABI double
-assoc_laguerre(unsigned __n, unsigned __m, _Int __x) noexcept {
+assoc_laguerre(unsigned __n, unsigned __m, _Integer __x) noexcept {
return __cmath::__assoc_laguerre(__n, __m, static_cast<double>(__x));
}
diff --git a/libcxx/include/cmath b/libcxx/include/cmath
index c4f4030c2049b..a3d2a3e0dbe0a 100644
--- a/libcxx/include/cmath
+++ b/libcxx/include/cmath
@@ -160,6 +160,14 @@ floating_point asinh (arithmetic x);
float asinhf(float x);
long double asinhl(long double x);
+double assoc_laguerre(unsigned n, unsigned m, double x); // C++17
+float assoc_laguerre(unsigned n, unsigned m, float x); // C++17
+long double assoc_laguerre(unsigned n, unsigned m, long double x); // C++17
+float assoc_laguerref(unsigned n, unsigned m, float x); // C++17
+long double assoc_laguerrel(unsigned n, unsigned m, long double x); // C++17
+template <class Integer>
+double assoc_laguerre(unsigned n, unsigned m, Integer x); // C++17
+
floating_point atanh (arithmetic x);
float atanhf(float x);
long double atanhl(long double x);
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index b7c59db249810..1fb8a81b7eea9 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -14,9 +14,13 @@
// <cmath>
-// floating-point-type assoc_laguerre( unsigned n, unsigned m, floating-point-type x);
-// float assoc_laguerref(unsigned n, unsigned m, float x );
-// long double assoc_laguerrel(unsigned n, unsigned m, long double x );
+// double assoc_laguerre(unsigned n, unsigned m, double x);
+// float assoc_laguerre(unsigned n, unsigned m, float x);
+// long double assoc_laguerre(unsigned n, unsigned m, long double x);
+// float assoc_laguerref(unsigned n, unsigned m, float x);
+// long double assoc_laguerrel(unsigned n, unsigned m, long double x);
+// template <class Integer>
+// double assoc_laguerre(unsigned n, unsigned m, Integer x);
#include <cassert>
#include <cmath>
>From 94ee344d6b69d70c828ebd5771c50faa17b0fc64 Mon Sep 17 00:00:00 2001
From: PaulXiCao <paul.luckner at rwth-aachen.de>
Date: Sat, 12 Sep 2026 22:56:57 +0200
Subject: [PATCH 70/72] Update libcxx/cmake/config-ix.cmake
suggested by ldionne in review
Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>
---
libcxx/cmake/config-ix.cmake | 3 ---
1 file changed, 3 deletions(-)
diff --git a/libcxx/cmake/config-ix.cmake b/libcxx/cmake/config-ix.cmake
index aeab5ae10370b..3c3c1ab1f2bcd 100644
--- a/libcxx/cmake/config-ix.cmake
+++ b/libcxx/cmake/config-ix.cmake
@@ -142,9 +142,6 @@ endif()
# -nostdlib++ above: that is a C++ driver option, and check_library_exists compiles C, so on
# a GCC toolchain the C driver rejects it and the check answers NO for any library.
#
-# <fenv.h> rather than <cfenv>, because libc++'s <cfenv> is <fenv.h> plus a
-# `using ::feraiseexcept` -- the same declaration and the same symbol -- and the C header is
-# the one that exists while the C++ headers are still the libc++ being built.
if((WIN32 AND NOT MINGW) OR APPLE)
set(LIBCXX_HAS_M_LIB NO)
else()
>From 38ee129ce3b23c3afd3503f8563c68c93c7efc1d Mon Sep 17 00:00:00 2001
From: PaulXiCao <paul.luckner at rwth-aachen.de>
Date: Sat, 12 Sep 2026 22:57:25 +0200
Subject: [PATCH 71/72] Update libcxx/docs/ReleaseNotes/24.rst
suggested by ldionne in review
Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>
---
libcxx/docs/ReleaseNotes/24.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/docs/ReleaseNotes/24.rst b/libcxx/docs/ReleaseNotes/24.rst
index ef282a17f86de..6c08643ea9f05 100644
--- a/libcxx/docs/ReleaseNotes/24.rst
+++ b/libcxx/docs/ReleaseNotes/24.rst
@@ -52,7 +52,7 @@ Implemented Papers
- P2830R10: Standardized Constexpr Type Ordering (`Github <https://llvm.org/PR216616>`__)
- P3778R0: Fix for ``type_order`` template definition (`Github <https://llvm.org/PR216616>`__)
- P4140R0: Proposed resolution for US70-126: allow incomplete types in type_order (`Github <https://llvm.org/PR216616>`__)
-- P0226R1: Mathematical Special Functions for C++17 (`Github <https://github.com/llvm/llvm-project/issues/99939>`__) (``assoc_laguerre`` and ``hermite`` are implemented)
+- P0226R1: Mathematical Special Functions for C++17 (`Github <https://github.com/llvm/llvm-project/issues/99939>`__) (only ``assoc_laguerre`` and ``hermite`` are implemented)
Improvements and New Features
-----------------------------
>From 8cfef67d7e52931c751367ae4c84c60602ad227d Mon Sep 17 00:00:00 2001
From: PaulXiCao <paul.luckner at rwth-aachen.de>
Date: Sat, 12 Sep 2026 23:04:09 +0200
Subject: [PATCH 72/72] Update libcxx/include/__configuration/availability.h
suggested by ldionne in review
Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>
---
libcxx/include/__configuration/availability.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__configuration/availability.h b/libcxx/include/__configuration/availability.h
index a7430a25ad260..a01ff6125b318 100644
--- a/libcxx/include/__configuration/availability.h
+++ b/libcxx/include/__configuration/availability.h
@@ -296,7 +296,7 @@
#define _LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_20_ATTRIBUTE
// This controls the availability of the C++17 mathematical special functions
-// ([sf.cmath]). Their implementation lives in the built library (backed by Boost.Math).
+// ([sf.cmath]). Their implementation lives in the built library.
#define _LIBCPP_AVAILABILITY_HAS_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_24
#define _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_24_ATTRIBUTE
More information about the llvm-commits
mailing list