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

Reply via email to