[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 Jul 4 03:46:57 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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/52] 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,
+ ),
+ ),
]
More information about the llvm-commits
mailing list