[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