re PR c++/48536 ([C++0x] Automatic Enumerator Incrementation is not compliant with...
authorJason Merrill <jason@redhat.com>
Thu, 26 May 2011 02:23:02 +0000 (22:23 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 26 May 2011 02:23:02 +0000 (22:23 -0400)
PR c++/48536
* decl.c (build_enumerator): If incremented enumerator won't fit in
previous integral type, find one it will fit in.

From-SVN: r174258

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/enum17.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.jason/rfg10.C

index dad97add6c4ae946f3dd774420bdc33fe6743ac9..6277596f6ced2d8b1176df8a3d763641e613db76 100644 (file)
@@ -1,5 +1,9 @@
 2011-05-25  Jason Merrill  <jason@redhat.com>
 
+       PR c++/48536
+       * decl.c (build_enumerator): If incremented enumerator won't fit in
+       previous integral type, find one it will fit in.
+
        PR c++/48599
        * decl.c (create_array_type_for_decl): Complain about array of auto.
 
index 58cab51ab81f5ec452dd7313f9f81d5ad7d23481..8ab0c8afc7f532b0ccc0ff26b4dd054db2e12df7 100644 (file)
@@ -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)
                    {
index bcef9a9df2217da3069f00ae064962c8cf4b6030..367bd881fa6b1aaa9fec03793dbb8ab94df6d547 100644 (file)
@@ -1,5 +1,8 @@
 2011-05-25  Jason Merrill  <jason@redhat.com>
 
+       * g++.dg/cpp0x/enum17.C: New.
+       * g++.old-deja/g++.jason/rfg10.C: Adjust.
+
        * g++.dg/cpp0x/auto24.C: New.
 
        * g++.dg/cpp0x/error4.C: New.
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum17.C b/gcc/testsuite/g++.dg/cpp0x/enum17.C
new file mode 100644 (file)
index 0000000..8ba827e
--- /dev/null
@@ -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);
index f6d5af3a8b842839b1446459f8ed446711f7c2a1..58af19c33644832db276d47a164f6f61f9ebcf4a 100644 (file)
@@ -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" }
 };