diff mbox series

c++: Don't accept multiple enum definitions within template class [PR115806]

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

Commit Message

Simon Martin Aug. 9, 2024, 8:19 a.m. UTC
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.

	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

Comments

Jason Merrill Aug. 9, 2024, 3:08 p.m. UTC | #1
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 mbox series

Patch

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;