On Wed, 21 May 2025, Jason Merrill wrote:

> On 5/20/25 11:28 AM, Patrick Palka wrote:
> > On Mon, 19 May 2025, Patrick Palka wrote:
> > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > > OK for trunk/15/14?
> > 
> > Whoops, CI reports I missed a testsuite adjustment expecting an
> > additional error in other/default13.C, which seems reasonable.  Here's
> > an updated patch.
> 
> OK.

Thanks.  On second thought, the extra expected error in default13.C
seems unnecessary to me.  We can avoid it if we propagate
error_mark_node upon TREE_TYPE substitution failure only when in a
SFINAE context, otherwise we can assume we already issued an error,
and return a PARM_DECL anyway, for sake of error recovery.

Also I noticed that tsubst_tree_list and tsubst_arg_types return
error_mark_node upon TREE_CHAIN substitution failure rather than
returning something with TREE_CHAIN set to error_mark_node, so
I think we should do the same when substituting a chain of
PARM_DECLs for consistency.

So I think I prefer the following version of the patch.  Does it look OK
for trunk/15/14?

-- >8 --

Subject: [PATCH] c++: substituting fn parm redeclared with dep alias tmpl
 [PR120224]

        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 <ja...@redhat.com>
---
 gcc/cp/pt.cc                               | 14 ++++++++++++--
 gcc/testsuite/g++.dg/cpp0x/alias-decl-80.C | 21 +++++++++++++++++++++
 2 files changed, 33 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-80.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index c5a3abe6d8b9..b5c877a385f5 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -14983,6 +14983,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))
@@ -15555,6 +15557,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);
@@ -15592,8 +15597,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
index 000000000000..9c0eadc967c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-80.C
@@ -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" }
+}
-- 
2.50.0.rc1


> 
> > -- >8 --
> > 
> > Here we declare f twice, first ordinarily and then using a dependent
> > alias template.  Due to alias template transparency these logically
> > declare the same overload.  But now the function type of f, which was
> > produced from the first declaration, diverges from the type of its
> > formal parameter, which is 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 function call, leading to
> > a sanity check failure added in r14-6343-g0c018a74eb1aff.
> > 
> > Before r14-6343, we would later reject the testcase albeit from
> > regenerate_decl_from_template when instantiating the definition of f,
> > making this a regression.
> > 
> > To fix this, it seems we just need to check for errors when substituting
> > the type of a PARM_DECL, since that could still fail despite substitution
> > into the function type succeeding.
> > 
> >     PR c++/120224
> > 
> > gcc/cp/ChangeLog:
> > 
> >     * pt.cc (tsubst_function_decl): Return error_mark_node if any
> >     of the substituted function parameters are erroneous.
> >     (tsubst_decl) <case PARM_DECL>: Return error_mark_node if
> >     the substituted function parameter type is erroneous.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     * g++.dg/other/default13.C: Expect additional overload
> >     resolution failure diagnostic.
> >     * g++.dg/cpp0x/alias-decl-80.C: New test.
> > ---
> >   gcc/cp/pt.cc                               |  9 ++++++++-
> >   gcc/testsuite/g++.dg/cpp0x/alias-decl-80.C | 14 ++++++++++++++
> >   gcc/testsuite/g++.dg/other/default13.C     |  2 +-
> >   3 files changed, 23 insertions(+), 2 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-80.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 1973d25b61a0..df6d7bb136ea 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -14903,7 +14903,11 @@ tsubst_function_decl (tree t, tree args,
> > tsubst_flags_t complain,
> >       parms = DECL_CHAIN (parms);
> >     parms = tsubst (parms, args, complain, t);
> >     for (tree parm = parms; parm; parm = DECL_CHAIN (parm))
> > -    DECL_CONTEXT (parm) = r;
> > +    {
> > +      if (parm == error_mark_node)
> > +   return error_mark_node;
> > +      DECL_CONTEXT (parm) = r;
> > +    }
> >     if (closure && DECL_IOBJ_MEMBER_FUNCTION_P (t))
> >       {
> >         tree tparm = build_this_parm (r, closure, type_memfn_quals (type));
> > @@ -15474,6 +15478,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)
> > +         RETURN (error_mark_node);
> > +
> >               type = type_decays_to (type);
> >               TREE_TYPE (r) = type;
> >               cp_apply_type_quals_to_decl (cp_type_quals (type), 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
> > index 000000000000..e2ff663843de
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-80.C
> > @@ -0,0 +1,14 @@
> > +// 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" } #2
> > +
> > +int main() {
> > +  f<int>(0); // { dg-error "no match" }
> > +}
> > diff --git a/gcc/testsuite/g++.dg/other/default13.C
> > b/gcc/testsuite/g++.dg/other/default13.C
> > index eae23ffdf2d1..381aee78ea2c 100644
> > --- a/gcc/testsuite/g++.dg/other/default13.C
> > +++ b/gcc/testsuite/g++.dg/other/default13.C
> > @@ -8,4 +8,4 @@ template < typename > struct B
> >     int f;
> >   };
> >   -B < int > b (0);
> > +B < int > b (0); // { dg-error "no match" }
> 
> 

Reply via email to