https://gcc.gnu.org/g:786ebbd6058540b2110da16a693f0c582c11413c

commit r15-2855-g786ebbd6058540b2110da16a693f0c582c11413c
Author: Simon Martin <si...@nasilyan.com>
Date:   Thu Aug 8 14:59:49 2024 +0200

    c++: Don't accept multiple enum definitions within template class [PR115806]
    
    We have been accepting the following invalid code since revision 557831a91df
    
    === cut here ===
    template <typename T> struct S {
      enum E { a };
      enum E { b };
    };
    S<int> s;
    === cut here ===
    
    The problem is that start_enum will set OPAQUE_ENUM_P to true even if it
    retrieves an existing definition for the enum, which causes the redefinition
    check in cp_parser_enum_specifier to be bypassed.
    
    This patch only sets OPAQUE_ENUM_P and ENUM_FIXED_UNDERLYING_TYPE_P when
    actually pushing a new tag for the enum.
    
            PR c++/115806
    
    gcc/cp/ChangeLog:
    
            * decl.cc (start_enum): Only set OPAQUE_ENUM_P and
            ENUM_FIXED_UNDERLYING_TYPE_P when pushing a new tag.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/parse/enum15.C: New test.

Diff:
---
 gcc/cp/decl.cc                      | 22 ++++++++++++----------
 gcc/testsuite/g++.dg/parse/enum15.C |  9 +++++++++
 2 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index a468bfdb7b67..f23b635aec9f 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -17059,22 +17059,24 @@ start_enum (tree name, tree enumtype, tree 
underlying_type,
          enumtype = cxx_make_type (ENUMERAL_TYPE);
          enumtype = pushtag (name, enumtype);
 
-         /* std::byte aliases anything.  */
-         if (enumtype != error_mark_node
-             && TYPE_CONTEXT (enumtype) == std_node
-             && !strcmp ("byte", TYPE_NAME_STRING (enumtype)))
-           TYPE_ALIAS_SET (enumtype) = 0;
+         if (enumtype != error_mark_node)
+           {
+             /* The enum is considered opaque until the opening '{' of the
+                enumerator list.  */
+             SET_OPAQUE_ENUM_P (enumtype, true);
+             ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) = !! underlying_type;
+
+             /* std::byte aliases anything.  */
+             if (TYPE_CONTEXT (enumtype) == std_node
+                 && !strcmp ("byte", TYPE_NAME_STRING (enumtype)))
+               TYPE_ALIAS_SET (enumtype) = 0;
+           }
        }
       else
          enumtype = xref_tag (enum_type, name);
 
       if (enumtype == error_mark_node)
        return error_mark_node;
-
-      /* The enum is considered opaque until the opening '{' of the
-        enumerator list.  */
-      SET_OPAQUE_ENUM_P (enumtype, true);
-      ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) = !! underlying_type;
     }
 
   SET_SCOPED_ENUM_P (enumtype, scoped_enum_p);
diff --git a/gcc/testsuite/g++.dg/parse/enum15.C 
b/gcc/testsuite/g++.dg/parse/enum15.C
new file mode 100644
index 000000000000..d19262156b91
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/enum15.C
@@ -0,0 +1,9 @@
+// PR c++/115806
+// { dg-do compile }
+
+template <typename T>
+struct S {
+  enum E { a }; // { dg-note "previous definition" }
+  enum E { b }; // { dg-error "multiple definition" }
+};
+S<int> s;

Reply via email to