[libcxx-commits] [libcxx] [libc++][hardening] Always enable all checks during constant evaluation (PR #107713)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Sep 7 12:11:56 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Mital Ashok (MitalAshok)
<details>
<summary>Changes</summary>
Change `_LIBCPP_ASSUME` to test the expression when `__builtin_is_constant_evaluated()`, calling `__builtin_unreachable()` when it is `false`. This will cause it to not be a constant expression.
Also changes `_LIBCPP_ASSERT` to do the same when `__builtin_is_constant_evaluated()`. This is so the diagnostic will be consistent.
Fixes #<!-- -->107453
---
Full diff: https://github.com/llvm/llvm-project/pull/107713.diff
3 Files Affected:
- (modified) libcxx/docs/ReleaseNotes/20.rst (+2)
- (modified) libcxx/include/__assert (+14-4)
- (added) libcxx/test/libcxx/assertions/constant_expression.verify.cpp (+61)
``````````diff
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..d422a1ce7ae800 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)
+
#define _LIBCPP_ASSERT(expression, message) \
- (__builtin_expect(static_cast<bool>(expression), 1) \
- ? (void)0 \
+ (__builtin_expect(static_cast<bool>(expression), 1) ? (void)0 \
+ : _LIBCPP_ASSERT_IS_CONSTANT_EVALUATED \
+ ? __builtin_unreachable() \
: _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING( \
expression) " failed: " message "\n"))
@@ -27,13 +32,18 @@
// 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) \
+ (_LIBCPP_ASSERT_IS_CONSTANT_EVALUATED \
+ ? static_cast<bool>(expression) ? (void)0 : __builtin_unreachable() \
+ : _LIBCPP_RUNTIME_ASSUME(expression))
+
// clang-format off
// Fast hardening mode checks.
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..93ed0b595de57f
--- /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 bool f() {
+ return (_LIBCPP_ASSERT(false, "message"), true);
+ // expected-note at -1 {{subexpression not valid in a constant expression}}
+}
+constexpr bool g() {
+ return (_LIBCPP_ASSUME(false), true);
+ // expected-note at -1 {{subexpression not valid in a constant expression}}
+}
+static_assert(f(), "");
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+static_assert(g(), "");
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+#endif
+
+#if TEST_STD_VER >= 14
+constexpr bool ff() {
+ _LIBCPP_ASSERT(false, "message");
+ // expected-note at -1 {{subexpression not valid in a constant expression}}
+ return true;
+}
+constexpr bool gg() {
+ _LIBCPP_ASSUME(false);
+ // expected-note at -1 {{subexpression not valid in a constant expression}}
+ return true;
+}
+static_assert(ff(), "");
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+static_assert(gg(), "");
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+#endif
``````````
</details>
https://github.com/llvm/llvm-project/pull/107713
More information about the libcxx-commits
mailing list