[PATCH] c++: nested lambda capturing a capture proxy, part 2 [PR94376]
Jason Merrill
jason@redhat.com
Thu Dec 16 21:14:11 GMT 2021
On 12/16/21 11:28, Patrick Palka wrote:
> On Wed, 15 Dec 2021, Jason Merrill wrote:
>
>> On 12/15/21 15:36, Patrick Palka wrote:
>>> The r12-5403 fix apparently doesn't handle the case where the inner
>>> lambda explicitly rather implicitly captures the capture proxy from
>>> the outer lambda, and so we still reject the first example in the
>>> testcase below.
>>>
>>> The reason is that compared to an implicit capture, the effective
>>> initializer for an explicit capture is wrapped in a location wrapper
>>> (pointing to the source location of the explicit capture), and this
>>> wrapper foils the is_capture_proxy check. The simplest fix appears to
>>> be to strip location wrappers accordingly.
>>>
>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
>>> trunk?
>>>
>>> PR c++/94376
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> * lambda.c (lambda_capture_field_type): Strip location wrappers
>>> before checking for a capture proxy.
>>
>> I think either is_capture_proxy should strip location wrappers or
>> gcc_checking_assert that it doesn't see one.
>
> Good idea, here's v2 which adds an assert to is_capture_proxy. Only one
> other caller, mark_const_cap_r, had to be adjusted.
OK.
> -- >8 --
>
> The r12-5403 fix apparently doesn't handle the case where the inner
> lambda explicitly rather implicitly captures the capture proxy from
> the outer lambda, which causes us to reject the first example in the
> testcase below.
>
> This is because compared to an implicit capture, the effective initializer
> for an explicit capture is wrapped in a location wrapper (pointing to the
> capture list), and this wrapper foils the is_capture_proxy check added in
> r12-5403.
>
> The simplest fix appears to be to strip location wrappers accordingly
> before checking is_capture_proxy. To help prevent against other
> occurrences of this kind of bug, this patch also makes is_capture_proxy
> assert it doesn't see a location wrapper.
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
>
> PR c++/94376
>
> gcc/cp/ChangeLog:
>
> * lambda.c (lambda_capture_field_type): Strip location wrappers
> before checking for a capture proxy.
> (is_capture_proxy): Assert that we don't see a location wrapper.
> (mark_const_cap_r): Don't call is_constant_capture_proxy on a
> location wrapper.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp0x/lambda/lambda-nested9a.C: New test.
> ---
> gcc/cp/lambda.c | 7 ++++
> .../g++.dg/cpp0x/lambda/lambda-nested9a.C | 42 +++++++++++++++++++
> 2 files changed, 49 insertions(+)
> create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9a.C
>
> diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
> index c39a2bca416..d14e12c48f0 100644
> --- a/gcc/cp/lambda.c
> +++ b/gcc/cp/lambda.c
> @@ -221,6 +221,7 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
> }
> else
> {
> + STRIP_ANY_LOCATION_WRAPPER (expr);
> if (!by_reference_p && is_capture_proxy (expr))
> {
> /* When capturing by-value another capture proxy from an enclosing
> @@ -246,6 +247,10 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
> bool
> is_capture_proxy (tree decl)
> {
> + /* Location wrappers should be stripped or otherwise handled by the
> + caller before using this predicate. */
> + gcc_checking_assert (!location_wrapper_p (decl));
> +
> return (VAR_P (decl)
> && DECL_HAS_VALUE_EXPR_P (decl)
> && !DECL_ANON_UNION_VAR_P (decl)
> @@ -1496,6 +1501,8 @@ mark_const_cap_r (tree *t, int *walk_subtrees, void *data)
> *walk_subtrees = 0;
> }
> }
> + else if (location_wrapper_p (*t))
> + /* is_capture_proxy dislikes location wrappers. */;
> else if (is_constant_capture_proxy (*t))
> var = DECL_CAPTURED_VARIABLE (*t);
>
> diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9a.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9a.C
> new file mode 100644
> index 00000000000..d62f8f0c952
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9a.C
> @@ -0,0 +1,42 @@
> +// PR c++/94376
> +// Like lambda-nested9.C but using explicit captures in the inner lambda.
> +// { dg-do compile { target c++11 } }
> +
> +int main() {
> + // We used to incorrectly reject the first two cases.
> + int i = 0;
> + [=] () {
> + [i] () mutable {
> + ++i;
> + };
> + };
> +
> +#if __cpp_init_captures
> + [j=0] () {
> + [j] () mutable {
> + ++j;
> + };
> + };
> +#endif
> +
> + [=] () {
> + [&i] () mutable {
> + ++i; // { dg-error "read-only" }
> + };
> + };
> +
> + const int j = 0;
> + [=] () {
> + [j] () mutable {
> + ++j; // { dg-error "read-only" }
> + };
> + };
> +
> +#if __cpp_init_captures
> + [j=0] () {
> + [&j] () mutable {
> + ++j; // { dg-error "read-only" "" { target c++14 } }
> + };
> + };
> +#endif
> +}
More information about the Gcc-patches
mailing list