https://gcc.gnu.org/g:ceabea405ffdc851736e240111be9b297ad86c53

commit r15-7238-gceabea405ffdc851736e240111be9b297ad86c53
Author: Simon Martin <si...@nasilyan.com>
Date:   Wed Jan 22 16:19:47 2025 +0100

    c++: Don't prune constant capture proxies only used in array dimensions 
[PR114292]
    
    We currently ICE upon the following valid (under -Wno-vla) code
    
    === cut here ===
    void f(int c) {
      constexpr int r = 4;
      [&](auto) { int t[r * c]; }(0);
    }
    === cut here ===
    
    When parsing the lambda body, and more specifically the multiplication,
    we mark the lambda as LAMBDA_EXPR_CAPTURE_OPTIMIZED, which indicates to
    prune_lambda_captures that it might be possible to optimize out some
    captures.
    
    The problem is that prune_lambda_captures then misses the use of the r
    capture (because neither walk_tree_1 nor cp_walk_subtrees walks the
    dimensions of array types - here "r * c"), hence believes the capture
    can be pruned... and we trip on an assert when instantiating the lambda.
    
    This patch changes cp_walk_subtrees so that (1) when walking a
    DECL_EXPR, it also walks the DECL's type, and (2) when walking an
    INTEGER_TYPE, it also walks its TYPE_{MIN,MAX}_VALUE. Note that #2 makes
    a <case INTEGER_TYPE> redundant in for_each_template_parm_r, and removes
    it.
    
            PR c++/114292
    
    gcc/cp/ChangeLog:
    
            * pt.cc (for_each_template_parm_r) <INTEGER_TYPE>: Remove case
            now handled by cp_walk_subtrees.
            * tree.cc (cp_walk_subtrees): Walk the type of DECL_EXPR
            declarations, as well as the TYPE_{MIN,MAX}_VALUE of
            INTEGER_TYPEs.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp1y/lambda-ice4.C: New test.

Diff:
---
 gcc/cp/pt.cc                             |  5 ---
 gcc/cp/tree.cc                           |  7 ++++
 gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C | 63 ++++++++++++++++++++++++++++++++
 3 files changed, 70 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 6442ae947c32..d4a6e2e0675f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -10822,11 +10822,6 @@ for_each_template_parm_r (tree *tp, int 
*walk_subtrees, void *d)
        WALK_SUBTREE (TYPE_TI_ARGS (t));
       break;
 
-    case INTEGER_TYPE:
-      WALK_SUBTREE (TYPE_MIN_VALUE (t));
-      WALK_SUBTREE (TYPE_MAX_VALUE (t));
-      break;
-
     case METHOD_TYPE:
       /* Since we're not going to walk subtrees, we have to do this
         explicitly here.  */
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 36581865a177..e35432f43af9 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5793,6 +5793,7 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, 
walk_tree_fn func,
                  && !TREE_STATIC (TREE_OPERAND (t, 0)))))
        {
          tree decl = TREE_OPERAND (t, 0);
+         WALK_SUBTREE (TREE_TYPE (decl));
          WALK_SUBTREE (DECL_INITIAL (decl));
          WALK_SUBTREE (DECL_SIZE (decl));
          WALK_SUBTREE (DECL_SIZE_UNIT (decl));
@@ -5843,6 +5844,12 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, 
walk_tree_fn func,
       WALK_SUBTREE (STATIC_ASSERT_MESSAGE (t));
       break;
 
+    case INTEGER_TYPE:
+      /* Removed from walk_type_fields in r119481.  */
+      WALK_SUBTREE (TYPE_MIN_VALUE (t));
+      WALK_SUBTREE (TYPE_MAX_VALUE (t));
+      break;
+
     default:
       return NULL_TREE;
     }
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C 
b/gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C
new file mode 100644
index 000000000000..d8b7af9f9920
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C
@@ -0,0 +1,63 @@
+// PR c++/114292
+// { dg-do "compile" { target c++14 } }
+// { dg-additional-options "-Wno-vla" }
+
+#define ASSERT_CAPTURE_NUMBER(Lambda, NumCaptures) \
+  { \
+    auto oneCapture = [&](auto) { int t[c]; }; \
+    const auto sizeOneCapture = sizeof (oneCapture); \
+    const auto expected = NumCaptures ? NumCaptures * sizeOneCapture : 1; \
+    static_assert (sizeof (Lambda) == expected, ""); \
+  }
+
+template<int r, int c>
+struct Want_a_Typedef { typedef int Type[r*c]; };
+    
+void foo (int c)
+{
+  constexpr int r = 4;
+
+  // This used to ICE.
+  auto ice_1 = [&](auto) { int t[c * r]; };
+  ice_1 (0);
+  ASSERT_CAPTURE_NUMBER (ice_1, 2);
+
+  // Another ICE identified following a great question in the patch submission
+  // mail thread.
+  auto ice_2 = [&](auto) { typedef int MyT[c*r]; };
+  ice_2 (0);
+  ASSERT_CAPTURE_NUMBER (ice_2, 2);
+
+  // All those worked already, but were not covered by any test - do it here.
+  auto ok_0 = [&](auto) { typedef int MyT[c*r]; MyT t; };
+  ok_0 (0);
+  ASSERT_CAPTURE_NUMBER (ok_0, 2);
+
+  auto ok_1 = [&](auto) { Want_a_Typedef<r, 42>::Type t; };
+  ok_1 (0);
+  ASSERT_CAPTURE_NUMBER (ok_1, 0);
+
+  auto ok_2 = [&](auto) { int t[c]; };
+  ok_2 (0);
+  ASSERT_CAPTURE_NUMBER (ok_2, 1);
+
+  auto ok_3 = [&](auto) { int n = r * c; int t[n]; };
+  ok_3 (0);
+  ASSERT_CAPTURE_NUMBER (ok_3, 2);
+
+  auto ok_4 = [&](auto) { int t[r]; };
+  ok_4 (0);
+  ASSERT_CAPTURE_NUMBER (ok_4, 0);
+
+  auto ok_5 = [&](auto) { int t[c * 4]; };
+  ok_5 (0);
+  ASSERT_CAPTURE_NUMBER (ok_5, 1);
+
+  auto ok_6 = [&](auto) { int t[1]; };
+  ok_6 (0);
+  ASSERT_CAPTURE_NUMBER (ok_6, 0);
+
+  auto ok_7 = [&](auto) { int t[c * r]; };
+  ok_7 (0);
+  ASSERT_CAPTURE_NUMBER (ok_7, 2);
+}

Reply via email to