Skip to content

Commit e41c154

Browse files
committed
Explain which assertion failed during consteval
1 parent 834d426 commit e41c154

File tree

4 files changed

+55
-2
lines changed

4 files changed

+55
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,10 @@ Improvements to Clang's diagnostics
419419
- ``-Winitializer-overrides`` and ``-Wreorder-init-list`` are now grouped under
420420
the ``-Wc99-designator`` diagnostic group, as they also are about the
421421
behavior of the C99 feature as it was introduced into C++20. Fixes #GH47037
422+
423+
- Explanatory note is printed when ``assert`` fails during evaluation of a
424+
constant expression. Prior to this, the error inaccurately implied that assert
425+
could not be used at all in a constant expression (#GH130458)
422426

423427
Improvements to Clang's time-trace
424428
----------------------------------

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ def err_ice_too_large : Error<
162162
"integer constant expression evaluates to value %0 that cannot be "
163163
"represented in a %1-bit %select{signed|unsigned}2 integer type">;
164164
def err_expr_not_string_literal : Error<"expression is not a string literal">;
165+
def note_constexpr_assert_failed : Note<
166+
"assertion failed during evaluation of constant expression">;
165167

166168
// Semantic analysis of constant literals.
167169
def ext_predef_outside_function : Warning<

clang/lib/AST/ExprConstant.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5975,9 +5975,22 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
59755975
Definition->hasAttr<MSConstexprAttr>())))
59765976
return true;
59775977

5978-
if (Info.getLangOpts().CPlusPlus11) {
5979-
const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
5978+
const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
5979+
// Special note for the assert() macro, as the normal error message falsely
5980+
// implies we cannot use an assertion during constant evaluation.
5981+
if (CallLoc.isMacroID() && DiagDecl->getIdentifier()) {
5982+
// FIXME: Instead of checking for an implementation-defined function,
5983+
// check and evaluate the assert() macro.
5984+
const bool assertFailed = DiagDecl->getName() == "__assert_rtn" ||
5985+
DiagDecl->getName() == "__assert_fail" ||
5986+
DiagDecl->getName() == "_wassert";
5987+
if(assertFailed) {
5988+
Info.FFDiag(CallLoc, diag::note_constexpr_assert_failed);
5989+
return false;
5990+
}
5991+
}
59805992

5993+
if (Info.getLangOpts().CPlusPlus11) {
59815994
// If this function is not constexpr because it is an inherited
59825995
// non-constexpr constructor, diagnose that directly.
59835996
auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus -DTEST_LINUX %s
2+
// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus -DTEST_WINDOWS %s
3+
// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus -DTEST_DARWIN %s
4+
5+
#ifdef __ASSERT_FUNCTION
6+
#undef __ASSERT_FUNCTION
7+
#endif
8+
9+
#if defined(TEST_LINUX)
10+
extern "C" void __assert_fail(const char*, const char*, unsigned, const char*);
11+
#define assert(cond) \
12+
((cond) ? (void)0 : __assert_fail(#cond, __FILE__, __LINE__, __func__))
13+
#elif defined(TEST_DARWIN)
14+
void __assert_rtn(const char *, const char *, int, const char *);
15+
#define assert(cond) \
16+
(__builtin_expect(!(cond), 0) ? __assert_rtn(__func__, __FILE__, __LINE__, #cond) : (void)0)
17+
#elif defined(TEST_WINDOWS)
18+
void /*__cdecl*/ _wassert(const wchar_t*, const wchar_t*, unsigned);
19+
#define _CRT_WIDE_(s) L ## s
20+
#define _CRT_WIDE(s) _CRT_WIDE_(s)
21+
#define assert(cond) \
22+
(void)((!!(cond)) || (_wassert(_CRT_WIDE(#cond), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0))
23+
#endif
24+
25+
consteval int square(int x) {
26+
int result = x * x;
27+
assert(result == 42); // expected-note {{assertion failed during evaluation of constant expression}}
28+
return result;
29+
}
30+
31+
void test() {
32+
auto val = square(2); // expected-note {{in call to 'square(2)'}} \
33+
// expected-error {{call to consteval function 'square' is not a constant expression}}
34+
}

0 commit comments

Comments
 (0)