Message ID | 010201913638bf68-adec1c85-2856-4987-a6dd-de3fd53a5767-000000@eu-west-1.amazonses.com |
---|---|
State | New |
Headers | show |
Series | c++: Don't accept multiple enum definitions within template class [PR115806] | expand |
On 8/9/24 4:19 AM, Simon Martin wrote: > 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. > > Successfully tested on x86_64-pc-linux-gnu. OK. > 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. > > --- > gcc/cp/decl.cc | 22 ++++++++++++---------- > gcc/testsuite/g++.dg/parse/enum15.C | 9 +++++++++ > 2 files changed, 21 insertions(+), 10 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/parse/enum15.C > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > index a468bfdb7b6..f23b635aec9 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 00000000000..d19262156b9 > --- /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;
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index a468bfdb7b6..f23b635aec9 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 00000000000..d19262156b9 --- /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;