c++: Fix return type deduction with an abbreviated function template

This patch fixes two issues with return type deduction in the presence of an
abbreviated function template.

The first issue (PR 69448) is that if a placeholder auto return type contains
any modifiers such as & or *, then the abbreviated function template
compensation in splice_late_return_type does not get performed for the
underlying auto node, leading to incorrect return type deduction.  This happens
because splice_late_return_type does not consider that a placeholder auto return
type might have modifiers.  To fix this it seems we need to look through
modifiers in the return type to obtain the location of the underlying auto node
in order to replace it with the adjusted auto node.  To that end this patch
refactors the utility function find_type_usage to return a pointer to the
matched tree, and uses it to find and replace the underlying auto node.

The second issue (PR 80471) is that the AUTO_IS_DECLTYPE flag is not being
preserved in splice_late_return_type when compensating for an abbreviated
function template, leading to us treating a decltype(auto) return type as if it
was an auto return type.  Fixed by making make_auto_1 set the AUTO_IS_DECLTYPE
flag whenever we're building a decltype(auto) node and adjusting callers
appropriately.  The test for PR 80471 is adjusted to expect the correct
behavior.

gcc/cp/ChangeLog:

	PR c++/69448
	PR c++/80471
	* type-utils.h (find_type_usage): Refactor to take a tree * and to
	return a tree *, and update documentation accordingly.
	* pt.c (make_auto_1): Set AUTO_IS_DECLTYPE when building a
	decltype(auto) node.
	(make_constrained_decltype_auto): No need to explicitly set
	AUTO_IS_DECLTYPE anymore.
	(splice_late_return_type): Use find_type_usage to find and
	replace a possibly nested auto node instead of using is_auto.
	Check test for is_auto into an assert when deciding whether
	to late_return_type.
	(type_uses_auto): Adjust the call to find_type_usage.
	* parser.c (cp_parser_decltype): No need to explicitly set
	AUTO_IS_DECLTYPE anymore.

libcc1/ChangeLog:

	PR c++/69448
	PR c++/80471
	* libcp1plugin.cc (plugin_get_expr_type): No need to explicitly set
	AUTO_IS_DECLTYPE anymore.

gcc/testsuite/ChangeLog:

	PR c++/69448
	PR c++/80471
	* g++.dg/concepts/abbrev3.C: New test.
	* g++.dg/cpp2a/concepts-pr80471.C: Adjust a static_assert to expect the
	correct behavior.
	* g++.dg/cpp0x/auto9.C: Adjust a dg-error directive.
This commit is contained in:
Patrick Palka 2020-02-09 22:23:25 -05:00
parent 91f4fc40bc
commit a6ee556c76
10 changed files with 72 additions and 32 deletions

View File

@ -1,5 +1,21 @@
2020-02-12 Patrick Palka <ppalka@redhat.com>
PR c++/69448
PR c++/80471
* type-utils.h (find_type_usage): Refactor to take a tree * and to
return a tree *, and update documentation accordingly.
* pt.c (make_auto_1): Set AUTO_IS_DECLTYPE when building a
decltype(auto) node.
(make_constrained_decltype_auto): No need to explicitly set
AUTO_IS_DECLTYPE anymore.
(splice_late_return_type): Use find_type_usage to find and
replace a possibly nested auto node instead of using is_auto.
Check test for is_auto into an assert when deciding whether
to late_return_type.
(type_uses_auto): Adjust the call to find_type_usage.
* parser.c (cp_parser_decltype): No need to explicitly set
AUTO_IS_DECLTYPE anymore.
* error.c (dump_decl) [CONCEPT_DECL]: Use dump_simple_decl.
(dump_simple_decl): Handle standard concept definitions as well as
variable concept definitions.

View File

@ -14901,11 +14901,8 @@ cp_parser_decltype (cp_parser *parser)
}
if (!expr)
{
/* Build auto. */
expr = make_decltype_auto ();
AUTO_IS_DECLTYPE (expr) = true;
}
/* Build auto. */
expr = make_decltype_auto ();
else
expr = finish_decltype_type (expr, id_expression_or_member_access_p,
tf_warning_or_error);

View File

@ -27513,6 +27513,8 @@ make_auto_1 (tree name, bool set_canonical)
TYPE_CANONICAL (au) = canonical_type_parameter (au);
DECL_ARTIFICIAL (TYPE_NAME (au)) = 1;
SET_DECL_TEMPLATE_PARM_P (TYPE_NAME (au));
if (name == decltype_auto_identifier)
AUTO_IS_DECLTYPE (au) = true;
return au;
}
@ -27590,8 +27592,6 @@ tree
make_constrained_decltype_auto (tree con, tree args)
{
tree type = make_auto_1 (decltype_auto_identifier, false);
/* FIXME: I don't know why this isn't done in make_auto_1. */
AUTO_IS_DECLTYPE (type) = true;
return make_constrained_placeholder_type (type, con, args);
}
@ -28904,17 +28904,20 @@ do_auto_deduction (tree type, tree init, tree auto_node,
tree
splice_late_return_type (tree type, tree late_return_type)
{
if (is_auto (type))
if (late_return_type)
{
if (late_return_type)
return late_return_type;
gcc_assert (is_auto (type) || seen_error ());
return late_return_type;
}
tree idx = get_template_parm_index (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. */
return make_auto_1 (TYPE_IDENTIFIER (type), true);
*auto_node = make_auto_1 (TYPE_IDENTIFIER (*auto_node), true);
}
return type;
}
@ -28960,8 +28963,10 @@ type_uses_auto (tree type)
else
return NULL_TREE;
}
else if (tree *tp = find_type_usage (&type, is_auto))
return *tp;
else
return find_type_usage (type, is_auto);
return NULL_TREE;
}
/* Report ill-formed occurrences of auto types in ARGUMENTS. If

View File

@ -20,36 +20,36 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_CP_TYPE_UTILS_H
#define GCC_CP_TYPE_UTILS_H
/* 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_TREE is returned if PRED does not match any
part of T.
/* 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.
This is primarily intended for detecting whether T uses `auto' or a concept
This is primarily intended for detecting whether *TP 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 t, bool (*pred) (const_tree))
inline tree *
find_type_usage (tree *tp, bool (*pred) (const_tree))
{
enum tree_code code;
tree t = *tp;
if (pred (t))
return t;
return tp;
code = TREE_CODE (t);
enum tree_code code = TREE_CODE (t);
if (code == POINTER_TYPE || code == REFERENCE_TYPE
|| 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_TREE;
return NULL;
}
#endif // GCC_CP_TYPE_UTILS_H

View File

@ -1,5 +1,12 @@
2020-02-12 Patrick Palka <ppalka@redhat.com>
PR c++/69448
PR c++/80471
* g++.dg/concepts/abbrev3.C: New test.
* g++.dg/cpp2a/concepts-pr80471.C: Adjust a static_assert to expect the
correct behavior.
* g++.dg/cpp0x/auto9.C: Adjust a dg-error directive.
* g++.dg/cpp2a/concepts6.C: New test.
2020-02-10 David Malcolm <dmalcolm@redhat.com>

View File

@ -0,0 +1,11 @@
// PR c++/69448
// { dg-do compile { target c++14 } }
// { dg-additional-options "-fconcepts" }
long x;
auto& f(auto) { return x; }
auto* g(auto) { return &x; }
long& r = f(1);
long* p = g(1);

View File

@ -22,7 +22,7 @@ struct A
struct A2
{
operator auto () -> int; // { dg-error "invalid use of|trailing return type" }
operator auto*() -> int; // { dg-error "invalid use of|trailing return type" }
operator auto*() -> int; // { dg-error "invalid use of|trailing return type|cannot be overloaded" }
};
template <typename> struct B

View File

@ -18,6 +18,6 @@ int main()
{
int i;
static_assert(is_same< decltype(f(i)), int& >, "");
static_assert(is_same< decltype(g(i)), int >, "");
static_assert(is_same< decltype(g(i)), int& >, "");
static_assert(is_same< decltype(z(i)), int& >, "");
}

View File

@ -1,3 +1,10 @@
2020-02-12 Patrick Palka <ppalka@redhat.com>
PR c++/69448
PR c++/80471
* libcp1plugin.cc (plugin_get_expr_type): No need to explicitly set
AUTO_IS_DECLTYPE anymore.
2020-01-07 Paolo Carlini <paolo.carlini@oracle.com>
* libcp1plugin.cc (plugin_build_new_expr): Update build_new call.

View File

@ -3343,10 +3343,7 @@ plugin_get_expr_type (cc1_plugin::connection *self,
if (op0)
type = TREE_TYPE (op0);
else
{
type = make_decltype_auto ();
AUTO_IS_DECLTYPE (type) = true;
}
type = make_decltype_auto ();
return convert_out (ctx->preserve (type));
}