aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Martin <simon@nasilyan.com>2024-08-08 14:59:49 +0200
committerSimon Martin <simon@nasilyan.com>2024-08-09 17:15:43 +0200
commit786ebbd6058540b2110da16a693f0c582c11413c (patch)
tree2b8b054fc1985983924c083df92589040872c66d
parent180ede3543e98ade8f809afe8be5af0eeaeff7bb (diff)
downloadgcc-786ebbd6058540b2110da16a693f0c582c11413c.zip
gcc-786ebbd6058540b2110da16a693f0c582c11413c.tar.gz
gcc-786ebbd6058540b2110da16a693f0c582c11413c.tar.bz2
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.
-rw-r--r--gcc/cp/decl.cc22
-rw-r--r--gcc/testsuite/g++.dg/parse/enum15.C9
2 files changed, 21 insertions, 10 deletions
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index a468bfd..f23b635 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 0000000..d192621
--- /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;