On Thu, Jan 23, 2025 at 02:40:09PM +0000, Simon Martin wrote:
> Hi Jason,
> 
> On 20 Jan 2025, at 22:49, Jason Merrill wrote:
> 
> > On 1/20/25 2:11 PM, Simon Martin wrote:
> >> Hi Jason,
> >>
> >> On 15 Jan 2025, at 22:42, Jason Merrill wrote:
> >>
> >>> On 12/12/24 2:07 PM, Simon Martin wrote:
> >>>> 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 ===
> >>>>
> >>>> The problem is that when parsing the lambda body, and more
> >>>> specifically
> >>>> the multiplication, we mark the lambda as
> >>>> LAMBDA_EXPR_CAPTURE_OPTIMIZED
> >>>> even though the replacement of r by 4 is "undone" by the call to
> >>>> build_min_non_dep in build_x_binary_op. This makes
> >>>> prune_lambda_captures
> >>>> remove the proxy declaration while it should not, and we trip on an
> 
> >>>> assert at instantiation time.
> >>>
> >>> Why does prune_lambda_captures remove the declaration if it's still
> >>> used in the function body?  Setting LAMBDA_EXPR_CAPTURE_OPTIMIZED 
> >>> just
> >>> means "we might have optimized away some captures", the tree walk
> >>> should have found the use put back by build_x_binary_op.
> >> I think that this is due to a bug in mark_const_cap_r, that’s been
> >> here since the beginning, i.e. r8-7213-g1577f10a637352: it decides 
> 
> >> NOT
> >> to walk sub-trees when encountering a DECL_EXPR for a constant 
> >> capture
> >> proxy (at lambda.cc:1769). I don’t understand why we wouldn’t 
> >> want
> >> to continue.
> >
> > Because that's the declaration of the capture proxy, not a use of it.
> Indeed, thanks for clarifying.
> 
> > Why aren't we finding the use in the declaration of t?
> After further investigation, the problem is rather that neither 
> walk_tree_1 nor cp_walk_subtrees walk the dimensions of array types, so 
> we miss the uses.
> 
> >> Removing that line fixes the PR, but breaks 3 existing tests
> >> (lambda-capture1.C, lambda-const11.C and lambda-const11a.C, that all
> >> assert that we optimise out the capture); that’s why I did not 
> >> pursue
> >> it in the first place.
> >
> > Right.
> >
> >> But taking another look, it might not be that big a deal that we 
> >> don’t
> >> optimise those out: as soon as we use -O1 or above, the assignment to
> 
> >> the closure field actually disappears.
> >
> > Completely breaking this optimization is a big deal, particularly 
> > since it affects the layout of closure objects.  We can't always 
> > optimize everything away.
> ACK.
> 
> The attached updated patch makes cp_walk_subtrees walk array type 
> dimensions, which fixes the initial PR without those 3 regressions.
> 
> Successfully tested on x86_64-pc-linux-gnu. Is it OK?
> 
> Simon
> 
> PS: In theory I think it’d make sense to do do this change in 
> 
> walk_tree_1 since C also supports VLAs, but doing so breaks some OMP 
> tests. OMP can do interesting things with array bounds (see 
> r9-5354-gda972c05f48637), and fixing those would require teaching 
> walk_tree_1 about the “omp dummy var” array bounds, which I think 
> would be a bit ugly. And I’m not aware of any C case that would be 
> improved/fixed by doing this change, so we’re probably fine not doing 
> it.

> From e19bb6c943a422b1201c5c9a2a1d4f32141baf84 Mon Sep 17 00:00:00 2001
> From: Simon Martin <si...@nasilyan.com>
> Date: Wed, 22 Jan 2025 16:19:47 +0100
> Subject: [PATCH] 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 when walking a declaration
> with an array type, it walks that array type's dimensions. Since C also
> supports VLAs, I thought it'd make sense to do this in walk_tree_1, but
> this breaks some omp-low related test cases (because OMP can do funky
> things with array bounds when adjust_array_error_bounds is set), and I
> don't really want to add code to walk_tree_1 to skips arrays whose
> dimension is a temporary variable with the "omp dummy var" attribute.
> 
> Successfully tested on x86_64-pc-linux-gnu.
> 
>       PR c++/114292
> 
> gcc/cp/ChangeLog:
> 
>       * tree.cc (cp_walk_subtrees): Walk array type dimensions.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/cpp1y/lambda-ice4.C: New test.
> 
> ---
>  gcc/cp/tree.cc                           | 11 ++++++
>  gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C | 44 ++++++++++++++++++++++++
>  2 files changed, 55 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-ice4.C
> 
> diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> index 36581865a17..fc9a2fbff32 100644
> --- a/gcc/cp/tree.cc
> +++ b/gcc/cp/tree.cc
> @@ -5844,6 +5844,17 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, 
> walk_tree_fn func,
>        break;
>  
>      default:
> +      /* If this is an array, walk its dimensions.  */
> +      if (DECL_P (t) && TREE_TYPE (t)
> +       && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
> +     {
> +       tree domain = TYPE_DOMAIN (TREE_TYPE (t));
> +       if (domain)
> +         {
> +           WALK_SUBTREE (TYPE_MIN_VALUE (domain));
> +           WALK_SUBTREE (TYPE_MAX_VALUE (domain));
> +         }
> +     }
>        return NULL_TREE;
>      }

Is there a reason I'm missing not to put this into the TYPE_P block above?

Marek

Reply via email to