[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
Tue Aug 25 13:55:37 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] 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/62] guard via
 _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS

---
 libcxx/include/__configuration/availability.h |  5 +++++
 libcxx/include/__math/special_functions.h     | 20 ++++++++++++-------
 .../c.math/sf.cmath/nodiscard.verify.cpp      |  4 ++++
 .../c.math/sf.cmath/noexcept.compile.pass.cpp |  4 ++++
 .../c.math/sf.cmath/assoc_laguerre.pass.cpp   |  4 ++++
 .../libcxx/test/features/availability.py      |  8 ++++++++
 6 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/libcxx/include/__configuration/availability.h b/libcxx/include/__configuration/availability.h
index 735af5d431cb1..72eb50721338f 100644
--- a/libcxx/include/__configuration/availability.h
+++ b/libcxx/include/__configuration/availability.h
@@ -271,6 +271,11 @@
 #define _LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_20
 #define _LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_20_ATTRIBUTE
 
+// This controls the availability of the C++17 mathematical special functions
+// ([sf.cmath]). Their implementation lives in the built library (backed by Boost.Math).
+#define _LIBCPP_AVAILABILITY_HAS_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_23
+#define _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_23_ATTRIBUTE
+
 // This controls the availability of the C++20 time zone database.
 // The parser code is built in the library.
 #define _LIBCPP_AVAILABILITY_HAS_TZDB _LIBCPP_INTRODUCED_IN_LLVM_19
diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 5021e5a54b634..546600b72bce0 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -29,26 +29,32 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 
 // assoc_laguerre
 namespace __math {
-[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI float __assoc_laguerre(unsigned, unsigned, float) noexcept;
-[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI double __assoc_laguerre(unsigned, unsigned, double) noexcept;
-[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI long double __assoc_laguerre(unsigned, unsigned, long double) noexcept;
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_EXPORTED_FROM_ABI float
+__assoc_laguerre(unsigned, unsigned, float) noexcept;
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_EXPORTED_FROM_ABI double
+__assoc_laguerre(unsigned, unsigned, double) noexcept;
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_EXPORTED_FROM_ABI long double
+__assoc_laguerre(unsigned, unsigned, long double) noexcept;
 } // namespace __math
 
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI float assoc_laguerref(unsigned __n, unsigned __m, float __x) noexcept {
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI float
+assoc_laguerref(unsigned __n, unsigned __m, float __x) noexcept {
   return __math::__assoc_laguerre(__n, __m, __x);
 }
 
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI double assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI double
+assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
   return __math::__assoc_laguerre(__n, __m, __x);
 }
 
-[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI long double
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI long double
 assoc_laguerrel(unsigned __n, unsigned __m, long double __x) noexcept {
   return __math::__assoc_laguerre(__n, __m, __x);
 }
 
 template <class _Int, std::enable_if_t<std::is_integral_v<_Int>, int> = 0>
-[[nodiscard]] _LIBCPP_HIDE_FROM_ABI double assoc_laguerre(unsigned __n, unsigned __m, _Int __x) noexcept {
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_HIDE_FROM_ABI double
+assoc_laguerre(unsigned __n, unsigned __m, _Int __x) noexcept {
   return __math::__assoc_laguerre(__n, __m, static_cast<double>(__x));
 }
 
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
index b83070f4f984d..598311f20917d 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
@@ -8,6 +8,10 @@
 
 // REQUIRES: std-at-least-c++17
 
+// The functions carry availability markup, so referencing them fails to compile against a
+// back-deployment target whose libc++ predates them.
+// XFAIL: availability-mathematical_special_functions-missing
+
 // Check that functions are marked [[nodiscard]]
 
 #include <cmath>
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
index cca9c1e924a8c..8f9dd87c0ee87 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
@@ -8,6 +8,10 @@
 
 // REQUIRES: std-at-least-c++17
 
+// The functions carry availability markup, so referencing them fails to compile against a
+// back-deployment target whose libc++ predates them.
+// XFAIL: availability-mathematical_special_functions-missing
+
 // Check that functions are marked noexcept
 
 #include <cmath>
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index b39e20fe6288a..91a7c4a3d2047 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -8,6 +8,10 @@
 
 // REQUIRES: std-at-least-c++17
 
+// These functions are implemented in the built library, so a program using them fails to
+// load against a back-deployment target whose libc++ predates them.
+// XFAIL: availability-mathematical_special_functions-missing
+
 // <cmath>
 
 // double      assoc_laguerre(unsigned n, unsigned m, double x);
diff --git a/libcxx/utils/libcxx/test/features/availability.py b/libcxx/utils/libcxx/test/features/availability.py
index c0f2a3d4cdc88..7bb1add0e9e9c 100644
--- a/libcxx/utils/libcxx/test/features/availability.py
+++ b/libcxx/utils/libcxx/test/features/availability.py
@@ -211,4 +211,12 @@
             cfg.available_features,
         ),
     ),
+    # Tests that require the C++17 mathematical special functions in the built library
+    Feature(
+        name="availability-mathematical_special_functions-missing",
+        when=lambda cfg: BooleanExpression.evaluate(
+            "!libcpp-has-no-availability-markup && (stdlib=apple-libc++ && !_target-has-llvm-23)",
+            cfg.available_features,
+        ),
+    ),
 ]

>From c63f3e0b04b37c5dcd6294473878de37d612a0f7 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 4 Jul 2026 13:31:20 +0200
Subject: [PATCH 53/62] cleanup header includes

---
 libcxx/include/__math/special_functions.h     | 1 -
 libcxx/src/mathematical_special_functions.cpp | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 546600b72bce0..9721430ee0c64 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -11,7 +11,6 @@
 #define _LIBCPP___MATH_SPECIAL_FUNCTIONS_H
 
 #include <__config>
-#include <__configuration/attributes.h>
 #include <__math/copysign.h>
 #include <__math/traits.h>
 #include <__type_traits/enable_if.h>
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index dc046b3a845df..e9f655d56aa69 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -37,6 +37,7 @@
 #endif
 
 #define BOOST_MATH_NO_EXCEPTIONS
+#include <boost/math/policies/policy.hpp>
 #include <boost/math/special_functions/laguerre.hpp>
 
 _LIBCPP_BEGIN_NAMESPACE_STD

>From 8afb315b5746d25b2c2f915d91fffa49b41720f8 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 4 Jul 2026 14:02:44 +0200
Subject: [PATCH 54/62] test: add integral tests; refactor

---
 .../c.math/sf.cmath/assoc_laguerre.pass.cpp   | 72 +++++++++----------
 1 file changed, 36 insertions(+), 36 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index 91a7c4a3d2047..7561cb27b6020 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -14,62 +14,62 @@
 
 // <cmath>
 
-// double      assoc_laguerre(unsigned n, unsigned m, double x);
-// float       assoc_laguerref(unsigned n, unsigned m, float x);
-// long double assoc_laguerrel(unsigned n, unsigned m, long double x);
+// floating-point-type assoc_laguerre( unsigned n, unsigned m, floating-point-type x);
+// float               assoc_laguerref(unsigned n, unsigned m, float x              );
+// long double         assoc_laguerrel(unsigned n, unsigned m, long double x        );
 
 #include <cassert>
 #include <cmath>
+#include <initializer_list>
 #include <limits>
 #include <type_traits>
 
 #include "common.h"
 #include "type_algorithms.h"
 
-// Each overload is fixed to a single floating-point type, so it is tested
-// directly with that type. The integer-argument overload
-// (assoc_laguerre(unsigned, unsigned, Integer) -> double) is not implemented yet.
-template <class ExpectedFuncRet, class FuncArgX, class Func>
-void test(Func assoc_laguerre) {
-  // sample values
-  assert(between(0.99, assoc_laguerre(0, 0, FuncArgX(0)), 1.01));
-  assert(between(0.99, assoc_laguerre(1, 1, FuncArgX(1)), 1.01));
-  assert(between(-1.01, assoc_laguerre(2, 0, FuncArgX(2)), -0.99));
-  assert(between(-0.01, assoc_laguerre(2, 2, FuncArgX(2)), 0.01));
-  if constexpr (std::is_floating_point_v<FuncArgX>)
-    assert(between(60.124, assoc_laguerre(2, 10, FuncArgX(0.5)), 60.126));
+// Tests a fixed-precision overload (assoc_laguerre / assoc_laguerref / assoc_laguerrel),
+// whose argument and return type are both `Float`.
+template <class Float, class Func>
+void test_floating_point(Func assoc_laguerre) {
+  // return type is the argument type
+  static_assert(std::is_same_v<decltype(assoc_laguerre(0, 0, Float(0))), Float>);
 
-  static_assert(std::is_same_v<decltype(assoc_laguerre(0, 0, FuncArgX(0))), ExpectedFuncRet>);
+  // sample values
+  assert(between(0.99, assoc_laguerre(0, 0, Float(0)), 1.01));
+  assert(between(0.99, assoc_laguerre(1, 1, Float(1)), 1.01));
+  assert(between(-1.01, assoc_laguerre(2, 0, Float(2)), -0.99));
+  assert(between(-0.01, assoc_laguerre(2, 2, Float(2)), 0.01));
+  assert(between(60.124, assoc_laguerre(2, 10, Float(0.5)), 60.126));
 
-  // NaN argument -> NaN result, without a domain error ([sf.cmath.general]/1).
-  if constexpr (std::is_floating_point_v<FuncArgX>) {
-    auto test_nan = [&](FuncArgX nan) {
-      check_no_domain_error([&] { assert(std::isnan(assoc_laguerre(0, 0, nan))); });
-    };
-    if (std::numeric_limits<FuncArgX>::has_quiet_NaN)
-      test_nan(std::numeric_limits<FuncArgX>::quiet_NaN());
-    if (std::numeric_limits<FuncArgX>::has_signaling_NaN)
-      test_nan(std::numeric_limits<FuncArgX>::signaling_NaN());
-  }
+  // a negative argument is in the domain (no domain error)
+  check_no_domain_error([&] { assert(between(1.99, assoc_laguerre(1, 0, Float(-1)), 2.01)); });
 
-  // A negative argument is in the domain (no domain error).
-  check_no_domain_error([&] { assert(between(1.99, assoc_laguerre(1, 0, FuncArgX(-1)), 2.01)); });
+  // NaN argument -> NaN result, without a domain error ([sf.cmath.general]/1)
+  auto test_nan = [&](Float nan) { check_no_domain_error([&] { assert(std::isnan(assoc_laguerre(0, 0, nan))); }); };
+  if (std::numeric_limits<Float>::has_quiet_NaN)
+    test_nan(std::numeric_limits<Float>::quiet_NaN());
+  if (std::numeric_limits<Float>::has_signaling_NaN)
+    test_nan(std::numeric_limits<Float>::signaling_NaN());
 }
 
-struct TestIntegral {
-  template <class Int>
+// Tests the integer-argument overload: it promotes the argument to double and returns double.
+struct TestInteger {
+  template <class Integer>
   void operator()() const {
-    test<double, Int>([](unsigned n, unsigned m, Int x) { return std::assoc_laguerre(n, m, x); });
+    static_assert(std::is_same_v<decltype(std::assoc_laguerre(0u, 0u, Integer(0))), double>);
+
+    // same result as the double overload with the argument cast to double
+    for (Integer x : {Integer(0), Integer(1), Integer(2)})
+      assert(std::assoc_laguerre(2, 0, x) == std::assoc_laguerre(2, 0, static_cast<double>(x)));
   }
 };
 
 int main(int, char**) {
-  test<double, double>([](unsigned n, unsigned m, double x) { return std::assoc_laguerre(n, m, x); });
-
-  test<float, float>([](unsigned n, unsigned m, float x) { return std::assoc_laguerref(n, m, x); });
-  test<long double, long double>([](unsigned n, unsigned m, long double x) { return std::assoc_laguerrel(n, m, x); });
+  test_floating_point<float>([](unsigned n, unsigned m, float x) { return std::assoc_laguerref(n, m, x); });
+  test_floating_point<double>([](unsigned n, unsigned m, double x) { return std::assoc_laguerre(n, m, x); });
+  test_floating_point<long double>([](unsigned n, unsigned m, long double x) { return std::assoc_laguerrel(n, m, x); });
 
-  // types::for_each(types::integral_types{}, TestIntegral{}); WIP
+  types::for_each(types::integral_types{}, TestInteger{});
 
   return 0;
 }

>From 7236c0aa7861a04227195f8fa88d0f7efde7267c Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 4 Jul 2026 14:21:17 +0200
Subject: [PATCH 55/62] impl assoc_laguerre(float/long double) + tests

---
 libcxx/include/__math/special_functions.h          | 14 ++++++++++++--
 .../numerics/c.math/sf.cmath/nodiscard.verify.cpp  |  6 ++++--
 .../c.math/sf.cmath/noexcept.compile.pass.cpp      | 13 +++----------
 .../c.math/sf.cmath/assoc_laguerre.pass.cpp        |  2 ++
 4 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/libcxx/include/__math/special_functions.h b/libcxx/include/__math/special_functions.h
index 9721430ee0c64..8bb805d721b5f 100644
--- a/libcxx/include/__math/special_functions.h
+++ b/libcxx/include/__math/special_functions.h
@@ -37,7 +37,7 @@ __assoc_laguerre(unsigned, unsigned, long double) noexcept;
 } // namespace __math
 
 [[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI float
-assoc_laguerref(unsigned __n, unsigned __m, float __x) noexcept {
+assoc_laguerre(unsigned __n, unsigned __m, float __x) noexcept {
   return __math::__assoc_laguerre(__n, __m, __x);
 }
 
@@ -47,7 +47,7 @@ assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
 }
 
 [[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI long double
-assoc_laguerrel(unsigned __n, unsigned __m, long double __x) noexcept {
+assoc_laguerre(unsigned __n, unsigned __m, long double __x) noexcept {
   return __math::__assoc_laguerre(__n, __m, __x);
 }
 
@@ -57,6 +57,16 @@ assoc_laguerre(unsigned __n, unsigned __m, _Int __x) noexcept {
   return __math::__assoc_laguerre(__n, __m, static_cast<double>(__x));
 }
 
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI float
+assoc_laguerref(unsigned __n, unsigned __m, float __x) noexcept {
+  return __math::__assoc_laguerre(__n, __m, __x);
+}
+
+[[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI long double
+assoc_laguerrel(unsigned __n, unsigned __m, long double __x) noexcept {
+  return __math::__assoc_laguerre(__n, __m, __x);
+}
+
 _LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
 
 // hermite
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
index 598311f20917d..4729dbd23c58e 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
@@ -19,8 +19,10 @@
 void test() {
   // clang-format off
   // assoc_laguerre
-  std::assoc_laguerre(0, 0, 0.0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::assoc_laguerre(0, 0, 0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::assoc_laguerre(0, 0, 0.0f);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::assoc_laguerre(0, 0, 0.0);   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::assoc_laguerre(0, 0, 0.0l);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::assoc_laguerre(0, 0, 0);     // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
 
   std::assoc_laguerref(0, 0, 0.0f); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
   std::assoc_laguerrel(0, 0, 0.0l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
index 8f9dd87c0ee87..b9993ab6500a7 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
@@ -17,21 +17,14 @@
 #include <cmath>
 
 #include "test_macros.h"
-#include "type_algorithms.h"
-
-struct TestIntegral {
-  template <class T>
-  void operator()() const {
-    ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, T{}));
-  }
-};
 
 void test() {
   // assoc_laguerre
+  ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0f));
   ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0));
+  ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0l));
+  ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0));
 
   ASSERT_NOEXCEPT(std::assoc_laguerref(0, 0, 0.0f));
   ASSERT_NOEXCEPT(std::assoc_laguerrel(0, 0, 0.0l));
-
-  types::for_each(types::integral_types{}, TestIntegral{});
 }
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index 7561cb27b6020..a0dca3cf5ce14 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -66,8 +66,10 @@ struct TestInteger {
 
 int main(int, char**) {
   test_floating_point<float>([](unsigned n, unsigned m, float x) { return std::assoc_laguerref(n, m, x); });
+  test_floating_point<float>([](unsigned n, unsigned m, float x) { return std::assoc_laguerre(n, m, x); });
   test_floating_point<double>([](unsigned n, unsigned m, double x) { return std::assoc_laguerre(n, m, x); });
   test_floating_point<long double>([](unsigned n, unsigned m, long double x) { return std::assoc_laguerrel(n, m, x); });
+  test_floating_point<long double>([](unsigned n, unsigned m, long double x) { return std::assoc_laguerre(n, m, x); });
 
   types::for_each(types::integral_types{}, TestInteger{});
 

>From 743cc59817c20cb989c244ba6ad9588586777993 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 4 Jul 2026 22:59:48 +0200
Subject: [PATCH 56/62] test: if constexpr on NaN support

---
 .../std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp  | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index a0dca3cf5ce14..dbd8a5d24eaee 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -45,10 +45,12 @@ void test_floating_point(Func assoc_laguerre) {
   check_no_domain_error([&] { assert(between(1.99, assoc_laguerre(1, 0, Float(-1)), 2.01)); });
 
   // NaN argument -> NaN result, without a domain error ([sf.cmath.general]/1)
-  auto test_nan = [&](Float nan) { check_no_domain_error([&] { assert(std::isnan(assoc_laguerre(0, 0, nan))); }); };
-  if (std::numeric_limits<Float>::has_quiet_NaN)
+  [[maybe_unused]] auto test_nan = [&](Float nan) {
+    check_no_domain_error([&] { assert(std::isnan(assoc_laguerre(0, 0, nan))); });
+  };
+  if constexpr (std::numeric_limits<Float>::has_quiet_NaN)
     test_nan(std::numeric_limits<Float>::quiet_NaN());
-  if (std::numeric_limits<Float>::has_signaling_NaN)
+  if constexpr (std::numeric_limits<Float>::has_signaling_NaN)
     test_nan(std::numeric_limits<Float>::signaling_NaN());
 }
 

>From 4745005a1a88853ea9af7d9ce8c4525e5004f9d0 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 25 Aug 2026 22:19:54 +0200
Subject: [PATCH 57/62] report domain and range errors for assoc_laguerre

[sf.cmath.general]/1.1 makes an argument outside the domain stated in a
function's Returns: element a domain error, and [cmath.syn]/1 imports C
7.12.1 for how one is reported: errno = EDOM plus FE_INVALID, and
errno = ERANGE plus FE_OVERFLOW for a range error from overflow. Boost
only ever sets errno, so raise the flags here.

Both channels are used unconditionally: math_errhandling describes the
caller's translation unit, which these out-of-line definitions cannot
see, so a caller built with -fno-math-errno or -ffast-math must still
get both.

assoc_laguerre specifics: x >= 0 is the domain, so a negative x (-inf
included) is a domain error. x == +inf is in the domain and its value
follows the leading term (-1)^n x^n / n! -- answered directly because
Boost's recurrence forms inf - inf for n >= 3. A non-finite result from
finite arguments is an overflow; Boost's recurrence can produce either
an infinity or, two steps later, inf - inf == NaN, and past the largest
root the sign is again the leading term's.

Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
 libcxx/src/mathematical_special_functions.cpp | 121 ++++++++++++------
 .../c.math/sf.cmath/assoc_laguerre.pass.cpp   |  29 ++++-
 .../std/numerics/c.math/sf.cmath/common.h     |  39 ++++++
 3 files changed, 151 insertions(+), 38 deletions(-)

diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index 2d43f25dc4914..6c597561344b1 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -6,11 +6,12 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include <__config>
 #include <__cmath/special_functions.h>
+#include <__config>
+#include <cerrno>
+#include <cfenv>
 #include <cmath>
-#include <optional>
-#include <type_traits>
+#include <limits>
 
 // GCC defines __STDCPP_FLOATnn_T__ whenever the _Floatnn extended types exist at the
 // language level, independent of the standard library. libc++ currently ships no
@@ -45,6 +46,16 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 #if _LIBCPP_STD_VER >= 17
 
 namespace __math {
+
+// Boost.Math computes; the per-function wrappers below add the standard's error rules.
+// Notes that apply to all of them:
+//  - underflow is left alone: C 7.12.1/5 makes both the ERANGE and the flag
+//    implementation-defined there, and Boost's underflow policy defaults to ignore.
+//  - C 7.12.1/1 ("as if a single operation") is not implemented: intermediate flags from
+//    Boost's recurrences leak into the caller's environment.
+//  - promotion: Boost's default promote_float=true computes float inputs in double and
+//    rounds once -- more accurate and overflow-resistant, matching the existing
+//    std::hermite(float) approach. We keep it.
 namespace {
 // Error policy for all Boost.Math calls: report domain/pole/overflow/evaluation
 // errors via errno (errno_on_error) instead of throwing. Boost sets errno to
@@ -57,52 +68,90 @@ using __policy =
                   __bmp::overflow_error<__bmp::errno_on_error>,
                   __bmp::evaluation_error<__bmp::errno_on_error>>;
 
+// Reports a domain error and returns the value libc++ hands back for one.
+//
+// C 7.12.1/2, imported by [cmath.syn]/1: errno acquires EDOM when math_errhandling &
+// MATH_ERRNO, "invalid" is raised when math_errhandling & MATH_ERREXCEPT, and the
+// returned value is implementation-defined. Both channels are used unconditionally
+// because math_errhandling describes the caller's translation unit, which this
+// out-of-line definition cannot see. FE_INVALID is optional -- picolibc without
+// hardware floating point does not define it.
 template <class _Ret>
-std::optional<_Ret> __check_nan() {
-  return std::nullopt;
+_Ret __report_domain_error() {
+  errno = EDOM;
+#  ifdef FE_INVALID
+  std::feraiseexcept(FE_INVALID);
+#  endif
+  return std::numeric_limits<_Ret>::quiet_NaN();
 }
 
-template <class _Ret, class _Arg, class... _Args>
-std::optional<_Ret> __check_nan(_Arg __arg, _Args... __args) {
-  if constexpr (std::is_floating_point_v<_Arg>)
-    if (std::isnan(__arg))
-      return __arg;
-  return __check_nan<_Ret>(__args...);
-}
-
-// Shared back-end for the C++17 mathematical special functions ([sf.cmath]).
-// Boost.Math is the compute kernel; this wrapper enforces the standard's
-// error-reporting rules ([sf.cmath.general]):
-//   1. NaN argument -> return NaN, do NOT report a domain error (the
-//      __check_nan pre-filter below).
-//   2. domain/range error -> reported via errno only: Boost's errno_on_error
-//      policy sets errno = EDOM (domain/pole/evaluation) or ERANGE (overflow).
-//      The <cfenv> floating-point-exception side of math_errhandling
-//      (MATH_ERREXCEPT) is intentionally not mirrored, matching the shipped
-//      std::hermite and libstdc++'s special-function implementations.
-// Promotion: Boost's default promote_float=true computes float inputs in double
-// and rounds once -- more accurate and overflow-resistant, matching the
-// existing std::hermite(float) approach. We keep it.
-template <class _Func, class... _Args, class _Ret = std::invoke_result_t<_Func, _Args...>>
-_Ret __invoke_boost_math(_Func __f, _Args... __args) {
-  if (auto __maybe_nan = __check_nan<_Ret>(__args...); __maybe_nan.has_value())
-    return *__maybe_nan;
-
-  return __f(__args..., __policy{});
+// Reports a range error from overflow and returns __value, which the caller supplies as
+// the correctly signed HUGE_VAL (an infinity on IEEE 754 targets), per C 7.12.1/4. No
+// Boost policy raises floating-point exceptions, so the flag is ours to raise; Boost's
+// own overflow detection sets ERANGE too, and the two channels have to agree. A pole would
+// want FE_DIVBYZERO instead, and Boost's policies cannot tell the two apart (both map to
+// ERANGE) -- none of the functions implemented so far has one.
+template <class _Ret>
+_Ret __report_overflow(_Ret __value) {
+  errno = ERANGE;
+#  ifdef FE_OVERFLOW
+  std::feraiseexcept(FE_OVERFLOW);
+#  endif
+  return __value;
 }
 } // namespace
 
 // assoc_laguerre
-float __assoc_laguerre(unsigned __n, unsigned __m, float __x) noexcept {
-  return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
+namespace {
+template <class _Real>
+_Real __assoc_laguerre_impl(unsigned __n, unsigned __m, _Real __x) {
+  // [sf.cmath.general]/1: a NaN argument returns a NaN and reports no domain error. It is
+  // returned unchanged, so a signaling NaN stays signaling. IEEE 754 would raise "invalid"
+  // for it -- and the comparisons below can too, since the relational operators may signal
+  // for unordered operands (C 7.12.14) -- which [sf.cmath] neither requires nor forbids
+  // for a NaN argument. Quiet NaNs, the case that matters, reach neither.
+  if (std::isnan(__x))
+    return __x;
+
+  // [sf.cmath.assoc.laguerre] Returns: states the domain as x >= 0, so a negative
+  // argument -- -inf included ([sf.cmath.general]/2) -- is a domain error
+  // ([sf.cmath.general]/1.1). Boost evaluates such an argument happily, so the check has
+  // to live here.
+  if (__x < 0)
+    return __report_domain_error<_Real>();
+
+  // x == +inf is in the domain. The leading term of L^m_n is (-1)^n x^n / n!, so the value
+  // there is 1 for n == 0 and (-1)^n * inf otherwise. That is not a range error: the
+  // mathematical result is itself infinite. Answered here because Boost's recurrence is
+  // not infinity-safe (it forms inf - inf for n >= 3) and its narrowing cast reports a
+  // spurious ERANGE for an infinite value.
+  if (std::isinf(__x))
+    return __n == 0 ? _Real(1) : (__n % 2 == 0 ? __x : -__x);
+
+  _Real __result = boost::math::laguerre(__n, __m, __x, __policy{});
+
+  // A non-finite result from finite arguments is a range error from overflow (C 7.12.1/4).
+  // Boost runs the recurrence in the result type, so a value on the way to L^m_n that does
+  // not fit becomes an infinity and, two steps further, inf - inf == NaN. Past its largest
+  // root L^m_n has the sign of its leading term, so both cases are overflowed values with
+  // a known sign rather than undefined ones.
+  if (!std::isfinite(__result)) {
+    _Real __inf = std::numeric_limits<_Real>::infinity();
+    return __report_overflow(__n % 2 == 0 ? __inf : -__inf);
+  }
+
+  return __result;
 }
+} // namespace
+
+float __assoc_laguerre(unsigned __n, unsigned __m, float __x) noexcept { return __assoc_laguerre_impl(__n, __m, __x); }
 
 double __assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
-  return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
+  return __assoc_laguerre_impl(__n, __m, __x);
 }
 
 long double __assoc_laguerre(unsigned __n, unsigned __m, long double __x) noexcept {
-  return __invoke_boost_math([](auto... __args) { return boost::math::laguerre(__args...); }, __n, __m, __x);
+  return __assoc_laguerre_impl(__n, __m, __x);
 }
 
 } // namespace __math
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
index dbd8a5d24eaee..b7c59db249810 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/assoc_laguerre.pass.cpp
@@ -41,8 +41,33 @@ void test_floating_point(Func assoc_laguerre) {
   assert(between(-0.01, assoc_laguerre(2, 2, Float(2)), 0.01));
   assert(between(60.124, assoc_laguerre(2, 10, Float(0.5)), 60.126));
 
-  // a negative argument is in the domain (no domain error)
-  check_no_domain_error([&] { assert(between(1.99, assoc_laguerre(1, 0, Float(-1)), 2.01)); });
+  // [sf.cmath.assoc.laguerre] Returns: states the domain as x >= 0, so a negative
+  // argument is a domain error ([sf.cmath.general]/1.1)
+  check_domain_error([&] { assoc_laguerre(1, 0, Float(-1)); });
+
+  // [sf.cmath.general]/2 leaves both infinities in the domain unless the Returns:
+  // element excludes them, and x >= 0 excludes -inf but not +inf. The leading term of
+  // L^m_n is (-1)^n x^n / n!, so L^m_n(+inf) is 1 for n == 0 and (-1)^n * inf otherwise.
+  if constexpr (std::numeric_limits<Float>::has_infinity) {
+    const Float inf = std::numeric_limits<Float>::infinity();
+
+    check_domain_error([&] { assoc_laguerre(1, 0, -inf); });
+
+    check_no_domain_error([&] { assert(assoc_laguerre(0, 0, inf) == Float(1)); });
+    check_no_domain_error([&] { assert(assoc_laguerre(1, 0, inf) == -inf); });
+    check_no_domain_error([&] { assert(assoc_laguerre(2, 0, inf) == inf); });
+    check_no_domain_error([&] { assert(assoc_laguerre(3, 5, inf) == -inf); });
+
+    // An infinity produced from finite arguments is a range error, not a domain error:
+    // errno == ERANGE and the value is +-HUGE_VAL, again with the sign of the leading
+    // term (C 7.12.1/4).
+    const Float max = std::numeric_limits<Float>::max();
+
+    check_range_error([&] { assert(assoc_laguerre(2, 0, max) == inf); });
+    check_range_error([&] { assert(assoc_laguerre(3, 0, max) == -inf); });
+    check_range_error([&] { assert(assoc_laguerre(4, 1, max) == inf); });
+    check_range_error([&] { assert(assoc_laguerre(5, 1, max) == -inf); });
+  }
 
   // NaN argument -> NaN result, without a domain error ([sf.cmath.general]/1)
   [[maybe_unused]] auto test_nan = [&](Float nan) {
diff --git a/libcxx/test/std/numerics/c.math/sf.cmath/common.h b/libcxx/test/std/numerics/c.math/sf.cmath/common.h
index ca6de9ea868bd..5d0d5f3a49eb9 100644
--- a/libcxx/test/std/numerics/c.math/sf.cmath/common.h
+++ b/libcxx/test/std/numerics/c.math/sf.cmath/common.h
@@ -11,6 +11,7 @@
 
 #include <cassert>
 #include <cerrno>
+#include <cfenv>
 #include <cmath>
 
 // std::type_identity is C++20 (we need to support C++17 here)
@@ -26,9 +27,18 @@ bool between(type_identity_t<T> lower, T value, type_identity_t<T> upper) {
   return lower < value && value < upper;
 }
 
+// C 7.12.1/2 and /4, imported by [cmath.syn]/1: a domain error sets errno to EDOM and
+// raises "invalid", a range error from overflow sets errno to ERANGE and raises
+// "overflow" -- each channel only when math_errhandling advertises it.
+//
 // Note: math_errhandling must be queried with a runtime `if`, not `#if`. On Apple
 // platforms it is defined as a function call (__math_errhandling()), so it is not a
 // preprocessor constant and would break `#if` under -Wundef.
+//
+// The FE_* macros are optional (picolibc without hardware floating point does not define
+// them), so every use is guarded. The flag is only asserted for the error cases: an
+// error-free call may still raise "inexact" or "overflow" from an intermediate step, and
+// a signaling NaN argument may raise "invalid" from a comparison.
 template <class Func>
 void check_no_domain_error(Func f) {
   if (math_errhandling & MATH_ERRNO)
@@ -42,9 +52,38 @@ template <class Func>
 void check_domain_error(Func f) {
   if (math_errhandling & MATH_ERRNO)
     errno = EACCES;
+#ifdef FE_INVALID
+  if (math_errhandling & MATH_ERREXCEPT)
+    std::feclearexcept(FE_INVALID);
+#endif
+
   f();
+
   if (math_errhandling & MATH_ERRNO)
     assert(errno == EDOM);
+#ifdef FE_INVALID
+  if (math_errhandling & MATH_ERREXCEPT)
+    assert(std::fetestexcept(FE_INVALID) != 0);
+#endif
+}
+
+template <class Func>
+void check_range_error(Func f) {
+  if (math_errhandling & MATH_ERRNO)
+    errno = EACCES;
+#ifdef FE_OVERFLOW
+  if (math_errhandling & MATH_ERREXCEPT)
+    std::feclearexcept(FE_OVERFLOW);
+#endif
+
+  f();
+
+  if (math_errhandling & MATH_ERRNO)
+    assert(errno == ERANGE);
+#ifdef FE_OVERFLOW
+  if (math_errhandling & MATH_ERREXCEPT)
+    assert(std::fetestexcept(FE_OVERFLOW) != 0);
+#endif
 }
 
 #endif // TEST_SF_CMATH_COMMON_H

>From 0857945b9d96f2d5c8c05abdfcfa7c9fd596c70d Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 25 Aug 2026 22:19:55 +0200
Subject: [PATCH 58/62] test error reporting under math-related compile flags

The reporting is unconditional by design, so pin it down where
math_errhandling changes: glibc drops it to MATH_ERREXCEPT under
-fno-math-errno and to 0 under -ffast-math. Three lit variants share one
body; -ffast-math implies -ffinite-math-only, which folds isnan and
comparisons against infinities, so only the channels are checked there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
 ...aguerre.error_reporting.fast_math.pass.cpp |  30 ++++++
 ...rre.error_reporting.no_math_errno.pass.cpp |  29 +++++
 .../assoc_laguerre.error_reporting.pass.cpp   |  26 +++++
 .../c.math/sf.cmath/error_reporting.h         | 102 ++++++++++++++++++
 4 files changed, 187 insertions(+)
 create mode 100644 libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.fast_math.pass.cpp
 create mode 100644 libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.no_math_errno.pass.cpp
 create mode 100644 libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.pass.cpp
 create mode 100644 libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h

diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.fast_math.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.fast_math.pass.cpp
new file mode 100644
index 0000000000000..7cad4f012e4a9
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.fast_math.pass.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// These functions are implemented in the built library, so a program using them fails to
+// load against a back-deployment target whose libc++ predates them.
+// XFAIL: availability-mathematical_special_functions-missing
+
+// ADDITIONAL_COMPILE_FLAGS: -ffast-math
+
+// Same as assoc_laguerre.error_reporting.pass.cpp, but compiled with -ffast-math, which
+// makes glibc define math_errhandling as 0. Both channels must still be reported by the
+// library. -ffinite-math-only makes the value assertions unusable, so error_reporting.h
+// drops them here. See error_reporting.h.
+
+#include <cmath>
+
+#include "error_reporting.h"
+
+int main(int, char**) {
+  test_error_reporting();
+
+  return 0;
+}
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.no_math_errno.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.no_math_errno.pass.cpp
new file mode 100644
index 0000000000000..eb128abac1689
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.no_math_errno.pass.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// These functions are implemented in the built library, so a program using them fails to
+// load against a back-deployment target whose libc++ predates them.
+// XFAIL: availability-mathematical_special_functions-missing
+
+// ADDITIONAL_COMPILE_FLAGS: -fno-math-errno
+
+// Same as assoc_laguerre.error_reporting.pass.cpp, but compiled with -fno-math-errno,
+// which makes glibc define math_errhandling as MATH_ERREXCEPT alone. The library still
+// has to set errno: it cannot see the caller's flags. See error_reporting.h.
+
+#include <cmath>
+
+#include "error_reporting.h"
+
+int main(int, char**) {
+  test_error_reporting();
+
+  return 0;
+}
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.pass.cpp
new file mode 100644
index 0000000000000..5c8443ad7a458
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/assoc_laguerre.error_reporting.pass.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// These functions are implemented in the built library, so a program using them fails to
+// load against a back-deployment target whose libc++ predates them.
+// XFAIL: availability-mathematical_special_functions-missing
+
+// Implementation-defined half of the error reporting for std::assoc_laguerre, with the
+// default math flags. See error_reporting.h.
+
+#include <cmath>
+
+#include "error_reporting.h"
+
+int main(int, char**) {
+  test_error_reporting();
+
+  return 0;
+}
diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h b/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h
new file mode 100644
index 0000000000000..5ac06d51dca5b
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/error_reporting.h
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Shared body for the assoc_laguerre error-reporting tests, which run it under several
+// math-related compile flags.
+//
+// C 7.12.1/2 and /4, imported by [cmath.syn]/1, tie the reporting channel to
+// math_errhandling and leave the value returned on a domain error implementation-defined.
+// libc++ returns a quiet NaN and reports on *both* channels unconditionally, because
+// math_errhandling describes the caller's translation unit while these functions are
+// defined out of line in the built library: a caller compiled with -fno-math-errno (glibc
+// then defines math_errhandling as MATH_ERREXCEPT) or with -ffast-math (math_errhandling
+// becomes 0) must still see errno and the flags set. That is what these tests pin down,
+// so the assertions here are deliberately not guarded on math_errhandling.
+
+#ifndef TEST_LIBCXX_SF_CMATH_ERROR_REPORTING_H
+#define TEST_LIBCXX_SF_CMATH_ERROR_REPORTING_H
+
+#include <cassert>
+#include <cerrno>
+#include <cfenv>
+#include <cmath>
+#include <limits>
+
+// -ffast-math implies -ffinite-math-only, which lets the compiler fold isnan and a
+// comparison against an infinity to a constant. Only the reporting channels are checked
+// there; the returned values are covered by the test in test/std.
+#ifdef __FAST_MATH__
+#  define TEST_SF_CHECK_VALUES 0
+#else
+#  define TEST_SF_CHECK_VALUES 1
+#endif
+
+// The FE_* macros are optional (picolibc without hardware floating point does not define
+// them), so every use is guarded.
+template <class Func, class Float>
+void test_domain_error(Func assoc_laguerre, Float x) {
+  errno = 0;
+#ifdef FE_INVALID
+  std::feclearexcept(FE_INVALID);
+#endif
+
+  [[maybe_unused]] Float result = assoc_laguerre(1, 0, x);
+
+  assert(errno == EDOM);
+#ifdef FE_INVALID
+  assert(std::fetestexcept(FE_INVALID) != 0);
+#endif
+#if TEST_SF_CHECK_VALUES
+  assert(std::isnan(result));
+#endif
+}
+
+template <class Func, class Float>
+void test_range_error(Func assoc_laguerre, Float x) {
+  errno = 0;
+#ifdef FE_OVERFLOW
+  std::feclearexcept(FE_OVERFLOW);
+#endif
+
+  // L^0_2(x) = 1 - 2x + x^2/2 does not fit for an x near the largest finite value
+  [[maybe_unused]] Float result = assoc_laguerre(2, 0, x);
+
+  assert(errno == ERANGE);
+#ifdef FE_OVERFLOW
+  assert(std::fetestexcept(FE_OVERFLOW) != 0);
+#endif
+#if TEST_SF_CHECK_VALUES
+  assert(result == std::numeric_limits<Float>::infinity());
+#endif
+}
+
+inline void test_error_reporting() {
+  auto laguerre_f  = [](unsigned n, unsigned m, float x) { return std::assoc_laguerref(n, m, x); };
+  auto laguerre    = [](unsigned n, unsigned m, double x) { return std::assoc_laguerre(n, m, x); };
+  auto laguerre_l  = [](unsigned n, unsigned m, long double x) { return std::assoc_laguerrel(n, m, x); };
+  auto laguerre_ff = [](unsigned n, unsigned m, float x) { return std::assoc_laguerre(n, m, x); };
+  auto laguerre_ll = [](unsigned n, unsigned m, long double x) { return std::assoc_laguerre(n, m, x); };
+
+  test_domain_error(laguerre_f, -1.0f);
+  test_domain_error(laguerre_ff, -1.0f);
+  test_domain_error(laguerre, -1.0);
+  test_domain_error(laguerre_l, -1.0L);
+  test_domain_error(laguerre_ll, -1.0L);
+
+  // -inf is outside the x >= 0 domain too ([sf.cmath.general]/2)
+  if (std::numeric_limits<double>::has_infinity)
+    test_domain_error(laguerre, -std::numeric_limits<double>::infinity());
+
+  test_range_error(laguerre_f, std::numeric_limits<float>::max());
+  test_range_error(laguerre_ff, std::numeric_limits<float>::max());
+  test_range_error(laguerre, std::numeric_limits<double>::max());
+  test_range_error(laguerre_l, std::numeric_limits<long double>::max());
+  test_range_error(laguerre_ll, std::numeric_limits<long double>::max());
+}
+
+#endif // TEST_LIBCXX_SF_CMATH_ERROR_REPORTING_H

>From 8dce1510d5ef464bbf8adb0a06262f2a6947fbf6 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 25 Aug 2026 22:33:34 +0200
Subject: [PATCH 59/62] rename the dylib namespace from __math to __cmath

__math/ and __cmath/ are split by which public header has to expose the
name: __math/ holds the C functions <math.h> also provides, in
std::__math::, re-exported to global scope by math.h; __cmath/ holds the
<cmath>-only additions. 8d47bda9cd1a moved this header out of __math/
precisely because these were the only functions there that were not in
the __math namespace -- declaring them in __math:: from __cmath/ was the
mirror image of the same inconsistency.

std::__cmath:: also stops the two from reading alike at the point of
use: special_functions.h calls both __math::isnan and, one line later,
its own helpers.

The three mangled names change with it, so all 9 libcxx/lib/abi lists
move: _ZNSt3__16__math16__assoc_laguerreEjjf becomes
_ZNSt3__17__cmath16__assoc_laguerreEjjf. Kept in generate_abi_list.py's
sort order (the pre-existing bad_array_new_length inversions are
untouched). No released symbol is affected -- these are new on this
branch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
 libcxx/include/__cmath/special_functions.h       | 16 ++++++++--------
 ....libcxxabi.v1.stable.exceptions.nonew.abilist |  6 +++---
 ....libcxxabi.v1.stable.exceptions.nonew.abilist |  6 +++---
 ....libcxxabi.v1.stable.exceptions.nonew.abilist |  6 +++---
 ....libcxxabi.v1.stable.exceptions.nonew.abilist |  6 +++---
 ....libcxxabi.v1.stable.exceptions.nonew.abilist |  6 +++---
 ....libcxxabi.v1.stable.exceptions.nonew.abilist |  6 +++---
 ....libcxxabi.v1.stable.exceptions.nonew.abilist |  6 +++---
 ....libcxxabi.v1.stable.exceptions.nonew.abilist |  6 +++---
 ...ibcxxabi.v1.stable.noexceptions.nonew.abilist |  6 +++---
 libcxx/src/mathematical_special_functions.cpp    |  4 ++--
 11 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/libcxx/include/__cmath/special_functions.h b/libcxx/include/__cmath/special_functions.h
index 17c4ba90cc0b7..ce1bdbc916639 100644
--- a/libcxx/include/__cmath/special_functions.h
+++ b/libcxx/include/__cmath/special_functions.h
@@ -27,44 +27,44 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 
 // assoc_laguerre
-namespace __math {
+namespace __cmath {
 [[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_EXPORTED_FROM_ABI float
 __assoc_laguerre(unsigned, unsigned, float) noexcept;
 [[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_EXPORTED_FROM_ABI double
 __assoc_laguerre(unsigned, unsigned, double) noexcept;
 [[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_EXPORTED_FROM_ABI long double
 __assoc_laguerre(unsigned, unsigned, long double) noexcept;
-} // namespace __math
+} // namespace __cmath
 
 [[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI float
 assoc_laguerre(unsigned __n, unsigned __m, float __x) noexcept {
-  return __math::__assoc_laguerre(__n, __m, __x);
+  return __cmath::__assoc_laguerre(__n, __m, __x);
 }
 
 [[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI double
 assoc_laguerre(unsigned __n, unsigned __m, double __x) noexcept {
-  return __math::__assoc_laguerre(__n, __m, __x);
+  return __cmath::__assoc_laguerre(__n, __m, __x);
 }
 
 [[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI long double
 assoc_laguerre(unsigned __n, unsigned __m, long double __x) noexcept {
-  return __math::__assoc_laguerre(__n, __m, __x);
+  return __cmath::__assoc_laguerre(__n, __m, __x);
 }
 
 template <class _Int, std::enable_if_t<std::is_integral_v<_Int>, int> = 0>
 [[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_HIDE_FROM_ABI double
 assoc_laguerre(unsigned __n, unsigned __m, _Int __x) noexcept {
-  return __math::__assoc_laguerre(__n, __m, static_cast<double>(__x));
+  return __cmath::__assoc_laguerre(__n, __m, static_cast<double>(__x));
 }
 
 [[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI float
 assoc_laguerref(unsigned __n, unsigned __m, float __x) noexcept {
-  return __math::__assoc_laguerre(__n, __m, __x);
+  return __cmath::__assoc_laguerre(__n, __m, __x);
 }
 
 [[nodiscard]] _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS inline _LIBCPP_HIDE_FROM_ABI long double
 assoc_laguerrel(unsigned __n, unsigned __m, long double __x) noexcept {
-  return __math::__assoc_laguerre(__n, __m, __x);
+  return __cmath::__assoc_laguerre(__n, __m, __x);
 }
 
 _LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
diff --git a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 629c34e5f3c72..0b35fefe2cd81 100644
--- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1701,9 +1701,6 @@
 {'is_defined': True, 'name': '__ZNSt3__15wcoutE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__16__itoa8__u64toaEyPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1772,6 +1769,9 @@
 {'is_defined': True, 'name': '__ZNSt3__16thread6detachEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__16threadD1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__17__cmath16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__17codecvtIDiDu11__mbstate_tE2idE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZNSt3__17codecvtIDiDu11__mbstate_tED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__17codecvtIDiDu11__mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index 2761e2a92ab58..ceed6e413dd2c 100644
--- a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1339,9 +1339,6 @@
 {'is_defined': True, 'name': '_ZNSt6__ndk16__clocEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u32toaEjPc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u64toaEyPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1410,6 +1407,9 @@
 {'is_defined': True, 'name': '_ZNSt6__ndk16thread6detachEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16threadD1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cmath16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk17codecvtIDiDu9mbstate_tE2idE', 'size': 8, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt6__ndk17codecvtIDiDu9mbstate_tED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk17codecvtIDiDu9mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 1ec9665f78ffc..2c022fd452fa9 100644
--- a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -687,9 +687,6 @@
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEyPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12steady_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12system_clock11from_time_tEi', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12system_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
@@ -741,6 +738,9 @@
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16thread6detachEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16threadD1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16threadD2Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjd', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjje', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjf', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDuPcE2idE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDuPcED0Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDuPcED1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 7761e33ff97d0..f90d482858f09 100644
--- a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -687,9 +687,6 @@
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
-{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12steady_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12system_clock11from_time_tEl', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16chrono12system_clock3nowEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
@@ -741,6 +738,9 @@
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16thread6detachEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16threadD1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__16threadD2Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjd', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjje', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjf', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDuPcE2idE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDuPcED0Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDuPcED1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 63a56a4a8f367..a387fd331f81d 100644
--- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1690,9 +1690,6 @@
 {'is_defined': True, 'name': '__ZNSt3__15wcoutE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__16__itoa8__u64toaEyPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1761,6 +1758,9 @@
 {'is_defined': True, 'name': '__ZNSt3__16thread6detachEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__16threadD1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__17__cmath16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__17codecvtIDiDu11__mbstate_tE2idE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZNSt3__17codecvtIDiDu11__mbstate_tED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__17codecvtIDiDu11__mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index 75936b3f0f102..5a20b6fde0d34 100644
--- a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1339,9 +1339,6 @@
 {'is_defined': True, 'name': '_ZNSt6__ndk16__clocEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u32toaEjPc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16__itoa8__u64toaEmPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt6__ndk16__math16__assoc_laguerreEjjg', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1410,6 +1407,9 @@
 {'is_defined': True, 'name': '_ZNSt6__ndk16thread6detachEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16threadD1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt6__ndk17__cmath16__assoc_laguerreEjjg', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk17codecvtIDiDu9mbstate_tE2idE', 'size': 16, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt6__ndk17codecvtIDiDu9mbstate_tED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt6__ndk17codecvtIDiDu9mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
index ba4ce0e65c354..506771d2fbcb3 100644
--- a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1351,9 +1351,6 @@
 {'is_defined': True, 'name': '_ZNSt3__15wcoutE', 'size': 160, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1422,6 +1419,9 @@
 {'is_defined': True, 'name': '_ZNSt3__16thread6detachEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16threadD1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tE2idE', 'size': 16, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
index 425b2f367013e..fcb1a3bef89c9 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1350,9 +1350,6 @@
 {'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1421,6 +1418,9 @@
 {'is_defined': True, 'name': '_ZNSt3__16thread6detachEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16threadD1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tE2idE', 'size': 16, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
index ebea1ab30439d..89367962fb850 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
@@ -1321,9 +1321,6 @@
 {'is_defined': True, 'name': '_ZNSt3__16__clocEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__itoa8__u32toaEjPc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__itoa8__u64toaEmPc', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjd', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjje', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__16__math16__assoc_laguerreEjjf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIccEEPcEEvT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIddEEPdEEvT0_S5_T_', 'type': 'FUNC'}
@@ -1392,6 +1389,9 @@
 {'is_defined': True, 'name': '_ZNSt3__16thread6detachEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16threadD1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__16threadD2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjd', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjje', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__17__cmath16__assoc_laguerreEjjf', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tE2idE', 'size': 16, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__17codecvtIDiDu11__mbstate_tED1Ev', 'type': 'FUNC'}
diff --git a/libcxx/src/mathematical_special_functions.cpp b/libcxx/src/mathematical_special_functions.cpp
index 6c597561344b1..fb606538acbcf 100644
--- a/libcxx/src/mathematical_special_functions.cpp
+++ b/libcxx/src/mathematical_special_functions.cpp
@@ -45,7 +45,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 #if _LIBCPP_STD_VER >= 17
 
-namespace __math {
+namespace __cmath {
 
 // Boost.Math computes; the per-function wrappers below add the standard's error rules.
 // Notes that apply to all of them:
@@ -154,7 +154,7 @@ long double __assoc_laguerre(unsigned __n, unsigned __m, long double __x) noexce
   return __assoc_laguerre_impl(__n, __m, __x);
 }
 
-} // namespace __math
+} // namespace __cmath
 
 #endif
 _LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS

>From 108b926d492b06bd9c4747dc8d3a164be1d27b0e Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 25 Aug 2026 22:44:15 +0200
Subject: [PATCH 60/62] add the LLVM 24 availability tier and mark the special
 functions with it

LLVM 23 has branched: cmake/Modules/LLVMVersion.cmake says
LLVM_VERSION_MAJOR 24 and libcxx/docs/ReleaseNotes.rst points at
ReleaseNotes/24.rst, so anything landing on main now ships in 24. Saying
_LIBCPP_INTRODUCED_IN_LLVM_23 told back-deployment targets the symbols
exist in a release that does not contain them.

_LIBCPP_INTRODUCED_IN_LLVM_24 did not exist -- 23 was the newest, added
by the <text_encoding> PR (#141312) -- so add the tier the same way:
available unconditionally when vendor annotations are off, and on Apple
a "TODO: Fill this in" placeholder that is 0 plus
__attribute__((unavailable)) until an OS release is synchronized to
LLVM 24, matching what LLVM 22 and 23 still look like there.

On the lit side, _target-has-llvm-24 takes over the "TBD" and
_target-has-llvm-23 chains off it, mirroring how 22 chains off 23. Both
still evaluate false, so no feature changes state; what changes is that
using-built-library-before-llvm-24, which the loop already generates and
libcxx/test/libcxx/input.output/iostream.objects/sync_with_stdio.buffer_type.pass.cpp
already uses, now resolves against a feature that exists.

Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
---
 libcxx/include/__configuration/availability.h     | 12 ++++++++++--
 libcxx/utils/libcxx/test/features/availability.py | 11 +++++++++--
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/__configuration/availability.h b/libcxx/include/__configuration/availability.h
index 9430f4976d23d..ff3c413922516 100644
--- a/libcxx/include/__configuration/availability.h
+++ b/libcxx/include/__configuration/availability.h
@@ -39,6 +39,9 @@
 // in all versions of the library are available.
 #if !_LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS
 
+#  define _LIBCPP_INTRODUCED_IN_LLVM_24 1
+#  define _LIBCPP_INTRODUCED_IN_LLVM_24_ATTRIBUTE /* nothing */
+
 #  define _LIBCPP_INTRODUCED_IN_LLVM_23 1
 #  define _LIBCPP_INTRODUCED_IN_LLVM_23_ATTRIBUTE /* nothing */
 
@@ -73,6 +76,11 @@
 
 // clang-format off
 
+// LLVM 24
+// TODO: Fill this in
+#  define _LIBCPP_INTRODUCED_IN_LLVM_24 0
+#  define _LIBCPP_INTRODUCED_IN_LLVM_24_ATTRIBUTE __attribute__((unavailable))
+
 // LLVM 23
 // TODO: Fill this in
 #  define _LIBCPP_INTRODUCED_IN_LLVM_23 0
@@ -275,8 +283,8 @@
 
 // This controls the availability of the C++17 mathematical special functions
 // ([sf.cmath]). Their implementation lives in the built library (backed by Boost.Math).
-#define _LIBCPP_AVAILABILITY_HAS_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_23
-#define _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_23_ATTRIBUTE
+#define _LIBCPP_AVAILABILITY_HAS_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_24
+#define _LIBCPP_AVAILABILITY_MATHEMATICAL_SPECIAL_FUNCTIONS _LIBCPP_INTRODUCED_IN_LLVM_24_ATTRIBUTE
 
 // This controls the availability of the C++20 time zone database.
 // The parser code is built in the library.
diff --git a/libcxx/utils/libcxx/test/features/availability.py b/libcxx/utils/libcxx/test/features/availability.py
index d2c655e61ed9f..4d75ac15371b0 100644
--- a/libcxx/utils/libcxx/test/features/availability.py
+++ b/libcxx/utils/libcxx/test/features/availability.py
@@ -13,12 +13,19 @@
 # Those are used for backdeployment features below, do not use directly in tests.
 features = [
     Feature(
-        name="_target-has-llvm-23",
+        name="_target-has-llvm-24",
         when=lambda cfg: BooleanExpression.evaluate(
             "TBD",
             cfg.available_features,
         ),
     ),
+    Feature(
+        name="_target-has-llvm-23",
+        when=lambda cfg: BooleanExpression.evaluate(
+            "_target-has-llvm-24",
+            cfg.available_features,
+        ),
+    ),
     Feature(
         name="_target-has-llvm-22",
         when=lambda cfg: BooleanExpression.evaluate(
@@ -215,7 +222,7 @@
     Feature(
         name="availability-mathematical_special_functions-missing",
         when=lambda cfg: BooleanExpression.evaluate(
-            "!libcpp-has-no-availability-markup && (stdlib=apple-libc++ && !_target-has-llvm-23)",
+            "!libcpp-has-no-availability-markup && (stdlib=apple-libc++ && !_target-has-llvm-24)",
             cfg.available_features,
         ),
     ),

>From fe37eeffd60ff2941e1774b8ac2285740c735c08 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 25 Aug 2026 22:52:40 +0200
Subject: [PATCH 61/62] nodiscard tests: use `// expected-warning at +1` style

---
 .../c.math/sf.cmath/nodiscard.verify.cpp      | 21 +++++++++++--------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
index 4729dbd23c58e..60d34199d745e 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/nodiscard.verify.cpp
@@ -17,14 +17,17 @@
 #include <cmath>
 
 void test() {
-  // clang-format off
   // assoc_laguerre
-  std::assoc_laguerre(0, 0, 0.0f);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::assoc_laguerre(0, 0, 0.0);   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::assoc_laguerre(0, 0, 0.0l);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::assoc_laguerre(0, 0, 0);     // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-
-  std::assoc_laguerref(0, 0, 0.0f); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::assoc_laguerrel(0, 0, 0.0l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-  // clang-format on
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::assoc_laguerre(0, 0, 0.0f);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::assoc_laguerre(0, 0, 0.0);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::assoc_laguerre(0, 0, 0.0l);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::assoc_laguerre(0, 0, 0);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::assoc_laguerref(0, 0, 0.0f);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::assoc_laguerrel(0, 0, 0.0l);
 }

>From d9ba8075ad051745e9578e68a36605f43d7a8450 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 25 Aug 2026 22:54:34 +0200
Subject: [PATCH 62/62] noexcept tests: inline ASSERT_NOEXCEPT macro

---
 .../c.math/sf.cmath/noexcept.compile.pass.cpp     | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
index b9993ab6500a7..a537712879323 100644
--- a/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/sf.cmath/noexcept.compile.pass.cpp
@@ -16,15 +16,12 @@
 
 #include <cmath>
 
-#include "test_macros.h"
-
 void test() {
   // assoc_laguerre
-  ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0f));
-  ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0));
-  ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0.0l));
-  ASSERT_NOEXCEPT(std::assoc_laguerre(0, 0, 0));
-
-  ASSERT_NOEXCEPT(std::assoc_laguerref(0, 0, 0.0f));
-  ASSERT_NOEXCEPT(std::assoc_laguerrel(0, 0, 0.0l));
+  static_assert(noexcept(std::assoc_laguerre(0, 0, 0.0f)));
+  static_assert(noexcept(std::assoc_laguerre(0, 0, 0.0)));
+  static_assert(noexcept(std::assoc_laguerre(0, 0, 0.0l)));
+  static_assert(noexcept(std::assoc_laguerre(0, 0, 0)));
+  static_assert(noexcept(std::assoc_laguerref(0, 0, 0.0f)));
+  static_assert(noexcept(std::assoc_laguerrel(0, 0, 0.0l)));
 }



More information about the llvm-commits mailing list