[libcxx-commits] [libcxx] [libc++] Handle Clang function effect analysis in hardening assertions (PR #177447)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jan 27 08:46:31 PST 2026


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/177447

>From f5d74052b3b1306e221de9c36fd6a8bcfa466a55 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Thu, 22 Jan 2026 13:30:01 -0500
Subject: [PATCH 01/12] [libc++] Handle Clang function effect analysis in
 hardening assertions

This patch ensures that libc++ assertions are compatible with the function
effect analysis extension in Clang. The function effect analysis extension
allows marking functions with attributes like [[nonblocking]], and Clang
will issue a diagnostic if such a function calls another function that
doesn't satisfy the requirements of the attribute.

When an assertion fails, libc++ sometimes calls potentially blocking
functions (e.g. in the observe mode). However, this only happens when
a precondition has been violated. Hence, it is acceptable not to satisfy
these function effect attributes once the assertion is known to fail.

The alternative would be that libc++ functions with preconditions cannot
be called from [[nonblocking]] functions, since we might add an assertion
in the future that would not satisfy the attribute.

rdar://164189063
---
 libcxx/include/__assert                       | 10 ++++-
 .../clang/function-effect-analysis.sh.cpp     | 41 +++++++++++++++++++
 2 files changed, 49 insertions(+), 2 deletions(-)
 create mode 100644 libcxx/test/extensions/clang/function-effect-analysis.sh.cpp

diff --git a/libcxx/include/__assert b/libcxx/include/__assert
index a9451daf47f2f..b114aa8c12dbb 100644
--- a/libcxx/include/__assert
+++ b/libcxx/include/__assert
@@ -17,11 +17,17 @@
 #  pragma GCC system_header
 #endif
 
+// Note that we disable -Wfunction-effects inside _LIBCPP_ASSERT when the assertion fails since
+// function effect attributes don't provide any guarantees once a function is determined to be
+// out of contract.
 #define _LIBCPP_ASSERT(expression, message)                                                                            \
   (__builtin_expect(static_cast<bool>(expression), 1)                                                                  \
        ? (void)0                                                                                                       \
-       : _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(                                                      \
-             __LINE__) ": libc++ Hardening assertion " _LIBCPP_TOSTRING(expression) " failed: " message "\n"))
+       : _LIBCPP_DIAGNOSTIC_PUSH                                    /*                                              */ \
+             _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wfunction-effects") /*                                              */ \
+       _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(                                                        \
+           __LINE__) ": libc++ Hardening assertion " _LIBCPP_TOSTRING(expression) " failed: " message "\n")            \
+           _LIBCPP_DIAGNOSTIC_POP)
 
 // WARNING: __builtin_assume can currently inhibit optimizations. Only add assumptions with a clear
 // optimization intent. See https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609 for a
diff --git a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
new file mode 100644
index 0000000000000..c1408724fc4c6
--- /dev/null
+++ b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// GCC doesn't support -Wfunction-effect-analysis and the associated attributes
+// UNSUPPORTED: gcc
+
+// The observe semantic requires experimental support for now.
+// XFAIL: libcpp-has-no-experimental-hardening-observe-semantic
+
+// Make sure that libc++ assertions are compatible with the function effect analysis
+// extension in Clang. The function effect analysis extension allows marking functions
+// with attributes like [[nonblocking]], and Clang will issue a diagnostic if such a
+// function calls another function that doesn't satisfy the requirements of the attribute.
+//
+// However, libc++'s assertion functions are called in a context where a precondition
+// has been violated. Hence, it is acceptable not to satisfy these function effect
+// attributes once the assertion is known to fail.
+//
+// This test ensures that we properly disable function effect analysis diagnostics
+// in libc++'s assertion macros, otherwise it becomes impossible to call a function
+// with hardened preconditions from e.g. a [[nonblocking]] function.
+
+// ADDITIONAL_COMPILE_FLAGS: -Wfunction-effects -Werror=function-effects
+
+// RUN: %{build}
+// RUN: %{build} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE
+// RUN: %{build} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE
+// RUN: %{build} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
+// RUN: %{build} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE
+
+#include <__assert>
+
+void f(bool condition) noexcept [[clang::nonblocking]] { _LIBCPP_ASSERT(condition, "message"); }
+void g(bool condition) noexcept [[clang::nonallocating]] { _LIBCPP_ASSERT(condition, "message"); }
+
+int main(int, char**) { return 0; }

>From 578715df4d199592ab3fd6b1c0d242d8fe59e1a1 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Fri, 23 Jan 2026 10:03:54 -0500
Subject: [PATCH 02/12] Reword comment

---
 libcxx/include/__assert | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__assert b/libcxx/include/__assert
index b114aa8c12dbb..388db33f12f20 100644
--- a/libcxx/include/__assert
+++ b/libcxx/include/__assert
@@ -17,9 +17,10 @@
 #  pragma GCC system_header
 #endif
 
-// Note that we disable -Wfunction-effects inside _LIBCPP_ASSERT when the assertion fails since
-// function effect attributes don't provide any guarantees once a function is determined to be
-// out of contract.
+// Note that we disable -Wfunction-effects inside _LIBCPP_ASSERT when the assertion fails because
+// once function's preconditions are violated, function effect analysis can no longer provide any
+// meaningful guarantees (e.g., cannot guarantee the caller is non-blocking, regardless of function
+// effect attributes).
 #define _LIBCPP_ASSERT(expression, message)                                                                            \
   (__builtin_expect(static_cast<bool>(expression), 1)                                                                  \
        ? (void)0                                                                                                       \

>From 27cdfbf633410b832f177e3a2cb75b1ed8c374b6 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Fri, 23 Jan 2026 10:04:45 -0500
Subject: [PATCH 03/12] Remove redundant warning

---
 libcxx/test/extensions/clang/function-effect-analysis.sh.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
index c1408724fc4c6..2693d3fb7aba3 100644
--- a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
+++ b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
@@ -25,7 +25,7 @@
 // in libc++'s assertion macros, otherwise it becomes impossible to call a function
 // with hardened preconditions from e.g. a [[nonblocking]] function.
 
-// ADDITIONAL_COMPILE_FLAGS: -Wfunction-effects -Werror=function-effects
+// ADDITIONAL_COMPILE_FLAGS: -Werror=function-effects
 
 // RUN: %{build}
 // RUN: %{build} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE

>From 50313f2bc5ca8e50fcc54a58c9b6b37b2b2e9593 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Fri, 23 Jan 2026 10:25:34 -0500
Subject: [PATCH 04/12] Use verify and apply attribute instead of pragmas

---
 libcxx/include/__log_hardening_failure        | 10 ++++-
 .../clang/function-effect-analysis.sh.cpp     | 45 ++++++++++++++-----
 2 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/libcxx/include/__log_hardening_failure b/libcxx/include/__log_hardening_failure
index d1805306f6b6e..200ade9a83be8 100644
--- a/libcxx/include/__log_hardening_failure
+++ b/libcxx/include/__log_hardening_failure
@@ -24,7 +24,15 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 // This function should never be called directly from the code -- it should only be called through the
 // `_LIBCPP_LOG_HARDENING_FAILURE` macro.
-[[__gnu__::__cold__]] _LIBCPP_EXPORTED_FROM_ABI void __log_hardening_failure(const char* __message) noexcept;
+//
+// Furthermore, note that we pretend that this is a non-blocking and non-allocating function per Clang's
+// function effect attributes. We do that because this function is only called once a function's preconditions
+// are violated, at which point function effect analysis can no longer provide any meaningful guarantees
+// (e.g., cannot guarantee the caller is non-blocking, regardless of function effect attributes). Failure
+// to mark this function with these attributes would render it (and anything calling it, such as span::operator[])
+// unusable from a [[nonblocking]] function.
+[[__gnu__::__cold__]] _LIBCPP_EXPORTED_FROM_ABI void __log_hardening_failure(const char* __message) noexcept
+    [[_Clang::__nonblocking__]] [[_Clang::__nonallocating__]];
 
 // _LIBCPP_LOG_HARDENING_FAILURE(message)
 //
diff --git a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
index 2693d3fb7aba3..815795e1d9025 100644
--- a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
+++ b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
@@ -27,15 +27,36 @@
 
 // ADDITIONAL_COMPILE_FLAGS: -Werror=function-effects
 
-// RUN: %{build}
-// RUN: %{build} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE
-// RUN: %{build} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE
-// RUN: %{build} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
-// RUN: %{build} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE
-
-#include <__assert>
-
-void f(bool condition) noexcept [[clang::nonblocking]] { _LIBCPP_ASSERT(condition, "message"); }
-void g(bool condition) noexcept [[clang::nonallocating]] { _LIBCPP_ASSERT(condition, "message"); }
-
-int main(int, char**) { return 0; }
+// RUN: %{verify}
+// RUN: %{verify} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE
+// RUN: %{verify} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE
+// RUN: %{verify} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
+// RUN: %{verify} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE
+
+#include <cstddef>
+#include <span>
+
+// Using _LIBCPP_ASSERT directly
+void f(bool condition) noexcept [[clang::nonblocking]] {
+  _LIBCPP_ASSERT(condition, "message"); // nothing
+}
+void g(bool condition) noexcept [[clang::nonallocating]] {
+  _LIBCPP_ASSERT(condition, "message"); // nothing
+}
+
+// Sanity check with an actual std::span
+void f(std::span<int> span, std::size_t index) noexcept [[clang::nonblocking]] {
+  (void)span[index]; // nothing
+}
+void g(std::span<int> span, std::size_t index) noexcept [[clang::nonallocating]] {
+  (void)span[index]; // nothing
+}
+
+// Test the test: ensure that a diagnostic would be emitted normally
+void __potentially_blocking();
+void f() noexcept [[clang::nonblocking]] {
+  __potentially_blocking(); // expected-error {{function with 'nonblocking' attribute must not call non-'nonblocking' function}}
+}
+void g() noexcept [[clang::nonallocating]] {
+  __potentially_blocking(); // expected-error {{function with 'nonallocating' attribute must not call non-'nonallocating' function}}
+}

>From 5d85f53390417ac8b6a71ebc79629b4e553a36fa Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Fri, 23 Jan 2026 10:32:45 -0500
Subject: [PATCH 05/12] Forgotten pragma

---
 libcxx/include/__assert | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/libcxx/include/__assert b/libcxx/include/__assert
index 388db33f12f20..debf046d22d04 100644
--- a/libcxx/include/__assert
+++ b/libcxx/include/__assert
@@ -24,11 +24,8 @@
 #define _LIBCPP_ASSERT(expression, message)                                                                            \
   (__builtin_expect(static_cast<bool>(expression), 1)                                                                  \
        ? (void)0                                                                                                       \
-       : _LIBCPP_DIAGNOSTIC_PUSH                                    /*                                              */ \
-             _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wfunction-effects") /*                                              */ \
        _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(                                                        \
-           __LINE__) ": libc++ Hardening assertion " _LIBCPP_TOSTRING(expression) " failed: " message "\n")            \
-           _LIBCPP_DIAGNOSTIC_POP)
+           __LINE__) ": libc++ Hardening assertion " _LIBCPP_TOSTRING(expression) " failed: " message "\n"))
 
 // WARNING: __builtin_assume can currently inhibit optimizations. Only add assumptions with a clear
 // optimization intent. See https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609 for a

>From a2e43e2c1c797c8cf7ccd6703faaa81142e8066e Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Fri, 23 Jan 2026 10:33:28 -0500
Subject: [PATCH 06/12] Revert changes to __assert

---
 libcxx/include/__assert | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/libcxx/include/__assert b/libcxx/include/__assert
index debf046d22d04..a9451daf47f2f 100644
--- a/libcxx/include/__assert
+++ b/libcxx/include/__assert
@@ -17,15 +17,11 @@
 #  pragma GCC system_header
 #endif
 
-// Note that we disable -Wfunction-effects inside _LIBCPP_ASSERT when the assertion fails because
-// once function's preconditions are violated, function effect analysis can no longer provide any
-// meaningful guarantees (e.g., cannot guarantee the caller is non-blocking, regardless of function
-// effect attributes).
 #define _LIBCPP_ASSERT(expression, message)                                                                            \
   (__builtin_expect(static_cast<bool>(expression), 1)                                                                  \
        ? (void)0                                                                                                       \
-       _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(                                                        \
-           __LINE__) ": libc++ Hardening assertion " _LIBCPP_TOSTRING(expression) " failed: " message "\n"))
+       : _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(                                                      \
+             __LINE__) ": libc++ Hardening assertion " _LIBCPP_TOSTRING(expression) " failed: " message "\n"))
 
 // WARNING: __builtin_assume can currently inhibit optimizations. Only add assumptions with a clear
 // optimization intent. See https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609 for a

>From f39943261e313154d34d0fa45a7047c0521af65c Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 26 Jan 2026 15:23:24 -0500
Subject: [PATCH 07/12] UNSUPPORTED in C++03

---
 libcxx/test/extensions/clang/function-effect-analysis.sh.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
index 815795e1d9025..4b1ce4cac82bd 100644
--- a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
+++ b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
@@ -6,6 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
+// This test requires noexcept
+// UNSUPPORTED: c++03
+
 // GCC doesn't support -Wfunction-effect-analysis and the associated attributes
 // UNSUPPORTED: gcc
 

>From 87106d5875a30fefdd17320238808906e8b852b0 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 26 Jan 2026 15:28:38 -0500
Subject: [PATCH 08/12] Drop nonallocating, add nonblocking to definition

---
 libcxx/include/__log_hardening_failure            | 13 ++++++-------
 libcxx/src/experimental/log_hardening_failure.cpp |  2 +-
 2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/libcxx/include/__log_hardening_failure b/libcxx/include/__log_hardening_failure
index 200ade9a83be8..8d34d3aabc2a9 100644
--- a/libcxx/include/__log_hardening_failure
+++ b/libcxx/include/__log_hardening_failure
@@ -25,14 +25,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 // This function should never be called directly from the code -- it should only be called through the
 // `_LIBCPP_LOG_HARDENING_FAILURE` macro.
 //
-// Furthermore, note that we pretend that this is a non-blocking and non-allocating function per Clang's
-// function effect attributes. We do that because this function is only called once a function's preconditions
-// are violated, at which point function effect analysis can no longer provide any meaningful guarantees
-// (e.g., cannot guarantee the caller is non-blocking, regardless of function effect attributes). Failure
-// to mark this function with these attributes would render it (and anything calling it, such as span::operator[])
-// unusable from a [[nonblocking]] function.
+// Furthermore, note that we pretend that this is a non-blocking function per Clang's function effect attributes.
+// We do that because this function is only called once a function's preconditions are violated, at which point
+// function effect analysis can no longer provide any meaningful guarantees (e.g., cannot guarantee the caller is
+// non-blocking, regardless of function effect attributes). Failure to mark this function nonblocking would render
+// it (and anything calling it, such as span::operator[]) unusable from a [[nonblocking]] function.
 [[__gnu__::__cold__]] _LIBCPP_EXPORTED_FROM_ABI void __log_hardening_failure(const char* __message) noexcept
-    [[_Clang::__nonblocking__]] [[_Clang::__nonallocating__]];
+    [[_Clang::__nonblocking__]];
 
 // _LIBCPP_LOG_HARDENING_FAILURE(message)
 //
diff --git a/libcxx/src/experimental/log_hardening_failure.cpp b/libcxx/src/experimental/log_hardening_failure.cpp
index f836c15452249..8b5a5168c4edb 100644
--- a/libcxx/src/experimental/log_hardening_failure.cpp
+++ b/libcxx/src/experimental/log_hardening_failure.cpp
@@ -16,7 +16,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-void __log_hardening_failure(const char* message) noexcept {
+void __log_hardening_failure(const char* message) noexcept [[_Clang::__nonblocking__]] {
   // Always log the message to `stderr` in case the platform-specific system calls fail.
   std::fputs(message, stderr);
 

>From 5d703ffae91350db23a3fea8afaaa68279e5b92d Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 26 Jan 2026 15:33:49 -0500
Subject: [PATCH 09/12] Remove reserved name

---
 .../test/extensions/clang/function-effect-analysis.sh.cpp   | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
index 4b1ce4cac82bd..af95ee0ce6fe2 100644
--- a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
+++ b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
@@ -56,10 +56,10 @@ void g(std::span<int> span, std::size_t index) noexcept [[clang::nonallocating]]
 }
 
 // Test the test: ensure that a diagnostic would be emitted normally
-void __potentially_blocking();
+void potentially_blocking();
 void f() noexcept [[clang::nonblocking]] {
-  __potentially_blocking(); // expected-error {{function with 'nonblocking' attribute must not call non-'nonblocking' function}}
+  potentially_blocking(); // expected-error {{function with 'nonblocking' attribute must not call non-'nonblocking' function}}
 }
 void g() noexcept [[clang::nonallocating]] {
-  __potentially_blocking(); // expected-error {{function with 'nonallocating' attribute must not call non-'nonallocating' function}}
+  potentially_blocking(); // expected-error {{function with 'nonallocating' attribute must not call non-'nonallocating' function}}
 }

>From d0f804145e82cec8d996ce359fe1443779184e62 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 26 Jan 2026 15:36:57 -0500
Subject: [PATCH 10/12] Use __has_cpp_attribute

---
 libcxx/include/__configuration/attributes.h       | 6 ++++++
 libcxx/include/__log_hardening_failure            | 4 ++--
 libcxx/src/experimental/log_hardening_failure.cpp | 2 +-
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__configuration/attributes.h b/libcxx/include/__configuration/attributes.h
index 7322995701ba2..3254853f812f2 100644
--- a/libcxx/include/__configuration/attributes.h
+++ b/libcxx/include/__configuration/attributes.h
@@ -392,6 +392,12 @@
 #  define _LIBCPP_NOINLINE
 #endif
 
+#if __has_cpp_attribute(_Clang::__nonblocking__)
+#  define _LIBCPP_NONBLOCKING [[_Clang::__nonblocking__]]
+#else
+#  define _LIBCPP_NONBLOCKING
+#endif
+
 // Deprecation macros
 // ------------------
 
diff --git a/libcxx/include/__log_hardening_failure b/libcxx/include/__log_hardening_failure
index 8d34d3aabc2a9..ced392e45dc08 100644
--- a/libcxx/include/__log_hardening_failure
+++ b/libcxx/include/__log_hardening_failure
@@ -30,8 +30,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 // function effect analysis can no longer provide any meaningful guarantees (e.g., cannot guarantee the caller is
 // non-blocking, regardless of function effect attributes). Failure to mark this function nonblocking would render
 // it (and anything calling it, such as span::operator[]) unusable from a [[nonblocking]] function.
-[[__gnu__::__cold__]] _LIBCPP_EXPORTED_FROM_ABI void __log_hardening_failure(const char* __message) noexcept
-    [[_Clang::__nonblocking__]];
+[[__gnu__::__cold__]] _LIBCPP_EXPORTED_FROM_ABI void
+__log_hardening_failure(const char* __message) noexcept _LIBCPP_NONBLOCKING;
 
 // _LIBCPP_LOG_HARDENING_FAILURE(message)
 //
diff --git a/libcxx/src/experimental/log_hardening_failure.cpp b/libcxx/src/experimental/log_hardening_failure.cpp
index 8b5a5168c4edb..0c3f28b060809 100644
--- a/libcxx/src/experimental/log_hardening_failure.cpp
+++ b/libcxx/src/experimental/log_hardening_failure.cpp
@@ -16,7 +16,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-void __log_hardening_failure(const char* message) noexcept [[_Clang::__nonblocking__]] {
+void __log_hardening_failure(const char* message) noexcept _LIBCPP_NONBLOCKING {
   // Always log the message to `stderr` in case the platform-specific system calls fail.
   std::fputs(message, stderr);
 

>From 4ecdbc21783e38263c28a51cf4a6bb7586d20ce1 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 26 Jan 2026 16:55:15 -0500
Subject: [PATCH 11/12] More unsupported standards

---
 libcxx/test/extensions/clang/function-effect-analysis.sh.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
index af95ee0ce6fe2..dedf29b265cdf 100644
--- a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
+++ b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-// This test requires noexcept
-// UNSUPPORTED: c++03
+// This test requires noexcept and std::span
+// UNSUPPORTED: c++03, c++11, c++14, c++17
 
 // GCC doesn't support -Wfunction-effect-analysis and the associated attributes
 // UNSUPPORTED: gcc

>From 80dc2d790dc4b4f33c5c4396ddd6138c9765191a Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Tue, 27 Jan 2026 11:46:10 -0500
Subject: [PATCH 12/12] Fix -Wmacro-redefined error

---
 .../test/extensions/clang/function-effect-analysis.sh.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
index dedf29b265cdf..3fe3328bb26ca 100644
--- a/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
+++ b/libcxx/test/extensions/clang/function-effect-analysis.sh.cpp
@@ -31,10 +31,10 @@
 // ADDITIONAL_COMPILE_FLAGS: -Werror=function-effects
 
 // RUN: %{verify}
-// RUN: %{verify} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE
-// RUN: %{verify} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE
-// RUN: %{verify} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
-// RUN: %{verify} -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE
+// RUN: %{verify} -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_IGNORE
+// RUN: %{verify} -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_OBSERVE
+// RUN: %{verify} -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
+// RUN: %{verify} -U_LIBCPP_ASSERTION_SEMANTIC -D_LIBCPP_ASSERTION_SEMANTIC=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE
 
 #include <cstddef>
 #include <span>



More information about the libcxx-commits mailing list