[gcc r10-9637] c++: abbreviated function template return type rewriting [PR98990]

Patrick Palka ppalka@gcc.gnu.org
Wed Mar 31 12:33:51 GMT 2021


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

commit r10-9637-gc76d503527394839f9192ee27abbc0626b4e40d8
Author: Patrick Palka <ppalka@redhat.com>
Date:   Thu Feb 25 19:55:43 2021 -0500

    c++: abbreviated function template return type rewriting [PR98990]
    
    When an abbreviated function template has a complex placeholder return
    type such auto& or auto**, the level adjustment performed by
    splice_late_return_type directly replaces the 'auto' inside the original
    return type with the level-adjusted 'auto', but that breaks
    TYPE_CANONICAL caching.  Instead, we should rebuild the entire return
    type using the adjusted 'auto'.
    
    This patch makes this happen by tsubsting the original return type with
    an argument vector that maps the original 'auto' to the adjusted 'auto'.
    In passing, this patch also reverts the misguided changes to
    find_type_usage in r10-6571 that made find_type_usage return a tree*
    instead of a tree so as to discourage this kind of in-place type
    modification.
    
    It occurred to me that the constraint also needs to be rebuilt so that
    it refers to the adjusted 'auto', but this oversight doesn't seem to
    cause any issues at the moment due to how do_auto_deduction "manually"
    substitutes the 'auto' inside the constraint before performing
    satisfaction.  So this'll be fixed later as part of a rework of
    placeholder type constraint checking.
    
    gcc/cp/ChangeLog:
    
            PR c++/98990
            * pt.c (splice_late_return_type): Rebuild the entire return type
            if we have to adjust the level of an auto within.
            (type_uses_auto): Adjust call to find_type_usage.
            * type-utils.h (find_type_usage): Revert r10-6571 change that
            made this function return a pointer to the auto node.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/98990
            * g++.dg/concepts/abbrev8.C: New test.
    
    (cherry picked from commit 6bd409cfc83683a9be5c6b3b8f9a3ec8959f9356)

Diff:
---
 gcc/cp/pt.c                             | 38 ++++++++++++++++-----------------
 gcc/cp/type-utils.h                     | 23 ++++++++++----------
 gcc/testsuite/g++.dg/concepts/abbrev8.C | 22 +++++++++++++++++++
 3 files changed, 52 insertions(+), 31 deletions(-)

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a6ea6737d99..d329c0128ba 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -29322,22 +29322,24 @@ splice_late_return_type (tree type, tree late_return_type)
       return late_return_type;
     }
 
-  if (tree *auto_node = find_type_usage (&type, is_auto))
-    {
-      tree idx = get_template_parm_index (*auto_node);
-      if (TEMPLATE_PARM_LEVEL (idx) <= processing_template_decl)
-	{
-	  /* In an abbreviated function template we didn't know we were dealing
-	     with a function template when we saw the auto return type, so update
-	     it to have the correct level.  */
-	  tree new_auto = make_auto_1 (TYPE_IDENTIFIER (*auto_node), false);
-	  PLACEHOLDER_TYPE_CONSTRAINTS (new_auto)
-	    = PLACEHOLDER_TYPE_CONSTRAINTS (*auto_node);
-	  TYPE_CANONICAL (new_auto) = canonical_type_parameter (new_auto);
-	  new_auto = cp_build_qualified_type (new_auto, TYPE_QUALS (*auto_node));
-	  *auto_node = new_auto;
-	}
-    }
+  if (tree auto_node = find_type_usage (type, is_auto))
+    if (TEMPLATE_TYPE_LEVEL (auto_node) <= processing_template_decl)
+      {
+	/* In an abbreviated function template we didn't know we were dealing
+	   with a function template when we saw the auto return type, so rebuild
+	   the return type using an auto with the correct level.  */
+	tree new_auto = make_auto_1 (TYPE_IDENTIFIER (auto_node), false);
+	tree auto_vec = make_tree_vec (1);
+	TREE_VEC_ELT (auto_vec, 0) = new_auto;
+	tree targs = add_outermost_template_args (current_template_args (),
+						  auto_vec);
+	/* FIXME: We should also rebuild the constraint to refer to the new
+	   auto.  */
+	PLACEHOLDER_TYPE_CONSTRAINTS (new_auto)
+	  = PLACEHOLDER_TYPE_CONSTRAINTS (auto_node);
+	TYPE_CANONICAL (new_auto) = canonical_type_parameter (new_auto);
+	return tsubst (type, targs, tf_none, NULL_TREE);
+      }
   return type;
 }
 
@@ -29382,10 +29384,8 @@ type_uses_auto (tree type)
       else
 	return NULL_TREE;
     }
-  else if (tree *tp = find_type_usage (&type, is_auto))
-    return *tp;
   else
-    return NULL_TREE;
+    return find_type_usage (type, is_auto);
 }
 
 /* Report ill-formed occurrences of auto types in ARGUMENTS.  If
diff --git a/gcc/cp/type-utils.h b/gcc/cp/type-utils.h
index 4ad0d822119..0de0a45876a 100644
--- a/gcc/cp/type-utils.h
+++ b/gcc/cp/type-utils.h
@@ -20,22 +20,21 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_CP_TYPE_UTILS_H
 #define GCC_CP_TYPE_UTILS_H
 
-/* Returns a pointer to the first tree within *TP that is directly matched by
-   PRED.  *TP may be a type or PARM_DECL and is incrementally decomposed toward
-   its type-specifier until a match is found.  NULL is returned if PRED does not
-   match any part of *TP.
+/* Returns the first tree within T that is directly matched by PRED.  T may be a
+   type or PARM_DECL and is incrementally decomposed toward its type-specifier
+   until a match is found.  NULL is returned if PRED does not match any
+   part of T.
 
-   This is primarily intended for detecting whether *TP uses `auto' or a concept
+   This is primarily intended for detecting whether T uses `auto' or a concept
    identifier.  Since either of these can only appear as a type-specifier for
    the declaration in question, only top-level qualifications are traversed;
    find_type_usage does not look through the whole type.  */
 
-inline tree *
-find_type_usage (tree *tp, bool (*pred) (const_tree))
+inline tree
+find_type_usage (tree t, bool (*pred) (const_tree))
 {
-  tree t = *tp;
   if (pred (t))
-    return tp;
+    return t;
 
   enum tree_code code = TREE_CODE (t);
 
@@ -43,13 +42,13 @@ find_type_usage (tree *tp, bool (*pred) (const_tree))
       || code == PARM_DECL || code == OFFSET_TYPE
       || code == FUNCTION_TYPE || code == METHOD_TYPE
       || code == ARRAY_TYPE)
-    return find_type_usage (&TREE_TYPE (t), pred);
+    return find_type_usage (TREE_TYPE (t), pred);
 
   if (TYPE_PTRMEMFUNC_P (t))
     return find_type_usage
-      (&TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (t)), pred);
+      (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (t)), pred);
 
-  return NULL;
+  return NULL_TREE;
 }
 
 #endif // GCC_CP_TYPE_UTILS_H
diff --git a/gcc/testsuite/g++.dg/concepts/abbrev8.C b/gcc/testsuite/g++.dg/concepts/abbrev8.C
new file mode 100644
index 00000000000..51828b66d45
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/abbrev8.C
@@ -0,0 +1,22 @@
+// PR c++/98990
+// { dg-do compile { target concepts } }
+
+int x;
+
+auto& f() { return x; }
+auto& f(auto) { return x; }
+
+using T1 = int&;
+using T1 = decltype(f('a'));
+
+int* y;
+
+template <class>
+struct S
+{
+  static auto** f() { return &y; }
+  static auto** f(auto) { return &y; }
+};
+
+using T2 = int**;
+using T2 = decltype(S<void>::f('a'));


More information about the Gcc-cvs mailing list