[PATCH] c++: abbreviated function template return type rewriting [PR98990]

Patrick Palka ppalka@redhat.com
Thu Feb 25 22:09:11 GMT 2021


On Tue, 9 Feb 2021, Patrick Palka wrote:

> 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 will instead be fixed as part of a broader rework
> of placeholder type constraint checking.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk/10?

Ping.  Note that this patch will cause a merge conflict with the
uncommitted patch at
https://gcc.gnu.org/pipermail/gcc-patches/2021-February/565205.html,
so I plan to address the FIXME below as part of a new version of
that patch.

> 
> 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 the auto.  Use
> 	TEMPLATE_TYPE_LEVEL for brevity.
> 	(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.
> ---
>  gcc/cp/pt.c                             | 39 +++++++++++++------------
>  gcc/cp/type-utils.h                     | 23 +++++++--------
>  gcc/testsuite/g++.dg/concepts/abbrev8.C | 22 ++++++++++++++
>  3 files changed, 53 insertions(+), 31 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/concepts/abbrev8.C
> 
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index c5b0a9292db..46cd322fbf4 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -29601,22 +29601,25 @@ 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);
> +	new_auto = cp_build_qualified_type (new_auto, TYPE_QUALS (auto_node));
> +	return tsubst (type, targs, tf_none, NULL_TREE);
> +      }
>    return type;
>  }
>  
> @@ -29661,10 +29664,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 5551e8f5ef1..138fed6c51e 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..ece9b0e44fd
> --- /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<char>::f('a'));
> -- 
> 2.30.0.452.gfb7fa4a1fd
> 
> 



More information about the Gcc-patches mailing list