[libcxx-commits] [libcxx] [libc++][hardening] Always enable all checks during constant evaluation (PR #107713)
Mital Ashok via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Sep 13 06:51:17 PDT 2024
https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/107713
>From c115b147efc0baba1a5ebba546295855106f08cb Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sat, 7 Sep 2024 18:58:00 +0100
Subject: [PATCH 1/7] [libc++][hardening] Always enable all checks during
constant evaluation
---
libcxx/docs/ReleaseNotes/20.rst | 2 +
libcxx/include/__assert | 82 ++++++++++++-------
.../assertions/constant_expression.verify.cpp | 61 ++++++++++++++
3 files changed, 115 insertions(+), 30 deletions(-)
create mode 100644 libcxx/test/libcxx/assertions/constant_expression.verify.cpp
diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index 93d6027291ad95..875b0a361576a9 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -51,6 +51,8 @@ Improvements and New Features
- The ``_LIBCPP_ENABLE_CXX20_REMOVED_UNCAUGHT_EXCEPTION`` macro has been added to make ``std::uncaught_exception`` available in C++20 and later modes.
+- ``_LIBCPP_ASSUME(expression)`` now checks the expression is ``true`` during constant evaluation.
+ This means that all assertions are now checked regardless of hardening mode in constant expressions.
Deprecations and Removals
-------------------------
diff --git a/libcxx/include/__assert b/libcxx/include/__assert
index 49769fb4d44978..53663b73769330 100644
--- a/libcxx/include/__assert
+++ b/libcxx/include/__assert
@@ -17,23 +17,45 @@
# pragma GCC system_header
#endif
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR int
+__assertion_failed_during_constant_evaluation(bool __value, const char*) _NOEXCEPT {
+ return __value ? 0 : (__builtin_unreachable(), 0);
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#define _LIBCPP_ASSERT_IS_CONSTANT_EVALUATED \
+ (_LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wconstant-evaluated") __builtin_is_constant_evaluated() \
+ _LIBCPP_DIAGNOSTIC_POP)
+
+#define _LIBCPP_ASSERTTION_MESSAGE(__message) \
+ __FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING(expression) " failed: " __message "\n"
+
#define _LIBCPP_ASSERT(expression, message) \
- (__builtin_expect(static_cast<bool>(expression), 1) \
- ? (void)0 \
- : _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING( \
- expression) " failed: " message "\n"))
+ (__builtin_expect(static_cast<bool>(expression), 1) ? (void)0 \
+ : _LIBCPP_ASSERT_IS_CONSTANT_EVALUATED \
+ ? (void)__assertion_failed_during_constant_evaluation(false, _LIBCPP_ASSERTTION_MESSAGE(message)) \
+ : _LIBCPP_ASSERTION_HANDLER(_LIBCPP_ASSERTTION_MESSAGE(message)))
// TODO: __builtin_assume can currently inhibit optimizations. Until this has been fixed and we can add
// assumptions without a clear optimization intent, disable that to avoid worsening the code generation.
// See https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609 for a discussion.
#if 0 && __has_builtin(__builtin_assume)
-# define _LIBCPP_ASSUME(expression) \
+# define _LIBCPP_RUNTIME_ASSUME(expression) \
(_LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wassume") \
__builtin_assume(static_cast<bool>(expression)) _LIBCPP_DIAGNOSTIC_POP)
#else
-# define _LIBCPP_ASSUME(expression) ((void)0)
+# define _LIBCPP_RUNTIME_ASSUME(expression) ((void)0)
#endif
+#define _LIBCPP_ASSUME(expression, message) \
+ (_LIBCPP_ASSERT_IS_CONSTANT_EVALUATED \
+ ? (void)__assertion_failed_during_constant_evaluation( \
+ static_cast<bool>(expression), _LIBCPP_ASSERTTION_MESSAGE(message)) \
+ : _LIBCPP_RUNTIME_ASSUME(expression))
+
// clang-format off
// Fast hardening mode checks.
@@ -44,18 +66,18 @@
# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message)
// Disabled checks.
// On most modern platforms, dereferencing a null pointer does not lead to an actual memory access.
-# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression, message)
// Overlapping ranges will make algorithms produce incorrect results but don't directly lead to a security
// vulnerability.
-# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression, message)
// Extensive hardening mode checks.
@@ -73,8 +95,8 @@
# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message)
# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message)
// Disabled checks.
-# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression, message)
// Debug hardening mode checks.
@@ -99,18 +121,18 @@
#else
// All checks disabled.
-# define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
-# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression, message)
#endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_FAST
// clang-format on
diff --git a/libcxx/test/libcxx/assertions/constant_expression.verify.cpp b/libcxx/test/libcxx/assertions/constant_expression.verify.cpp
new file mode 100644
index 00000000000000..9b55300a0b1645
--- /dev/null
+++ b/libcxx/test/libcxx/assertions/constant_expression.verify.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that both `_LIBCPP_ASSERT(false, ...)` and `_LIBCPP_ASSUME(false)`
+// mean that a constant expression cannot be formed.
+
+#include <__assert>
+#include "test_macros.h"
+
+// expected-note@*:* 0+ {{expanded from macro}}
+
+static_assert((_LIBCPP_ASSERT(false, "message"), true), "");
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+
+static_assert((_LIBCPP_ASSUME(false), true), "");
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+
+const int i = (_LIBCPP_ASSERT(false, "message"), 1);
+const int j = (_LIBCPP_ASSUME(false), 1);
+
+static_assert(i, "");
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+static_assert(j, "");
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+
+#if TEST_STD_VER >= 11
+constexpr int f(int x) {
+ return (_LIBCPP_ASSERT(x != 6, "message"), x);
+ // expected-note at -1 {{subexpression not valid in a constant expression}}
+}
+constexpr int g(int x) {
+ return (_LIBCPP_ASSUME(x != 6), x);
+ // expected-note at -1 {{subexpression not valid in a constant expression}}
+}
+static_assert(f(6) == 6, "");
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+static_assert(g(6) == 6, "");
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+#endif
+
+#if TEST_STD_VER >= 14
+constexpr int ff(int x) {
+ _LIBCPP_ASSERT(x != 6, "message");
+ // expected-note at -1 {{subexpression not valid in a constant expression}}
+ return x;
+}
+constexpr int gg(int x) {
+ _LIBCPP_ASSUME(x != 6);
+ // expected-note at -1 {{subexpression not valid in a constant expression}}
+ return x;
+}
+static_assert(ff(6) == 6, "");
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+static_assert(gg(6) == 6, "");
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+#endif
>From 817d0190643ecd8a6a1fdfebdeb7973b581e2a16 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sat, 7 Sep 2024 19:27:33 +0100
Subject: [PATCH 2/7] Cut out function call
It was originally added so that the assertion message would be in the
constexpr call stack but Clang just shows the source location,
including the line number, expression and message anyways
---
libcxx/include/__assert | 70 +++++++++++++++++------------------------
1 file changed, 29 insertions(+), 41 deletions(-)
diff --git a/libcxx/include/__assert b/libcxx/include/__assert
index 53663b73769330..d422a1ce7ae800 100644
--- a/libcxx/include/__assert
+++ b/libcxx/include/__assert
@@ -17,27 +17,16 @@
# pragma GCC system_header
#endif
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR int
-__assertion_failed_during_constant_evaluation(bool __value, const char*) _NOEXCEPT {
- return __value ? 0 : (__builtin_unreachable(), 0);
-}
-
-_LIBCPP_END_NAMESPACE_STD
-
#define _LIBCPP_ASSERT_IS_CONSTANT_EVALUATED \
(_LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wconstant-evaluated") __builtin_is_constant_evaluated() \
_LIBCPP_DIAGNOSTIC_POP)
-#define _LIBCPP_ASSERTTION_MESSAGE(__message) \
- __FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING(expression) " failed: " __message "\n"
-
#define _LIBCPP_ASSERT(expression, message) \
(__builtin_expect(static_cast<bool>(expression), 1) ? (void)0 \
: _LIBCPP_ASSERT_IS_CONSTANT_EVALUATED \
- ? (void)__assertion_failed_during_constant_evaluation(false, _LIBCPP_ASSERTTION_MESSAGE(message)) \
- : _LIBCPP_ASSERTION_HANDLER(_LIBCPP_ASSERTTION_MESSAGE(message)))
+ ? __builtin_unreachable() \
+ : _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING( \
+ expression) " failed: " message "\n"))
// TODO: __builtin_assume can currently inhibit optimizations. Until this has been fixed and we can add
// assumptions without a clear optimization intent, disable that to avoid worsening the code generation.
@@ -50,10 +39,9 @@ _LIBCPP_END_NAMESPACE_STD
# define _LIBCPP_RUNTIME_ASSUME(expression) ((void)0)
#endif
-#define _LIBCPP_ASSUME(expression, message) \
+#define _LIBCPP_ASSUME(expression) \
(_LIBCPP_ASSERT_IS_CONSTANT_EVALUATED \
- ? (void)__assertion_failed_during_constant_evaluation( \
- static_cast<bool>(expression), _LIBCPP_ASSERTTION_MESSAGE(message)) \
+ ? static_cast<bool>(expression) ? (void)0 : __builtin_unreachable() \
: _LIBCPP_RUNTIME_ASSUME(expression))
// clang-format off
@@ -66,18 +54,18 @@ _LIBCPP_END_NAMESPACE_STD
# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message)
// Disabled checks.
// On most modern platforms, dereferencing a null pointer does not lead to an actual memory access.
-# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression)
// Overlapping ranges will make algorithms produce incorrect results but don't directly lead to a security
// vulnerability.
-# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression)
// Extensive hardening mode checks.
@@ -95,8 +83,8 @@ _LIBCPP_END_NAMESPACE_STD
# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message)
# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message)
// Disabled checks.
-# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
// Debug hardening mode checks.
@@ -121,18 +109,18 @@ _LIBCPP_END_NAMESPACE_STD
#else
// All checks disabled.
-# define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression, message)
-# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression, message)
+# define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
+# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression)
#endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_FAST
// clang-format on
>From 9320bb2c1bee82555eeb27be3641aebe93da2bfe Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sat, 7 Sep 2024 21:03:33 +0100
Subject: [PATCH 3/7] Fix test failures
---
libcxx/include/__assert | 11 ++++++++---
.../alg.sorting/alg.clamp/ranges.clamp.pass.cpp | 4 +++-
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/__assert b/libcxx/include/__assert
index d422a1ce7ae800..59cfeea2190be1 100644
--- a/libcxx/include/__assert
+++ b/libcxx/include/__assert
@@ -17,9 +17,14 @@
# pragma GCC system_header
#endif
-#define _LIBCPP_ASSERT_IS_CONSTANT_EVALUATED \
- (_LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wconstant-evaluated") __builtin_is_constant_evaluated() \
- _LIBCPP_DIAGNOSTIC_POP)
+#ifdef _LIBCPP_COMPILER_CLANG_BASED
+// TODO: use `_LIBCPP_DIAGNOSTIC_*` macros after #107715 is fixed in all supported clang compilers
+# define _LIBCPP_ASSERT_IS_CONSTANT_EVALUATED \
+ (_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wconstant-evaluated\"") \
+ __builtin_is_constant_evaluated() _Pragma("clang diagnostic pop"))
+#else
+# define _LIBCPP_ASSERT_IS_CONSTANT_EVALUATED (__builtin_is_constant_evaluated())
+#endif
#define _LIBCPP_ASSERT(expression, message) \
(__builtin_expect(static_cast<bool>(expression), 1) ? (void)0 \
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.clamp/ranges.clamp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.clamp/ranges.clamp.pass.cpp
index d59864eb87023d..33e73d1a4ffa72 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.clamp/ranges.clamp.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.clamp/ranges.clamp.pass.cpp
@@ -108,10 +108,12 @@ constexpr bool test() {
return value;
};
assert(std::ranges::clamp(3, 2, 4, std::ranges::less{}, projection_function) == 3);
+ // When assertions are enabled, we call the projection more times
#if defined(_LIBCPP_HARDENING_MODE) && \
_LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_EXTENSIVE && \
_LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
- assert(counter <= 3);
+ if (!std::__libcpp_is_constant_evaluated())
+ assert(counter <= 3);
#endif
}
>From c1c4505e4b459a5e703b35cbbaa1951488980b8a Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sat, 7 Sep 2024 21:53:13 +0100
Subject: [PATCH 4/7] Fix gcc -Werror=type-limits
---
libcxx/include/experimental/__simd/vec_ext.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/experimental/__simd/vec_ext.h b/libcxx/include/experimental/__simd/vec_ext.h
index 5787f237bb01ef..ce60a4c6c0fd35 100644
--- a/libcxx/include/experimental/__simd/vec_ext.h
+++ b/libcxx/include/experimental/__simd/vec_ext.h
@@ -40,11 +40,11 @@ struct __simd_storage<_Tp, simd_abi::__vec_ext<_Np>> {
_Tp __data __attribute__((__vector_size__(std::__bit_ceil((sizeof(_Tp) * _Np)))));
_LIBCPP_HIDE_FROM_ABI _Tp __get(size_t __idx) const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx >= 0 && __idx < _Np, "Index is out of bounds");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < _Np, "Index is out of bounds");
return __data[__idx];
}
_LIBCPP_HIDE_FROM_ABI void __set(size_t __idx, _Tp __v) noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx >= 0 && __idx < _Np, "Index is out of bounds");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < _Np, "Index is out of bounds");
__data[__idx] = __v;
}
};
>From 006e98d038755e04655dbbc64e5ec21cb34c7619 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sun, 8 Sep 2024 07:22:36 +0100
Subject: [PATCH 5/7] Workaround for GCC bug for
__builtin_is_constant_evaluated when evaluating attribute argument
---
libcxx/include/experimental/__simd/vec_ext.h | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/experimental/__simd/vec_ext.h b/libcxx/include/experimental/__simd/vec_ext.h
index ce60a4c6c0fd35..d65f524060fc9c 100644
--- a/libcxx/include/experimental/__simd/vec_ext.h
+++ b/libcxx/include/experimental/__simd/vec_ext.h
@@ -37,7 +37,11 @@ inline constexpr bool is_abi_tag_v<simd_abi::__vec_ext<_Np>> = _Np > 0 && _Np <=
template <class _Tp, int _Np>
struct __simd_storage<_Tp, simd_abi::__vec_ext<_Np>> {
- _Tp __data __attribute__((__vector_size__(std::__bit_ceil((sizeof(_Tp) * _Np)))));
+ // This doesn't work in GCC if it is directly inside the __vector_size__ attribute because of a call to
+ // __builtin_is_constant_evaluated. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105233
+ static constexpr size_t __vector_size = std::__bit_ceil(sizeof(_Tp) * _Np);
+
+ _Tp __data __attribute__((__vector_size__(__vector_size)));
_LIBCPP_HIDE_FROM_ABI _Tp __get(size_t __idx) const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < _Np, "Index is out of bounds");
>From c9ac5fea96fe065ebacc540d70ffaf47930e6a9c Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sun, 8 Sep 2024 13:55:42 +0100
Subject: [PATCH 6/7] Disable tests related to #107747
---
libcxx/test/support/nasty_string.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/libcxx/test/support/nasty_string.h b/libcxx/test/support/nasty_string.h
index ea9d83ccf282aa..37ad9a762e5a80 100644
--- a/libcxx/test/support/nasty_string.h
+++ b/libcxx/test/support/nasty_string.h
@@ -37,6 +37,11 @@
# define TEST_HAS_NO_NASTY_STRING
#endif
+// TODO re-enable after #107747 is fixed
+#ifndef TEST_HAS_NO_NASTY_STRING
+# define TEST_HAS_NO_NASTY_STRING
+#endif
+
#ifndef TEST_HAS_NO_NASTY_STRING
// Make sure the char-like operations in strings do not depend on the char-like type.
struct nasty_char {
>From a05ff1071bf3104dbce6d3997ccc71ef6f7ca50c Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sun, 8 Sep 2024 17:40:58 +0100
Subject: [PATCH 7/7] Address some of the comments
---
libcxx/include/__assert | 5 +--
libcxx/include/experimental/__simd/vec_ext.h | 4 +-
.../assertions/constant_expression.verify.cpp | 41 +------------------
libcxx/test/support/nasty_string.h | 9 +---
4 files changed, 8 insertions(+), 51 deletions(-)
diff --git a/libcxx/include/__assert b/libcxx/include/__assert
index 59cfeea2190be1..b03c1067717934 100644
--- a/libcxx/include/__assert
+++ b/libcxx/include/__assert
@@ -27,9 +27,8 @@
#endif
#define _LIBCPP_ASSERT(expression, message) \
- (__builtin_expect(static_cast<bool>(expression), 1) ? (void)0 \
- : _LIBCPP_ASSERT_IS_CONSTANT_EVALUATED \
- ? __builtin_unreachable() \
+ (__builtin_expect(static_cast<bool>(expression), 1) \
+ ? (void)0 \
: _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING( \
expression) " failed: " message "\n"))
diff --git a/libcxx/include/experimental/__simd/vec_ext.h b/libcxx/include/experimental/__simd/vec_ext.h
index d65f524060fc9c..e1c667b21702ec 100644
--- a/libcxx/include/experimental/__simd/vec_ext.h
+++ b/libcxx/include/experimental/__simd/vec_ext.h
@@ -39,9 +39,9 @@ template <class _Tp, int _Np>
struct __simd_storage<_Tp, simd_abi::__vec_ext<_Np>> {
// This doesn't work in GCC if it is directly inside the __vector_size__ attribute because of a call to
// __builtin_is_constant_evaluated. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105233
- static constexpr size_t __vector_size = std::__bit_ceil(sizeof(_Tp) * _Np);
+ static constexpr size_t __n_bytes = std::__bit_ceil(sizeof(_Tp) * _Np);
- _Tp __data __attribute__((__vector_size__(__vector_size)));
+ _Tp __data __attribute__((__vector_size__(__n_bytes)));
_LIBCPP_HIDE_FROM_ABI _Tp __get(size_t __idx) const noexcept {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < _Np, "Index is out of bounds");
diff --git a/libcxx/test/libcxx/assertions/constant_expression.verify.cpp b/libcxx/test/libcxx/assertions/constant_expression.verify.cpp
index 9b55300a0b1645..a1fd93539c05b3 100644
--- a/libcxx/test/libcxx/assertions/constant_expression.verify.cpp
+++ b/libcxx/test/libcxx/assertions/constant_expression.verify.cpp
@@ -20,42 +20,5 @@ static_assert((_LIBCPP_ASSERT(false, "message"), true), "");
static_assert((_LIBCPP_ASSUME(false), true), "");
// expected-error at -1 {{static assertion expression is not an integral constant expression}}
-const int i = (_LIBCPP_ASSERT(false, "message"), 1);
-const int j = (_LIBCPP_ASSUME(false), 1);
-
-static_assert(i, "");
-// expected-error at -1 {{static assertion expression is not an integral constant expression}}
-static_assert(j, "");
-// expected-error at -1 {{static assertion expression is not an integral constant expression}}
-
-#if TEST_STD_VER >= 11
-constexpr int f(int x) {
- return (_LIBCPP_ASSERT(x != 6, "message"), x);
- // expected-note at -1 {{subexpression not valid in a constant expression}}
-}
-constexpr int g(int x) {
- return (_LIBCPP_ASSUME(x != 6), x);
- // expected-note at -1 {{subexpression not valid in a constant expression}}
-}
-static_assert(f(6) == 6, "");
-// expected-error at -1 {{static assertion expression is not an integral constant expression}}
-static_assert(g(6) == 6, "");
-// expected-error at -1 {{static assertion expression is not an integral constant expression}}
-#endif
-
-#if TEST_STD_VER >= 14
-constexpr int ff(int x) {
- _LIBCPP_ASSERT(x != 6, "message");
- // expected-note at -1 {{subexpression not valid in a constant expression}}
- return x;
-}
-constexpr int gg(int x) {
- _LIBCPP_ASSUME(x != 6);
- // expected-note at -1 {{subexpression not valid in a constant expression}}
- return x;
-}
-static_assert(ff(6) == 6, "");
-// expected-error at -1 {{static assertion expression is not an integral constant expression}}
-static_assert(gg(6) == 6, "");
-// expected-error at -1 {{static assertion expression is not an integral constant expression}}
-#endif
+static_assert(!__builtin_constant_p(_LIBCPP_ASSERT(false, "message")), "");
+static_assert(!__builtin_constant_p(_LIBCPP_ASSUME(false)), "");
diff --git a/libcxx/test/support/nasty_string.h b/libcxx/test/support/nasty_string.h
index 37ad9a762e5a80..6b3a82f71438fd 100644
--- a/libcxx/test/support/nasty_string.h
+++ b/libcxx/test/support/nasty_string.h
@@ -37,16 +37,11 @@
# define TEST_HAS_NO_NASTY_STRING
#endif
-// TODO re-enable after #107747 is fixed
-#ifndef TEST_HAS_NO_NASTY_STRING
-# define TEST_HAS_NO_NASTY_STRING
-#endif
-
#ifndef TEST_HAS_NO_NASTY_STRING
// Make sure the char-like operations in strings do not depend on the char-like type.
struct nasty_char {
- template <typename T>
- friend auto operator<=>(T, T) = delete;
+ template <typename T, typename U>
+ friend auto operator<=>(T, U) = delete;
template <typename T>
friend void operator+(T&&) = delete;
More information about the libcxx-commits
mailing list