]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Set OLD_PARM_DECL_P even in regenerate_decl_from_template [PR124306]
authorJakub Jelinek <jakub@redhat.com>
Tue, 3 Mar 2026 14:44:19 +0000 (15:44 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 3 Mar 2026 14:44:19 +0000 (15:44 +0100)
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.

gcc/cp/pt.cc
gcc/testsuite/g++.dg/reflect/parameters_of8.C [new file with mode: 0644]

index 1793f58b1ae5f75531dbc1dd88a7a1755ae59f30..33a9ab3ef6daffa7957f35bd10bece000f8cd7b9 100644 (file)
@@ -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 (file)
index 0000000..5310339
--- /dev/null
@@ -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);
+}