aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2023-06-11 11:27:10 -0400
committerPatrick Palka <ppalka@redhat.com>2023-06-11 11:27:10 -0400
commit59946a4c0c97c842ac5a34de5b1aadb73b738809 (patch)
tree675ba6ac0b3e6d7a6a634e3c88a4b22a576d7a21
parent682d401a6ba723b2bf98779d056efc8ff2640178 (diff)
downloadgcc-59946a4c0c97c842ac5a34de5b1aadb73b738809.zip
gcc-59946a4c0c97c842ac5a34de5b1aadb73b738809.tar.gz
gcc-59946a4c0c97c842ac5a34de5b1aadb73b738809.tar.bz2
c++: unsynthesized defaulted constexpr fn [PR110122]
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.
-rw-r--r--gcc/cp/constexpr.cc14
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/nontype-class59.C23
2 files changed, 33 insertions, 4 deletions
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 8f7f0b7..9122a5e 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-class59.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class59.C
new file mode 100644
index 0000000..6e40698
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class59.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{}>();
+}