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 ();

Reply via email to