Patchwork C++ PATCH for c++/48536 (type of enumerators with no explicit initializer)

login
register
mail settings
Submitter Jason Merrill
Date May 26, 2011, 12:21 a.m.
Message ID <4DDD9D20.6020600@redhat.com>
Download mbox | patch
Permalink /patch/97478/
State New
Headers show

Comments

Jason Merrill - May 26, 2011, 12:21 a.m.
I haven't checked the ARM, but as far back as C++98 it was specified 
that the type of an enumerator with no initializer is the type of the 
previous enumerator, unless the new value won't fit in that type, in 
which case it's an unspecified integral type.  We weren't implementing 
that latter part.

Tested x86_64-pc-linux-gnu, applying to trunk.

Patch

commit 387edd6ad6b16abc052bd51847f83607e958a7dc
Author: Jason Merrill <jason@redhat.com>
Date:   Wed May 25 17:12:27 2011 -0400

    	PR c++/48536
    	* decl.c (build_enumerator): If incremented enumerator won't fit in
    	previous integral type, find one it will fit in.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 58cab51..8ab0c8a 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -12190,9 +12190,13 @@  build_enumerator (tree name, tree value, tree enumtype, location_t loc)
 	      tree prev_value;
 	      bool overflowed;
 
-	      /* The next value is the previous value plus one.
-		 add_double doesn't know the type of the target expression,
-		 so we must check with int_fits_type_p as well.  */
+	      /* C++03 7.2/4: If no initializer is specified for the first
+		 enumerator, the type is an unspecified integral
+		 type. Otherwise the type is the same as the type of the
+		 initializing value of the preceding enumerator unless the
+		 incremented value is not representable in that type, in
+		 which case the type is an unspecified integral type
+		 sufficient to contain the incremented value.  */
 	      prev_value = DECL_INITIAL (TREE_VALUE (TYPE_VALUES (enumtype)));
 	      if (error_operand_p (prev_value))
 		value = error_mark_node;
@@ -12201,9 +12205,34 @@  build_enumerator (tree name, tree value, tree enumtype, location_t loc)
 		  overflowed = add_double (TREE_INT_CST_LOW (prev_value),
 					   TREE_INT_CST_HIGH (prev_value),
 					   1, 0, &lo, &hi);
-		  value = build_int_cst_wide (TREE_TYPE (prev_value), lo, hi);
-		  overflowed
-		    |= !int_fits_type_p (value, TREE_TYPE (prev_value));
+		  if (!overflowed)
+		    {
+		      double_int di;
+		      tree type = TREE_TYPE (prev_value);
+		      bool pos = (TYPE_UNSIGNED (type) || hi >= 0);
+		      di.low = lo; di.high = hi;
+		      if (!double_int_fits_to_tree_p (type, di))
+			{
+			  unsigned int itk;
+			  for (itk = itk_int; itk != itk_none; itk++)
+			    {
+			      type = integer_types[itk];
+			      if (type != NULL_TREE
+				  && (pos || !TYPE_UNSIGNED (type))
+				  && double_int_fits_to_tree_p (type, di))
+				break;
+			    }
+			  if (type && cxx_dialect < cxx0x
+			      && itk > itk_unsigned_long)
+			    pedwarn (input_location, OPT_Wlong_long, pos ? "\
+incremented enumerator value is too large for %<unsigned long%>" :  "\
+incremented enumerator value is too large for %<long%>");
+			}
+		      if (type == NULL_TREE)
+			overflowed = true;
+		      else
+			value = double_int_to_tree (type, di);
+		    }
 
 		  if (overflowed)
 		    {
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum17.C b/gcc/testsuite/g++.dg/cpp0x/enum17.C
new file mode 100644
index 0000000..8ba827e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/enum17.C
@@ -0,0 +1,17 @@ 
+// PR c++/48536
+// { dg-options "-std=c++0x -pedantic-errors" }
+
+#include <climits>
+
+// According to C++11 / Clause 7.2/5 the following enumeration is
+// well-formed.  It is also well-formed in C++03 if UINT_MAX < ULONG_MAX,
+// but C++11 adds long long.
+
+enum Enum_Inc  { EI_1=UINT_MAX, EI_2 }; // #1
+
+// It is not equivalent to the following.
+enum Enum_Inc2 { FI_1=UINT_MAX, FI_2=FI_1+1 }; // #2
+
+#define SA(X) static_assert(X,#X)
+SA (EI_2 != 0);
+SA (FI_2 == 0);
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/rfg10.C b/gcc/testsuite/g++.old-deja/g++.jason/rfg10.C
index f6d5af3..58af19c 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/rfg10.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/rfg10.C
@@ -1,4 +1,5 @@ 
 // { dg-do assemble  }
+// { dg-options "-pedantic-errors" }
 // Bug: g++ doesn't notice the overflow in the enum values.
 
 #include <limits.h>
@@ -7,5 +8,5 @@  enum COLOR
 {
     red,
     green = ULONG_MAX,
-    blue // { dg-error "overflow in enumeration" }
+    blue		     // { dg-error "too large for .unsigned long" }
 };