Skip to content

Commit ceabea4

Browse files
committed
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.
1 parent f7dc4fd commit ceabea4

File tree

3 files changed

+70
-5
lines changed

3 files changed

+70
-5
lines changed

gcc/cp/pt.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10822,11 +10822,6 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
1082210822
WALK_SUBTREE (TYPE_TI_ARGS (t));
1082310823
break;
1082410824

10825-
case INTEGER_TYPE:
10826-
WALK_SUBTREE (TYPE_MIN_VALUE (t));
10827-
WALK_SUBTREE (TYPE_MAX_VALUE (t));
10828-
break;
10829-
1083010825
case METHOD_TYPE:
1083110826
/* Since we're not going to walk subtrees, we have to do this
1083210827
explicitly here. */

gcc/cp/tree.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5793,6 +5793,7 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
57935793
&& !TREE_STATIC (TREE_OPERAND (t, 0)))))
57945794
{
57955795
tree decl = TREE_OPERAND (t, 0);
5796+
WALK_SUBTREE (TREE_TYPE (decl));
57965797
WALK_SUBTREE (DECL_INITIAL (decl));
57975798
WALK_SUBTREE (DECL_SIZE (decl));
57985799
WALK_SUBTREE (DECL_SIZE_UNIT (decl));
@@ -5843,6 +5844,12 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
58435844
WALK_SUBTREE (STATIC_ASSERT_MESSAGE (t));
58445845
break;
58455846

5847+
case INTEGER_TYPE:
5848+
/* Removed from walk_type_fields in r119481. */
5849+
WALK_SUBTREE (TYPE_MIN_VALUE (t));
5850+
WALK_SUBTREE (TYPE_MAX_VALUE (t));
5851+
break;
5852+
58465853
default:
58475854
return NULL_TREE;
58485855
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// PR c++/114292
2+
// { dg-do "compile" { target c++14 } }
3+
// { dg-additional-options "-Wno-vla" }
4+
5+
#define ASSERT_CAPTURE_NUMBER(Lambda, NumCaptures) \
6+
{ \
7+
auto oneCapture = [&](auto) { int t[c]; }; \
8+
const auto sizeOneCapture = sizeof (oneCapture); \
9+
const auto expected = NumCaptures ? NumCaptures * sizeOneCapture : 1; \
10+
static_assert (sizeof (Lambda) == expected, ""); \
11+
}
12+
13+
template<int r, int c>
14+
struct Want_a_Typedef { typedef int Type[r*c]; };
15+
16+
void foo (int c)
17+
{
18+
constexpr int r = 4;
19+
20+
// This used to ICE.
21+
auto ice_1 = [&](auto) { int t[c * r]; };
22+
ice_1 (0);
23+
ASSERT_CAPTURE_NUMBER (ice_1, 2);
24+
25+
// Another ICE identified following a great question in the patch submission
26+
// mail thread.
27+
auto ice_2 = [&](auto) { typedef int MyT[c*r]; };
28+
ice_2 (0);
29+
ASSERT_CAPTURE_NUMBER (ice_2, 2);
30+
31+
// All those worked already, but were not covered by any test - do it here.
32+
auto ok_0 = [&](auto) { typedef int MyT[c*r]; MyT t; };
33+
ok_0 (0);
34+
ASSERT_CAPTURE_NUMBER (ok_0, 2);
35+
36+
auto ok_1 = [&](auto) { Want_a_Typedef<r, 42>::Type t; };
37+
ok_1 (0);
38+
ASSERT_CAPTURE_NUMBER (ok_1, 0);
39+
40+
auto ok_2 = [&](auto) { int t[c]; };
41+
ok_2 (0);
42+
ASSERT_CAPTURE_NUMBER (ok_2, 1);
43+
44+
auto ok_3 = [&](auto) { int n = r * c; int t[n]; };
45+
ok_3 (0);
46+
ASSERT_CAPTURE_NUMBER (ok_3, 2);
47+
48+
auto ok_4 = [&](auto) { int t[r]; };
49+
ok_4 (0);
50+
ASSERT_CAPTURE_NUMBER (ok_4, 0);
51+
52+
auto ok_5 = [&](auto) { int t[c * 4]; };
53+
ok_5 (0);
54+
ASSERT_CAPTURE_NUMBER (ok_5, 1);
55+
56+
auto ok_6 = [&](auto) { int t[1]; };
57+
ok_6 (0);
58+
ASSERT_CAPTURE_NUMBER (ok_6, 0);
59+
60+
auto ok_7 = [&](auto) { int t[c * r]; };
61+
ok_7 (0);
62+
ASSERT_CAPTURE_NUMBER (ok_7, 2);
63+
}

0 commit comments

Comments
 (0)