public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-1398] c++: Substitute into function parms in lexical order [PR96560]
@ 2021-06-11 20:09 Patrick Palka
  0 siblings, 0 replies; only message in thread
From: Patrick Palka @ 2021-06-11 20:09 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:b0d73a66ae3962fa83309527d85613d72a6aa43d

commit r12-1398-gb0d73a66ae3962fa83309527d85613d72a6aa43d
Author: Patrick Palka <ppalka@redhat.com>
Date:   Fri Jun 11 16:00:52 2021 -0400

    c++: Substitute into function parms in lexical order [PR96560]
    
    This makes tsubst_arg_types substitute into a function's parameter types
    in left-to-right instead of right-to-left order, in accordance with DR 1227.
    
            DR 1227
            PR c++/96560
    
    gcc/cp/ChangeLog:
    
            * pt.c (tsubst_arg_types): Rearrange so that we substitute into
            TYPE_ARG_TYPES in forward order while short circuiting
            appropriately.  Adjust formatting.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/template/sfinae-dr1227.C: New test.

Diff:
---
 gcc/cp/pt.c                                   | 115 ++++++++++++++------------
 gcc/testsuite/g++.dg/template/sfinae-dr1227.C |  23 ++++++
 2 files changed, 83 insertions(+), 55 deletions(-)

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b53df9e2ad6..141388ad2e5 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14946,20 +14946,13 @@ tsubst_arg_types (tree arg_types,
 		  tsubst_flags_t complain,
 		  tree in_decl)
 {
-  tree remaining_arg_types;
   tree type = NULL_TREE;
-  int i = 1;
+  int len = 1;
   tree expanded_args = NULL_TREE;
-  tree default_arg;
 
   if (!arg_types || arg_types == void_list_node || arg_types == end)
     return arg_types;
 
-  remaining_arg_types = tsubst_arg_types (TREE_CHAIN (arg_types),
-					  args, end, complain, in_decl);
-  if (remaining_arg_types == error_mark_node)
-    return error_mark_node;
-
   if (PACK_EXPANSION_P (TREE_VALUE (arg_types)))
     {
       /* For a pack expansion, perform substitution on the
@@ -14970,7 +14963,7 @@ tsubst_arg_types (tree arg_types,
 
       if (TREE_CODE (expanded_args) == TREE_VEC)
         /* So that we'll spin through the parameters, one by one.  */
-        i = TREE_VEC_LENGTH (expanded_args);
+	len = TREE_VEC_LENGTH (expanded_args);
       else
         {
           /* We only partially substituted into the parameter
@@ -14979,59 +14972,71 @@ tsubst_arg_types (tree arg_types,
           expanded_args = NULL_TREE;
         }
     }
+  else
+    type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl);
 
-  while (i > 0) {
-    --i;
-
-    if (expanded_args)
-      type = TREE_VEC_ELT (expanded_args, i);
-    else if (!type)
-      type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl);
+  /* Check if a substituted type is erroneous before substituting into
+     the rest of the chain.  */
+  for (int i = 0; i < len; i++)
+    {
+      if (expanded_args)
+	type = TREE_VEC_ELT (expanded_args, i);
 
-    if (type == error_mark_node)
-      return error_mark_node;
-    if (VOID_TYPE_P (type))
-      {
-        if (complain & tf_error)
-          {
-            error ("invalid parameter type %qT", type);
-            if (in_decl)
-              error ("in declaration %q+D", in_decl);
-          }
-        return error_mark_node;
+      if (type == error_mark_node)
+	return error_mark_node;
+      if (VOID_TYPE_P (type))
+	{
+	  if (complain & tf_error)
+	    {
+	      error ("invalid parameter type %qT", type);
+	      if (in_decl)
+		error ("in declaration %q+D", in_decl);
+	    }
+	  return error_mark_node;
+	}
     }
 
-    /* Do array-to-pointer, function-to-pointer conversion, and ignore
-       top-level qualifiers as required.  */
-    type = cv_unqualified (type_decays_to (type));
+  /* We do not substitute into default arguments here.  The standard
+     mandates that they be instantiated only when needed, which is
+     done in build_over_call.  */
+  tree default_arg = TREE_PURPOSE (arg_types);
 
-    /* We do not substitute into default arguments here.  The standard
-       mandates that they be instantiated only when needed, which is
-       done in build_over_call.  */
-    default_arg = TREE_PURPOSE (arg_types);
+  /* Except that we do substitute default arguments under tsubst_lambda_expr,
+     since the new op() won't have any associated template arguments for us
+     to refer to later.  */
+  if (lambda_fn_in_template_p (in_decl))
+    default_arg = tsubst_copy_and_build (default_arg, args, complain, in_decl,
+					 false/*fn*/, false/*constexpr*/);
 
-    /* Except that we do substitute default arguments under tsubst_lambda_expr,
-       since the new op() won't have any associated template arguments for us
-       to refer to later.  */
-    if (lambda_fn_in_template_p (in_decl))
-      default_arg = tsubst_copy_and_build (default_arg, args, complain, in_decl,
-					   false/*fn*/, false/*constexpr*/);
+  tree remaining_arg_types = tsubst_arg_types (TREE_CHAIN (arg_types),
+					       args, end, complain, in_decl);
+  if (remaining_arg_types == error_mark_node)
+    return error_mark_node;
 
-    if (default_arg && TREE_CODE (default_arg) == DEFERRED_PARSE)
-      {
-        /* We've instantiated a template before its default arguments
-           have been parsed.  This can happen for a nested template
-           class, and is not an error unless we require the default
-           argument in a call of this function.  */
-        remaining_arg_types = 
-          tree_cons (default_arg, type, remaining_arg_types);
-	vec_safe_push (DEFPARSE_INSTANTIATIONS (default_arg),
-		       remaining_arg_types);
-      }
-    else
-      remaining_arg_types =
-        hash_tree_cons (default_arg, type, remaining_arg_types);
-  }
+  for (int i = len-1; i >= 0; i--)
+    {
+      if (expanded_args)
+	type = TREE_VEC_ELT (expanded_args, i);
+
+      /* Do array-to-pointer, function-to-pointer conversion, and ignore
+	 top-level qualifiers as required.  */
+      type = cv_unqualified (type_decays_to (type));
+
+      if (default_arg && TREE_CODE (default_arg) == DEFERRED_PARSE)
+	{
+	  /* We've instantiated a template before its default arguments
+	     have been parsed.  This can happen for a nested template
+	     class, and is not an error unless we require the default
+	     argument in a call of this function.  */
+	  remaining_arg_types
+	    = tree_cons (default_arg, type, remaining_arg_types);
+	  vec_safe_push (DEFPARSE_INSTANTIATIONS (default_arg),
+			 remaining_arg_types);
+	}
+      else
+	remaining_arg_types
+	  = hash_tree_cons (default_arg, type, remaining_arg_types);
+    }
 
   return remaining_arg_types;
 }
diff --git a/gcc/testsuite/g++.dg/template/sfinae-dr1227.C b/gcc/testsuite/g++.dg/template/sfinae-dr1227.C
new file mode 100644
index 00000000000..821ff0313b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/sfinae-dr1227.C
@@ -0,0 +1,23 @@
+// PR c++/96560
+// DR 1227
+// Test that we substitute function parameter types in lexical order.
+
+template <class T>
+struct A { typedef typename T::type type; }; // { dg-error "void" }
+
+template <class T> void f(typename T::type, typename A<T>::type);
+template <class T> long f(...);
+
+long x = f<int>(0, 0); // { dg-bogus "" } OK
+
+
+template <class T> void g(T, typename A<T>::type);
+template <class T> long g(...);
+
+long y = g<void>(0, 0); // { dg-bogus "" } OK
+
+
+template <class T> void h(typename A<T>::type, T);
+template <class T> long h(...);
+
+long z = h<void>(0, 0); // { dg-message "required from here" } hard error


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-06-11 20:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-11 20:09 [gcc r12-1398] c++: Substitute into function parms in lexical order [PR96560] Patrick Palka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).