Better diagnostics when assertion fails in consteval
by jj-marr · Pull Request #130458 · llvm/llvm-project (original) (raw)
@llvm/pr-subscribers-clang
Author: JJ Marr (jj-marr)
Changes
Take this piece of code:
#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):
<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:
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}} +}