[gcc r14-11426] c++: Don't prune constant capture proxies only used in array dimensions [PR114292]
Simon Martin
simartin@gcc.gnu.org
Thu Mar 20 19:38:28 GMT 2025
https://gcc.gnu.org/g:f86d274ab76fdd89d7afd9b2eab28f3a61749cfb
commit r14-11426-gf86d274ab76fdd89d7afd9b2eab28f3a61749cfb
Author: Simon Martin <simon@nasilyan.com>
Date: Thu Mar 20 20:36:26 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 and processing a template declaration, it also walks its
TYPE_{MIN,MAX}_VALUE.
PR c++/114292
gcc/cp/ChangeLog:
* tree.cc (cp_walk_subtrees): Walk the type of DECL_EXPR
declarations, as well as the TYPE_{MIN,MAX}_VALUE of
INTEGER_TYPEs for template declarations.
gcc/testsuite/ChangeLog:
* g++.dg/cpp1y/lambda-ice4.C: New test.
Diff:
---
gcc/cp/tree.cc | 10 +++++
gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C | 63 ++++++++++++++++++++++++++++++++
2 files changed, 73 insertions(+)
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index abed2ce859c7..c6a4d89f4a34 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5701,6 +5701,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));
@@ -5751,6 +5752,15 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
WALK_SUBTREE (STATIC_ASSERT_MESSAGE (t));
break;
+ case INTEGER_TYPE:
+ if (processing_template_decl)
+ {
+ /* 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);
+}
More information about the Gcc-cvs
mailing list