aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/AST
diff options
context:
space:
mode:
authorJJ Marr <168750718+jj-marr@users.noreply.github.com>2025-05-14 02:47:38 -0400
committerGitHub <noreply@github.com>2025-05-14 08:47:38 +0200
commitb77109ff8c17cd20ac2c791761028a358c9e3447 (patch)
tree52b8e7953a800901f35b37ed553bfaf25343b75a /clang/lib/AST
parent6c1bb48cc45396894597c8cb897c31205d1bdeb6 (diff)
downloadllvm-b77109ff8c17cd20ac2c791761028a358c9e3447.zip
llvm-b77109ff8c17cd20ac2c791761028a358c9e3447.tar.gz
llvm-b77109ff8c17cd20ac2c791761028a358c9e3447.tar.bz2
Better diagnostics when assertion fails in `consteval` (#130458)
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.```
Diffstat (limited to 'clang/lib/AST')
-rw-r--r--clang/lib/AST/ExprConstant.cpp17
1 files changed, 15 insertions, 2 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 500d43a..c09afef9 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5975,9 +5975,22 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
Definition->hasAttr<MSConstexprAttr>())))
return true;
- if (Info.getLangOpts().CPlusPlus11) {
- const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
+ const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
+ // Special note for the assert() macro, as the normal error message falsely
+ // implies we cannot use an assertion during constant evaluation.
+ if (CallLoc.isMacroID() && DiagDecl->getIdentifier()) {
+ // FIXME: Instead of checking for an implementation-defined function,
+ // check and evaluate the assert() macro.
+ StringRef Name = DiagDecl->getName();
+ bool AssertFailed =
+ Name == "__assert_rtn" || Name == "__assert_fail" || Name == "_wassert";
+ if (AssertFailed) {
+ Info.FFDiag(CallLoc, diag::note_constexpr_assert_failed);
+ return false;
+ }
+ }
+ if (Info.getLangOpts().CPlusPlus11) {
// If this function is not constexpr because it is an inherited
// non-constexpr constructor, diagnose that directly.
auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);