On 3/3/26 2:49 AM, Jakub Jelinek wrote:
Hi!
The following testcase ICEs, because we try to instantiate the PARM_DECLs
of foo <int> twice, once when parsing ^^foo <int> and remember in a
REFLECT_EXPR a PARM_DECL in there, later on regenerate_decl_from_template
is called and creates new set of PARM_DECLs and changes DECL_ARGUMENTS
(or something later on in that chain) to the new set.
This means when we call parameters_of on ^^foo <int> later on, they won't
compare equal to the earlier acquired ones, and when we do e.g. type_of
or other operation on the old PARM_DECL where it needs to search the
DECL_ARGUMENTS (DECL_CONTEXT (parm_decl)) list, it will ICE because it
won't find it there.
The following patch fixes it similarly to how duplicate_decls deals
with those, by setting OLD_PARM_DECL_P flag on the old PARM_DECLs, so that
before using reflections of those we search DECL_ARGUMENTS and find the
corresponding new PARM_DECL.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
OK.
2026-03-03 Jakub Jelinek <[email protected]>
PR c++/124306
* pt.cc (regenerate_decl_from_template): Mark the old PARM_DECLs
replaced with tsubst_decl result with OLD_PARM_DECL_P flag.
* g++.dg/reflect/parameters_of8.C: New test.
--- gcc/cp/pt.cc.jj 2026-03-02 07:43:12.000000000 +0100
+++ gcc/cp/pt.cc 2026-03-02 11:54:50.959715415 +0100
@@ -28032,9 +28032,18 @@ regenerate_decl_from_template (tree decl
tree *p = &DECL_ARGUMENTS (decl);
for (int skip = num_artificial_parms_for (decl); skip; --skip)
p = &DECL_CHAIN (*p);
+ tree oldarg = *p;
*p = tsubst_decl (pattern_parm, args, tf_error);
for (tree t = *p; t; t = DECL_CHAIN (t))
DECL_CONTEXT (t) = decl;
+ /* Mark the old PARM_DECLs in case std::meta::parameters_of has
+ been called on the old declaration and reflections of those
+ arguments are held across this point and used later.
+ Such PARM_DECLs are no longer present in
+ DECL_ARGUMENTS (DECL_CONTEXT (oldarg)) chain. */
+ if (*p != oldarg)
+ for (tree t = oldarg; t; t = DECL_CHAIN (t))
+ OLD_PARM_DECL_P (t) = 1;
}
if (tree attr = get_fn_contract_specifiers (decl))
--- gcc/testsuite/g++.dg/reflect/parameters_of8.C.jj 2026-03-02
12:08:37.252950114 +0100
+++ gcc/testsuite/g++.dg/reflect/parameters_of8.C 2026-03-02
12:08:05.957471197 +0100
@@ -0,0 +1,19 @@
+// PR c++/124306
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+template <typename T>
+void
+foo (int a)
+{
+ constexpr auto b = parameters_of (^^foo <int>)[0];
+ constexpr auto c = identifier_of (type_of (b)); // { dg-error "uncaught
exception of type 'std::meta::exception'; 'what\\\(\\\)': 'reflection with has_identifier
false'" }
+}
+
+void
+bar (int a)
+{
+ foo <int> (a);
+}
Jakub