c++: Unshare constructors in convert_reflect_constant_arg [PR124792]
Commit Message
Hi!
The following testcase is miscompiled due to incorrect CONSTRUCTOR sharing.
For reflect_constant_array elts which aren't integral we call
convert_reflect_constant_arg (but reflect_constant etc. do the same) and
that eventually indirectly calls get_template_parm_object which creates
the TPO VAR_DECL with DECL_INITIAL. Unfortunately, some CONSTRUCTORs
in that DECL_INITIAL can be shared with whatever we use during constant
expression evaluation later on, so when we evaluate ~vector, we modify
those and with that modify also the CONSTRUCTORs inside of TPO
DECL_INITIAL CONSTRUCTOR.
So we need to unshare it somewhere. One possibility is in
get_template_parm_object but I don't think we have CONSTRUCTOR sharing
issues when building normal templates, so we'd unshare in 99.9% of cases
uselessly, another one is where the patch does it and yet another
one would be in the reflect.cc convert_reflect_constant_arg and
get_template_parm_object callers (but there are several). Furthermore,
I think for the 2 get_template_parm_object callers in reflect.cc we
don't need it, for the eval_reflect_constant_string case the argument
is always a STRING_CST and for eval_reflect_constant_array everything
is already unshared when needed.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2026-04-08 Jakub Jelinek <jakub@redhat.com>
PR c++/124792
* pt.cc (convert_reflect_constant_arg): Call unshare_constructor
on expr.
* g++.dg/reflect/pr124792.C: New test.
Jakub
@@ -33674,7 +33674,7 @@ convert_reflect_constant_arg (tree type,
if (invalid_nontype_parm_type_p (type, tf_none))
return error_mark_node;
- expr = convert_nontype_argument (type, expr, tf_none);
+ expr = convert_nontype_argument (type, unshare_constructor (expr), tf_none);
if (!expr)
return error_mark_node;
return expr;
@@ -0,0 +1,11 @@
+// PR c++/124792
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+struct S { const char *name = nullptr; };
+
+constexpr auto a = std::define_static_array (std::vector { S { std::define_static_string ("foo") } });
+constexpr auto b = std::define_static_array (std::vector { S { std::define_static_string ("foo") },
+ S { std::define_static_string ("bar") } });