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
> 
> 

Reply via email to