[C++] PR c++/96442: Another improved error recovery in enumerations.

Message ID 001701d827e4$18186bb0$48494310$@nextmovesoftware.com
State New
Headers
Series [C++] PR c++/96442: Another improved error recovery in enumerations. |

Commit Message

Roger Sayle Feb. 22, 2022, 12:02 p.m. UTC
  This patch resolves PR c++/96442, another ICE-after-error regression.
In this case, invalid code attempts to use a non-integral type as the
underlying type for an enumeration (a record_type in the example given
in the bugzilla PR), for which the parser emits an error message but
allows the inappropriate type to leak to downstream code.  The minimal
safe fix is to double check that the enumeration's underlying type
EUTYPE satisfies INTEGRAL_TYPE_P before calling int_fits_type_p in
build_enumerator.  This is a one line fix, but correcting indentation
and storing a common subexpression in a variable makes the change look
a little bigger.

This patch has been tested on x86_64-pc-linunx-gnu with make bootstrap
and make -k check with no new (unexpected) failures.  Ok for mainline?


2022-02-22  Roger Sayle  <roger@nextmovesoftware.com>

gcc/cp/ChangeLog
	PR c++/96442
	* decl.cc (build_enumeration): Check ENUM_UNDERLYING_TYPE is
	INTEGRAL_TYPE_P before calling int_fits_type_p.

gcc/testsuite/ChangeLog
	PR c++/96442
	* g++.dg/pr96442.C: New test cae.


Thanks in advance,
Roger
--
  

Comments

Jason Merrill March 10, 2022, 5:05 a.m. UTC | #1
On 2/22/22 08:02, Roger Sayle wrote:
> 
> This patch resolves PR c++/96442, another ICE-after-error regression.
> In this case, invalid code attempts to use a non-integral type as the
> underlying type for an enumeration (a record_type in the example given
> in the bugzilla PR), for which the parser emits an error message but
> allows the inappropriate type to leak to downstream code.

How does that happen?

Would it help to change dependent_type_p in start_enum to WILDCARD_TYPE_P?

> The minimal
> safe fix is to double check that the enumeration's underlying type
> EUTYPE satisfies INTEGRAL_TYPE_P before calling int_fits_type_p in
> build_enumerator.  This is a one line fix, but correcting indentation
> and storing a common subexpression in a variable makes the change look
> a little bigger.
> 
> This patch has been tested on x86_64-pc-linunx-gnu with make bootstrap
> and make -k check with no new (unexpected) failures.  Ok for mainline?
> 
> 
> 2022-02-22  Roger Sayle  <roger@nextmovesoftware.com>
> 
> gcc/cp/ChangeLog
> 	PR c++/96442
> 	* decl.cc (build_enumeration): Check ENUM_UNDERLYING_TYPE is
> 	INTEGRAL_TYPE_P before calling int_fits_type_p.
> 
> gcc/testsuite/ChangeLog
> 	PR c++/96442
> 	* g++.dg/pr96442.C: New test cae.
> 
> 
> Thanks in advance,
> Roger
> --
>
  

Patch

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 7b48b56..c430f78 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -16542,19 +16542,21 @@  incremented enumerator value is too large for %<long%>"));
       STRIP_TYPE_NOPS (value);
 
       /* If the underlying type of the enum is fixed, check whether
-         the enumerator values fits in the underlying type.  If it
-         does not fit, the program is ill-formed [C++0x dcl.enum].  */
-      if (ENUM_UNDERLYING_TYPE (enumtype)
-          && value
-          && TREE_CODE (value) == INTEGER_CST)
-        {
-	  if (!int_fits_type_p (value, ENUM_UNDERLYING_TYPE (enumtype)))
+	 the enumerator values fits in the underlying type.  If it
+	 does not fit, the program is ill-formed [C++0x dcl.enum].  */
+      tree eutype = ENUM_UNDERLYING_TYPE (enumtype);
+      if (eutype
+	  && value
+	  && INTEGRAL_TYPE_P (eutype)
+	  && TREE_CODE (value) == INTEGER_CST)
+	{
+	  if (!int_fits_type_p (value, eutype))
 	    error ("enumerator value %qE is outside the range of underlying "
-		   "type %qT", value, ENUM_UNDERLYING_TYPE (enumtype));
+		   "type %qT", value, eutype);
 
-          /* Convert the value to the appropriate type.  */
-          value = fold_convert (ENUM_UNDERLYING_TYPE (enumtype), value);
-        }
+	  /* Convert the value to the appropriate type.  */
+	  value = fold_convert (eutype, value);
+	}
     }
 
   /* C++ associates enums with global, function, or class declarations.  */
diff --git a/gcc/testsuite/g++.dg/pr96442.C b/gcc/testsuite/g++.dg/pr96442.C
new file mode 100644
index 0000000..235bb11
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr96442.C
@@ -0,0 +1,6 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+enum struct a : struct {};
+template <class b> enum class a : class c{};
+enum struct a {b};
+// { dg-excess-errors "" }