Hi! For C++26 P2786R13 I'm afraid I'll need 4 new flags on class types in struct lang_type (1 bit for trivially_relocatable_if_eligible, 1 for replaceable_if_eligible, 1 for not_trivially_relocatable and 1 for not_replaceable) and there are just 2 bits left.
The following patch is an attempt to save 8 bytes of memory in those structures when not compiling ObjC or ObjC++ (I think those are used fairly rarely and the patch keeps the sizes unmodified for those 2). The old allocations were 32 bytes for C and 120 bytes for C++. The patch moves the objc_info member last in the C++ case (it was already last in the C case), arranges for GC to skip it for C and C++ but walk for ObjC and ObjC++ and allocates or copies over just offsetof bytes instead of sizeof. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2025-06-09 Jakub Jelinek <ja...@redhat.com> gcc/c/ * c-lang.h (union lang_type::maybe_objc_info): New type. (struct lang_type): Use union maybe_objc_info info member instead of tree objc_info. * c-decl.cc (finish_struct): Allocate struct lang_type using ggc_internal_cleared_alloc instead of ggc_cleared_alloc, and use sizeof (struct lang_type) for ObjC and otherwise offsetof (struct lang_type, info) as size. (finish_enum): Likewise. gcc/cp/ * cp-tree.h (union lang_type::maybe_objc_info): New type. (struct lang_type): Use union maybe_objc_info info member instead of tree objc_info. * lex.cc (copy_lang_type): Use sizeof (struct lang_type) just for ObjC++ and otherwise offsetof (struct lang_type, info). (maybe_add_lang_type_raw): Likewise. (cxx_make_type): Formatting fix. gcc/objc/ * objc-act.h (TYPE_OBJC_INFO): Define to info.objc_info instead of objc_info. gcc/objcp/ * objcp-decl.h (TYPE_OBJC_INFO): Define to info.objc_info instead of objc_info. --- gcc/c/c-lang.h.jj 2025-04-08 14:08:48.398321583 +0200 +++ gcc/c/c-lang.h 2025-06-09 12:50:21.631284689 +0200 @@ -35,10 +35,14 @@ struct GTY(()) lang_type { /* In an ENUMERAL_TYPE, the min and max values. */ tree enum_min; tree enum_max; - /* In a RECORD_TYPE, information specific to Objective-C, such - as a list of adopted protocols or a pointer to a corresponding - @interface. See objc/objc-act.h for details. */ - tree objc_info; + union maybe_objc_info { + /* If not c_dialect_objc, this part is not even allocated. */ + char GTY((tag ("0"))) non_objc; + /* In a RECORD_TYPE, information specific to Objective-C, such + as a list of adopted protocols or a pointer to a corresponding + @interface. See objc/objc-act.h for details. */ + tree GTY((tag ("1"))) objc_info; + } GTY ((desc ("c_dialect_objc ()"))) info; }; struct GTY(()) lang_decl { --- gcc/c/c-decl.cc.jj 2025-06-04 17:21:01.111783263 +0200 +++ gcc/c/c-decl.cc 2025-06-09 13:10:56.724561444 +0200 @@ -9790,12 +9790,17 @@ finish_struct (location_t loc, tree t, t len += list_length (x); /* Use the same allocation policy here that make_node uses, to - ensure that this lives as long as the rest of the struct decl. - All decls in an inline function need to be saved. */ + ensure that this lives as long as the rest of the struct decl. + All decls in an inline function need to be saved. */ - space = ggc_cleared_alloc<struct lang_type> (); - space2 = (sorted_fields_type *) ggc_internal_alloc - (sizeof (struct sorted_fields_type) + len * sizeof (tree)); + space = ((struct lang_type *) + ggc_internal_cleared_alloc (c_dialect_objc () + ? sizeof (struct lang_type) + : offsetof (struct lang_type, + info))); + space2 = ((sorted_fields_type *) + ggc_internal_alloc (sizeof (struct sorted_fields_type) + + len * sizeof (tree))); len = 0; space->s = space2; @@ -10269,7 +10274,10 @@ finish_enum (tree enumtype, tree values, /* Record the min/max values so that we can warn about bit-field enumerations that are too small for the values. */ - lt = ggc_cleared_alloc<struct lang_type> (); + lt = ((struct lang_type *) + ggc_internal_cleared_alloc (c_dialect_objc () + ? sizeof (struct lang_type) + : offsetof (struct lang_type, info))); lt->enum_min = minnode; lt->enum_max = maxnode; TYPE_LANG_SPECIFIC (enumtype) = lt; --- gcc/cp/cp-tree.h.jj 2025-06-07 09:46:31.602393864 +0200 +++ gcc/cp/cp-tree.h 2025-06-09 12:51:02.905724560 +0200 @@ -2514,12 +2514,16 @@ struct GTY(()) lang_type { tree key_method; tree decl_list; tree befriending_classes; - /* In a RECORD_TYPE, information specific to Objective-C++, such - as a list of adopted protocols or a pointer to a corresponding - @interface. See objc/objc-act.h for details. */ - tree objc_info; /* FIXME reuse another field? */ tree lambda_expr; + union maybe_objc_info { + /* If not c_dialect_objc, this part is not even allocated. */ + char GTY((tag ("0"))) non_objc; + /* In a RECORD_TYPE, information specific to Objective-C, such + as a list of adopted protocols or a pointer to a corresponding + @interface. See objc/objc-act.h for details. */ + tree GTY((tag ("1"))) objc_info; + } GTY ((desc ("c_dialect_objc ()"))) info; }; /* We used to have a variant type for lang_type. Keep the name of the --- gcc/cp/lex.cc.jj 2025-04-18 11:23:53.809175088 +0200 +++ gcc/cp/lex.cc 2025-06-09 13:05:32.117951517 +0200 @@ -1082,15 +1082,17 @@ copy_lang_type (tree node) if (! TYPE_LANG_SPECIFIC (node)) return; - auto *lt = (struct lang_type *) ggc_internal_alloc (sizeof (struct lang_type)); + size_t sz = (c_dialect_objc () ? sizeof (struct lang_type) + : offsetof (struct lang_type, info)); + auto *lt = (struct lang_type *) ggc_internal_alloc (sz); - memcpy (lt, TYPE_LANG_SPECIFIC (node), (sizeof (struct lang_type))); + memcpy (lt, TYPE_LANG_SPECIFIC (node), sz); TYPE_LANG_SPECIFIC (node) = lt; if (GATHER_STATISTICS) { tree_node_counts[(int)lang_type] += 1; - tree_node_sizes[(int)lang_type] += sizeof (struct lang_type); + tree_node_sizes[(int)lang_type] += sz; } } @@ -1114,14 +1116,15 @@ maybe_add_lang_type_raw (tree t) if (!RECORD_OR_UNION_CODE_P (TREE_CODE (t))) return false; - auto *lt = (struct lang_type *) (ggc_internal_cleared_alloc - (sizeof (struct lang_type))); + size_t sz = (c_dialect_objc () ? sizeof (struct lang_type) + : offsetof (struct lang_type, info)); + auto *lt = (struct lang_type *) (ggc_internal_cleared_alloc (sz)); TYPE_LANG_SPECIFIC (t) = lt; if (GATHER_STATISTICS) { tree_node_counts[(int)lang_type] += 1; - tree_node_sizes[(int)lang_type] += sizeof (struct lang_type); + tree_node_sizes[(int)lang_type] += sz; } return true; @@ -1135,8 +1138,8 @@ cxx_make_type (enum tree_code code MEM_S if (maybe_add_lang_type_raw (t)) { /* Set up some flags that give proper default behavior. */ - struct c_fileinfo *finfo = - get_fileinfo (LOCATION_FILE (input_location)); + struct c_fileinfo *finfo + = get_fileinfo (LOCATION_FILE (input_location)); SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, finfo->interface_unknown); CLASSTYPE_INTERFACE_ONLY (t) = finfo->interface_only; } --- gcc/objc/objc-act.h.jj 2025-04-08 14:08:54.870231485 +0200 +++ gcc/objc/objc-act.h 2025-06-09 12:54:46.780686364 +0200 @@ -228,7 +228,7 @@ enum objc_property_nullability { /* The following three macros must be overridden (in objcp/objcp-decl.h) for Objective-C++. */ -#define TYPE_OBJC_INFO(TYPE) TYPE_LANG_SPECIFIC (TYPE)->objc_info +#define TYPE_OBJC_INFO(TYPE) TYPE_LANG_SPECIFIC (TYPE)->info.objc_info #define SIZEOF_OBJC_TYPE_LANG_SPECIFIC sizeof (struct lang_type) #define ALLOC_OBJC_TYPE_LANG_SPECIFIC(NODE) \ do { \ --- gcc/objcp/objcp-decl.h.jj 2025-04-08 14:08:54.874231429 +0200 +++ gcc/objcp/objcp-decl.h 2025-06-09 12:52:36.351456410 +0200 @@ -60,7 +60,7 @@ extern tree objcp_end_compound_stmt (tre #define OBJC_SET_TYPE_NAME(type, name) (TYPE_IDENTIFIER (type) = (name)) #undef TYPE_OBJC_INFO -#define TYPE_OBJC_INFO(TYPE) LANG_TYPE_CLASS_CHECK (TYPE)->objc_info +#define TYPE_OBJC_INFO(TYPE) LANG_TYPE_CLASS_CHECK (TYPE)->info.objc_info #undef SIZEOF_OBJC_TYPE_LANG_SPECIFIC #define SIZEOF_OBJC_TYPE_LANG_SPECIFIC sizeof (struct lang_type) #undef ALLOC_OBJC_TYPE_LANG_SPECIFIC Jakub