[libcxx-commits] [libcxx] [libc++] Document the strengthened noexcept convention (PR #203869)

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jun 15 03:48:49 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Louis Dionne (ldionne)

<details>
<summary>Changes</summary>

The C++ standard explicitly permits implementations to add `noexcept` to non-virtual library functions whose specification does not require it, and libc++ already does this in many places. Since implementing <expected>, we've been using the "// strengthened" end-of-line comment pattern also used by MSVC to flag places where we strengthen the noexcept specification.

This patch documents that convention in the Coding Guidelines. It also applies the change to a few places to show what that would look like. If we decide to actually commit to this convention, this PR would be ammended to fix them all.

---
Full diff: https://github.com/llvm/llvm-project/pull/203869.diff


2 Files Affected:

- (modified) libcxx/docs/CodingGuidelines.rst (+19) 
- (modified) libcxx/include/__functional/operations.h (+5-5) 


``````````diff
diff --git a/libcxx/docs/CodingGuidelines.rst b/libcxx/docs/CodingGuidelines.rst
index d91e3f22f36b6..94cf59614ef9f 100644
--- a/libcxx/docs/CodingGuidelines.rst
+++ b/libcxx/docs/CodingGuidelines.rst
@@ -225,3 +225,22 @@ after the function they are measuring, with a few transformations to help filter
 When multiple benchmarks measure the same function under different circumstances, we add context as a parenthesis
 after the function signature. For example, ``std::vector<bool>::ctor(Self&&, const allocator_type&) (equal allocators)``
 would be the allocator-aware move constructor for ``std::vector<bool>`` in the case of equal allocators.
+
+Mark strengthened ``noexcept`` specifiers with ``// strengthened``
+==================================================================
+
+The C++ standard explicitly permits implementations to add ``noexcept`` to non-virtual library
+functions whose specification does not require it (`[res.on.exception.handling]/5
+<http://eel.is/c++draft/res.on.exception.handling#5>`_):
+
+  An implementation may strengthen the exception specification for a non-virtual function by
+  adding a non-throwing exception specification.
+
+Every libc++ ``noexcept`` clause that goes beyond what the standard mandates is annotated with an
+end-of-line ``// strengthened`` comment:
+
+.. code-block:: cpp
+
+  _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept(is_nothrow_default_constructible_v<_Tp>) // strengthened
+    requires is_default_constructible_v<_Tp>
+      : __base(in_place) {}
diff --git a/libcxx/include/__functional/operations.h b/libcxx/include/__functional/operations.h
index 7a80dce648fa1..ae3ed385dc648 100644
--- a/libcxx/include/__functional/operations.h
+++ b/libcxx/include/__functional/operations.h
@@ -54,7 +54,7 @@ template <>
 struct plus<void> {
   template <class _T1, class _T2>
   _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const
-      noexcept(noexcept(std::forward<_T1>(__t) + std::forward<_T2>(__u))) //
+      noexcept(noexcept(std::forward<_T1>(__t) + std::forward<_T2>(__u))) // strengthened
       -> decltype(std::forward<_T1>(__t) + std::forward<_T2>(__u)) {
     return std::forward<_T1>(__t) + std::forward<_T2>(__u);
   }
@@ -80,7 +80,7 @@ template <>
 struct minus<void> {
   template <class _T1, class _T2>
   _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const
-      noexcept(noexcept(std::forward<_T1>(__t) - std::forward<_T2>(__u))) //
+      noexcept(noexcept(std::forward<_T1>(__t) - std::forward<_T2>(__u))) // strengthened
       -> decltype(std::forward<_T1>(__t) - std::forward<_T2>(__u)) {
     return std::forward<_T1>(__t) - std::forward<_T2>(__u);
   }
@@ -106,7 +106,7 @@ template <>
 struct multiplies<void> {
   template <class _T1, class _T2>
   _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const
-      noexcept(noexcept(std::forward<_T1>(__t) * std::forward<_T2>(__u))) //
+      noexcept(noexcept(std::forward<_T1>(__t) * std::forward<_T2>(__u))) // strengthened
       -> decltype(std::forward<_T1>(__t) * std::forward<_T2>(__u)) {
     return std::forward<_T1>(__t) * std::forward<_T2>(__u);
   }
@@ -132,7 +132,7 @@ template <>
 struct divides<void> {
   template <class _T1, class _T2>
   _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const
-      noexcept(noexcept(std::forward<_T1>(__t) / std::forward<_T2>(__u))) //
+      noexcept(noexcept(std::forward<_T1>(__t) / std::forward<_T2>(__u))) // strengthened
       -> decltype(std::forward<_T1>(__t) / std::forward<_T2>(__u)) {
     return std::forward<_T1>(__t) / std::forward<_T2>(__u);
   }
@@ -158,7 +158,7 @@ template <>
 struct modulus<void> {
   template <class _T1, class _T2>
   _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const
-      noexcept(noexcept(std::forward<_T1>(__t) % std::forward<_T2>(__u))) //
+      noexcept(noexcept(std::forward<_T1>(__t) % std::forward<_T2>(__u))) // strengthened
       -> decltype(std::forward<_T1>(__t) % std::forward<_T2>(__u)) {
     return std::forward<_T1>(__t) % std::forward<_T2>(__u);
   }

``````````

</details>


https://github.com/llvm/llvm-project/pull/203869


More information about the libcxx-commits mailing list