This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH, RFC] Make generic functions work with 'auto' return types (PR64969)


Hello all,

As noted in the bug, and a couple of times on StackOverflow, generic functions and 'auto' return types do not play nice together. This happens because the parser does not expect a level of template parameters to be added to a function after it has already parsed 'auto' in a return type. To make it work requires either patching up existing references to 'auto' after that additional level of template parameters gets added, or change the representation of 'auto' to something that does not depend on the level of template parameters. The latter seemed easiest: a fixed level of 0 (otherwise unused) works well.

The added test used to fail, passes with this patch, and there's no other change in test results (--enable-languages=c,c++).

Does this approach look correct?

Does the patch itself look correct?

Is fixing this appropriate for GCC 5.0? It's not a regression, it fails on 4.9 (the first version that added support for generic functions) too. I'm happy to wait until after 5.0 is released.

Note: I don't have any copyright assignment, and getting that may be troublesome right now. However, a copyright disclaimer for this change should not be a problem. Who should I contact about that?

Cheers,
Harald van Dijk
    gcc/cp/
    
        PR 64969
        * cp-tree.h (tsubst_flags): Add tf_auto.
        * pt.c (make_auto_1): Encode auto with a level of 0.
        (tsubst): Change auto to its proper level. Ignore unless tf_auto.
        (tsubst_pack_expansion): Add sanity check.
        (reduce_template_parm_level): Ignore auto.
        (listify_autos): Pass tf_auto.
        (do_auto_deduction): Likewise.
        (splice_late_return_type): Likewise.
    
    gcc/testsuite/
    
        PR 64969
        * g++.dg/cpp1y/pr64969.C: New test.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 65219f1..575cb4d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4427,6 +4427,7 @@ enum tsubst_flags {
 				    for calls in decltype (5.2.2/11).  */
   tf_partial = 1 << 8,		 /* Doing initial explicit argument
 				    substitution in fn_type_unification.  */
+  tf_auto = 1 << 9,		 /* Substitute auto.  */
   /* Convenient substitution flags combinations.  */
   tf_warning_or_error = tf_warning | tf_error
 };
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9a00d0d..0221d48 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3699,8 +3699,10 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
       DECL_ARTIFICIAL (decl) = 1;
       SET_DECL_TEMPLATE_PARM_P (decl);
 
-      t = build_template_parm_index (TEMPLATE_PARM_IDX (index),
-				     TEMPLATE_PARM_LEVEL (index) - levels,
+      int level = TEMPLATE_PARM_LEVEL (index);
+      if (level)
+	level -= levels;
+      t = build_template_parm_index (TEMPLATE_PARM_IDX (index), level,
 				     TEMPLATE_PARM_ORIG_LEVEL (index),
 				     decl, type);
       TEMPLATE_PARM_DESCENDANTS (index) = t;
@@ -10003,6 +10005,9 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 	  int idx;
           template_parm_level_and_index (parm_pack, &level, &idx);
 
+          /* A pack can never be 'auto'.  */
+          gcc_assert (level);
+
           if (level <= levels)
             arg_pack = TMPL_ARG (args, level, idx);
         }
@@ -11968,8 +11973,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	gcc_assert (TREE_VEC_LENGTH (args) > 0);
 	template_parm_level_and_index (t, &level, &idx); 
 
+	/* A level of zero represents 'auto'.  If complain & tf_auto,
+	   then the template arguments will contain a deduced or
+	   specified type for auto at one level deeper than the current
+	   template parameters.  The value of processing_template_decl
+	   is not meaningful here in other cases.  */
+	if (complain & tf_auto && !level)
+	  level = processing_template_decl + 1;
+
 	levels = TMPL_ARGS_DEPTH (args);
-	if (level <= levels)
+	if (level && level <= levels)
 	  {
 	    arg = TMPL_ARG (args, level, idx);
 
@@ -22095,8 +22108,7 @@ make_args_non_dependent (vec<tree, va_gc> *args)
 }
 
 /* Returns a type which represents 'auto' or 'decltype(auto)'.  We use a
-   TEMPLATE_TYPE_PARM with a level one deeper than the actual template
-   parms.  */
+   TEMPLATE_TYPE_PARM with a level of 0.  */
 
 static tree
 make_auto_1 (tree name)
@@ -22106,8 +22118,7 @@ make_auto_1 (tree name)
 			       TYPE_DECL, name, au);
   TYPE_STUB_DECL (au) = TYPE_NAME (au);
   TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
-    (0, processing_template_decl + 1, processing_template_decl + 1,
-     TYPE_NAME (au), NULL_TREE);
+    (0, 0, 0, TYPE_NAME (au), NULL_TREE);
   TYPE_CANONICAL (au) = canonical_type_parameter (au);
   DECL_ARTIFICIAL (TYPE_NAME (au)) = 1;
   SET_DECL_TEMPLATE_PARM_P (TYPE_NAME (au));
@@ -22157,7 +22168,7 @@ listify_autos (tree type, tree auto_node)
   TREE_VEC_ELT (argvec, 0) = init_auto;
   if (processing_template_decl)
     argvec = add_to_template_args (current_template_args (), argvec);
-  return tsubst (type, argvec, tf_warning_or_error, NULL_TREE);
+  return tsubst (type, argvec, tf_warning_or_error | tf_auto, NULL_TREE);
 }
 
 /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
@@ -22264,7 +22275,7 @@ do_auto_deduction (tree type, tree init, tree auto_node)
 
   if (processing_template_decl)
     targs = add_to_template_args (current_template_args (), targs);
-  return tsubst (type, targs, tf_warning_or_error, NULL_TREE);
+  return tsubst (type, targs, tf_warning_or_error | tf_auto, NULL_TREE);
 }
 
 /* Substitutes LATE_RETURN_TYPE for 'auto' in TYPE and returns the
@@ -22286,7 +22297,7 @@ splice_late_return_type (tree type, tree late_return_type)
       (make_tree_vec (processing_template_parmlist), argvec);
   if (current_template_parms)
     argvec = add_to_template_args (current_template_args (), argvec);
-  return tsubst (type, argvec, tf_warning_or_error, NULL_TREE);
+  return tsubst (type, argvec, tf_warning_or_error | tf_auto, NULL_TREE);
 }
 
 /* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto' or
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr64969.C b/gcc/testsuite/g++.dg/cpp1y/pr64969.C
new file mode 100644
index 0000000..05848b9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr64969.C
@@ -0,0 +1,23 @@
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+int f();
+
+auto t1(auto f)
+{ return f(); }
+
+decltype(auto) t2(auto f)
+{ return f(); }
+
+template <typename T>
+auto t3(auto f)
+{ return f(); }
+
+template <typename T>
+decltype(auto) t4(auto f)
+{ return f(); }
+
+int r1 = t1(f);
+int r2 = t2(f);
+int r3 = t3<void>(f) | t3<void, int()>(f);
+int r4 = t4<void>(f) | t4<void, int()>(f);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]