Skip to content

Commit 49386f4

Browse files
authored
[Clang] Run destructors of variables declared in the second part of a for loop during constant evaluation (#140278)
Within the condition statement of the for block, the destructor doesn't get called when evaluating compile time constants. Resolves #139818
1 parent 1d6e8ec commit 49386f4

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,8 @@ Bug Fixes in This Version
685685
- Fixed an assertion failure in serialization of constexpr structs containing unions. (#GH140130)
686686
- Fixed duplicate entries in TableGen that caused the wrong attribute to be selected. (GH#140701)
687687
- Fixed type mismatch error when 'builtin-elementwise-math' arguments have different qualifiers, this should be well-formed. (#GH141397)
688+
- Constant evaluation now correctly runs the destructor of a variable declared in
689+
the second clause of a C-style ``for`` loop. (#GH139818)
688690

689691
Bug Fixes to Compiler Builtins
690692
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/AST/ExprConstant.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5761,8 +5761,12 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
57615761
if (FS->getCond() && !EvaluateCond(Info, FS->getConditionVariable(),
57625762
FS->getCond(), Continue))
57635763
return ESR_Failed;
5764-
if (!Continue)
5764+
5765+
if (!Continue) {
5766+
if (!IterScope.destroy())
5767+
return ESR_Failed;
57655768
break;
5769+
}
57665770

57675771
EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody());
57685772
if (ESR != ESR_Continue) {

clang/test/SemaCXX/gh139818.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %clang_cc1 -std=c++23 -fsyntax-only %s -verify -fcxx-exceptions
2+
// RUN: %clang_cc1 -std=c++23 -fsyntax-only %s -verify -fexperimental-new-constant-interpreter -fcxx-exceptions
3+
4+
namespace GH139818{
5+
struct A {
6+
constexpr ~A() { ref = false; }
7+
constexpr operator bool() {
8+
return b;
9+
}
10+
bool b;
11+
bool& ref;
12+
};
13+
14+
constexpr bool f1() {
15+
bool ret = true;
16+
for (bool b = false; A x{b, ret}; b = true) {}
17+
return ret;
18+
}
19+
20+
static_assert(!f1());
21+
22+
struct Y {
23+
constexpr ~Y() noexcept(false) { throw "oops"; } // expected-note {{subexpression not valid in a constant expression}}
24+
25+
constexpr operator bool() {
26+
return b;
27+
}
28+
bool b;
29+
};
30+
constexpr bool f2() {
31+
for (bool b = false; Y x = {b}; b = true) {} // expected-note {{in call to 'x.~Y()'}}
32+
return true;
33+
}
34+
static_assert(f2()); // expected-error {{static assertion expression is not an integral constant expression}}
35+
// expected-note@-1 {{in call to 'f2()'}}
36+
};

0 commit comments

Comments
 (0)