On 2/14/23 14:15, Jason Merrill wrote:
On 2/13/23 09:23, Patrick Palka wrote:
[N.B. this is a corrected version of
https://gcc.gnu.org/pipermail/gcc-patches/2022-November/607443.html ]

This patch factors out the TYPENAME_TYPE case of tsubst into a separate
function tsubst_typename_type.  It also factors out the two tsubst flags
controlling TYPENAME_TYPE substitution, tf_keep_type_decl and tf_tst_ok,
into distinct boolean parameters of this new function (and of
make_typename_type).  Consequently, callers which used to pass tf_tst_ok
to tsubst now instead must directly call tsubst_typename_type when
appropriate.

Hmm, I don't love how that turns 4 lines into 8 more complex lines in each caller.  And the previous approach of saying "a CTAD placeholder is OK" seem like better abstraction than repeating the specific TYPENAME_TYPE handling in each place.

tsubst_maybe_ctad_type?

In a subsequent patch we'll add another flag to
tsubst_typename_type controlling whether we want to ignore non-types
during the qualified lookup.

gcc/cp/ChangeLog:

    * cp-tree.h (enum tsubst_flags): Remove tf_keep_type_decl
    and tf_tst_ok.
    (make_typename_type): Add two trailing boolean parameters
    defaulted to false.
    * decl.cc (make_typename_type): Replace uses of
    tf_keep_type_decl and tf_tst_ok with the corresponding new
    boolean parameters.
    * pt.cc (tsubst_typename_type): New, factored out from tsubst
    and adjusted after removing tf_keep_type_decl and tf_tst_ok.
    (tsubst_decl) <case VAR_DECL>: Conditionally call
    tsubst_typename_type directly instead of using tf_tst_ok.
    (tsubst) <case TYPENAME_TYPE>: Call tsubst_typename_type.
    (tsubst_copy) <case CAST_EXPR>: Conditionally call
    tsubst_typename_type directly instead of using tf_tst_ok.
    (tsubst_copy_and_build) <case CAST_EXPR>: Likewise.
    <case CONSTRUCTOR>: Likewise.
---
  gcc/cp/cp-tree.h |   9 +-
  gcc/cp/decl.cc   |  17 ++--
  gcc/cp/pt.cc     | 223 +++++++++++++++++++++++++----------------------
  3 files changed, 134 insertions(+), 115 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 06bc64a6b8d..a7c5765fc33 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5573,8 +5573,7 @@ enum tsubst_flags {
    tf_error = 1 << 0,         /* give error messages  */
    tf_warning = 1 << 1,          /* give warnings too  */
    tf_ignore_bad_quals = 1 << 2,     /* ignore bad cvr qualifiers */
-  tf_keep_type_decl = 1 << 3,     /* retain typedef type decls
-                    (make_typename_type use) */
+  /* 1 << 3 available */
    tf_ptrmem_ok = 1 << 4,     /* pointers to member ok (internal
                      instantiate_type use) */
    tf_user = 1 << 5,         /* found template must be a user template
@@ -5594,8 +5593,7 @@ enum tsubst_flags {
                  (build_target_expr and friends) */
    tf_norm = 1 << 11,         /* Build diagnostic information during
                      constraint normalization.  */
-  tf_tst_ok = 1 << 12,         /* Allow a typename-specifier to name
-                    a template (C++17 or later).  */
+  /* 1 << 12 available */
    tf_dguide = 1 << 13,        /* Building a deduction guide from a ctor.  */
    /* Convenient substitution flags combinations.  */
    tf_warning_or_error = tf_warning | tf_error
@@ -6846,7 +6844,8 @@ extern tree declare_local_label            (tree);
  extern tree define_label            (location_t, tree);
  extern void check_goto                (tree);
  extern bool check_omp_return            (void);
-extern tree make_typename_type            (tree, tree, enum tag_types, tsubst_flags_t); +extern tree make_typename_type            (tree, tree, enum tag_types, tsubst_flags_t,
+                         bool = false, bool = false);
  extern tree build_typename_type            (tree, tree, tree, tag_types);   extern tree make_unbound_class_template        (tree, tree, tree, tsubst_flags_t);
  extern tree make_unbound_class_template_raw    (tree, tree, tree);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index d606b31d7a7..430533606b0 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -4228,14 +4228,17 @@ build_typename_type (tree context, tree name, tree fullname,
  /* Resolve `typename CONTEXT::NAME'.  TAG_TYPE indicates the tag
     provided to name the type.  Returns an appropriate type, unless an
     error occurs, in which case error_mark_node is returned.  If we
-   locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is set, we
+   locate a non-artificial TYPE_DECL and KEEP_TYPE_DECL is true, we
     return that, rather than the _TYPE it corresponds to, in other
-   cases we look through the type decl.  If TF_ERROR is set, complain
-   about errors, otherwise be quiet.  */
+   cases we look through the type decl.  If TEMPLATE_OK is true and
+   we found a TEMPLATE_DECL then we return a CTAD placeholder for the
+   TEMPLATE_DECL.  If TF_ERROR is set, complain about errors, otherwise
+   be quiet.  */
  tree
  make_typename_type (tree context, tree name, enum tag_types tag_type,
-            tsubst_flags_t complain)
+            tsubst_flags_t complain, bool keep_type_decl /* = false */,
+            bool template_ok /* = false */)
  {
    tree fullname;
    tree t;
@@ -4352,8 +4355,8 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
      }
    if (!want_template && TREE_CODE (t) != TYPE_DECL)
      {
-      if ((complain & tf_tst_ok) && cxx_dialect >= cxx17
-      && DECL_TYPE_TEMPLATE_P (t))
+      if (template_ok && DECL_TYPE_TEMPLATE_P (t)
+      && cxx_dialect >= cxx17)
      /* The caller permits this typename-specifier to name a template
         (because it appears in a CTAD-enabled context).  */;
        else
@@ -4383,7 +4386,7 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
        t = TYPE_NAME (t);
      }
-  if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
+  if (DECL_ARTIFICIAL (t) || !keep_type_decl)
      t = TREE_TYPE (t);
    maybe_record_typedef_use (t);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e89dbf47097..bc47bf15d38 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -13949,6 +13949,94 @@ tsubst_aggr_type_1 (tree t,
      return t;
  }
+/* Substitute ARGS into the TYPENAME_TYPE T.  The flag TEMPLATE_OK
+   is passed to make_typename_type.  */
+
+static tree
+tsubst_typename_type (tree t, tree args, tsubst_flags_t complain, tree in_decl,
+              bool template_ok = false)
+{
+  tree ctx = TYPE_CONTEXT (t);
+  if (TREE_CODE (ctx) == TYPE_PACK_EXPANSION)
+    {
+      ctx = tsubst_pack_expansion (ctx, args, complain, in_decl);
+      if (ctx == error_mark_node
+      || TREE_VEC_LENGTH (ctx) > 1)
+    return error_mark_node;
+      if (TREE_VEC_LENGTH (ctx) == 0)
+    {
+      if (complain & tf_error)
+        error ("%qD is instantiated for an empty pack",
+           TYPENAME_TYPE_FULLNAME (t));
+      return error_mark_node;
+    }
+      ctx = TREE_VEC_ELT (ctx, 0);
+    }
+  else
+    ctx = tsubst_aggr_type (ctx, args, complain, in_decl,
+                /*entering_scope=*/1);
+  if (ctx == error_mark_node)
+    return error_mark_node;
+
+  tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args,
+            complain, in_decl);
+  if (f == error_mark_node)
+    return error_mark_node;
+
+  if (!MAYBE_CLASS_TYPE_P (ctx))
+    {
+      if (complain & tf_error)
+    error ("%qT is not a class, struct, or union type", ctx);
+      return error_mark_node;
+    }
+  else if (!uses_template_parms (ctx) && !TYPE_BEING_DEFINED (ctx))
+    {
+      /* Normally, make_typename_type does not require that the CTX
+     have complete type in order to allow things like:
+
+       template <class T> struct S { typename S<T>::X Y; };
+
+     But, such constructs have already been resolved by this
+     point, so here CTX really should have complete type, unless
+     it's a partial instantiation.  */
+      if (!complete_type_or_maybe_complain (ctx, NULL_TREE, complain))
+    return error_mark_node;
+    }
+
+  f = make_typename_type (ctx, f, typename_type, complain,
+              /*keep_type_decl=*/true, template_ok);
+  if (f == error_mark_node)
+    return f;
+  if (TREE_CODE (f) == TYPE_DECL)
+    {
+      complain |= tf_ignore_bad_quals;
+      f = TREE_TYPE (f);
+    }
+
+  if (TREE_CODE (f) != TYPENAME_TYPE)
+    {
+      if (TYPENAME_IS_ENUM_P (t) && TREE_CODE (f) != ENUMERAL_TYPE)
+    {
+      if (complain & tf_error)
+        error ("%qT resolves to %qT, which is not an enumeration type",
+           t, f);
+      else
+        return error_mark_node;
+    }
+      else if (TYPENAME_IS_CLASS_P (t) && !CLASS_TYPE_P (f))
+    {
+      if (complain & tf_error)
+        error ("%qT resolves to %qT, which is not a class type",
+           t, f);
+      else
+        return error_mark_node;
+    }
+    }
+
+  return cp_build_qualified_type
+    (f, cp_type_quals (f) | cp_type_quals (t), complain);
+}
+
  /* Map from a FUNCTION_DECL to a vec of default argument instantiations,
     indexed in reverse order of the parameters.  */
@@ -15193,10 +15281,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
          && VAR_HAD_UNKNOWN_BOUND (t)
          && type != error_mark_node)
            type = strip_array_domain (type);
-        tsubst_flags_t tcomplain = complain;
-        if (VAR_P (t))
-          tcomplain |= tf_tst_ok;
-        type = tsubst (type, args, tcomplain, in_decl);
+        if (VAR_P (t)
+        && TREE_CODE (type) == TYPENAME_TYPE
+        && !typedef_variant_p (type))
+          type = tsubst_typename_type (type, args, complain, in_decl,
+                       /*template_ok=*/true);
+        else
+          type = tsubst (type, args, complain, in_decl);
          /* Substituting the type might have recursively instantiated this
             same alias (c++/86171).  */
          if (gen_tmpl && DECL_ALIAS_TEMPLATE_P (gen_tmpl)
@@ -15889,9 +15980,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
    bool fndecl_type = (complain & tf_fndecl_type);
    complain &= ~tf_fndecl_type;
-  bool tst_ok = (complain & tf_tst_ok);
-  complain &= ~tf_tst_ok;
-
    if (type
        && code != TYPENAME_TYPE
        && code != TEMPLATE_TYPE_PARM
@@ -16424,89 +16512,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
        }
      case TYPENAME_TYPE:
-      {
-    tree ctx = TYPE_CONTEXT (t);
-    if (TREE_CODE (ctx) == TYPE_PACK_EXPANSION)
-      {
-        ctx = tsubst_pack_expansion (ctx, args, complain, in_decl);
-        if (ctx == error_mark_node
-        || TREE_VEC_LENGTH (ctx) > 1)
-          return error_mark_node;
-        if (TREE_VEC_LENGTH (ctx) == 0)
-          {
-        if (complain & tf_error)
-          error ("%qD is instantiated for an empty pack",
-             TYPENAME_TYPE_FULLNAME (t));
-        return error_mark_node;
-          }
-        ctx = TREE_VEC_ELT (ctx, 0);
-      }
-    else
-      ctx = tsubst_aggr_type (ctx, args, complain, in_decl,
-                  /*entering_scope=*/1);
-    if (ctx == error_mark_node)
-      return error_mark_node;
-
-    tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args,
-                  complain, in_decl);
-    if (f == error_mark_node)
-      return error_mark_node;
-
-    if (!MAYBE_CLASS_TYPE_P (ctx))
-      {
-        if (complain & tf_error)
-          error ("%qT is not a class, struct, or union type", ctx);
-        return error_mark_node;
-      }
-    else if (!uses_template_parms (ctx) && !TYPE_BEING_DEFINED (ctx))
-      {
-        /* Normally, make_typename_type does not require that the CTX
-           have complete type in order to allow things like:
-
-         template <class T> struct S { typename S<T>::X Y; };
-
-           But, such constructs have already been resolved by this
-           point, so here CTX really should have complete type, unless
-           it's a partial instantiation.  */
-        if (!complete_type_or_maybe_complain (ctx, NULL_TREE, complain))
-          return error_mark_node;
-      }
-
-    tsubst_flags_t tcomplain = complain | tf_keep_type_decl;
-    if (tst_ok)
-      tcomplain |= tf_tst_ok;
-    f = make_typename_type (ctx, f, typename_type, tcomplain);
-    if (f == error_mark_node)
-      return f;
-    if (TREE_CODE (f) == TYPE_DECL)
-      {
-        complain |= tf_ignore_bad_quals;
-        f = TREE_TYPE (f);
-      }
-
-    if (TREE_CODE (f) != TYPENAME_TYPE)
-      {
-        if (TYPENAME_IS_ENUM_P (t) && TREE_CODE (f) != ENUMERAL_TYPE)
-          {
-        if (complain & tf_error)
-          error ("%qT resolves to %qT, which is not an enumeration type",
-             t, f);
-        else
-          return error_mark_node;
-          }
-        else if (TYPENAME_IS_CLASS_P (t) && !CLASS_TYPE_P (f))
-          {
-        if (complain & tf_error)
-          error ("%qT resolves to %qT, which is not a class type",
-             t, f);
-        else
-          return error_mark_node;
-          }
-      }
-
-    return cp_build_qualified_type
-      (f, cp_type_quals (f) | cp_type_quals (t), complain);
-      }
+      return tsubst_typename_type (t, args, complain, in_decl);
      case UNBOUND_CLASS_TEMPLATE:
        {
@@ -17391,10 +17397,14 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
      case IMPLICIT_CONV_EXPR:
      CASE_CONVERT:
        {
-    tsubst_flags_t tcomplain = complain;
-    if (code == CAST_EXPR)
-      tcomplain |= tf_tst_ok;
-    tree type = tsubst (TREE_TYPE (t), args, tcomplain, in_decl);
+    tree type = TREE_TYPE (t);
+    if (code == CAST_EXPR
+        && TREE_CODE (type) == TYPENAME_TYPE
+        && !typedef_variant_p (type))
+      type = tsubst_typename_type (type, args, complain, in_decl,
+                       /*template_ok=*/true);
+    else
+      type = tsubst (type, args, complain, in_decl);
      tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
      return build1 (code, type, op0);
        }
@@ -20430,13 +20440,16 @@ tsubst_copy_and_build (tree t,
      case DYNAMIC_CAST_EXPR:
      case STATIC_CAST_EXPR:
        {
-    tree type;
+    tree type = TREE_TYPE (t);
      tree op, r = NULL_TREE;
-    tsubst_flags_t tcomplain = complain;
-    if (TREE_CODE (t) == CAST_EXPR)
-      tcomplain |= tf_tst_ok;
-    type = tsubst (TREE_TYPE (t), args, tcomplain, in_decl);
+    if (TREE_CODE (t) == CAST_EXPR
+        && TREE_CODE (type) == TYPENAME_TYPE
+        && !typedef_variant_p (type))
+      type = tsubst_typename_type (type, args, complain, in_decl,
+                       /*template_ok=*/true);
+    else
+      type = tsubst (type, args, complain, in_decl);
      op = RECUR (TREE_OPERAND (t, 0));
@@ -21421,10 +21434,14 @@ tsubst_copy_and_build (tree t,
          bool need_copy_p = false;
      tree r;
-    tsubst_flags_t tcomplain = complain;
-    if (COMPOUND_LITERAL_P (t))
-      tcomplain |= tf_tst_ok;
-    tree type = tsubst (TREE_TYPE (t), args, tcomplain, in_decl);
+    tree type = TREE_TYPE (t);
+    if (COMPOUND_LITERAL_P (t)
+        && TREE_CODE (type) == TYPENAME_TYPE
+        && !typedef_variant_p (type))
+      type = tsubst_typename_type (type, args, complain, in_decl,
+                       /*template_ok=*/true);
+    else
+      type = tsubst (type, args, complain, in_decl);
      if (type == error_mark_node)
        RETURN (error_mark_node);


Reply via email to