[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)

via cfe-commits cfe-commits at lists.llvm.org
Sat Mar 8 19:44:43 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: JJ Marr (jj-marr)

<details>
<summary>Changes</summary>

Take this piece of code:
```cpp
#include <cassert>

consteval int square(int x) {
  int result = x * x;
  assert(result == 42);
  return result;
}

void test() {
  auto val = square(2);
}
```
The assertion will fail, and `clang++` will output (https://godbolt.org/z/hjz3KbTTv):
```cpp
<source>:10:14: error: call to consteval function 'square' is not a constant expression
   10 |   auto val = square(2);
      |              ^
<source>:5:3: note: non-constexpr function '__assert_fail' cannot be used in a constant expression
    5 |   assert(result == 42);
      |   ^
/usr/include/assert.h:95:9: note: expanded from macro 'assert'
   95 |       : __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION))
      |         ^
<source>:10:14: note: in call to 'square(2)'
   10 |   auto val = square(2);
      |              ^~~~~~~~~
/usr/include/assert.h:69:13: note: declared here
   69 | extern void __assert_fail (const char *__assertion, const char *__file,
      |             ^
1 error generated.
Compiler returned: 1
```
This is confusing because it implies that the issue was using an assertion in a constant-evaluted context, and not that the assertion failed (`assert()` is OK in constant evaluation). This PR changes the error message to:
```cpp
test.cpp:10:14: error: call to consteval function 'square' is not a constant expression
   10 |   auto val = square(2);
      |              ^
test.cpp:5:3: note: assertion failed in consteval context: 'result == 42'
    5 |   assert(result == 42);
      |   ^
/nix/store/lw21wr626v5sdcaxxkv2k4zf1121hfc9-glibc-2.40-36-dev/include/assert.h:102:9: note: expanded from macro 'assert'
  102 |       : __assert_fail (#expr, __ASSERT_FILE, __ASSERT_LINE,             \
      |         ^
test.cpp:10:14: note: in call to 'square(2)'
   10 |   auto val = square(2);
      |              ^~~~~~~~~
1 error generated.```

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


3 Files Affected:

- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2) 
- (modified) clang/lib/AST/ExprConstant.cpp (+11) 
- (added) clang/test/SemaCXX/consteval_assert.cpp (+20) 


``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 21be7c358a61d..ff5f88d6ac572 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -107,6 +107,8 @@ def err_ice_too_large : Error<
   "integer constant expression evaluates to value %0 that cannot be "
   "represented in a %1-bit %select{signed|unsigned}2 integer type">;
 def err_expr_not_string_literal : Error<"expression is not a string literal">;
+def note_constexpr_assert_failed : Note<
+  "assertion failed in consteval context: '%0'">;
 
 // Semantic analysis of constant literals.
 def ext_predef_outside_function : Warning<
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d9a1e5bb42343..7013f0b143a0a 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -8361,6 +8361,17 @@ class ExprEvaluatorBase
         return false;
     }
 
+    // If an assertion fails during constant evaluation, give a specific note explaining that
+    if (FD->getName() == "__assert_fail") {
+      const Expr *AssertionExpr = E->getArg(0);
+      const StringLiteral *AssertionText = dyn_cast<StringLiteral>(AssertionExpr->IgnoreParens()->IgnoreParenImpCasts());
+
+      Info.FFDiag(E->getBeginLoc(), diag::note_constexpr_assert_failed)
+          << (AssertionText ? AssertionText->getString() : "<unknown assertion>");
+
+      return false;
+    }
+
     SmallVector<QualType, 4> CovariantAdjustmentPath;
     if (This) {
       auto *NamedMember = dyn_cast<CXXMethodDecl>(FD);
diff --git a/clang/test/SemaCXX/consteval_assert.cpp b/clang/test/SemaCXX/consteval_assert.cpp
new file mode 100644
index 0000000000000..94ca9ffd4888d
--- /dev/null
+++ b/clang/test/SemaCXX/consteval_assert.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus %s
+
+#ifdef __ASSERT_FUNCTION
+#undef __ASSERT_FUNCTION
+#endif
+extern "C" void __assert_fail(const char*, const char*, unsigned, const char*);
+
+#define assert(cond) \
+  ((cond) ? (void)0 : __assert_fail(#cond, __FILE__, __LINE__, __func__))
+
+consteval int square(int x) {
+  int result = x * x;
+  assert(result == 42); // expected-note {{assertion failed in consteval context: 'result == 42'}}
+  return result;
+}
+
+void test() {
+  auto val = square(2); // expected-note {{in call to 'square(2)'}} \
+  // expected-error {{call to consteval function 'square' is not a constant expression}}
+}

``````````

</details>


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


More information about the cfe-commits mailing list