]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: unsynthesized defaulted constexpr fn [PR110122]
authorPatrick Palka <ppalka@redhat.com>
Sun, 11 Jun 2023 15:27:10 +0000 (11:27 -0400)
committerPatrick Palka <ppalka@redhat.com>
Sun, 11 Jun 2023 15:27:10 +0000 (11:27 -0400)
In this other testcase from 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-class59.C: In instantiation of ‘void f() [with Bar V = Bar{Foo()}]’:
  nontype-class59.C:22:11:   required from here
  nontype-class59.C:18:18: error: ‘constexpr Bar::Bar(const Bar&)’ used before its definition

We already make sure to instantiate templated constexpr functions needed
for constant evaluation (as per P0859R0).  So this patch fixes this by
making us synthesize defaulted constexpr functions needed for constant
evaluation as well.

PR c++/110122

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_call_expression): Synthesize defaulted
functions needed for constant evaluation.
(instantiate_cx_fn_r): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/nontype-class59.C: New test.

gcc/cp/constexpr.cc
gcc/testsuite/g++.dg/cpp2a/nontype-class59.C [new file with mode: 0644]

index 8f7f0b7d325e001e9b029bd94b8927924f41d547..9122a5efa6511a5498a69a704357ea797b065f6a 100644 (file)
@@ -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-class59.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class59.C
new file mode 100644 (file)
index 0000000..6e40698
--- /dev/null
@@ -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{}>();
+}