On Wed, Feb 25, 2026 at 08:50:40PM +0100, Jakub Jelinek wrote:
Will change next week.
Here is an updated patch.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2026-03-04 Jakub Jelinek <[email protected]>
PR c++/123810
* cp-tree.h (TYPE_DECL_FOR_LINKAGE_PURPOSES_P): Define.
(TYPE_DECL_WAS_UNNAMED): Likewise.
(TYPE_WAS_UNNAMED): Also check TYPE_DECL_WAS_UNNAMED.
* decl.cc (start_decl): Use TYPE_DECL_FOR_LINKAGE_PURPOSES_P.
(maybe_diagnose_non_c_class_typedef_for_l): If t == type, use
DECL_SOURCE_LOCATION (orig) instead of
DECL_SOURCE_LOCATION (TYPE_NAME (t)).
(name_unnamed_type): Set TYPE_DECL_FOR_LINKAGE_PURPOSES_P
on decl. For -freflection don't change TYPE_NAME from
orig to decl, but instead change DECL_NAME (orig) to
DECL_NAME (decl) and set TYPE_DECL_FOR_LINKAGE_PURPOSES_P on
orig too.
* decl2.cc (grokfield): Use TYPE_DECL_FOR_LINKAGE_PURPOSES_P.
* name-lookup.cc (fields_linear_search): Ignore
TYPE_DECL_WAS_UNNAMED decls.
(count_class_fields): Likewise.
(member_vec_append_class_fields): Likewise.
(pop_local_binding): Likewise.
* reflect.cc (namespace_members_of): For TYPE_DECL with
TYPE_DECL_FOR_LINKAGE_PURPOSES_P set also append
reflection of strip_typedefs (m).
* class.cc (find_flexarrays): Handle TYPE_DECLs with
TYPE_DECL_FOR_LINKAGE_PURPOSES_P like the ones with IDENTIFIER_ANON_P
name.
* g++.dg/reflect/members_of10.C: New test.
* g++.dg/cpp2a/typedef1.C: Expect one message on a different line.
--- gcc/cp/cp-tree.h.jj 2026-03-02 07:43:12.342788130 +0100
+++ gcc/cp/cp-tree.h 2026-03-03 17:22:57.917038151 +0100
@@ -591,6 +591,7 @@ extern GTY(()) tree cp_global_trees[CPTI
7: DECL_THUNK_P (in a member FUNCTION_DECL)
DECL_NORMAL_CAPTURE_P (in FIELD_DECL)
DECL_DECLARED_CONSTINIT_P (in VAR_DECL)
+ TYPE_DECL_FOR_LINKAGE_PURPOSES_P (in TYPE_DECL)
8: DECL_DECLARED_CONSTEXPR_P (in VAR_DECL, FUNCTION_DECL)
Usage of language-independent fields in a language-dependent manner:
@@ -4000,6 +4001,20 @@ struct GTY(()) lang_decl {
&& TREE_CODE (TYPE_NAME (NODE)) == TYPE_DECL \
&& TYPE_DECL_ALIAS_P (TYPE_NAME (NODE)))
+/* Nonzero for typedef name for linkage purposes. For -freflection
+ set also on the originally unnamed TYPE_DECL. */
+#define TYPE_DECL_FOR_LINKAGE_PURPOSES_P(NODE) \
+ DECL_LANG_FLAG_7 (TYPE_DECL_CHECK (NODE))
+
+/* Nonzero for TYPE_DECL originally with IDENTIFIER_ANON_P DECL_NAME
+ later on named by a typedef name for linkage purposes in the
+ -freflection case (otherwise the TYPE_DECL keeps IDENTIFIER_ANON_P
+ DECL_NAME). */
+#define TYPE_DECL_WAS_UNNAMED(NODE) \
+ (TREE_CODE (NODE) == TYPE_DECL \
+ && TYPE_DECL_FOR_LINKAGE_PURPOSES_P (NODE) \
+ && DECL_IMPLICIT_TYPEDEF_P (NODE))
+
/* If non-NULL for a VAR_DECL, FUNCTION_DECL, TYPE_DECL, TEMPLATE_DECL,
or CONCEPT_DECL, the entity is either a template specialization (if
DECL_USE_TEMPLATE is nonzero) or the abstract instance of the
@@ -5372,10 +5387,13 @@ get_vec_init_expr (tree t)
/* True if TYPE is an unnamed structured type with a typedef for
linkage purposes. In that case TYPE_NAME and TYPE_STUB_DECL of the
- MAIN-VARIANT are different. */
+ MAIN-VARIANT are different or TYPE_DECL_WAS_UNNAMED
+ is true for the TYPE_NAME. */
#define TYPE_WAS_UNNAMED(NODE) \
(TYPE_NAME (TYPE_MAIN_VARIANT (NODE)) \
- != TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE)))
+ != TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE)) \
+ || TYPE_DECL_WAS_UNNAMED \
+ (TYPE_NAME (TYPE_MAIN_VARIANT (NODE))))
/* C++: all of these are overloaded! These apply only to TYPE_DECLs. */
--- gcc/cp/decl.cc.jj 2026-02-17 15:56:52.071376438 +0100
+++ gcc/cp/decl.cc 2026-03-03 17:22:57.919239897 +0100
@@ -6618,8 +6618,7 @@ start_decl (const cp_declarator *declara
/* If this is a typedef that names the class for linkage purposes
(7.1.3p8), apply any attributes directly to the type. */
if (TREE_CODE (decl) == TYPE_DECL
- && OVERLOAD_TYPE_P (TREE_TYPE (decl))
- && decl == TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl))))
+ && TYPE_DECL_FOR_LINKAGE_PURPOSES_P (decl))
flags = ATTR_FLAG_TYPE_IN_PLACE;
else
flags = 0;
@@ -13731,7 +13730,8 @@ maybe_diagnose_non_c_class_typedef_for_l
{
auto_diagnostic_group d;
if (diagnose_non_c_class_typedef_for_linkage (type, orig))
- inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)),
+ inform (type == t ? DECL_SOURCE_LOCATION (orig)
+ : DECL_SOURCE_LOCATION (TYPE_NAME (t)),
"type is not C-compatible because it has a base class");
return true;
}
@@ -13797,12 +13797,22 @@ name_unnamed_type (tree type, tree decl)
gcc_assert (TYPE_UNNAMED_P (type)
|| enum_with_enumerator_for_linkage_p (type));
- /* Replace the anonymous decl with the real decl. Be careful not to
- rename other typedefs (such as the self-reference) of type. */
tree orig = TYPE_NAME (type);
- for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
- if (TYPE_NAME (t) == orig)
- TYPE_NAME (t) = decl;
+ if (flag_reflection)
+ {
+ /* For -freflection for typedef struct { ... } S; ^^S needs to be
+ a reflection of a type alias. So, TREE_TYPE (DECL) can't be
+ TYPE. Instead of what we do below, override DECL_NAME (orig). */
+ DECL_NAME (orig) = DECL_NAME (decl);
+ TYPE_DECL_FOR_LINKAGE_PURPOSES_P (orig) = 1;
+ }
+ else
+ /* Replace the anonymous decl with the real decl. Be careful not to
+ rename other typedefs (such as the self-reference) of type. */
+ for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+ if (TYPE_NAME (t) == orig)
+ TYPE_NAME (t) = decl;
+ TYPE_DECL_FOR_LINKAGE_PURPOSES_P (decl) = 1;
/* If this is a typedef within a template class, the nested
type is a (non-primary) template. The name for the
--- gcc/cp/decl2.cc.jj 2026-02-12 17:51:31.805334303 +0100
+++ gcc/cp/decl2.cc 2026-03-03 17:22:57.920518198 +0100
@@ -1303,8 +1303,7 @@ grokfield (const cp_declarator *declarat
/* If this is a typedef that names the class for linkage purposes
(7.1.3p8), apply any attributes directly to the type. */
- if (OVERLOAD_TYPE_P (TREE_TYPE (value))
- && value == TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (value))))
+ if (TYPE_DECL_FOR_LINKAGE_PURPOSES_P (value))
attrflags = ATTR_FLAG_TYPE_IN_PLACE;
cplus_decl_attributes (&value, attrlist, attrflags);
--- gcc/cp/name-lookup.cc.jj 2026-03-02 07:43:12.343788113 +0100
+++ gcc/cp/name-lookup.cc 2026-03-03 17:57:41.387644318 +0100
@@ -1869,6 +1869,11 @@ fields_linear_search (tree klass, tree n
continue;
}
+ if (TYPE_DECL_WAS_UNNAMED (decl))
+ /* Ignore DECL_NAME given to unnamed TYPE_DECLs named for linkage
+ purposes. */
+ continue;
+
if (DECL_DECLARES_FUNCTION_P (decl))
/* Functions are found separately. */
continue;
@@ -2345,7 +2350,13 @@ count_class_fields (tree klass)
&& ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
n_fields += count_class_fields (TREE_TYPE (fields));
else if (DECL_NAME (fields))
- n_fields += 1;
+ {
+ if (TYPE_DECL_WAS_UNNAMED (fields))
+ /* Ignore DECL_NAME given to unnamed TYPE_DECLs named for linkage
+ purposes. */
+ continue;
+ n_fields += 1;
+ }
return n_fields;
}
@@ -2369,6 +2380,10 @@ member_vec_append_class_fields (vec<tree
if (TREE_CODE (field) == USING_DECL
&& IDENTIFIER_CONV_OP_P (DECL_NAME (field)))
field = ovl_make (conv_op_marker, field);
+ else if (TYPE_DECL_WAS_UNNAMED (field))
+ /* Ignore DECL_NAME given to unnamed TYPE_DECLs named for linkage
+ purposes. */
+ continue;
member_vec->quick_push (field);
}
}
@@ -2700,7 +2715,9 @@ pop_local_binding (tree id, tree decl)
binding->value = NULL_TREE;
else if (binding->type == decl)
binding->type = NULL_TREE;
- else
+ /* Ignore DECL_NAME given to unnamed TYPE_DECLs named for linkage
+ purposes. */
+ else if (!TYPE_DECL_WAS_UNNAMED (decl))
{
/* Name-independent variable was found after at least one declaration
with the same name. */
--- gcc/cp/reflect.cc.jj 2026-03-03 16:42:26.904622279 +0100
+++ gcc/cp/reflect.cc 2026-03-03 17:22:57.921903017 +0100
@@ -6545,6 +6545,14 @@ namespace_members_of (location_t loc, tr
so don't bother calling it here. */
CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE,
get_reflection_raw (loc, m));
+ /* For typedef struct { ... } S; include both the S type
+ alias (added above) and dealias of that for the originally
+ unnamed type (added below). */
+ if (TREE_CODE (b) == TYPE_DECL
+ && TYPE_DECL_FOR_LINKAGE_PURPOSES_P (b))