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);
+}

Reply via email to