Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? Alternatively, if preferred I also experimented with a patch that cached the property as a TYPE_LANG_FLAG for ENUMERAL_TYPEs, which was possibly slightly neater at the cost of using up a flag bit. I've attached this alternative patch as well.
Let me know if you have any suggestions on the ABI front as well; I wasn't able to find any open issue for this on the github, but I'm happy to make an issue if you like. -- >8 -- We currently list P2115R0 as implemented, but only the modules changes had been done. This patch implements the linkage changes so that unnamed unscoped enums will use the name of the first enumerator for linkage purposes. This is (strictly speaking) a breaking change, as code that previously relied on unnamed enumerations being internal linkage may have overloads using those types become exposed and clash with other functions in a different TU that have been similarly exposed. As such this feature is only implemented for C++20. No ABI flag warning is provided, partly because C++20 is still an experimental standard, but also because any affected functions could not have been part of an ABI until this change anyway. A number of testcases that are testing for behaviour of no-linkage types are adjusted to use an enumeration with no values, so that the pre-C++20 and post-C++20 behaviour is equivalently tested. In terms of implementation, I had originally considered adjusting the DECL_NAME of the enum, as with 'name_unnamed_type', but this ended up being more complicated as it had unwanted interactions with the existing modules streaming and with name lookup and diagnostic messages. This patch instead uses a new function to derive this case. The standard says that ([dcl.enum] p11) such an enum "...is denoted, for linkage purposes, by its underlying type and its first enumerator"; for simplicity this patch currently just mangles using the first enumerator, but we'll probably need to provide a new ABI production to include the type as well properly. PR c++/120503 PR c++/120824 gcc/cp/ChangeLog: * cp-tree.h (TYPE_UNNAMED_P): Adjust for enums with enumerators for linkage purposes. (enum_with_enumerator_for_linkage_p): Declare. * decl.cc (name_unnamed_type): Adjust assertions to handle enums with enumerators for linkage purposes. (grokdeclarator): Use a typedef name for enums with enumerators for linkage purposes. (enum_with_enumerator_for_linkage_p): New function. (finish_enum_value_list): Reset type linkage for enums with enumerators for linkage purposes. * mangle.cc (write_unqualified_name): Handle enums with enumerators for linkage purposes. * tree.cc (decl_linkage): Fixup unnamed enums. gcc/testsuite/ChangeLog: * g++.dg/abi/mangle32.C: Remove enumerator list. * g++.dg/cpp0x/linkage2.C: Likewise. * g++.dg/ext/vector26.C: Likewise. * g++.dg/other/anon3.C: Likewise. * g++.dg/abi/mangle82.C: New test. * g++.dg/modules/enum-15_a.C: New test. * g++.dg/modules/enum-15_b.C: New test. Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com> --- gcc/cp/cp-tree.h | 4 +++- gcc/cp/decl.cc | 28 +++++++++++++++++++++--- gcc/cp/mangle.cc | 8 ++++++- gcc/cp/tree.cc | 4 ++-- gcc/testsuite/g++.dg/abi/mangle32.C | 4 ++-- gcc/testsuite/g++.dg/abi/mangle82.C | 24 ++++++++++++++++++++ gcc/testsuite/g++.dg/cpp0x/linkage2.C | 6 ++--- gcc/testsuite/g++.dg/ext/vector26.C | 2 +- gcc/testsuite/g++.dg/modules/enum-15_a.C | 10 +++++++++ gcc/testsuite/g++.dg/modules/enum-15_b.C | 18 +++++++++++++++ gcc/testsuite/g++.dg/other/anon3.C | 2 +- 11 files changed, 96 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/g++.dg/abi/mangle82.C create mode 100644 gcc/testsuite/g++.dg/modules/enum-15_a.C create mode 100644 gcc/testsuite/g++.dg/modules/enum-15_b.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fb8e0d8d98e..090f08a78fc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2330,7 +2330,8 @@ enum languages { lang_c, lang_cplusplus }; /* Nonzero if NODE, a TYPE, has no name for linkage purposes. */ #define TYPE_UNNAMED_P(NODE) \ (TYPE_ANON_P (NODE) \ - && !IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE))) + && !IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE)) \ + && !enum_with_enumerator_for_linkage_p (NODE)) /* The _DECL for this _TYPE. */ #define TYPE_MAIN_DECL(NODE) (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE))) @@ -7298,6 +7299,7 @@ extern tree xref_tag (tag_types, tree, bool tpl_header_p = false); extern void xref_basetypes (tree, tree); extern tree start_enum (tree, tree, tree, tree, bool, bool *); +extern bool enum_with_enumerator_for_linkage_p (tree); extern void finish_enum_value_list (tree); extern void finish_enum (tree); extern tree build_enumerator (tree, tree, tree, tree, location_t); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index cb3ebfff429..90f736f9b6c 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -12677,7 +12677,8 @@ mark_inline_variable (tree decl, location_t loc) void name_unnamed_type (tree type, tree decl) { - gcc_assert (TYPE_UNNAMED_P (type)); + 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. */ @@ -12700,7 +12701,8 @@ name_unnamed_type (tree type, tree decl) /* Check that our job is done, and that it would fail if we attempted to do it again. */ - gcc_assert (!TYPE_UNNAMED_P (type)); + gcc_assert (!TYPE_UNNAMED_P (type) + && !enum_with_enumerator_for_linkage_p (type)); } /* Check that decltype(auto) was well-formed: only plain decltype(auto) @@ -14950,7 +14952,10 @@ grokdeclarator (const cp_declarator *declarator, && unqualified_id && TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && TYPE_UNNAMED_P (type) + && (TYPE_UNNAMED_P (type) + /* An enum may have previously used an enumerator for linkage + purposes, but we want the typedef name to take priority. */ + || enum_with_enumerator_for_linkage_p (type)) && declspecs->type_definition_p && attributes_naming_typedef_ok (*attrlist) && cp_type_quals (type) == TYPE_UNQUALIFIED) @@ -17793,6 +17798,18 @@ start_enum (tree name, tree enumtype, tree underlying_type, return enumtype; } +/* Returns true if TYPE is an enum that uses an enumerator name for + linkage purposes. */ + +bool +enum_with_enumerator_for_linkage_p (tree type) +{ + return (cxx_dialect >= cxx20 + && UNSCOPED_ENUM_P (type) + && TYPE_ANON_P (type) + && TYPE_VALUES (type)); +} + /* After processing and defining all the values of an enumeration type, install their decls in the enumeration type. ENUMTYPE is the type object. */ @@ -18023,6 +18040,11 @@ finish_enum_value_list (tree enumtype) fixup_type_variants (current_class_type); } + /* P2115: An unnamed enum uses the name of its first enumerator for + linkage purposes; reset the type linkage if that is the case. */ + if (enum_with_enumerator_for_linkage_p (enumtype)) + reset_type_linkage (enumtype); + /* Finish debugging output for this type. */ rest_of_type_compilation (enumtype, namespace_bindings_p ()); diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 13d5dedebd2..59636e87f6e 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -1591,7 +1591,13 @@ write_unqualified_name (tree decl) tree type = TREE_TYPE (decl); if (TREE_CODE (decl) == TYPE_DECL - && TYPE_UNNAMED_P (type)) + && enum_with_enumerator_for_linkage_p (type)) + { + /* FIXME mangle the type as well? */ + tree enumerator = TREE_VALUE (TYPE_VALUES (type)); + write_source_name (DECL_NAME (enumerator)); + } + else if (TREE_CODE (decl) == TYPE_DECL && TYPE_UNNAMED_P (type)) write_unnamed_type_name (type); else if (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (type)) write_closure_type_name (type); diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index d56d73fe217..59d626c86d5 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -6394,8 +6394,8 @@ decl_linkage (tree decl) if (NAMESPACE_SCOPE_P (decl) && (!DECL_NAME (decl) || IDENTIFIER_ANON_P (DECL_NAME (decl)))) { - if (TREE_CODE (decl) == TYPE_DECL && !TYPE_ANON_P (TREE_TYPE (decl))) - /* This entity has a typedef name for linkage purposes. */; + if (TREE_CODE (decl) == TYPE_DECL && !TYPE_UNNAMED_P (TREE_TYPE (decl))) + /* This entity has a name for linkage purposes. */; else if (DECL_DECOMPOSITION_P (decl) && DECL_DECOMP_IS_BASE (decl)) /* Namespace-scope structured bindings can have linkage. */; else if (TREE_CODE (decl) == NAMESPACE_DECL && cxx_dialect >= cxx11) diff --git a/gcc/testsuite/g++.dg/abi/mangle32.C b/gcc/testsuite/g++.dg/abi/mangle32.C index 4c5b33b8b4d..edb542e28c1 100644 --- a/gcc/testsuite/g++.dg/abi/mangle32.C +++ b/gcc/testsuite/g++.dg/abi/mangle32.C @@ -15,7 +15,7 @@ void f(B) { } struct C { typedef struct { }* D; - typedef enum { e }* E; + typedef enum { }* E; }; // { dg-final { scan-assembler "_Z2g1PN1CUt_E" } } @@ -31,7 +31,7 @@ void h2(T t) { } inline void j() { - typedef enum { f }* F; + typedef enum { }* F; // { dg-final { scan-assembler "_Z2h1IPZ1jvEUt_EvT_" } } h1(F()); typedef struct { }* G; diff --git a/gcc/testsuite/g++.dg/abi/mangle82.C b/gcc/testsuite/g++.dg/abi/mangle82.C new file mode 100644 index 00000000000..eed01b9e8e3 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle82.C @@ -0,0 +1,24 @@ +// PR c++/120503 +// Implement P2115r0 "merging definitions of unnamed unscoped enums" +// { dg-do compile { target c++14 } } + +template<auto V> int Frob () { return int (V); } + +enum { A = 195'936'478, B = 0 }; +template int Frob<A> (); +template int Frob<B> (); +// { dg-final { scan-assembler {_Z4FrobITnDaL1A195936478EEiv:} { target c++20 } } } +// { dg-final { scan-assembler {_Z4FrobITnDaL8._anon_0195936478EEiv:} { target c++17_down } } } +// { dg-final { scan-assembler {_Z4FrobITnDaL1A0EEiv:} { target c++20 } } } +// { dg-final { scan-assembler {_Z4FrobITnDaL8._anon_00EEiv:} { target c++17_down } } } + +enum { C = 5 } typedef X; +template int Frob<C> (); +// typedef name 'X' should take precedence +// { dg-final { scan-assembler {_Z4FrobITnDaL1X5EEiv:} } } + +typedef enum { D = 8 }* Y; +template int Frob<D> (); +// but 'Y' is not a typedef name here +// { dg-final { scan-assembler {_Z4FrobITnDaL1D8EEiv:} { target c++20 } } } +// { dg-final { scan-assembler {_Z4FrobITnDaL8._anon_28EEiv:} { target c++17_down } } } diff --git a/gcc/testsuite/g++.dg/cpp0x/linkage2.C b/gcc/testsuite/g++.dg/cpp0x/linkage2.C index 34a36c45a58..0ec2cec8a99 100644 --- a/gcc/testsuite/g++.dg/cpp0x/linkage2.C +++ b/gcc/testsuite/g++.dg/cpp0x/linkage2.C @@ -16,9 +16,9 @@ template <typename T> struct B { template <typename T> T B<T>::t2 = { }; -enum { E1 } e1; // OK, defined -extern enum { E2 } e2; // { dg-error "never defined" } -extern "C" enum { E3 } e3; // OK, extern "C" +enum { } e1; // OK, defined +extern enum { } e2; // { dg-error "never defined" } +extern "C" enum { } e3; // OK, extern "C" void f() { struct A { int x; }; // no linkage diff --git a/gcc/testsuite/g++.dg/ext/vector26.C b/gcc/testsuite/g++.dg/ext/vector26.C index 1d7a1e47160..95cae393fb5 100644 --- a/gcc/testsuite/g++.dg/ext/vector26.C +++ b/gcc/testsuite/g++.dg/ext/vector26.C @@ -3,7 +3,7 @@ // gets internal linkage. // { dg-options "-mmmx" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */ -typedef enum { e } T __attribute__((vector_size(8))); +typedef enum { } T __attribute__((vector_size(8))); static void foo(T t) {} void bar (T t) {} // { dg-error "no linkage" "" { target { ! c++11 } } } // { dg-final { scan-assembler-not "globl\[ \t]*_Z3bar" { target c++11 } } } diff --git a/gcc/testsuite/g++.dg/modules/enum-15_a.C b/gcc/testsuite/g++.dg/modules/enum-15_a.C new file mode 100644 index 00000000000..e59a73a09e9 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/enum-15_a.C @@ -0,0 +1,10 @@ +// PR c++/120824 +// { dg-additional-options "-fmodules -Wno-global-module -std=c++20" } +// { dg-module-cmi M } + +module; +enum { E }; +enum { F }; +export module M; +export using ::E; +export using ::F; diff --git a/gcc/testsuite/g++.dg/modules/enum-15_b.C b/gcc/testsuite/g++.dg/modules/enum-15_b.C new file mode 100644 index 00000000000..43d7865e749 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/enum-15_b.C @@ -0,0 +1,18 @@ +// PR c++/120824 +// { dg-additional-options "-fmodules -Wno-global-module -std=c++20" } +// { dg-module-cmi !bad } + +module; +enum { E }; +namespace { + enum { G }; // { dg-message "internal" } +} +export module bad; +import M; +inline void ok() { + auto a = E; + auto b = F; +} +inline void err() { // { dg-error "TU-local" } + auto c = G; +} diff --git a/gcc/testsuite/g++.dg/other/anon3.C b/gcc/testsuite/g++.dg/other/anon3.C index d33eb413ccf..36bf2d64520 100644 --- a/gcc/testsuite/g++.dg/other/anon3.C +++ b/gcc/testsuite/g++.dg/other/anon3.C @@ -4,4 +4,4 @@ // { dg-do compile } -enum { a = 3 } x; // { dg-warning "unnamed type" "" { target { ! c++11 } } } +enum { } x; // { dg-warning "unnamed type" "" { target { ! c++11 } } } -- 2.47.0
>From 5ede4b36675eb68f23e0b9292f4942559697bd17 Mon Sep 17 00:00:00 2001 From: Nathaniel Shead <nathanielosh...@gmail.com> Date: Fri, 8 Aug 2025 23:23:18 +1000 Subject: [PATCH v2] c++: Implement P2115R0 linkage changes for unnamed unscoped enums [PR120503] We currently list P2115R0 as implemented, but only the modules changes had been done. This patch implements the linkage changes so that unnamed unscoped enums will use the name of the first enumerator for linkage purposes. This is (strictly speaking) a breaking change, as code that previously relied on unnamed enumerations being internal linkage may have overloads using those types become exposed and clash with other functions in a different TU that have been similarly exposed. As such this feature is only implemented for C++20. No ABI flag warning is provided, partly because C++20 is still an experimental standard, but also because any affected functions could not have been part of an ABI until this change anyway. A number of testcases that are testing for behaviour of no-linkage types are adjusted to use an enumeration with no values, so that the pre-C++20 and post-C++20 behaviour is equivalently tested. In terms of implementation, I had originally considered adjusting the DECL_NAME of the enum, as with 'name_unnamed_type', but this ended up being more complicated as it had unwanted interactions with the existing modules streaming and with name lookup and diagnostic messages. This patch instead uses a new function to derive this case. The standard says that ([dcl.enum] p11) such an enum "...is denoted, for linkage purposes, by its underlying type and its first enumerator"; for simplicity this patch currently just mangles using the first enumerator, but we'll probably need to provide a new ABI production to include the type as well properly. PR c++/120503 PR c++/120824 gcc/cp/ChangeLog: * cp-tree.h (TYPE_UNNAMED_P): Adjust for enums with enumerators for linkage purposes. (enum_with_enumerator_for_linkage_p): Declare. * decl.cc (name_unnamed_type): Adjust assertions to handle enums with enumerators for linkage purposes. (grokdeclarator): Use a typedef name for enums with enumerators for linkage purposes. (enum_with_enumerator_for_linkage_p): New function. (finish_enum_value_list): Reset type linkage for enums with enumerators for linkage purposes. * mangle.cc (write_unqualified_name): Handle enums with enumerators for linkage purposes. * tree.cc (decl_linkage): Fixup unnamed enums. gcc/testsuite/ChangeLog: * g++.dg/abi/mangle32.C: Remove enumerator list. * g++.dg/cpp0x/linkage2.C: Likewise. * g++.dg/ext/vector26.C: Likewise. * g++.dg/other/anon3.C: Likewise. * g++.dg/abi/mangle82.C: New test. * g++.dg/modules/enum-15_a.C: New test. * g++.dg/modules/enum-15_b.C: New test. Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com> --- gcc/cp/cp-tree.h | 4 +++- gcc/cp/decl.cc | 28 +++++++++++++++++++++--- gcc/cp/mangle.cc | 8 ++++++- gcc/cp/tree.cc | 4 ++-- gcc/testsuite/g++.dg/abi/mangle32.C | 4 ++-- gcc/testsuite/g++.dg/abi/mangle82.C | 24 ++++++++++++++++++++ gcc/testsuite/g++.dg/cpp0x/linkage2.C | 6 ++--- gcc/testsuite/g++.dg/ext/vector26.C | 2 +- gcc/testsuite/g++.dg/modules/enum-15_a.C | 10 +++++++++ gcc/testsuite/g++.dg/modules/enum-15_b.C | 18 +++++++++++++++ gcc/testsuite/g++.dg/other/anon3.C | 2 +- 11 files changed, 96 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/g++.dg/abi/mangle82.C create mode 100644 gcc/testsuite/g++.dg/modules/enum-15_a.C create mode 100644 gcc/testsuite/g++.dg/modules/enum-15_b.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fb8e0d8d98e..090f08a78fc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2330,7 +2330,8 @@ enum languages { lang_c, lang_cplusplus }; /* Nonzero if NODE, a TYPE, has no name for linkage purposes. */ #define TYPE_UNNAMED_P(NODE) \ (TYPE_ANON_P (NODE) \ - && !IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE))) + && !IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE)) \ + && !enum_with_enumerator_for_linkage_p (NODE)) /* The _DECL for this _TYPE. */ #define TYPE_MAIN_DECL(NODE) (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE))) @@ -7298,6 +7299,7 @@ extern tree xref_tag (tag_types, tree, bool tpl_header_p = false); extern void xref_basetypes (tree, tree); extern tree start_enum (tree, tree, tree, tree, bool, bool *); +extern bool enum_with_enumerator_for_linkage_p (tree); extern void finish_enum_value_list (tree); extern void finish_enum (tree); extern tree build_enumerator (tree, tree, tree, tree, location_t); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index cb3ebfff429..90f736f9b6c 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -12677,7 +12677,8 @@ mark_inline_variable (tree decl, location_t loc) void name_unnamed_type (tree type, tree decl) { - gcc_assert (TYPE_UNNAMED_P (type)); + 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. */ @@ -12700,7 +12701,8 @@ name_unnamed_type (tree type, tree decl) /* Check that our job is done, and that it would fail if we attempted to do it again. */ - gcc_assert (!TYPE_UNNAMED_P (type)); + gcc_assert (!TYPE_UNNAMED_P (type) + && !enum_with_enumerator_for_linkage_p (type)); } /* Check that decltype(auto) was well-formed: only plain decltype(auto) @@ -14950,7 +14952,10 @@ grokdeclarator (const cp_declarator *declarator, && unqualified_id && TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && TYPE_UNNAMED_P (type) + && (TYPE_UNNAMED_P (type) + /* An enum may have previously used an enumerator for linkage + purposes, but we want the typedef name to take priority. */ + || enum_with_enumerator_for_linkage_p (type)) && declspecs->type_definition_p && attributes_naming_typedef_ok (*attrlist) && cp_type_quals (type) == TYPE_UNQUALIFIED) @@ -17793,6 +17798,18 @@ start_enum (tree name, tree enumtype, tree underlying_type, return enumtype; } +/* Returns true if TYPE is an enum that uses an enumerator name for + linkage purposes. */ + +bool +enum_with_enumerator_for_linkage_p (tree type) +{ + return (cxx_dialect >= cxx20 + && UNSCOPED_ENUM_P (type) + && TYPE_ANON_P (type) + && TYPE_VALUES (type)); +} + /* After processing and defining all the values of an enumeration type, install their decls in the enumeration type. ENUMTYPE is the type object. */ @@ -18023,6 +18040,11 @@ finish_enum_value_list (tree enumtype) fixup_type_variants (current_class_type); } + /* P2115: An unnamed enum uses the name of its first enumerator for + linkage purposes; reset the type linkage if that is the case. */ + if (enum_with_enumerator_for_linkage_p (enumtype)) + reset_type_linkage (enumtype); + /* Finish debugging output for this type. */ rest_of_type_compilation (enumtype, namespace_bindings_p ()); diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 13d5dedebd2..59636e87f6e 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -1591,7 +1591,13 @@ write_unqualified_name (tree decl) tree type = TREE_TYPE (decl); if (TREE_CODE (decl) == TYPE_DECL - && TYPE_UNNAMED_P (type)) + && enum_with_enumerator_for_linkage_p (type)) + { + /* FIXME mangle the type as well? */ + tree enumerator = TREE_VALUE (TYPE_VALUES (type)); + write_source_name (DECL_NAME (enumerator)); + } + else if (TREE_CODE (decl) == TYPE_DECL && TYPE_UNNAMED_P (type)) write_unnamed_type_name (type); else if (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (type)) write_closure_type_name (type); diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index d56d73fe217..59d626c86d5 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -6394,8 +6394,8 @@ decl_linkage (tree decl) if (NAMESPACE_SCOPE_P (decl) && (!DECL_NAME (decl) || IDENTIFIER_ANON_P (DECL_NAME (decl)))) { - if (TREE_CODE (decl) == TYPE_DECL && !TYPE_ANON_P (TREE_TYPE (decl))) - /* This entity has a typedef name for linkage purposes. */; + if (TREE_CODE (decl) == TYPE_DECL && !TYPE_UNNAMED_P (TREE_TYPE (decl))) + /* This entity has a name for linkage purposes. */; else if (DECL_DECOMPOSITION_P (decl) && DECL_DECOMP_IS_BASE (decl)) /* Namespace-scope structured bindings can have linkage. */; else if (TREE_CODE (decl) == NAMESPACE_DECL && cxx_dialect >= cxx11) diff --git a/gcc/testsuite/g++.dg/abi/mangle32.C b/gcc/testsuite/g++.dg/abi/mangle32.C index 4c5b33b8b4d..edb542e28c1 100644 --- a/gcc/testsuite/g++.dg/abi/mangle32.C +++ b/gcc/testsuite/g++.dg/abi/mangle32.C @@ -15,7 +15,7 @@ void f(B) { } struct C { typedef struct { }* D; - typedef enum { e }* E; + typedef enum { }* E; }; // { dg-final { scan-assembler "_Z2g1PN1CUt_E" } } @@ -31,7 +31,7 @@ void h2(T t) { } inline void j() { - typedef enum { f }* F; + typedef enum { }* F; // { dg-final { scan-assembler "_Z2h1IPZ1jvEUt_EvT_" } } h1(F()); typedef struct { }* G; diff --git a/gcc/testsuite/g++.dg/abi/mangle82.C b/gcc/testsuite/g++.dg/abi/mangle82.C new file mode 100644 index 00000000000..eed01b9e8e3 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle82.C @@ -0,0 +1,24 @@ +// PR c++/120503 +// Implement P2115r0 "merging definitions of unnamed unscoped enums" +// { dg-do compile { target c++14 } } + +template<auto V> int Frob () { return int (V); } + +enum { A = 195'936'478, B = 0 }; +template int Frob<A> (); +template int Frob<B> (); +// { dg-final { scan-assembler {_Z4FrobITnDaL1A195936478EEiv:} { target c++20 } } } +// { dg-final { scan-assembler {_Z4FrobITnDaL8._anon_0195936478EEiv:} { target c++17_down } } } +// { dg-final { scan-assembler {_Z4FrobITnDaL1A0EEiv:} { target c++20 } } } +// { dg-final { scan-assembler {_Z4FrobITnDaL8._anon_00EEiv:} { target c++17_down } } } + +enum { C = 5 } typedef X; +template int Frob<C> (); +// typedef name 'X' should take precedence +// { dg-final { scan-assembler {_Z4FrobITnDaL1X5EEiv:} } } + +typedef enum { D = 8 }* Y; +template int Frob<D> (); +// but 'Y' is not a typedef name here +// { dg-final { scan-assembler {_Z4FrobITnDaL1D8EEiv:} { target c++20 } } } +// { dg-final { scan-assembler {_Z4FrobITnDaL8._anon_28EEiv:} { target c++17_down } } } diff --git a/gcc/testsuite/g++.dg/cpp0x/linkage2.C b/gcc/testsuite/g++.dg/cpp0x/linkage2.C index 34a36c45a58..0ec2cec8a99 100644 --- a/gcc/testsuite/g++.dg/cpp0x/linkage2.C +++ b/gcc/testsuite/g++.dg/cpp0x/linkage2.C @@ -16,9 +16,9 @@ template <typename T> struct B { template <typename T> T B<T>::t2 = { }; -enum { E1 } e1; // OK, defined -extern enum { E2 } e2; // { dg-error "never defined" } -extern "C" enum { E3 } e3; // OK, extern "C" +enum { } e1; // OK, defined +extern enum { } e2; // { dg-error "never defined" } +extern "C" enum { } e3; // OK, extern "C" void f() { struct A { int x; }; // no linkage diff --git a/gcc/testsuite/g++.dg/ext/vector26.C b/gcc/testsuite/g++.dg/ext/vector26.C index 1d7a1e47160..95cae393fb5 100644 --- a/gcc/testsuite/g++.dg/ext/vector26.C +++ b/gcc/testsuite/g++.dg/ext/vector26.C @@ -3,7 +3,7 @@ // gets internal linkage. // { dg-options "-mmmx" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */ -typedef enum { e } T __attribute__((vector_size(8))); +typedef enum { } T __attribute__((vector_size(8))); static void foo(T t) {} void bar (T t) {} // { dg-error "no linkage" "" { target { ! c++11 } } } // { dg-final { scan-assembler-not "globl\[ \t]*_Z3bar" { target c++11 } } } diff --git a/gcc/testsuite/g++.dg/modules/enum-15_a.C b/gcc/testsuite/g++.dg/modules/enum-15_a.C new file mode 100644 index 00000000000..e59a73a09e9 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/enum-15_a.C @@ -0,0 +1,10 @@ +// PR c++/120824 +// { dg-additional-options "-fmodules -Wno-global-module -std=c++20" } +// { dg-module-cmi M } + +module; +enum { E }; +enum { F }; +export module M; +export using ::E; +export using ::F; diff --git a/gcc/testsuite/g++.dg/modules/enum-15_b.C b/gcc/testsuite/g++.dg/modules/enum-15_b.C new file mode 100644 index 00000000000..43d7865e749 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/enum-15_b.C @@ -0,0 +1,18 @@ +// PR c++/120824 +// { dg-additional-options "-fmodules -Wno-global-module -std=c++20" } +// { dg-module-cmi !bad } + +module; +enum { E }; +namespace { + enum { G }; // { dg-message "internal" } +} +export module bad; +import M; +inline void ok() { + auto a = E; + auto b = F; +} +inline void err() { // { dg-error "TU-local" } + auto c = G; +} diff --git a/gcc/testsuite/g++.dg/other/anon3.C b/gcc/testsuite/g++.dg/other/anon3.C index d33eb413ccf..36bf2d64520 100644 --- a/gcc/testsuite/g++.dg/other/anon3.C +++ b/gcc/testsuite/g++.dg/other/anon3.C @@ -4,4 +4,4 @@ // { dg-do compile } -enum { a = 3 } x; // { dg-warning "unnamed type" "" { target { ! c++11 } } } +enum { } x; // { dg-warning "unnamed type" "" { target { ! c++11 } } } -- 2.47.0