From 265133917c2cc24309c97b0836007742407469a0 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 25 May 2011 22:23:02 -0400 Subject: [PATCH] re PR c++/48536 ([C++0x] Automatic Enumerator Incrementation is not compliant with Clause 7.2/5) 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 | 4 ++ gcc/cp/decl.c | 41 +++++++++++++++++--- gcc/testsuite/ChangeLog | 3 ++ gcc/testsuite/g++.dg/cpp0x/enum17.C | 17 ++++++++ gcc/testsuite/g++.old-deja/g++.jason/rfg10.C | 3 +- 5 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/enum17.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index dad97add6c4..6277596f6ce 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2011-05-25 Jason Merrill + 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. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 58cab51ab81..8ab0c8afc7f 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 %" : "\ +incremented enumerator value is too large for %"); + } + if (type == NULL_TREE) + overflowed = true; + else + value = double_int_to_tree (type, di); + } if (overflowed) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bcef9a9df22..367bd881fa6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2011-05-25 Jason Merrill + * 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 index 00000000000..8ba827e50f4 --- /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 + +// 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 f6d5af3a8b8..58af19c3364 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 @@ -7,5 +8,5 @@ enum COLOR { red, green = ULONG_MAX, - blue // { dg-error "overflow in enumeration" } + blue // { dg-error "too large for .unsigned long" } }; -- 2.30.2