[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