[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