Skip to content

Commit c496aa3

Browse files
authored
[clang] Fix a crash from nested ArrayInitLoopExpr (#67722)
This patch makes sure that everything is cleaned up properly when ExprConstant evaluates an ArrayInitLoopExpr. Fixes #57135
1 parent e997dca commit c496aa3

File tree

5 files changed

+67
-5
lines changed

5 files changed

+67
-5
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,8 @@ Bug Fixes in This Version
269269
- Fixes crash when trying to obtain the common sugared type of
270270
`decltype(instantiation-dependent-expr)`.
271271
Fixes (`#67603 <https://github.com/llvm/llvm-project/issues/67603>`_)
272+
- Fixes a crash caused by a multidimensional array being captured by a lambda
273+
(`#67722 <https://github.com/llvm/llvm-project/issues/67722>`_).
272274

273275
Bug Fixes to Compiler Builtins
274276
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -370,6 +372,9 @@ Bug Fixes to C++ Support
370372
argument. Fixes:
371373
(`#67395 <https://github.com/llvm/llvm-project/issues/67395>`_)
372374

375+
- Fixed a bug causing destructors of constant-evaluated structured bindings
376+
initialized by array elements to be called in the wrong evaluation context.
377+
373378
Bug Fixes to AST Handling
374379
^^^^^^^^^^^^^^^^^^^^^^^^^
375380
- Fixed an import failure of recursive friend class template.

clang/lib/AST/ExprConstant.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10969,6 +10969,16 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
1096910969

1097010970
bool Success = true;
1097110971
for (EvalInfo::ArrayInitLoopIndex Index(Info); Index != Elements; ++Index) {
10972+
// C++ [class.temporary]/5
10973+
// There are four contexts in which temporaries are destroyed at a different
10974+
// point than the end of the full-expression. [...] The second context is
10975+
// when a copy constructor is called to copy an element of an array while
10976+
// the entire array is copied [...]. In either case, if the constructor has
10977+
// one or more default arguments, the destruction of every temporary created
10978+
// in a default argument is sequenced before the construction of the next
10979+
// array element, if any.
10980+
FullExpressionRAII Scope(Info);
10981+
1097210982
if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
1097310983
Info, Subobject, E->getSubExpr()) ||
1097410984
!HandleLValueArrayAdjustment(Info, E, Subobject,
@@ -10977,6 +10987,9 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
1097710987
return false;
1097810988
Success = false;
1097910989
}
10990+
10991+
// Make sure we run the destructors too.
10992+
Scope.destroy();
1098010993
}
1098110994

1098210995
return Success;

clang/test/AST/Interp/arrays.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
2-
// RUN: %clang_cc1 -verify=ref -DCUR_INTERP %s
2+
// RUN: %clang_cc1 -verify=ref %s
33

44
constexpr int m = 3;
55
constexpr const int *foo[][5] = {
@@ -355,7 +355,6 @@ namespace ArrayInitLoop {
355355
/// FIXME: The ArrayInitLoop for the decomposition initializer in g() has
356356
/// f(n) as its CommonExpr. We need to evaluate that exactly once and not
357357
/// N times as we do right now.
358-
#ifndef CUR_INTERP
359358
struct X {
360359
int arr[3];
361360
};
@@ -369,5 +368,4 @@ namespace ArrayInitLoop {
369368
}
370369
static_assert(g() == 6); // expected-error {{failed}} \
371370
// expected-note {{15 == 6}}
372-
#endif
373371
}

clang/test/AST/Interp/cxx20.cpp

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify %s
2-
// RUN: %clang_cc1 -std=c++20 -verify=ref %s
1+
// RUN: %clang_cc1 -fcxx-exceptions -fexperimental-new-constant-interpreter -std=c++20 -verify %s
2+
// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -verify=ref %s
33

44
void test_alignas_operand() {
55
alignas(8) char dummy;
@@ -700,3 +700,36 @@ namespace ThreeWayCmp {
700700
static_assert(pa1 <=> pa2 == -1, "");
701701
static_assert(pa2 <=> pa1 == 1, "");
702702
}
703+
704+
// FIXME: Interp should also be able to evaluate this snippet properly.
705+
namespace ConstexprArrayInitLoopExprDestructors
706+
{
707+
struct Highlander {
708+
int *p = 0;
709+
constexpr Highlander() {}
710+
constexpr void set(int *p) { this->p = p; ++*p; if (*p != 1) throw "there can be only one"; } // expected-note {{not valid in a constant expression}}
711+
constexpr ~Highlander() { --*p; }
712+
};
713+
714+
struct X {
715+
int *p;
716+
constexpr X(int *p) : p(p) {}
717+
constexpr X(const X &x, Highlander &&h = Highlander()) : p(x.p) {
718+
h.set(p); // expected-note {{in call to '&Highlander()->set(&n)'}}
719+
}
720+
};
721+
722+
constexpr int f() {
723+
int n = 0;
724+
X x[3] = {&n, &n, &n};
725+
auto [a, b, c] = x; // expected-note {{in call to 'X(x[0], Highlander())'}}
726+
return n;
727+
}
728+
729+
static_assert(f() == 0); // expected-error {{not an integral constant expression}} \
730+
// expected-note {{in call to 'f()'}}
731+
732+
int main() {
733+
return f();
734+
}
735+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify %s
2+
// RUN: %clang_cc1 -std=c++17 -verify=ref %s
3+
4+
// ref-no-diagnostics
5+
// expected-no-diagnostics
6+
7+
void used_to_crash() {
8+
int s[2][2];
9+
10+
int arr[4];
11+
12+
arr[0] = [s] { return s[0][0]; }();
13+
}

0 commit comments

Comments
 (0)