From: Patrick Palka Date: Mon, 15 Dec 2025 20:03:39 +0000 (-0500) Subject: c++: losslessly encode TYPENAME_TYPE tag X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a7a3d1d64d3b275d03382b84f04a2bbda45c0b7d;p=thirdparty%2Fgcc.git c++: losslessly encode TYPENAME_TYPE tag 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) : Use tag_name. * module.cc (trees_out::type_node) : Use get_typename_tag. * pt.cc (tsubst) : Likewise. Reviewed-by: Jason Merrill --- diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6f244a8bdfd..1f00898cfad 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 74c862ec1c7..30f38f1e099 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -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 @@ -4883,9 +4880,7 @@ struct typename_hasher : ggc_ptr_hash 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) /* 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 diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index ae899ec9f77..4e35a4fcbc2 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -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; diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 7899fac8a2d..b0755e58d4b 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -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; diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index a5d932ac9ea..435be711d98 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -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 "