[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.  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);
 
-- 
2.39.1.433.g23c56f7bd5

Reply via email to