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