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.
@@ -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)
{
new file mode 100644
@@ -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);
@@ -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" }
};