diff options
author | Jason Merrill <jason@redhat.com> | 2011-05-25 22:23:02 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2011-05-25 22:23:02 -0400 |
commit | 265133917c2cc24309c97b0836007742407469a0 (patch) | |
tree | e67f36fe735543b104f9dc811c2c3459aae0d708 /gcc | |
parent | 5df0c0c767de7cc44474504d0de8e15ac96c97b9 (diff) | |
download | gcc-265133917c2cc24309c97b0836007742407469a0.zip gcc-265133917c2cc24309c97b0836007742407469a0.tar.gz gcc-265133917c2cc24309c97b0836007742407469a0.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/cp/decl.c | 41 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 3 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/enum17.C | 17 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.jason/rfg10.C | 3 |
5 files changed, 61 insertions, 7 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index dad97ad..6277596 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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. 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/ChangeLog b/gcc/testsuite/ChangeLog index bcef9a9..367bd88 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 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" } }; |