public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Fix PR c++/70121 (premature folding of const var that was implicitly captured)
@ 2016-03-10 22:58 Patrick Palka
  2016-03-10 23:06 ` Patrick Palka
  2016-03-18 15:22 ` Jason Merrill
  0 siblings, 2 replies; 5+ messages in thread
From: Patrick Palka @ 2016-03-10 22:58 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason, Patrick Palka

Within a lambda we should implicitly capture an outer const variable
only if it's odr-used in the body of the lambda.  But we are currently
making the decision of whether to capture such a variable, or else to
fold it to a constant, too early -- before we can know whether it's
being odr-used or not.  So we currently always fold a const variable to
a constant if possible instead of otherwise capturing it, but of course
doing this is wrong if e.g. the address of this variable is taken inside
the lambda's body.

This patch reverses the behavior of process_outer_var_ref, so that we
always implicitly capture a const variable if it's capturable, instead
of always trying to first fold it to a constant.  This behavior however
is wrong too, and introduces a different but perhaps less important
regression: if we implicitly capture by value a const object that is not
actually odr-used within the body of the lambda, we may introduce a
redundant call to its copy/move constructor, see pr70121-2.C.

Ideally we should be capturing a variable only if it's not odr-used
within the entire body of the lambda, but doing that would be a
significantly less trivial patch I think.  So I wonder if this patch is
a good tradeoff for GCC 6.  But I mostly wonder if my analysis and
proposed ideal solution is correct :)  Either way I'm planning to
bootstrap + regtest this patch and also test it against Boost.

gcc/cp/ChangeLog:

	PR c++/70121
	* semantics.c (process_outer_var_ref): Don't fold DECL to a
	constant if it's otherwise going to get implicitly captured.

gcc/testsuite/ChangeLog:

	PR c++/70121
	* g++.dg/cpp0x/lambda/pr70121.C: New test.
	* g++.dg/cpp0x/lambda/pr70121-2.C: New test.
---
 gcc/cp/semantics.c                            |  6 +++++
 gcc/testsuite/g++.dg/cpp0x/lambda/pr70121-2.C | 22 ++++++++++++++++
 gcc/testsuite/g++.dg/cpp0x/lambda/pr70121.C   | 37 +++++++++++++++++++++++++++
 3 files changed, 65 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/pr70121-2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/pr70121.C

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index ea72e0e..a9dbf16 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3332,6 +3332,12 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain)
 	   the closure type when instantiating the lambda context.  That is
 	   probably also the way to handle lambdas within pack expansions.  */
 	return decl;
+      /* Don't try to fold DECL to a constant if we are otherwise going to
+	 implicitly capture it.  FIXME we should avoid folding DECL to a
+	 constant only if it's odr-used within the lambda body, but we can't
+	 determine that at this point.  */
+      else if (lambda_expr && context == containing_function)
+	;
       else if (decl_constant_var_p (decl))
 	{
 	  tree t = maybe_constant_value (convert_from_reference (decl));
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/pr70121-2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/pr70121-2.C
new file mode 100644
index 0000000..4676068
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/pr70121-2.C
@@ -0,0 +1,22 @@
+// PR c++/70121
+// { dg-do compile { target c++11 } }
+
+struct X
+{
+  int a;
+
+  constexpr X () : a (28) { };
+  X (const X&) = delete;
+  X (const X&&) = delete;
+};
+
+void
+baz (void)
+{
+  constexpr X x;
+  // These are non-odr usages of x.a so they should each be folded to a
+  // constant expression without having to capture and copy x.
+  auto ff1 = [=] { return x.a; }; // { dg-bogus "deleted" "" { xfail *-*-* } }
+  const auto &ff2 = [=] { return x.a; }; // { dg-bogus "deleted" "" { xfail *-*-* } }
+  const auto &&ff3 = [=] { return x.a; }; // { dg-bogus "deleted" "" { xfail *-*-* } }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/pr70121.C b/gcc/testsuite/g++.dg/cpp0x/lambda/pr70121.C
new file mode 100644
index 0000000..db8a4ca
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/pr70121.C
@@ -0,0 +1,37 @@
+// PR c++/70121
+// { dg-do compile { target c++11 } }
+
+static void
+foo (void)
+{
+  const int val = 28;
+  auto ff_v = [=]() -> const int& { return val; }; // { dg-bogus "temporary" }
+  auto ff_r = [&]() -> const int& { return val; }; // { dg-bogus "temporary" }
+
+  if (&ff_r () != &val)
+    __builtin_abort ();
+
+  if (ff_v () + ff_r () != 56)
+    __builtin_abort ();
+}
+
+static void
+bar (void)
+{
+  const int val = 28;
+  static const int *p;
+  auto ff_v = [=] { p = &val; }; // { dg-bogus "lvalue required" }
+  auto ff_r = [&] { p = &val; }; // { dg-bogus "lvalue required" }
+
+  ff_v ();
+  ff_r ();
+  if (p != &val)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  foo ();
+  bar ();
+}
-- 
2.8.0.rc1.12.gfce6d53

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Fix PR c++/70121 (premature folding of const var that was implicitly captured)
  2016-03-10 22:58 [PATCH] Fix PR c++/70121 (premature folding of const var that was implicitly captured) Patrick Palka
@ 2016-03-10 23:06 ` Patrick Palka
  2016-03-18 15:14   ` Patrick Palka
  2016-03-18 15:22 ` Jason Merrill
  1 sibling, 1 reply; 5+ messages in thread
From: Patrick Palka @ 2016-03-10 23:06 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jason Merrill, Patrick Palka

On Thu, Mar 10, 2016 at 5:58 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
> Within a lambda we should implicitly capture an outer const variable
> only if it's odr-used in the body of the lambda.  But we are currently
> making the decision of whether to capture such a variable, or else to
> fold it to a constant, too early -- before we can know whether it's
> being odr-used or not.  So we currently always fold a const variable to
> a constant if possible instead of otherwise capturing it, but of course
> doing this is wrong if e.g. the address of this variable is taken inside
> the lambda's body.
>
> This patch reverses the behavior of process_outer_var_ref, so that we
> always implicitly capture a const variable if it's capturable, instead
> of always trying to first fold it to a constant.  This behavior however
> is wrong too, and introduces a different but perhaps less important
> regression: if we implicitly capture by value a const object that is not
> actually odr-used within the body of the lambda, we may introduce a
> redundant call to its copy/move constructor, see pr70121-2.C.
>
> Ideally we should be capturing a variable only if it's not odr-used

Er, this sentence should read

  Ideally we should be _implicitly_ capturing a variable only if it
_is_ odr-used ...

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Fix PR c++/70121 (premature folding of const var that was implicitly captured)
  2016-03-10 23:06 ` Patrick Palka
@ 2016-03-18 15:14   ` Patrick Palka
  0 siblings, 0 replies; 5+ messages in thread
From: Patrick Palka @ 2016-03-18 15:14 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jason Merrill, Patrick Palka

On Thu, Mar 10, 2016 at 6:06 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
> On Thu, Mar 10, 2016 at 5:58 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
>> Within a lambda we should implicitly capture an outer const variable
>> only if it's odr-used in the body of the lambda.  But we are currently
>> making the decision of whether to capture such a variable, or else to
>> fold it to a constant, too early -- before we can know whether it's
>> being odr-used or not.  So we currently always fold a const variable to
>> a constant if possible instead of otherwise capturing it, but of course
>> doing this is wrong if e.g. the address of this variable is taken inside
>> the lambda's body.
>>
>> This patch reverses the behavior of process_outer_var_ref, so that we
>> always implicitly capture a const variable if it's capturable, instead
>> of always trying to first fold it to a constant.  This behavior however
>> is wrong too, and introduces a different but perhaps less important
>> regression: if we implicitly capture by value a const object that is not
>> actually odr-used within the body of the lambda, we may introduce a
>> redundant call to its copy/move constructor, see pr70121-2.C.
>>
>> Ideally we should be capturing a variable only if it's not odr-used
>
> Er, this sentence should read
>
>   Ideally we should be _implicitly_ capturing a variable only if it
> _is_ odr-used ...

Ping.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Fix PR c++/70121 (premature folding of const var that was implicitly captured)
  2016-03-10 22:58 [PATCH] Fix PR c++/70121 (premature folding of const var that was implicitly captured) Patrick Palka
  2016-03-10 23:06 ` Patrick Palka
@ 2016-03-18 15:22 ` Jason Merrill
  2016-03-18 15:33   ` Patrick Palka
  1 sibling, 1 reply; 5+ messages in thread
From: Jason Merrill @ 2016-03-18 15:22 UTC (permalink / raw)
  To: Patrick Palka, gcc-patches

On 03/10/2016 05:58 PM, Patrick Palka wrote:
> This patch reverses the behavior of process_outer_var_ref, so that we
> always implicitly capture a const variable if it's capturable, instead
> of always trying to first fold it to a constant.  This behavior however
> is wrong too, and introduces a different but perhaps less important
> regression: if we implicitly capture by value a const object that is not
> actually odr-used within the body of the lambda, we may introduce a
> redundant call to its copy/move constructor, see pr70121-2.C.

In general I'm disinclined to trade one bug for another, and I'm 
skeptical that the different regression is less important; I imagine 
that most uses of const variables will be for their constant value 
rather than their address.

Jason

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Fix PR c++/70121 (premature folding of const var that was implicitly captured)
  2016-03-18 15:22 ` Jason Merrill
@ 2016-03-18 15:33   ` Patrick Palka
  0 siblings, 0 replies; 5+ messages in thread
From: Patrick Palka @ 2016-03-18 15:33 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

On Fri, Mar 18, 2016 at 11:14 AM, Jason Merrill <jason@redhat.com> wrote:
> On 03/10/2016 05:58 PM, Patrick Palka wrote:
>>
>> This patch reverses the behavior of process_outer_var_ref, so that we
>> always implicitly capture a const variable if it's capturable, instead
>> of always trying to first fold it to a constant.  This behavior however
>> is wrong too, and introduces a different but perhaps less important
>> regression: if we implicitly capture by value a const object that is not
>> actually odr-used within the body of the lambda, we may introduce a
>> redundant call to its copy/move constructor, see pr70121-2.C.
>
>
> In general I'm disinclined to trade one bug for another, and I'm skeptical
> that the different regression is less important; I imagine that most uses of
> const variables will be for their constant value rather than their address.

Okay, I may try to implement a complete fix for GCC 7 then.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-03-18 15:31 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-10 22:58 [PATCH] Fix PR c++/70121 (premature folding of const var that was implicitly captured) Patrick Palka
2016-03-10 23:06 ` Patrick Palka
2016-03-18 15:14   ` Patrick Palka
2016-03-18 15:22 ` Jason Merrill
2016-03-18 15:33   ` Patrick Palka

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).