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

Reply via email to