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