public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: unsynthesized defaulted constexpr fn [PR110122]
@ 2023-06-06 18:29 Patrick Palka
  2023-06-07 21:00 ` Jason Merrill
  0 siblings, 1 reply; 4+ messages in thread
From: Patrick Palka @ 2023-06-06 18:29 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason, Patrick Palka

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

-- >8 --

In the second testcase of PR110122, during regeneration of the generic
lambda with V=Bar{}, substitution followed by coerce_template_parms for
A<V>'s template argument naturally yields a copy of V in terms of Bar's
(implicitly) defaulted copy constructor.

This however happens inside a template context so although we introduced
a use of the copy constructor, mark_used didn't actually synthesize it,
which causes subsequent constant evaluation of the template argument to
fail with:

  nontype-class58.C: In instantiation of ‘void f() [with Bar V = Bar{Foo()}]’:
  nontype-class58.C:22:11:   required from here
  nontype-class58.C:18:18: error: ‘constexpr Bar::Bar(const Bar&)’ used before its definition

Conveniently we already make sure to instantiate eligible constexpr
functions before such (manifestly) constant evaluation, as per P0859R0.
So this patch fixes this by making sure to synthesize eligible defaulted
constexpr functions beforehand as well.

	PR c++/110122

gcc/cp/ChangeLog:

	* constexpr.cc (instantiate_cx_fn_r): Also synthesize defaulted
	functions.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/nontype-class58.C: New test.
---
 gcc/cp/constexpr.cc                          |  7 ++++--
 gcc/testsuite/g++.dg/cpp2a/nontype-class58.C | 23 ++++++++++++++++++++
 2 files changed, 28 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class58.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 8f7f0b7d325..a7efebcded1 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8110,11 +8110,14 @@ instantiate_cx_fn_r (tree *tp, int *walk_subtrees, void */*data*/)
       && DECL_DECLARED_CONSTEXPR_P (*tp)
       && !DECL_INITIAL (*tp)
       && !trivial_fn_p (*tp)
-      && DECL_TEMPLOID_INSTANTIATION (*tp)
+      && (DECL_TEMPLOID_INSTANTIATION (*tp) || DECL_DEFAULTED_FN (*tp))
       && !uid_sensitive_constexpr_evaluation_p ())
     {
       ++function_depth;
-      instantiate_decl (*tp, /*defer_ok*/false, /*expl_inst*/false);
+      if (DECL_TEMPLOID_INSTANTIATION (*tp))
+	instantiate_decl (*tp, /*defer_ok*/false, /*expl_inst*/false);
+      else
+	synthesize_method (*tp);
       --function_depth;
     }
   else if (TREE_CODE (*tp) == CALL_EXPR
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
new file mode 100644
index 00000000000..6e40698da2f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
@@ -0,0 +1,23 @@
+// PR c++/110122
+// { dg-do compile { target c++20 } }
+
+struct Foo {
+  Foo() = default;
+  constexpr Foo(const Foo&) { }
+};
+
+struct Bar {
+  Foo _;
+};
+
+template<Bar V>
+struct A { };
+
+template<Bar V>
+void f() {
+  [](auto){ A<V> d; }(0); // { dg-bogus "used before its definition" }
+};
+
+int main() {
+  f<Bar{}>();
+}
-- 
2.41.0.rc1.10.g9e49351c30


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

* Re: [PATCH] c++: unsynthesized defaulted constexpr fn [PR110122]
  2023-06-06 18:29 [PATCH] c++: unsynthesized defaulted constexpr fn [PR110122] Patrick Palka
@ 2023-06-07 21:00 ` Jason Merrill
  2023-06-08 19:54   ` Patrick Palka
  0 siblings, 1 reply; 4+ messages in thread
From: Jason Merrill @ 2023-06-07 21:00 UTC (permalink / raw)
  To: Patrick Palka, gcc-patches

On 6/6/23 14:29, Patrick Palka wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
> -- >8 --
> 
> In the second testcase of PR110122, during regeneration of the generic
> lambda with V=Bar{}, substitution followed by coerce_template_parms for
> A<V>'s template argument naturally yields a copy of V in terms of Bar's
> (implicitly) defaulted copy constructor.
> 
> This however happens inside a template context so although we introduced
> a use of the copy constructor, mark_used didn't actually synthesize it,
> which causes subsequent constant evaluation of the template argument to
> fail with:
> 
>    nontype-class58.C: In instantiation of ‘void f() [with Bar V = Bar{Foo()}]’:
>    nontype-class58.C:22:11:   required from here
>    nontype-class58.C:18:18: error: ‘constexpr Bar::Bar(const Bar&)’ used before its definition
> 
> Conveniently we already make sure to instantiate eligible constexpr
> functions before such (manifestly) constant evaluation, as per P0859R0.
> So this patch fixes this by making sure to synthesize eligible defaulted
> constexpr functions beforehand as well.

We probably also want to do this in cxx_eval_call_expression, under

>   /* We can't defer instantiating the function any longer.  */

Jason


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

* Re: [PATCH] c++: unsynthesized defaulted constexpr fn [PR110122]
  2023-06-07 21:00 ` Jason Merrill
@ 2023-06-08 19:54   ` Patrick Palka
  2023-06-08 23:50     ` Jason Merrill
  0 siblings, 1 reply; 4+ messages in thread
From: Patrick Palka @ 2023-06-08 19:54 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Patrick Palka, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 4565 bytes --]

On Wed, 7 Jun 2023, Jason Merrill wrote:

> On 6/6/23 14:29, Patrick Palka wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> > 
> > -- >8 --
> > 
> > In the second testcase of PR110122, during regeneration of the generic
> > lambda with V=Bar{}, substitution followed by coerce_template_parms for
> > A<V>'s template argument naturally yields a copy of V in terms of Bar's
> > (implicitly) defaulted copy constructor.
> > 
> > This however happens inside a template context so although we introduced
> > a use of the copy constructor, mark_used didn't actually synthesize it,
> > which causes subsequent constant evaluation of the template argument to
> > fail with:
> > 
> >    nontype-class58.C: In instantiation of ‘void f() [with Bar V =
> > Bar{Foo()}]’:
> >    nontype-class58.C:22:11:   required from here
> >    nontype-class58.C:18:18: error: ‘constexpr Bar::Bar(const Bar&)’ used
> > before its definition
> > 
> > Conveniently we already make sure to instantiate eligible constexpr
> > functions before such (manifestly) constant evaluation, as per P0859R0.
> > So this patch fixes this by making sure to synthesize eligible defaulted
> > constexpr functions beforehand as well.
> 
> We probably also want to do this in cxx_eval_call_expression, under

Makes sense, like so?  I'm not sure if it's possible to write a test
for which this code path makes an observable difference, but I verified
the code path is hit a couple of times throughout the testsuite (mainly
from fold_non_dependent_expr called from build_non_dependent_expr).
Bootstrapped and regtested on x86_64-pc-linux-gnu.

-->8 --

	PR c++/110122

gcc/cp/ChangeLog:

	* constexpr.cc (cxx_eval_call_expression): Also synthesize
	eligible defaulted functions.
	(instantiate_cx_fn_r): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/nontype-class58.C: New test.
---
 gcc/cp/constexpr.cc                          | 14 ++++++++----
 gcc/testsuite/g++.dg/cpp2a/nontype-class58.C | 23 ++++++++++++++++++++
 2 files changed, 33 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class58.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 8f7f0b7d325..9122a5efa65 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -2897,7 +2897,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 
   /* We can't defer instantiating the function any longer.  */
   if (!DECL_INITIAL (fun)
-      && DECL_TEMPLOID_INSTANTIATION (fun)
+      && (DECL_TEMPLOID_INSTANTIATION (fun) || DECL_DEFAULTED_FN (fun))
       && !uid_sensitive_constexpr_evaluation_p ())
     {
       location_t save_loc = input_location;
@@ -2905,7 +2905,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
       ++function_depth;
       if (ctx->manifestly_const_eval == mce_true)
 	FNDECL_MANIFESTLY_CONST_EVALUATED (fun) = true;
-      instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false);
+      if (DECL_TEMPLOID_INSTANTIATION (fun))
+	instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false);
+      else
+	synthesize_method (fun);
       --function_depth;
       input_location = save_loc;
     }
@@ -8110,11 +8113,14 @@ instantiate_cx_fn_r (tree *tp, int *walk_subtrees, void */*data*/)
       && DECL_DECLARED_CONSTEXPR_P (*tp)
       && !DECL_INITIAL (*tp)
       && !trivial_fn_p (*tp)
-      && DECL_TEMPLOID_INSTANTIATION (*tp)
+      && (DECL_TEMPLOID_INSTANTIATION (*tp) || DECL_DEFAULTED_FN (*tp))
       && !uid_sensitive_constexpr_evaluation_p ())
     {
       ++function_depth;
-      instantiate_decl (*tp, /*defer_ok*/false, /*expl_inst*/false);
+      if (DECL_TEMPLOID_INSTANTIATION (*tp))
+	instantiate_decl (*tp, /*defer_ok*/false, /*expl_inst*/false);
+      else
+	synthesize_method (*tp);
       --function_depth;
     }
   else if (TREE_CODE (*tp) == CALL_EXPR
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
new file mode 100644
index 00000000000..6e40698da2f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
@@ -0,0 +1,23 @@
+// PR c++/110122
+// { dg-do compile { target c++20 } }
+
+struct Foo {
+  Foo() = default;
+  constexpr Foo(const Foo&) { }
+};
+
+struct Bar {
+  Foo _;
+};
+
+template<Bar V>
+struct A { };
+
+template<Bar V>
+void f() {
+  [](auto){ A<V> d; }(0); // { dg-bogus "used before its definition" }
+};
+
+int main() {
+  f<Bar{}>();
+}
-- 
2.41.0.rc1.10.g9e49351c30


> 
> >   /* We can't defer instantiating the function any longer.  */
> 
> Jason
> 
> 

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

* Re: [PATCH] c++: unsynthesized defaulted constexpr fn [PR110122]
  2023-06-08 19:54   ` Patrick Palka
@ 2023-06-08 23:50     ` Jason Merrill
  0 siblings, 0 replies; 4+ messages in thread
From: Jason Merrill @ 2023-06-08 23:50 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches

On 6/8/23 15:54, Patrick Palka wrote:
> On Wed, 7 Jun 2023, Jason Merrill wrote:
> 
>> On 6/6/23 14:29, Patrick Palka wrote:
>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
>>> trunk?
>>>
>>> -- >8 --
>>>
>>> In the second testcase of PR110122, during regeneration of the generic
>>> lambda with V=Bar{}, substitution followed by coerce_template_parms for
>>> A<V>'s template argument naturally yields a copy of V in terms of Bar's
>>> (implicitly) defaulted copy constructor.
>>>
>>> This however happens inside a template context so although we introduced
>>> a use of the copy constructor, mark_used didn't actually synthesize it,
>>> which causes subsequent constant evaluation of the template argument to
>>> fail with:
>>>
>>>     nontype-class58.C: In instantiation of ‘void f() [with Bar V =
>>> Bar{Foo()}]’:
>>>     nontype-class58.C:22:11:   required from here
>>>     nontype-class58.C:18:18: error: ‘constexpr Bar::Bar(const Bar&)’ used
>>> before its definition
>>>
>>> Conveniently we already make sure to instantiate eligible constexpr
>>> functions before such (manifestly) constant evaluation, as per P0859R0.
>>> So this patch fixes this by making sure to synthesize eligible defaulted
>>> constexpr functions beforehand as well.
>>
>> We probably also want to do this in cxx_eval_call_expression, under
> 
> Makes sense, like so?  I'm not sure if it's possible to write a test
> for which this code path makes an observable difference, but I verified
> the code path is hit a couple of times throughout the testsuite (mainly
> from fold_non_dependent_expr called from build_non_dependent_expr).
> Bootstrapped and regtested on x86_64-pc-linux-gnu.

OK.

> -->8 --
> 
> 	PR c++/110122
> 
> gcc/cp/ChangeLog:
> 
> 	* constexpr.cc (cxx_eval_call_expression): Also synthesize
> 	eligible defaulted functions.
> 	(instantiate_cx_fn_r): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp2a/nontype-class58.C: New test.
> ---
>   gcc/cp/constexpr.cc                          | 14 ++++++++----
>   gcc/testsuite/g++.dg/cpp2a/nontype-class58.C | 23 ++++++++++++++++++++
>   2 files changed, 33 insertions(+), 4 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 8f7f0b7d325..9122a5efa65 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -2897,7 +2897,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
>   
>     /* We can't defer instantiating the function any longer.  */
>     if (!DECL_INITIAL (fun)
> -      && DECL_TEMPLOID_INSTANTIATION (fun)
> +      && (DECL_TEMPLOID_INSTANTIATION (fun) || DECL_DEFAULTED_FN (fun))
>         && !uid_sensitive_constexpr_evaluation_p ())
>       {
>         location_t save_loc = input_location;
> @@ -2905,7 +2905,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
>         ++function_depth;
>         if (ctx->manifestly_const_eval == mce_true)
>   	FNDECL_MANIFESTLY_CONST_EVALUATED (fun) = true;
> -      instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false);
> +      if (DECL_TEMPLOID_INSTANTIATION (fun))
> +	instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false);
> +      else
> +	synthesize_method (fun);
>         --function_depth;
>         input_location = save_loc;
>       }
> @@ -8110,11 +8113,14 @@ instantiate_cx_fn_r (tree *tp, int *walk_subtrees, void */*data*/)
>         && DECL_DECLARED_CONSTEXPR_P (*tp)
>         && !DECL_INITIAL (*tp)
>         && !trivial_fn_p (*tp)
> -      && DECL_TEMPLOID_INSTANTIATION (*tp)
> +      && (DECL_TEMPLOID_INSTANTIATION (*tp) || DECL_DEFAULTED_FN (*tp))
>         && !uid_sensitive_constexpr_evaluation_p ())
>       {
>         ++function_depth;
> -      instantiate_decl (*tp, /*defer_ok*/false, /*expl_inst*/false);
> +      if (DECL_TEMPLOID_INSTANTIATION (*tp))
> +	instantiate_decl (*tp, /*defer_ok*/false, /*expl_inst*/false);
> +      else
> +	synthesize_method (*tp);
>         --function_depth;
>       }
>     else if (TREE_CODE (*tp) == CALL_EXPR
> diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
> new file mode 100644
> index 00000000000..6e40698da2f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class58.C
> @@ -0,0 +1,23 @@
> +// PR c++/110122
> +// { dg-do compile { target c++20 } }
> +
> +struct Foo {
> +  Foo() = default;
> +  constexpr Foo(const Foo&) { }
> +};
> +
> +struct Bar {
> +  Foo _;
> +};
> +
> +template<Bar V>
> +struct A { };
> +
> +template<Bar V>
> +void f() {
> +  [](auto){ A<V> d; }(0); // { dg-bogus "used before its definition" }
> +};
> +
> +int main() {
> +  f<Bar{}>();
> +}


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

end of thread, other threads:[~2023-06-08 23:50 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-06 18:29 [PATCH] c++: unsynthesized defaulted constexpr fn [PR110122] Patrick Palka
2023-06-07 21:00 ` Jason Merrill
2023-06-08 19:54   ` Patrick Palka
2023-06-08 23:50     ` Jason Merrill

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