]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: substituting fn parm redeclared with dep alias tmpl [PR120224]
authorPatrick Palka <ppalka@redhat.com>
Thu, 5 Jun 2025 15:07:25 +0000 (11:07 -0400)
committerPatrick Palka <ppalka@redhat.com>
Thu, 31 Jul 2025 14:17:26 +0000 (10:17 -0400)
Here we declare f twice, the second time around using a dependent
alias template.  Due to alias template transparency these are logically
the same overload.  But now the function type of f (produced from the
first declaration) diverges from the type of its formal parameter
(produced from the subsequent redefinition) in that substituting T=int
succeeds for the function type but not for the formal parameter type.
This eventually causes us to produce an undiagnosed error_mark_node in
the AST of the function call, leading to failure of the sanity check
check added in r14-6343-g0c018a74eb1aff.

Before r14-6343 we would still go on to reject the testcase later at
instantiation time, from regenerate_decl_from_template, making this a
regression.

To fix this, it seems we just need to propagate error_mark_node upon
substitution failure into the type of a PARM_DECL.

PR c++/120224

gcc/cp/ChangeLog:

* pt.cc (tsubst_function_decl): Return error_mark_node if
substituting into the formal parameter list failed.
(tsubst_decl) <case PARM_DECL>: Return error_mark_node
upon TREE_TYPE substitution failure, when in a SFINAE
context.  Return error_mark_node upon DECL_CHAIN substitution
failure.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/alias-decl-80.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
(cherry picked from commit 51e93aadc94940e2da854cf1321a7ab1aebf8d1a)

gcc/cp/pt.cc
gcc/testsuite/g++.dg/cpp0x/alias-decl-80.C [new file with mode: 0644]

index 8b7dc5cb2235ebd6343137c019e67eb0eda58b10..aa19455e3213b9690ccc968efae54efe887b4d80 100644 (file)
@@ -14906,6 +14906,8 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
   if (closure && DECL_IOBJ_MEMBER_FUNCTION_P (t))
     parms = DECL_CHAIN (parms);
   parms = tsubst (parms, args, complain, t);
+  if (parms == error_mark_node)
+    return error_mark_node;
   for (tree parm = parms; parm; parm = DECL_CHAIN (parm))
     DECL_CONTEXT (parm) = r;
   if (closure && DECL_IOBJ_MEMBER_FUNCTION_P (t))
@@ -15478,6 +15480,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
               /* We're dealing with a normal parameter.  */
               type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 
+           if (type == error_mark_node && !(complain & tf_error))
+             RETURN (error_mark_node);
+
             type = type_decays_to (type);
             TREE_TYPE (r) = type;
             cp_apply_type_quals_to_decl (cp_type_quals (type), r);
@@ -15515,8 +15520,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
        /* If cp_unevaluated_operand is set, we're just looking for a
           single dummy parameter, so don't keep going.  */
        if (DECL_CHAIN (t) && !cp_unevaluated_operand)
-         DECL_CHAIN (r) = tsubst (DECL_CHAIN (t), args,
-                                  complain, DECL_CHAIN (t));
+         {
+           tree chain = tsubst (DECL_CHAIN (t), args,
+                                complain, DECL_CHAIN (t));
+           if (chain == error_mark_node)
+             RETURN (error_mark_node);
+           DECL_CHAIN (r) = chain;
+         }
 
         /* FIRST_R contains the start of the chain we've built.  */
         r = first_r;
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-80.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-80.C
new file mode 100644 (file)
index 0000000..9c0eadc
--- /dev/null
@@ -0,0 +1,21 @@
+// PR c++/120224
+// { dg-do compile { target c++11 } }
+
+template<class> using void_t = void;
+
+template<class T>
+void f(void*); // #1
+
+template<class T>
+void f(void_t<typename T::type>*) { } // { dg-error "not a class" } defn of #1
+
+template<class T>
+void g(int, void*); // #2
+
+template<class T>
+void g(int, void_t<typename T::type>*) { } // { dg-error "not a class" } defn of #2
+
+int main() {
+  f<int>(0); // { dg-error "no match" }
+  g<int>(0, 0); // { dg-error "no match" }
+}