From: Jason Merrill <jason@redhat.com>
To: Patrick Palka <ppalka@redhat.com>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: [pushed] c++: constant, array, lambda, template [PR108975]
Date: Tue, 25 Apr 2023 15:25:18 -0400 [thread overview]
Message-ID: <7b72e343-c946-eaa3-d6f5-042ee6e4b02e@redhat.com> (raw)
In-Reply-To: <7f027e55-1066-7e41-9158-e4d0189cbd83@idea>
On 4/25/23 10:55, Patrick Palka wrote:
> On Sat, 18 Mar 2023, Patrick Palka wrote:
>
>> On Fri, 17 Mar 2023, Jason Merrill via Gcc-patches wrote:
>>
>>> Tested x86_64-pc-linux-gnu, applying to trunk.
>>>
>>> -- 8< --
>>>
>>> When a lambda refers to a constant local variable in the enclosing scope, we
>>> tentatively capture it, but if we end up pulling out its constant value, we
>>> go back at the end of the lambda and prune any unneeded captures. Here
>>> while parsing the template we decided that the dim capture was unneeded,
>>> because we folded it away, but then we brought back the use in the template
>>> trees that try to preserve the source representation with added type info.
>>> So then when we tried to instantiate that use, we couldn't find what it was
>>> trying to use, and crashed.
>>>
>>> Fixed by not trying to prune when parsing a template; we'll prune at
>>> instantiation time.
>>>
>>> PR c++/108975
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> * lambda.cc (prune_lambda_captures): Don't bother in a template.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> * g++.dg/cpp0x/lambda/lambda-const11.C: New test.
>>> ---
>>> gcc/cp/lambda.cc | 3 +++
>>> gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const11.C | 14 ++++++++++++++
>>> 2 files changed, 17 insertions(+)
>>> create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const11.C
>>>
>>> diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
>>> index 212990a21bf..9925209b2ed 100644
>>> --- a/gcc/cp/lambda.cc
>>> +++ b/gcc/cp/lambda.cc
>>> @@ -1760,6 +1760,9 @@ prune_lambda_captures (tree body)
>>> if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) == CPLD_NONE)
>>> /* No default captures, and we don't prune explicit captures. */
>>> return;
>>> + /* Don't bother pruning in a template, we'll prune at instantiation time. */
>>> + if (dependent_type_p (TREE_TYPE (lam)))
>>> + return;
>>>
>>> hash_map<tree,tree*> const_vars;
>>>
>>> diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const11.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const11.C
>>> new file mode 100644
>>> index 00000000000..26af75bf132
>>> --- /dev/null
>>> +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const11.C
>>> @@ -0,0 +1,14 @@
>>> +// PR c++/108975
>>> +// { dg-do compile { target c++11 } }
>>> +
>>> +template<class T>
>>> +void f() {
>>> + constexpr int dim = 1;
>>> + auto l = [&] {
>>> + int n[dim * 1];
>>> + };
>>> + // In f<int>, we shouldn't actually capture dim.
>>> + static_assert (sizeof(l) == 1, "");
>>> +}
>>> +
>>> +template void f<int>();
>>
>> Sadly I think more is needed to fix the generic lambda case, we still
>> crash for:
>>
>> template<class T>
>> void f() {
>> constexpr int dim = 1;
>> auto l = [&] (auto) {
>> int n[dim * 1];
>> };
>> l(0);
>> // In f<int>, we shouldn't actually capture dim.
>> static_assert (sizeof(l) == 1, "");
>> }
>>
>> template void f<int>();
>>
>> It seems prune_lambda_captures doesn't thoroughly walk the lambda body,
>> and so fails to find all uses of constant captures such as in 'int n[dim * 1]'
>> or 'using type = decltype(g<dim * 1>())' (in the original testcase the
>> constant capture use occurred inside an alias declaration).
>
> I was curious why we ICE only with a by-ref capture and not with a by-value
> capture, and it turns out the difference is that we consider a by-ref
> capture of the constant variable 'dim' to be value-dependent, which
> prevents us from constant folding its uses ahead of time.
>
> So another approach to fixing the generic lambda version of this
> testcase would be to make value_dependent_expression_p treat by-value
> and by-ref captures of constant variables more similarly. What do you
> think of the following?
>
> -- >8 --
>
> Subject: [PATCH] c++: value dependence of by-ref lambda capture [PR108975]
>
> We are still ICEing in the generic lambda version of the testcase from
> this PR even after r13-6743-g6f90de97634d6f due to the by-ref capture of
> the constant local variable 'dim' being considered value-dependent when
> regenerating the lambda (at which point processing_template_decl is set
> since the lambda is generic), which prevents us from constant folding
> its uses. Later when calling prune_lambda_captures, we end up not
> thoroughly walking the body of the lambda and miss the non-folded uses
> of 'dim' within the array bounds and using-decl, and we prematurely
> prune the capture.
>
> We could fix this by making prune_lambda_captures walk the body of the
> lambda more thoroughly so that it finds these non-folded uses of 'dim',
> but ideally we should be able to constant fold all uses of 'dim' ahead
> of time and prune the implicit capture after all.
>
> To that end this patch makes value_dependent_expression_p consistently
> return false for such captures of constant local variables even if they
> are by-ref, allowing their uses to get constant folded ahead of time.
> It seems we just need to relax the conservative early exit for reference
> variables (added by r5-5022-g51d72abe5ea04e) when DECL_HAS_VALUE_EXPR_P.
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
OK.
> PR c++/108975
>
> gcc/cp/ChangeLog:
>
> * pt.cc (value_dependent_expression_p) <case VAR_DECL>:
> Suppress conservative early exit for reference variables
> when DECL_HAS_VALUE_EXPR_P.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp0x/lambda/lambda-const11a.C: New test.
> ---
> gcc/cp/pt.cc | 7 ++++---
> .../g++.dg/cpp0x/lambda/lambda-const11a.C | 21 +++++++++++++++++++
> 2 files changed, 25 insertions(+), 3 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const11a.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 3e5f0104056..a668825b5f9 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -27959,9 +27959,7 @@ value_dependent_expression_p (tree expression)
> case VAR_DECL:
> /* A constant with literal type and is initialized
> with an expression that is value-dependent. */
> - if (DECL_DEPENDENT_INIT_P (expression)
> - /* FIXME cp_finish_decl doesn't fold reference initializers. */
> - || TYPE_REF_P (TREE_TYPE (expression)))
> + if (DECL_DEPENDENT_INIT_P (expression))
> return true;
> if (DECL_HAS_VALUE_EXPR_P (expression))
> {
> @@ -27976,6 +27974,9 @@ value_dependent_expression_p (tree expression)
> && value_expr == error_mark_node))
> return true;
> }
> + else if (TYPE_REF_P (TREE_TYPE (expression)))
> + /* FIXME cp_finish_decl doesn't fold reference initializers. */
> + return true;
> return false;
>
> case DYNAMIC_CAST_EXPR:
> diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const11a.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const11a.C
> new file mode 100644
> index 00000000000..d3a6de8a138
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const11a.C
> @@ -0,0 +1,21 @@
> +// PR c++/108975
> +// A version of lambda-const11.C using a generic lambda.
> +// { dg-do compile { target c++11 } }
> +
> +template<int> void g();
> +template<int> struct A { };
> +
> +template<class T>
> +void f() {
> + constexpr int dim = 1;
> + auto f = [&](auto) {
> + int n[dim * 1];
> + using ty1 = decltype(g<dim * 2>());
> + using ty2 = A<dim * 3>;
> + };
> + // In f<int>, we shouldn't actually capture dim.
> + static_assert (sizeof(f) == 1, "");
> + f(0);
> +}
> +
> +template void f<int>();
prev parent reply other threads:[~2023-04-25 19:25 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-17 23:32 Jason Merrill
2023-03-18 13:50 ` Patrick Palka
2023-04-25 14:55 ` Patrick Palka
2023-04-25 19:25 ` Jason Merrill [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=7b72e343-c946-eaa3-d6f5-042ee6e4b02e@redhat.com \
--to=jason@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=ppalka@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).