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

Reply via email to