https://gcc.gnu.org/g:4d1bfc66f84de6b37b175a191cba8cdd552c4383
commit r16-5802-g4d1bfc66f84de6b37b175a191cba8cdd552c4383 Author: Jakub Jelinek <[email protected]> Date: Mon Dec 1 17:54:05 2025 +0100 c++: Fix ODR regressions caused by P2115R0 changes [PR122905] The following testcase fails due to ODR warnings starting with the r16-3233 change (P2115R0 PR120503 implementation). The problem is that for C++20 we mangle differently the anonymous union at the class scope from C++17, in C++17 the unnamed enumeration that has an enumerator as a name for linkage purposes before it is counted as TYPE_UNNAMED_P in nested_anon_class_index, but for C++20 it is not, therefore the ODR warning. While the term defined in https://eel.is/c++draft/dcl.enum#12.sentence-2 is defined for all enum types, its only use in https://eel.is/c++draft/basic.link#4.5 is solely for enumeration types at namespace scope, changing anything for those at class scope or block scope has undesirable ABI consequences. 2025-12-01 Jakub Jelinek <[email protected]> PR c++/122905 * decl.cc (enum_with_enumerator_for_linkage_p): Only return true for namespace scope types. * g++.dg/lto/pr122905.h: New file. * g++.dg/lto/pr122905_0.C: New test. * g++.dg/lto/pr122905_1.C: New test. Diff: --- gcc/cp/decl.cc | 9 +++++++-- gcc/testsuite/g++.dg/lto/pr122905.h | 9 +++++++++ gcc/testsuite/g++.dg/lto/pr122905_0.C | 16 ++++++++++++++++ gcc/testsuite/g++.dg/lto/pr122905_1.C | 5 +++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 4482633d3a0d..d1fbbab6e4c3 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -18760,7 +18760,11 @@ start_enum (tree name, tree enumtype, tree underlying_type, } /* Returns true if TYPE is an enum that uses an enumerator name for - linkage purposes. */ + linkage purposes at namespace scope. The term is defined in [dcl.enum]/12 + for all enums, not just those at namespace scope, but for backward ABI + compatibility we want to treat those not at namespace scope the old way + and e.g. mangle the class scope ones based on their position within the + class rather than the first enumerator. */ bool enum_with_enumerator_for_linkage_p (tree type) @@ -18768,7 +18772,8 @@ enum_with_enumerator_for_linkage_p (tree type) return (cxx_dialect >= cxx20 && UNSCOPED_ENUM_P (type) && TYPE_ANON_P (type) - && TYPE_VALUES (type)); + && TYPE_VALUES (type) + && TYPE_NAMESPACE_SCOPE_P (type)); } /* After processing and defining all the values of an enumeration type, diff --git a/gcc/testsuite/g++.dg/lto/pr122905.h b/gcc/testsuite/g++.dg/lto/pr122905.h new file mode 100644 index 000000000000..f345e18418f2 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr122905.h @@ -0,0 +1,9 @@ +struct A { + typedef char *B; + struct C { C (B x) {} }; + C c; + enum { D = 15 }; + union { char e[16]; }; + A (const char *x) : c {e} {} +}; +A foo (); diff --git a/gcc/testsuite/g++.dg/lto/pr122905_0.C b/gcc/testsuite/g++.dg/lto/pr122905_0.C new file mode 100644 index 000000000000..6cde9bcc278a --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr122905_0.C @@ -0,0 +1,16 @@ +/* PR c++/122905 */ +/* { dg-lto-do link } */ +/* { dg-lto-options { { -O2 -flto -std=c++20 } } } */ + +#include "pr122905.h" + +A +foo () +{ + return "foo"; +} + +int +main () +{ +} diff --git a/gcc/testsuite/g++.dg/lto/pr122905_1.C b/gcc/testsuite/g++.dg/lto/pr122905_1.C new file mode 100644 index 000000000000..549c3732bfdc --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr122905_1.C @@ -0,0 +1,5 @@ +// { dg-options "-O2 -flto -std=c++17" } + +#include "pr122905.h" + +volatile auto v = foo ();
