https://gcc.gnu.org/g:4a2d9d886ea03ad83e86dfc48df5351c22715722
commit r16-7869-g4a2d9d886ea03ad83e86dfc48df5351c22715722 Author: Jakub Jelinek <[email protected]> Date: Tue Mar 3 15:44:19 2026 +0100 c++: Set OLD_PARM_DECL_P even in regenerate_decl_from_template [PR124306] 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. 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. Diff: --- gcc/cp/pt.cc | 9 +++++++++ gcc/testsuite/g++.dg/reflect/parameters_of8.C | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 1793f58b1ae5..33a9ab3ef6da 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -28043,9 +28043,18 @@ regenerate_decl_from_template (tree decl, tree tmpl, tree args) 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)) diff --git a/gcc/testsuite/g++.dg/reflect/parameters_of8.C b/gcc/testsuite/g++.dg/reflect/parameters_of8.C new file mode 100644 index 000000000000..531033998539 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/parameters_of8.C @@ -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); +}
