@@ -2298,6 +2298,10 @@ c_common_type_for_size (unsigned int bits, int unsignedp)
if (bits <= TYPE_PRECISION (intDI_type_node))
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+ if (bits <= TYPE_PRECISION (widest_integer_literal_type_node))
+ return (unsignedp ? widest_unsigned_literal_type_node
+ : widest_integer_literal_type_node);
+
return NULL_TREE;
}
@@ -9385,6 +9385,10 @@ finish_enum (tree enumtype, tree values, tree attributes)
precision = MAX (tree_int_cst_min_precision (minnode, sign),
tree_int_cst_min_precision (maxnode, sign));
+ bool wider_than_int =
+ (tree_int_cst_lt (minnode, TYPE_MIN_VALUE (integer_type_node))
+ || tree_int_cst_lt (TYPE_MAX_VALUE (integer_type_node), maxnode));
+
/* If the precision of the type was specified with an attribute and it
was too small, give an error. Otherwise, use it. */
if (TYPE_PRECISION (enumtype) && lookup_attribute ("mode", attributes))
@@ -9407,9 +9411,20 @@ finish_enum (tree enumtype, tree values, tree attributes)
tem = c_common_type_for_size (precision, sign == UNSIGNED ? 1 : 0);
if (tem == NULL)
{
- warning (0, "enumeration values exceed range of largest integer");
- tem = long_long_integer_type_node;
- }
+ /* This should only occur when both signed and unsigned
+ values of maximum precision occur among the
+ enumerators. */
+ pedwarn (input_location, 0,
+ "enumeration values exceed range of largest integer");
+ tem = widest_integer_literal_type_node;
+ }
+ else if (precision > TYPE_PRECISION (intmax_type_node)
+ && !tree_int_cst_lt (minnode, TYPE_MIN_VALUE (intmax_type_node))
+ && !tree_int_cst_lt (TYPE_MAX_VALUE (uintmax_type_node),
+ maxnode))
+ pedwarn (input_location, OPT_Wpedantic,
+ "enumeration values exceed range of %qs",
+ sign == UNSIGNED ? "uintmax_t" : "intmax_t");
}
else
tem = sign == UNSIGNED ? unsigned_type_node : integer_type_node;
@@ -9439,17 +9454,17 @@ finish_enum (tree enumtype, tree values, tree attributes)
TREE_TYPE (enu) = enumtype;
- /* The ISO C Standard mandates enumerators to have type int,
- even though the underlying type of an enum type is
- unspecified. However, GCC allows enumerators of any
- integer type as an extensions. build_enumerator()
- converts any enumerators that fit in an int to type int,
- to avoid promotions to unsigned types when comparing
- integers with enumerators that fit in the int range.
- When -pedantic is given, build_enumerator() would have
- already warned about those that don't fit. Here we
- convert the rest to the enumerator type. */
- if (TREE_TYPE (ini) != integer_type_node)
+ /* Before C2X, the ISO C Standard mandates enumerators to
+ have type int, even though the underlying type of an enum
+ type is unspecified. However, C2X allows enumerators of
+ any integer type, and if an enumeration has any
+ enumerators wider than int, all enumerators have the
+ enumerated type after it is parsed. Any enumerators that
+ fit in int are given type int in build_enumerator (which
+ is the correct type while the enumeration is being
+ parsed), so no conversions are needed here if all
+ enumerators fit in int. */
+ if (wider_than_int)
ini = convert (enumtype, ini);
DECL_INITIAL (enu) = ini;
@@ -9517,7 +9532,7 @@ tree
build_enumerator (location_t decl_loc, location_t loc,
struct c_enum_contents *the_enum, tree name, tree value)
{
- tree decl, type;
+ tree decl;
/* Validate and default VALUE. */
@@ -9568,21 +9583,45 @@ build_enumerator (location_t decl_loc, location_t loc,
}
/* Even though the underlying type of an enum is unspecified, the
type of enumeration constants is explicitly defined as int
- (6.4.4.3/2 in the C99 Standard). GCC allows any integer type as
- an extension. */
- else if (!int_fits_type_p (value, integer_type_node))
- pedwarn (loc, OPT_Wpedantic,
- "ISO C restricts enumerator values to range of %<int%>");
-
- /* The ISO C Standard mandates enumerators to have type int, even
- though the underlying type of an enum type is unspecified.
- However, GCC allows enumerators of any integer type as an
- extensions. Here we convert any enumerators that fit in an int
- to type int, to avoid promotions to unsigned types when comparing
- integers with enumerators that fit in the int range. When
- -pedantic is given, we would have already warned about those that
- don't fit. We have to do this here rather than in finish_enum
- because this value may be used to define more enumerators. */
+ (6.4.4.3/2 in the C99 Standard). C2X allows any integer type, and
+ GCC allows such types for older standards as an extension. */
+ bool warned_range = false;
+ if (!int_fits_type_p (value,
+ (TYPE_UNSIGNED (TREE_TYPE (value))
+ ? uintmax_type_node
+ : intmax_type_node)))
+ /* GCC does not consider its types larger than intmax_t to be
+ extended integer types (although C2X would permit such types to
+ be considered extended integer types if all the features
+ required by <stdint.h> and <inttypes.h> macros, such as support
+ for integer constants and I/O, were present), so diagnose if
+ such a wider type is used. (If the wider type arose from a
+ constant of such a type, that will also have been diagnosed,
+ but this is the only diagnostic in the case where it arises
+ from choosing a wider type automatically when adding 1
+ overflows.) */
+ warned_range = pedwarn (loc, OPT_Wpedantic,
+ "enumerator value outside the range of %qs",
+ (TYPE_UNSIGNED (TREE_TYPE (value))
+ ? "uintmax_t"
+ : "intmax_t"));
+ if (!warned_range && !int_fits_type_p (value, integer_type_node))
+ pedwarn_c11 (loc, OPT_Wpedantic,
+ "ISO C restricts enumerator values to range of %<int%> "
+ "before C2X");
+
+ /* The ISO C Standard mandates enumerators to have type int before
+ C2X, even though the underlying type of an enum type is
+ unspecified. C2X allows enumerators of any integer type. During
+ the parsing of the enumeration, C2X specifies that constants
+ representable in int have type int, constants not representable
+ in int have the type of the given expression if any, and
+ constants not representable in int and derived by adding 1 to the
+ previous constant have the type of that constant unless the
+ addition would overflow or wraparound, in which case a wider type
+ of the same signedness is chosen automatically; after the
+ enumeration is parsed, all the constants have the type of the
+ enumeration if any do not fit in int. */
if (int_fits_type_p (value, integer_type_node))
value = convert (integer_type_node, value);
@@ -9591,18 +9630,38 @@ build_enumerator (location_t decl_loc, location_t loc,
= build_binary_op (EXPR_LOC_OR_LOC (value, input_location),
PLUS_EXPR, value, integer_one_node, false);
the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value);
+ if (the_enum->enum_overflow)
+ {
+ /* Choose a wider type with the same signedness if
+ available. */
+ int prec = TYPE_PRECISION (TREE_TYPE (value)) + 1;
+ bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (value));
+ tree new_type = (unsignedp
+ ? long_unsigned_type_node
+ : long_integer_type_node);
+ if (prec > TYPE_PRECISION (new_type))
+ new_type = (unsignedp
+ ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+ if (prec > TYPE_PRECISION (new_type))
+ new_type = (unsignedp
+ ? widest_unsigned_literal_type_node
+ : widest_integer_literal_type_node);
+ if (prec <= TYPE_PRECISION (new_type))
+ {
+ the_enum->enum_overflow = false;
+ the_enum->enum_next_value
+ = build_binary_op (EXPR_LOC_OR_LOC (value, input_location),
+ PLUS_EXPR, convert (new_type, value),
+ integer_one_node, false);
+ gcc_assert (!tree_int_cst_lt (the_enum->enum_next_value, value));
+ }
+ }
/* Now create a declaration for the enum value name. */
- type = TREE_TYPE (value);
- type = c_common_type_for_size (MAX (TYPE_PRECISION (type),
- TYPE_PRECISION (integer_type_node)),
- (TYPE_PRECISION (type)
- >= TYPE_PRECISION (integer_type_node)
- && TYPE_UNSIGNED (type)));
-
- decl = build_decl (decl_loc, CONST_DECL, name, type);
- DECL_INITIAL (decl) = convert (type, value);
+ decl = build_decl (decl_loc, CONST_DECL, name, TREE_TYPE (value));
+ DECL_INITIAL (decl) = value;
pushdecl (decl);
return tree_cons (decl, value, NULL_TREE);
new file mode 100644
@@ -0,0 +1,14 @@
+/* Test C2x enumerations with values not representable in int are diagnosed for
+ C11. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+enum e1 { e1a = -__LONG_LONG_MAX__ - 1 }; /* { dg-error "ISO C restricts enumerator values" } */
+
+enum e2 { e2a = __LONG_LONG_MAX__ }; /* { dg-error "ISO C restricts enumerator values" } */
+
+enum e3 { e3a = (unsigned int) -1 }; /* { dg-error "ISO C restricts enumerator values" } */
+
+enum e4 { e4a = (long long) -__INT_MAX__ - 1, e4b = (unsigned int) __INT_MAX__ };
+
+enum e5 { e5a = __INT_MAX__, e5b }; /* { dg-error "ISO C restricts enumerator values" } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* Test C2x enumerations with values not representable in int are diagnosed for
+ C11. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic" } */
+
+enum e1 { e1a = -__LONG_LONG_MAX__ - 1 }; /* { dg-warning "ISO C restricts enumerator values" } */
+
+enum e2 { e2a = __LONG_LONG_MAX__ }; /* { dg-warning "ISO C restricts enumerator values" } */
+
+enum e3 { e3a = (unsigned int) -1 }; /* { dg-warning "ISO C restricts enumerator values" } */
+
+enum e4 { e4a = (long long) -__INT_MAX__ - 1, e4b = (unsigned int) __INT_MAX__ };
+
+enum e5 { e5a = __INT_MAX__, e5b }; /* { dg-warning "ISO C restricts enumerator values" } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* Test C2x enumerations with values not representable in int are not diagnosed
+ for C11 with -pedantic-errors -Wno-c11-c2x-compat. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors -Wno-c11-c2x-compat" } */
+
+enum e1 { e1a = -__LONG_LONG_MAX__ - 1 };
+
+enum e2 { e2a = __LONG_LONG_MAX__ };
+
+enum e3 { e3a = (unsigned int) -1 };
+
+enum e4 { e4a = (long long) -__INT_MAX__ - 1, e4b = (unsigned int) __INT_MAX__ };
+
+enum e5 { e5a = __INT_MAX__, e5b };
new file mode 100644
@@ -0,0 +1,104 @@
+/* Test C2x enumerations with values not representable in int. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+/* Check a type while defining an enum (via a diagnostic for incompatible
+ pointer types if the wrong type was chosen). */
+#define TYPE_CHECK(cst, type) \
+ cst ## _type_check = sizeof (1 ? (type *) 0 : (typeof (cst) *) 0)
+
+/* Test various explicit values not representable in int. */
+
+enum e1 { e1a = -__LONG_LONG_MAX__ - 1, TYPE_CHECK (e1a, long long),
+ e1b = 0, TYPE_CHECK (e1b, int),
+ e1c = __LONG_LONG_MAX__, TYPE_CHECK (e1c, long long),
+ e1d = 1, TYPE_CHECK (e1d, int) };
+extern enum e1 e1v;
+extern typeof (e1a) e1v;
+extern typeof (e1b) e1v;
+extern typeof (e1c) e1v;
+extern typeof (e1d) e1v;
+static_assert (sizeof (enum e1) >= sizeof (long long));
+static_assert (e1a == -__LONG_LONG_MAX__ - 1);
+static_assert (e1b == 0);
+static_assert (e1c == __LONG_LONG_MAX__);
+static_assert (e1d == 1);
+static_assert (e1a < 0);
+static_assert (e1c > 0);
+
+/* This is a test where values are representable in int. */
+enum e2 { e2a = (long long) -__INT_MAX__ - 1, TYPE_CHECK (e2a, int),
+ e2b = (unsigned int) __INT_MAX__, TYPE_CHECK (e2b, int),
+ e2c = 2, TYPE_CHECK (e2c, int) };
+extern int e2v;
+extern typeof (e2a) e2v;
+extern typeof (e2b) e2v;
+extern typeof (e2c) e2v;
+static_assert (e2a == -__INT_MAX__ - 1);
+static_assert (e2b == __INT_MAX__);
+static_assert (e2c == 2);
+static_assert (e2a < 0);
+static_assert (e2b > 0);
+
+enum e3 { e3a = 0, TYPE_CHECK (e3a, int),
+ e3b = (unsigned int) -1, TYPE_CHECK (e3b, unsigned int) };
+extern enum e3 e3v;
+extern typeof (e3a) e3v;
+extern typeof (e3b) e3v;
+static_assert (e3a == 0u);
+static_assert (e3b == (unsigned int) -1);
+static_assert (e3b > 0);
+
+/* Test handling of overflow and wraparound (choosing a wider type). */
+#if __LONG_LONG_MAX__ > __INT_MAX__
+enum e4 { e4a = __INT_MAX__,
+ e4b, e4c, e4d = ((typeof (e4b)) -1) < 0,
+ e4e = (unsigned int) -1,
+ e4f, e4g = ((typeof (e4e)) -1) > 0,
+ TYPE_CHECK (e4a, int), TYPE_CHECK (e4e, unsigned int) };
+extern enum e4 e4v;
+extern typeof (e4a) e4v;
+extern typeof (e4b) e4v;
+extern typeof (e4c) e4v;
+extern typeof (e4d) e4v;
+extern typeof (e4e) e4v;
+extern typeof (e4f) e4v;
+extern typeof (e4g) e4v;
+static_assert (e4a == __INT_MAX__);
+static_assert (e4b == (long long) __INT_MAX__ + 1);
+static_assert (e4c == (long long) __INT_MAX__ + 2);
+static_assert (e4f == (unsigned long long) (unsigned int) -1 + 1);
+/* Verify the type chosen on overflow of a signed type while parsing was
+ signed. */
+static_assert (e4d == 1);
+/* Verify the type chosen on wraparound of an unsigned type while parsing was
+ unsigned. */
+static_assert (e4g == 1);
+#endif
+
+/* Likewise, for overflow from long to long long. */
+#if __LONG_LONG_MAX__ > __LONG_MAX__
+enum e5 { e5a = __LONG_MAX__,
+ e5b, e5c, e5d = ((typeof (e5b)) -1) < 0,
+ e5e = (unsigned long) -1,
+ e5f, e5g = ((typeof (e5e)) -1) > 0,
+ TYPE_CHECK (e5a, long), TYPE_CHECK (e5e, unsigned long) };
+extern enum e5 e5v;
+extern typeof (e5a) e5v;
+extern typeof (e5b) e5v;
+extern typeof (e5c) e5v;
+extern typeof (e5d) e5v;
+extern typeof (e5e) e5v;
+extern typeof (e5f) e5v;
+extern typeof (e5g) e5v;
+static_assert (e5a == __LONG_MAX__);
+static_assert (e5b == (long long) __LONG_MAX__ + 1);
+static_assert (e5c == (long long) __LONG_MAX__ + 2);
+static_assert (e5f == (unsigned long long) (unsigned long) -1 + 1);
+/* Verify the type chosen on overflow of a signed type while parsing was
+ signed. */
+static_assert (e5d == 1);
+/* Verify the type chosen on wraparound of an unsigned type while parsing was
+ unsigned. */
+static_assert (e5g == 1);
+#endif
new file mode 100644
@@ -0,0 +1,14 @@
+/* Test C2x enumerations with values not representable in int. Test values
+ outside the range of standard or extended integer types are diagnosed, even
+ when they can be represented in __int128. */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+enum e1 { e1a = __LONG_LONG_MAX__, e1b }; /* { dg-error "enumerator value outside the range" } */
+
+enum e2 { e2a = __LONG_LONG_MAX__ * 2ULL + 1ULL, e2b }; /* { dg-error "enumerator value outside the range" } */
+
+/* Likewise, when it's the enum as a whole that can't fit in any standard or
+ extended type, but the individual enumerators fit (some fitting a signed
+ type and some fitting an unsigned type). */
+enum e3 { e3a = -__LONG_LONG_MAX__ - 1, e3b = __LONG_LONG_MAX__ * 2ULL + 1ULL }; /* { dg-error "enumeration values exceed range of 'intmax_t'" } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* Test C2x enumerations with values not representable in int. Test values
+ outside the range of standard or extended integer types are diagnosed,
+ when __int128 is unsupported. */
+/* { dg-do compile { target { ! int128 } } } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+enum e1 { e1a = __LONG_LONG_MAX__, e1b }; /* { dg-error "overflow in enumeration values" } */
+
+enum e2 { e2a = __LONG_LONG_MAX__ * 2ULL + 1ULL, e2b }; /* { dg-error "overflow in enumeration values" } */
+
+/* Likewise, when it's the enum as a whole that can't fit in any standard or
+ extended type, but the individual enumerators fit (some fitting a signed
+ type and some fitting an unsigned type). */
+enum e3 { e3a = -__LONG_LONG_MAX__ - 1, e3b = __LONG_LONG_MAX__ * 2ULL + 1ULL }; /* { dg-error "enumeration values exceed range of largest integer" } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* Test C2x enumerations with values not representable in int. Test overflow
+ of __int128 is diagnosed. */
+/* { dg-do compile { target { int128 } } } */
+/* { dg-options "-std=c2x" } */
+
+enum e1 { e1a = (__int128) (((unsigned __int128) -1) >> 1), e1b }; /* { dg-error "overflow in enumeration values" } */
+
+enum e2 { e2a = (unsigned __int128) -1, e2b }; /* { dg-error "overflow in enumeration values" } */
+
+/* Likewise, when it's the enum as a whole that can't fit in __int128 or
+ unsigned __int128, but the individual enumerators fit (some fitting __int128
+ and some fitting unsigned __int128). */
+enum e3 { e3a = -(__int128) (((unsigned __int128) -1) >> 1) - 1,
+ e3b = (unsigned __int128) -1 }; /* { dg-warning "enumeration values exceed range of largest integer" } */
new file mode 100644
@@ -0,0 +1,12 @@
+/* Test C2x enumerations with values not representable in int. Test
+ -Wc11-c2x-compat warnings. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors -Wc11-c2x-compat" } */
+
+enum e1 { e1a = -__LONG_LONG_MAX__ - 1 }; /* { dg-warning "ISO C restricts enumerator values" } */
+
+enum e2 { e2a = __LONG_LONG_MAX__ }; /* { dg-warning "ISO C restricts enumerator values" } */
+
+enum e3 { e3a = (unsigned int) -1 }; /* { dg-warning "ISO C restricts enumerator values" } */
+
+enum e4 { e4a = (long long) -__INT_MAX__ - 1, e4b = (unsigned int) __INT_MAX__ };
@@ -1,6 +1,6 @@
/* PR 30260 */
/* { dg-do link } */
-/* { dg-options "-pedantic -O" } */
+/* { dg-options "-std=gnu11 -pedantic -O" } */
#include <limits.h>
void link_error (void);
@@ -30,5 +30,5 @@ int main(void)
return 0;
}
-enum E1 { e10 = INT_MAX, e11 }; /* { dg-error "overflow in enumeration values" } */
-enum E2 { e20 = (unsigned) INT_MAX, e21 }; /* { dg-error "overflow in enumeration values" } */
+enum E1 { e10 = INT_MAX, e11 }; /* { dg-warning "ISO C restricts enumerator values to range of 'int' before C2X" } */
+enum E2 { e20 = (unsigned) INT_MAX, e21 }; /* { dg-warning "ISO C restricts enumerator values to range of 'int' before C2X" } */
@@ -3,10 +3,10 @@
enum err {
err_IO = 0x8a450000, /* { dg-warning "int" } */
- err_NM,
- err_EOF,
- err_SE,
- err_PT
+ err_NM, /* { dg-warning "int" } */
+ err_EOF, /* { dg-warning "int" } */
+ err_SE, /* { dg-warning "int" } */
+ err_PT /* { dg-warning "int" } */
};
static enum err E_;
int error()