On 2/27/24 15:48, Patrick Palka wrote:
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk and perhaps 13?
-- >8 --
In r12-6773-g09845ad7569bac we gave CTAD placeholders a level of 0 and
ensured we never replaced them via tsubst. It turns out that autos
representing an explicit cast need the same treatment and for the same
reason: such autos appear in an expression context and so their level
gets easily messed up after partial substitution, leading to premature
replacement via an incidental tsubst instead of via do_auto_deduction.
This patch fixes this by extending the r12-6773 approach to auto(x) and
auto{x}.
PR c++/110025
PR c++/114138
gcc/cp/ChangeLog:
* cp-tree.h (make_cast_auto): Declare.
* parser.cc (cp_parser_functional_cast): Replace a parsed auto
with a level-less one via make_cast_auto.
* pt.cc (find_parameter_packs_r): Don't treat level-less auto
as a type parameter pack.
(tsubst) <case TEMPLATE_TYPE_PARM>: Generalized CTAD placeholder
handling to all level-less autos.
(make_cast_auto): Define.
(do_auto_deduction): Handle deduction of a level-less non-CTAD
auto.
gcc/testsuite/ChangeLog:
* g++.dg/cpp23/auto-fncast16.C: New test.
* g++.dg/cpp23/auto-fncast17.C: New test.
* g++.dg/cpp23/auto-fncast18.C: New test.
---
gcc/cp/cp-tree.h | 1 +
gcc/cp/parser.cc | 11 ++++
gcc/cp/pt.cc | 31 +++++++++-
gcc/testsuite/g++.dg/cpp23/auto-fncast16.C | 12 ++++
gcc/testsuite/g++.dg/cpp23/auto-fncast17.C | 15 +++++
gcc/testsuite/g++.dg/cpp23/auto-fncast18.C | 71 ++++++++++++++++++++++
6 files changed, 138 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast16.C
create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast17.C
create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast18.C
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 04c3aa6cd91..6f1da1c7bad 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7476,6 +7476,7 @@ extern tree make_decltype_auto (void);
extern tree make_constrained_auto (tree, tree);
extern tree make_constrained_decltype_auto (tree, tree);
extern tree make_template_placeholder (tree);
+extern tree make_cast_auto (void);
extern bool template_placeholder_p (tree);
extern bool ctad_template_p (tree);
extern bool unparenthesized_id_or_class_member_access_p (tree);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 3ee9d49fb8e..1e518e6ef51 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -33314,6 +33314,17 @@ cp_parser_functional_cast (cp_parser* parser, tree
type)
if (!type)
type = error_mark_node;
+ if (TREE_CODE (type) == TYPE_DECL
+ && is_auto (TREE_TYPE (type)))
+ type = TREE_TYPE (type);
+
+ if (is_auto (type)
+ && !AUTO_IS_DECLTYPE (type)
+ && !PLACEHOLDER_TYPE_CONSTRAINTS (type)
+ && !CLASS_PLACEHOLDER_TEMPLATE (type))
+ /* auto(x) and auto{x} are represented using a level-less auto. */
+ type = make_cast_auto ();
+
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
cp_lexer_set_source_position (parser->lexer);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2803824d11e..620fe5cdbfa 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3921,7 +3921,8 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees,
void* data)
parameter pack (14.6.3), or the type-specifier-seq of a type-id that
is a pack expansion, the invented template parameter is a template
parameter pack. */
- if (ppd->type_pack_expansion_p && is_auto (t))
+ if (ppd->type_pack_expansion_p && is_auto (t)
+ && TEMPLATE_TYPE_LEVEL (t) != 0)
TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
if (TEMPLATE_TYPE_PARAMETER_PACK (t))
parameter_pack_p = true;
@@ -16297,9 +16298,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain,
tree in_decl)
}
case TEMPLATE_TYPE_PARM:
- if (template_placeholder_p (t))
+ if (TEMPLATE_TYPE_LEVEL (t) == 0)
{
+ /* Level-less auto must be replaced via do_auto_deduction. */
This comment could use clarification about the CTAD case.
+ gcc_checking_assert (is_auto (t));
tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (t);
+ if (!tmpl)
+ return t;
+
tmpl = tsubst_expr (tmpl, args, complain, in_decl);
if (TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)
tmpl = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (tmpl);
@@ -29311,6 +29317,17 @@ template_placeholder_p (tree t)
return is_auto (t) && CLASS_PLACEHOLDER_TEMPLATE (t);
}
+/* Return an auto for an explicit cast, e.g. auto(x) or auto{x}.
+ Like CTAD placeholders, these have level 0 so that they're not
+ accidentally replaced via tsubst, and are always directly resolved
+ via do_auto_deduction. */
+
+tree
+make_cast_auto ()
+{
+ return make_auto_1 (auto_identifier, true, /*level=*/0);
+}
+
/* Make a "constrained auto" type-specifier. This is an auto or
decltype(auto) type with constraints that must be associated after
deduction. The constraint is formed from the given concept CON
@@ -31213,7 +31230,15 @@ do_auto_deduction (tree type, tree init, tree
auto_node,
}
}
- if (TEMPLATE_TYPE_LEVEL (auto_node) == 1)
+ if (TEMPLATE_TYPE_LEVEL (auto_node) == 0)
+ {
+ /* Level-less auto can't be replaced via tsubst, so do it directly. */
I wonder about, rather than returning it directly, setting its level to
1 for the substitution?
Then I wonder if it would be feasible to give all autos level 0 and
adjust it here? That's probably not a stage 4 change, though...
Jason