[gcc r16-7869] c++: Set OLD_PARM_DECL_P even in regenerate_decl_from_template [PR124306]

Jakub Jelinek jakub@gcc.gnu.org
Tue Mar 3 14:45:21 GMT 2026


https://gcc.gnu.org/g:4a2d9d886ea03ad83e86dfc48df5351c22715722

commit r16-7869-g4a2d9d886ea03ad83e86dfc48df5351c22715722
Author: Jakub Jelinek <jakub@redhat.com>
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  <jakub@redhat.com>
    
            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);
+}


More information about the Gcc-cvs mailing list