https://github.com/isuckatcs updated https://github.com/llvm/llvm-project/pull/67722
>From a6d3c27ea0b35e32198e1652fe3f6d647bc8cec4 Mon Sep 17 00:00:00 2001 From: isuckatcs <65320245+isucka...@users.noreply.github.com> Date: Thu, 28 Sep 2023 20:43:23 +0200 Subject: [PATCH 1/6] [clang] Fix a crash from nested ArrayInitLoopExpr When visiting an ArrayInitLoopExpr, clang creates a temporary variable for the source array, however in a nested AILE this variable is created multiple times, in every iteration as they have the same AST node and clang is unable to differentiate them. Fixes #57135 --- clang/lib/AST/ExprConstant.cpp | 11 ++++++----- .../nested-array-init-loop-in-lambda-capture.cpp | 13 +++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 clang/test/AST/nested-array-init-loop-in-lambda-capture.cpp diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fea06b97259fe31..a1f5c262ca10be3 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -10967,19 +10967,20 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { LValue Subobject = This; Subobject.addArray(Info, E, CAT); - bool Success = true; for (EvalInfo::ArrayInitLoopIndex Index(Info); Index != Elements; ++Index) { if (!EvaluateInPlace(Result.getArrayInitializedElt(Index), Info, Subobject, E->getSubExpr()) || !HandleLValueArrayAdjustment(Info, E, Subobject, CAT->getElementType(), 1)) { - if (!Info.noteFailure()) - return false; - Success = false; + + // There's no need to try and evaluate the rest, as those are the exact + // same expressions. + std::ignore = Info.noteFailure(); + return false; } } - return Success; + return true; } bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { diff --git a/clang/test/AST/nested-array-init-loop-in-lambda-capture.cpp b/clang/test/AST/nested-array-init-loop-in-lambda-capture.cpp new file mode 100644 index 000000000000000..82d27380b637d03 --- /dev/null +++ b/clang/test/AST/nested-array-init-loop-in-lambda-capture.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify %s +// RUN: %clang_cc1 -std=c++17 -verify=ref %s + +// ref-no-diagnostics +// expected-no-diagnostics + +void used_to_crash() { + int s[2][2]; + + int arr[4]; + + arr[0] = [s] { return s[0][0]; }(); +} >From 8f8f2b9ce187a5479b7c6bced51bff97c38f36bc Mon Sep 17 00:00:00 2001 From: isuckatcs <65320245+isucka...@users.noreply.github.com> Date: Thu, 28 Sep 2023 21:26:40 +0200 Subject: [PATCH 2/6] wrapping the temporary into a scope --- clang/lib/AST/ExprConstant.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index a1f5c262ca10be3..12b4d6b22c2c2bc 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -10950,6 +10950,9 @@ bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr( } bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { + + FullExpressionRAII Scope(Info); + LValue CommonLV; if (E->getCommonExpr() && !Evaluate(Info.CurrentCall->createTemporary( @@ -10967,20 +10970,19 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { LValue Subobject = This; Subobject.addArray(Info, E, CAT); + bool Success = true; for (EvalInfo::ArrayInitLoopIndex Index(Info); Index != Elements; ++Index) { if (!EvaluateInPlace(Result.getArrayInitializedElt(Index), Info, Subobject, E->getSubExpr()) || !HandleLValueArrayAdjustment(Info, E, Subobject, CAT->getElementType(), 1)) { - - // There's no need to try and evaluate the rest, as those are the exact - // same expressions. - std::ignore = Info.noteFailure(); - return false; + if (!Info.noteFailure()) + return false; + Success = false; } } - return true; + return Success; } bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { >From fb659cb7620d396882964ab628319643212a75b8 Mon Sep 17 00:00:00 2001 From: isuckatcs <65320245+isucka...@users.noreply.github.com> Date: Fri, 29 Sep 2023 07:30:12 +0200 Subject: [PATCH 3/6] addressed comments --- clang/lib/AST/ExprConstant.cpp | 16 +++++++++++--- clang/test/AST/Interp/cxx20.cpp | 37 +++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 12b4d6b22c2c2bc..1c0fa3ad2b6fb3e 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -10950,9 +10950,6 @@ bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr( } bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { - - FullExpressionRAII Scope(Info); - LValue CommonLV; if (E->getCommonExpr() && !Evaluate(Info.CurrentCall->createTemporary( @@ -10972,6 +10969,16 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { bool Success = true; for (EvalInfo::ArrayInitLoopIndex Index(Info); Index != Elements; ++Index) { + // C++ [class.temporary]/5 + // There are four contexts in which temporaries are destroyed at a different + // point than the end of the full-expression. [...] The second context is + // when a copy constructor is called to copy an element of an array while + // the entire array is copied [...]. In either case, if the constructor has + // one or more default arguments, the destruction of every temporary created + // in a default argument is sequenced before the construction of the next + // array element, if any. + FullExpressionRAII Scope(Info); + if (!EvaluateInPlace(Result.getArrayInitializedElt(Index), Info, Subobject, E->getSubExpr()) || !HandleLValueArrayAdjustment(Info, E, Subobject, @@ -10980,6 +10987,9 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { return false; Success = false; } + + // Make sure we run the destructors too. + Scope.destroy(); } return Success; diff --git a/clang/test/AST/Interp/cxx20.cpp b/clang/test/AST/Interp/cxx20.cpp index 0b13f41270a95b8..197090b0a37d9df 100644 --- a/clang/test/AST/Interp/cxx20.cpp +++ b/clang/test/AST/Interp/cxx20.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify %s -// RUN: %clang_cc1 -std=c++20 -verify=ref %s +// RUN: %clang_cc1 -fcxx-exceptions -fexperimental-new-constant-interpreter -std=c++20 -verify %s +// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -verify=ref %s void test_alignas_operand() { alignas(8) char dummy; @@ -700,3 +700,36 @@ namespace ThreeWayCmp { static_assert(pa1 <=> pa2 == -1, ""); static_assert(pa2 <=> pa1 == 1, ""); } + +// FIXME: Interp should also be able to evaluate this snippet properly. +namespace ConstexprArrayInitLoopExprDestructors +{ + struct Highlander { + int *p = 0; + constexpr Highlander() {} + 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}} + constexpr ~Highlander() { --*p; } + }; + + struct X { + int *p; + constexpr X(int *p) : p(p) {} + constexpr X(const X &x, Highlander &&h = Highlander()) : p(x.p) { + h.set(p); // expected-note {{in call to '&Highlander()->set(&n)'}} + } + }; + + constexpr int f() { + int n = 0; + X x[3] = {&n, &n, &n}; + auto [a, b, c] = x; // expected-note {{in call to 'X(x[0], Highlander())'}} + return n; + } + + static_assert(f() == 0); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to 'f()'}} + + int main() { + return f(); + } +} >From bedfe40d2bab344d8f2720a2ac47dfc991b2f403 Mon Sep 17 00:00:00 2001 From: isuckatcs <65320245+isucka...@users.noreply.github.com> Date: Fri, 29 Sep 2023 13:25:25 +0200 Subject: [PATCH 4/6] addressed comments --- clang/docs/ReleaseNotes.rst | 5 +++++ clang/test/AST/Interp/arrays.cpp | 7 +------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 09302040a3510b6..47d409eadf5b30e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -269,6 +269,8 @@ Bug Fixes in This Version - Fixes crash when trying to obtain the common sugared type of `decltype(instantiation-dependent-expr)`. Fixes (`#67603 <https://github.com/llvm/llvm-project/issues/67603>`_) +- Fixes a crash caused by a multidimensional array being captured by a lambda + (`#67722 <https://github.com/llvm/llvm-project/issues/67722>`_). Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -370,6 +372,9 @@ Bug Fixes to C++ Support argument. Fixes: (`#67395 <https://github.com/llvm/llvm-project/issues/67395>`_) +- Fix a bug when destructors in a ``constexpr`` structured binding were + called at the wrong place. + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an import failure of recursive friend class template. diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp index 5640f57f6aeb826..303ad6839208e43 100644 --- a/clang/test/AST/Interp/arrays.cpp +++ b/clang/test/AST/Interp/arrays.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s -// RUN: %clang_cc1 -verify=ref -DCUR_INTERP %s +// RUN: %clang_cc1 -verify=ref %s constexpr int m = 3; constexpr const int *foo[][5] = { @@ -352,10 +352,6 @@ namespace ZeroInit { } namespace ArrayInitLoop { - /// FIXME: The ArrayInitLoop for the decomposition initializer in g() has - /// f(n) as its CommonExpr. We need to evaluate that exactly once and not - /// N times as we do right now. -#ifndef CUR_INTERP struct X { int arr[3]; }; @@ -369,5 +365,4 @@ namespace ArrayInitLoop { } static_assert(g() == 6); // expected-error {{failed}} \ // expected-note {{15 == 6}} -#endif } >From 4382ca06317df3b3efe150a0396bf431e544238d Mon Sep 17 00:00:00 2001 From: isuckatcs <65320245+isucka...@users.noreply.github.com> Date: Fri, 29 Sep 2023 14:51:46 +0200 Subject: [PATCH 5/6] addressed comments --- clang/docs/ReleaseNotes.rst | 4 ++-- clang/test/AST/Interp/arrays.cpp | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 47d409eadf5b30e..942168b2c014a5b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -372,8 +372,8 @@ Bug Fixes to C++ Support argument. Fixes: (`#67395 <https://github.com/llvm/llvm-project/issues/67395>`_) -- Fix a bug when destructors in a ``constexpr`` structured binding were - called at the wrong place. +- Fixed a bug causing destructors of constant-evaluated structured bindings + initialized by array elements to be called in the wrong evaluation context. Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp index 303ad6839208e43..7985f6841658e56 100644 --- a/clang/test/AST/Interp/arrays.cpp +++ b/clang/test/AST/Interp/arrays.cpp @@ -352,6 +352,9 @@ namespace ZeroInit { } namespace ArrayInitLoop { + /// FIXME: The ArrayInitLoop for the decomposition initializer in g() has + /// f(n) as its CommonExpr. We need to evaluate that exactly once and not + /// N times as we do right now. struct X { int arr[3]; }; >From 6cac65d1c91d4e6a887d0e5196b06569ad4fc540 Mon Sep 17 00:00:00 2001 From: isuckatcs <65320245+isucka...@users.noreply.github.com> Date: Fri, 29 Sep 2023 16:08:43 +0200 Subject: [PATCH 6/6] format --- clang/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 942168b2c014a5b..829ec2e334a068d 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -372,7 +372,7 @@ Bug Fixes to C++ Support argument. Fixes: (`#67395 <https://github.com/llvm/llvm-project/issues/67395>`_) -- Fixed a bug causing destructors of constant-evaluated structured bindings +- Fixed a bug causing destructors of constant-evaluated structured bindings initialized by array elements to be called in the wrong evaluation context. Bug Fixes to AST Handling _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits