]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: losslessly encode TYPENAME_TYPE tag
authorPatrick Palka <ppalka@redhat.com>
Mon, 15 Dec 2025 20:03:39 +0000 (15:03 -0500)
committerPatrick Palka <ppalka@redhat.com>
Mon, 15 Dec 2025 20:03:39 +0000 (15:03 -0500)
We currently have 7 distinct tag_types, but our TYPENAME_TYPE
representation effectively only differentiates between 4 of them at the
expense of struct_type (which gets conflated with class_type),
none_type and scope_type (which get conflated with typename_type).

struct_type / class_type conflation is mostly harmless, but it
probably affects -Wmismatched-tags.  none_type / typename_type too
should be harmless.  But scope_type / typename_type conflation is
problematic because scope_type indicates a type-only lookup unlike
typename_type.

This patch makes our representation of TYPENAME_TYPE encode the numeric
tag type value losslessly using the first three adjacent tree flag bits.
We already use three flag bits for the tag encoding (but inefficiently)
so no additional space is needed.

gcc/cp/ChangeLog:

* cp-tree.h (TYPENAME_TYPE_TAG_BIT_0): New.
(TYPENAME_TYPE_TAG_BIT_1): New.
(TYPENAME_TYPE_TAG_BIT_2): New.
(TYPENAME_IS_ENUM_P): Use get_typename_tag.
(TYPENAME_IS_CLASS_P): Rename to ...
(TYPENAME_IS_CLASS_OR_STRUCT_P): ... this, and use
get_typename_tag.
(TYPENAME_IS_UNION_P): Use get_typename_tag.
(TYPENAME_IS_RESOLVING_P): Use TREE_LANG_FLAG_3
instead of _2.
(get_typename_tag): New.
(set_typename_tag): New.
(tag_name): Declare.
* decl.cc (typename_info): Replace bool fields with a single
tag_types field.
(typename_hasher::equal): Adjust.
(build_typename_type): Adjust.
(tag_name): Handle none_type and scope_type.
* error.cc (dump_type) <case TYPENAME_TYPE>: Use tag_name.
* module.cc (trees_out::type_node) <case TYPENAME_TYPE>: Use
get_typename_tag.
* pt.cc (tsubst) <case TYPENAME_TYPE>: Likewise.

Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/cp-tree.h
gcc/cp/decl.cc
gcc/cp/error.cc
gcc/cp/module.cc
gcc/cp/pt.cc

index 6f244a8bdfd423853e6bf4e15d419bc65c8e96f0..1f00898cfad0a2e48c307acc2baa1f2775bbd090 100644 (file)
@@ -417,7 +417,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       EXPR_STMT_STMT_EXPR_RESULT (in EXPR_STMT)
       STMT_EXPR_NO_SCOPE (in STMT_EXPR)
       BIND_EXPR_TRY_BLOCK (in BIND_EXPR)
-      TYPENAME_IS_ENUM_P (in TYPENAME_TYPE)
+      TYPENAME_TYPE_TAG_BIT_0 (in TYPENAME_TYPE)
       OMP_FOR_GIMPLIFYING_P (in OMP_FOR, OMP_SIMD, OMP_DISTRIBUTE,
                             and OMP_TASKLOOP)
       BASELINK_QUALIFIED_P (in BASELINK)
@@ -460,7 +460,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       DELETE_EXPR_USE_VEC (in DELETE_EXPR).
       ICS_ELLIPSIS_FLAG (in _CONV)
       DECL_INITIALIZED_P (in VAR_DECL)
-      TYPENAME_IS_CLASS_P (in TYPENAME_TYPE)
+      TYPENAME_TYPE_TAG_BIT_1 (in TYPENAME_TYPE)
       STMT_IS_FULL_EXPR_P (in _STMT)
       TARGET_EXPR_LIST_INIT_P (in TARGET_EXPR)
       DECL_FINAL_P (in FUNCTION_DECL)
@@ -480,7 +480,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       ICS_THIS_FLAG (in _CONV)
       DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
       STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST)
-      TYPENAME_IS_RESOLVING_P (in TYPENAME_TYPE)
+      TYPENAME_TYPE_TAG_BIT_2 (in TYPENAME_TYPE)
       TYPE_POLYMORPHIC_P (in RECORD_TYPE and UNION_TYPE)
       TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR)
       FNDECL_USED_AUTO (in FUNCTION_DECL)
@@ -513,7 +513,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       TARGET_EXPR_ELIDING_P (in TARGET_EXPR)
       IF_STMT_VACUOUS_INIT_P (IF_STMT)
       contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
-      TYPENAME_IS_UNION_P (in TYPENAME_TYPE)
+      TYPENAME_IS_RESOLVING_P (in TYPENAME_TYPE)
    4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
       TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
          CALL_EXPR, or FIELD_DECL).
@@ -4551,21 +4551,30 @@ get_vec_init_expr (tree t)
 #define TYPENAME_TYPE_FULLNAME(NODE) \
   (TYPE_VALUES_RAW (TYPENAME_TYPE_CHECK (NODE)))
 
+/* Storage for the tag type of a TYPENAME_TYPE.  */
+#define TYPENAME_TYPE_TAG_BIT_0(NODE) \
+  (TREE_LANG_FLAG_0 (TYPENAME_TYPE_CHECK (NODE)))
+#define TYPENAME_TYPE_TAG_BIT_1(NODE) \
+  (TREE_LANG_FLAG_1 (TYPENAME_TYPE_CHECK (NODE)))
+#define TYPENAME_TYPE_TAG_BIT_2(NODE) \
+  (TREE_LANG_FLAG_2 (TYPENAME_TYPE_CHECK (NODE)))
+
 /* True if a TYPENAME_TYPE was declared as an "enum".  */
 #define TYPENAME_IS_ENUM_P(NODE) \
-  (TREE_LANG_FLAG_0 (TYPENAME_TYPE_CHECK (NODE)))
+  (get_typename_tag (NODE) == enum_type)
 
 /* True if a TYPENAME_TYPE was declared as a "class" or "struct".  */
-#define TYPENAME_IS_CLASS_P(NODE) \
-  (TREE_LANG_FLAG_1 (TYPENAME_TYPE_CHECK (NODE)))
+#define TYPENAME_IS_CLASS_OR_STRUCT_P(NODE) \
+  (get_typename_tag (NODE) == class_type \
+   || get_typename_tag (NODE) == record_type)
 
 /* True if a TYPENAME_TYPE was declared as a "union".  */
 #define TYPENAME_IS_UNION_P(NODE) \
-  (TREE_LANG_FLAG_3 (TYPENAME_TYPE_CHECK (NODE)))
+  (get_typename_tag (NODE) == union_type)
 
 /* True if a TYPENAME_TYPE is in the process of being resolved.  */
 #define TYPENAME_IS_RESOLVING_P(NODE) \
-  (TREE_LANG_FLAG_2 (TYPENAME_TYPE_CHECK (NODE)))
+  (TREE_LANG_FLAG_3 (TYPENAME_TYPE_CHECK (NODE)))
 
 /* [class.virtual]
 
@@ -5791,6 +5800,28 @@ enum tag_types {
   scope_type    /* namespace or tagged type name followed by :: */
 };
 
+/* Return the tag type of the given TYPENAME_TYPE.  */
+
+inline tag_types
+get_typename_tag (tree t)
+{
+  unsigned bit0 = TYPENAME_TYPE_TAG_BIT_0 (t);
+  unsigned bit1 = TYPENAME_TYPE_TAG_BIT_1 (t);
+  unsigned bit2 = TYPENAME_TYPE_TAG_BIT_2 (t);
+  return tag_types ((bit2 << 2) | (bit1 << 1) | bit0);
+}
+
+/* Set the tag type of the given TYPENAME_TYPE.  */
+
+inline void
+set_typename_tag (tree t, tag_types tag)
+{
+  gcc_checking_assert ((tag & 7) == tag);
+  TYPENAME_TYPE_TAG_BIT_0 (t) = (tag >> 0) & 1;
+  TYPENAME_TYPE_TAG_BIT_1 (t) = (tag >> 1) & 1;
+  TYPENAME_TYPE_TAG_BIT_2 (t) = (tag >> 2) & 1;
+}
+
 /* The various kinds of lvalues we distinguish.  */
 enum cp_lvalue_kind_flags {
   clk_none = 0,     /* Things that are not an lvalue.  */
@@ -7364,6 +7395,7 @@ extern bool use_eh_spec_block                     (tree);
 extern void do_push_parm_decls                 (tree, tree, tree *);
 extern tree do_aggregate_paren_init            (tree, tree);
 extern void maybe_mark_function_versioned      (tree);
+extern const char *tag_name                    (enum tag_types);
 
 /* in decl2.cc */
 extern void record_mangling                    (tree, bool);
index 74c862ec1c7d6eab29f1c2f35cc4cae4a518a4a5..30f38f1e099dac96a1899b4bc014456ba663b906 100644 (file)
@@ -85,7 +85,6 @@ static void check_static_variable_definition (tree, tree);
 static void record_unknown_type (tree, const char *);
 static int member_function_or_else (tree, tree, enum overload_flags);
 static tree local_variable_p_walkfn (tree *, int *, void *);
-static const char *tag_name (enum tag_types);
 static tree lookup_and_check_tag (enum tag_types, tree, TAG_how, bool);
 static void maybe_deduce_size_from_array_init (tree, tree);
 static void layout_var_decl (tree);
@@ -4843,9 +4842,7 @@ struct typename_info {
   tree scope;
   tree name;
   tree template_id;
-  bool enum_p;
-  bool class_p;
-  bool union_p;
+  tag_types tag_type;
 };
 
 struct typename_hasher : ggc_ptr_hash<tree_node>
@@ -4883,9 +4880,7 @@ struct typename_hasher : ggc_ptr_hash<tree_node>
     return (TYPE_IDENTIFIER (t1) == t2->name
            && TYPE_CONTEXT (t1) == t2->scope
            && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id
-           && TYPENAME_IS_ENUM_P (t1) == t2->enum_p
-           && TYPENAME_IS_CLASS_P (t1) == t2->class_p
-           && TYPENAME_IS_UNION_P (t1) == t2->union_p);
+           && get_typename_tag (t1) == t2->tag_type);
   }
 };
 
@@ -4908,9 +4903,7 @@ build_typename_type (tree context, tree name, tree fullname,
   ti.scope = FROB_CONTEXT (context);
   ti.name = name;
   ti.template_id = fullname;
-  ti.enum_p = tag_type == enum_type;
-  ti.class_p = (tag_type == class_type || tag_type == record_type);
-  ti.union_p = tag_type == union_type;
+  ti.tag_type = tag_type;
   hashval_t hash = typename_hasher::hash (&ti);
 
   /* See if we already have this type.  */
@@ -4924,9 +4917,7 @@ build_typename_type (tree context, tree name, tree fullname,
       t = cxx_make_type (TYPENAME_TYPE);
       TYPE_CONTEXT (t) = ti.scope;
       TYPENAME_TYPE_FULLNAME (t) = ti.template_id;
-      TYPENAME_IS_ENUM_P (t) = ti.enum_p;
-      TYPENAME_IS_CLASS_P (t) = ti.class_p;
-      TYPENAME_IS_UNION_P (t) = ti.union_p;
+      set_typename_tag (t, ti.tag_type);
 
       /* Build the corresponding TYPE_DECL.  */
       tree d = build_decl (input_location, TYPE_DECL, name, t);
@@ -17941,7 +17932,7 @@ grok_op_properties (tree decl, bool complain)
 \f
 /* Return a string giving the keyword associate with CODE.  */
 
-static const char *
+const char *
 tag_name (enum tag_types code)
 {
   switch (code)
@@ -17956,9 +17947,11 @@ tag_name (enum tag_types code)
       return "enum";
     case typename_type:
       return "typename";
-    default:
-      gcc_unreachable ();
+    case none_type:
+    case scope_type:
+      return nullptr;
     }
+  gcc_unreachable ();
 }
 
 /* Name lookup in an elaborated-type-specifier (after the keyword
index ae899ec9f770bbebe2b3b96441b6508d39ba6d94..4e35a4fcbc2146092e19e59116fced9ae9c6725c 100644 (file)
@@ -822,11 +822,8 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
          break;
        }
       pp_cxx_cv_qualifier_seq (pp, t);
-      pp_cxx_ws_string (pp,
-                        TYPENAME_IS_ENUM_P (t) ? "enum"
-                        : TYPENAME_IS_CLASS_P (t) ? "class"
-                        : TYPENAME_IS_UNION_P (t) ? "union"
-                        : "typename");
+      if (const char *tag = tag_name (get_typename_tag (t)))
+       pp_cxx_ws_string (pp, tag);
       dump_typename (pp, t, flags);
       break;
 
index 7899fac8a2db74b2f285d26a204030d6dbab56c5..b0755e58d4bca327d1a74109f9fab7c119d1d2a4 100644 (file)
@@ -9727,16 +9727,7 @@ trees_out::type_node (tree type)
        tree_node (DECL_NAME (TYPE_NAME (type)));
        tree_node (TYPENAME_TYPE_FULLNAME (type));
        if (streaming_p ())
-         {
-           enum tag_types tag_type = none_type;
-           if (TYPENAME_IS_ENUM_P (type))
-             tag_type = enum_type;
-           else if (TYPENAME_IS_CLASS_P (type))
-             tag_type = class_type;
-           else if (TYPENAME_IS_UNION_P (type))
-             tag_type = union_type;
-           u (int (tag_type));
-         }
+         u (get_typename_tag (type));
        }
       break;
 
index a5d932ac9ea6900a3a10aab6d26e83686a0bc7ce..435be711d98b874f0085bcb67f5a83f4ed5f7302 100644 (file)
@@ -17323,14 +17323,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
              return error_mark_node;
          }
 
-       /* FIXME: TYPENAME_IS_CLASS_P conflates 'class' vs 'struct' tags.
-          TYPENAME_TYPE should probably remember the exact tag that
-          was written for -Wmismatched-tags.  */
-       enum tag_types tag_type
-         = (TYPENAME_IS_CLASS_P (t) ? class_type
-            : TYPENAME_IS_UNION_P (t) ? union_type
-            : TYPENAME_IS_ENUM_P (t) ? enum_type
-            : typename_type);
+       enum tag_types tag_type = get_typename_tag (t);
        tsubst_flags_t tcomplain = complain | tf_keep_type_decl;
        tcomplain |= tst_ok_flag | qualifying_scope_flag;
        f = make_typename_type (ctx, f, tag_type, tcomplain);
@@ -17352,7 +17345,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
                else
                  return error_mark_node;
              }
-           else if (TYPENAME_IS_CLASS_P (t) && !NON_UNION_CLASS_TYPE_P (f))
+           else if (TYPENAME_IS_CLASS_OR_STRUCT_P (t)
+                    && !NON_UNION_CLASS_TYPE_P (f))
              {
                if (complain & tf_error)
                  error ("%qT resolves to %qT, which is not a non-union "