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