[clang] c496aa3 - [clang] Fix a crash from nested ArrayInitLoopExpr (#67722)

via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 29 10:12:54 PDT 2023


Author: isuckatcs
Date: 2023-09-29T19:12:49+02:00
New Revision: c496aa34c0e82a4322143105fd4410cd05b49921

URL: https://github.com/llvm/llvm-project/commit/c496aa34c0e82a4322143105fd4410cd05b49921
DIFF: https://github.com/llvm/llvm-project/commit/c496aa34c0e82a4322143105fd4410cd05b49921.diff

LOG: [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

Added: 
    clang/test/AST/nested-array-init-loop-in-lambda-capture.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/AST/ExprConstant.cpp
    clang/test/AST/Interp/arrays.cpp
    clang/test/AST/Interp/cxx20.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 09302040a3510b6..829ec2e334a068d 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>`_)
 
+- 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
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 - Fixed an import failure of recursive friend class template.

diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f0d53d6ae18e804..f7a99bdae18f985 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -10969,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 
diff erent
+    // 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,
@@ -10977,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/arrays.cpp b/clang/test/AST/Interp/arrays.cpp
index 5640f57f6aeb826..7985f6841658e56 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] = {
@@ -355,7 +355,6 @@ 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 +368,4 @@ namespace ArrayInitLoop {
   }
   static_assert(g() == 6); // expected-error {{failed}} \
                            // expected-note {{15 == 6}}
-#endif
 }

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();
+  }
+}

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]; }();
+}


        


More information about the cfe-commits mailing list