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