302 lines
12 KiB
Diff
302 lines
12 KiB
Diff
|
2012-05-03 Jason Merrill <jason@redhat.com>
|
||
|
|
||
|
PR c++/43680
|
||
|
* c.opt (-fstrict-enums): New.
|
||
|
* doc/invoke.texi (C++ Dialect Options): Document -fstrict-enums.
|
||
|
* tree-vrp.c (needs_overflow_infinity): TREE_TYPE of an
|
||
|
ENUMERAL_TYPE is not an integer base type.
|
||
|
(vrp_val_min, vrp_val_max): Likewise.
|
||
|
(extract_range_from_binary_expr): Likewise.
|
||
|
|
||
|
* decl.c (finish_enum): Use the TYPE_MIN_VALUE and TYPE_MAX_VALUE
|
||
|
from the selected underlying type unless -fstrict-enums. Set
|
||
|
ENUM_UNDERLYING_TYPE to have the restricted range.
|
||
|
* cvt.c (type_promotes_to): Use ENUM_UNDERLYING_TYPE.
|
||
|
* class.c (check_bitfield_decl): Likewise.
|
||
|
|
||
|
--- gcc/c.opt
|
||
|
+++ gcc/c.opt
|
||
|
@@ -759,6 +759,10 @@ fstats
|
||
|
C++ ObjC++
|
||
|
Display statistics accumulated during compilation
|
||
|
|
||
|
+fstrict-enums
|
||
|
+C++ ObjC++ Optimization Var(flag_strict_enums)
|
||
|
+Assume that values of enumeration type are always within the minimum range of that type
|
||
|
+
|
||
|
fstrict-prototype
|
||
|
C++ ObjC++
|
||
|
|
||
|
--- gcc/cp/class.c
|
||
|
+++ gcc/cp/class.c
|
||
|
@@ -2727,14 +2727,8 @@ check_bitfield_decl (tree field)
|
||
|
&& TREE_CODE (type) != BOOLEAN_TYPE)
|
||
|
warning (0, "width of %q+D exceeds its type", field);
|
||
|
else if (TREE_CODE (type) == ENUMERAL_TYPE
|
||
|
- && (0 > compare_tree_int (w,
|
||
|
- tree_int_cst_min_precision
|
||
|
- (TYPE_MIN_VALUE (type),
|
||
|
- TYPE_UNSIGNED (type)))
|
||
|
- || 0 > compare_tree_int (w,
|
||
|
- tree_int_cst_min_precision
|
||
|
- (TYPE_MAX_VALUE (type),
|
||
|
- TYPE_UNSIGNED (type)))))
|
||
|
+ && (0 > (compare_tree_int
|
||
|
+ (w, TYPE_PRECISION (ENUM_UNDERLYING_TYPE (type))))))
|
||
|
warning (0, "%q+D is too small to hold all values of %q#T", field, type);
|
||
|
}
|
||
|
|
||
|
--- gcc/cp/cvt.c
|
||
|
+++ gcc/cp/cvt.c
|
||
|
@@ -662,7 +662,8 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
|
||
|
the original value is within the range of the enumeration
|
||
|
values. Otherwise, the resulting enumeration value is
|
||
|
unspecified. */
|
||
|
- if (TREE_CODE (expr) == INTEGER_CST && !int_fits_type_p (expr, type))
|
||
|
+ if (TREE_CODE (expr) == INTEGER_CST
|
||
|
+ && !int_fits_type_p (expr, ENUM_UNDERLYING_TYPE (type)))
|
||
|
warning (OPT_Wconversion,
|
||
|
"the result of the conversion is unspecified because "
|
||
|
"%qE is outside the range of type %qT",
|
||
|
@@ -1251,6 +1252,8 @@ type_promotes_to (tree type)
|
||
|
int precision = MAX (TYPE_PRECISION (type),
|
||
|
TYPE_PRECISION (integer_type_node));
|
||
|
tree totype = c_common_type_for_size (precision, 0);
|
||
|
+ if (TREE_CODE (type) == ENUMERAL_TYPE)
|
||
|
+ type = ENUM_UNDERLYING_TYPE (type);
|
||
|
if (TYPE_UNSIGNED (type)
|
||
|
&& ! int_fits_type_p (TYPE_MAX_VALUE (type), totype))
|
||
|
type = c_common_type_for_size (precision, 1);
|
||
|
--- gcc/cp/decl.c
|
||
|
+++ gcc/cp/decl.c
|
||
|
@@ -11070,12 +11070,6 @@ finish_enum (tree enumtype)
|
||
|
tree maxnode;
|
||
|
tree value;
|
||
|
tree t;
|
||
|
- bool unsignedp;
|
||
|
- bool use_short_enum;
|
||
|
- int lowprec;
|
||
|
- int highprec;
|
||
|
- int precision;
|
||
|
- integer_type_kind itk;
|
||
|
tree underlying_type = NULL_TREE;
|
||
|
bool fixed_underlying_type_p
|
||
|
= ENUM_UNDERLYING_TYPE (enumtype) != NULL_TREE;
|
||
|
@@ -11138,17 +11132,19 @@ finish_enum (tree enumtype)
|
||
|
the enumeration had a single enumerator with value 0. */
|
||
|
minnode = maxnode = integer_zero_node;
|
||
|
|
||
|
- /* Compute the number of bits require to represent all values of the
|
||
|
- enumeration. We must do this before the type of MINNODE and
|
||
|
- MAXNODE are transformed, since tree_int_cst_min_precision relies
|
||
|
- on the TREE_TYPE of the value it is passed. */
|
||
|
- unsignedp = tree_int_cst_sgn (minnode) >= 0;
|
||
|
- lowprec = tree_int_cst_min_precision (minnode, unsignedp);
|
||
|
- highprec = tree_int_cst_min_precision (maxnode, unsignedp);
|
||
|
- precision = MAX (lowprec, highprec);
|
||
|
-
|
||
|
if (!fixed_underlying_type_p)
|
||
|
{
|
||
|
+ /* Compute the number of bits require to represent all values of the
|
||
|
+ enumeration. We must do this before the type of MINNODE and
|
||
|
+ MAXNODE are transformed, since tree_int_cst_min_precision relies
|
||
|
+ on the TREE_TYPE of the value it is passed. */
|
||
|
+ bool unsignedp = tree_int_cst_sgn (minnode) >= 0;
|
||
|
+ int lowprec = tree_int_cst_min_precision (minnode, unsignedp);
|
||
|
+ int highprec = tree_int_cst_min_precision (maxnode, unsignedp);
|
||
|
+ int precision = MAX (lowprec, highprec);
|
||
|
+ unsigned int itk;
|
||
|
+ bool use_short_enum;
|
||
|
+
|
||
|
/* Determine the underlying type of the enumeration.
|
||
|
|
||
|
[dcl.enum]
|
||
|
@@ -11195,42 +11191,51 @@ finish_enum (tree enumtype)
|
||
|
The value of sizeof() applied to an enumeration type, an object
|
||
|
of an enumeration type, or an enumerator, is the value of sizeof()
|
||
|
applied to the underlying type. */
|
||
|
+ TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (underlying_type);
|
||
|
+ TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (underlying_type);
|
||
|
TYPE_SIZE (enumtype) = TYPE_SIZE (underlying_type);
|
||
|
TYPE_SIZE_UNIT (enumtype) = TYPE_SIZE_UNIT (underlying_type);
|
||
|
SET_TYPE_MODE (enumtype, TYPE_MODE (underlying_type));
|
||
|
+ TYPE_PRECISION (enumtype) = TYPE_PRECISION (underlying_type);
|
||
|
TYPE_ALIGN (enumtype) = TYPE_ALIGN (underlying_type);
|
||
|
TYPE_USER_ALIGN (enumtype) = TYPE_USER_ALIGN (underlying_type);
|
||
|
TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (underlying_type);
|
||
|
|
||
|
- /* Set the underlying type of the enumeration type to the
|
||
|
- computed enumeration type, restricted to the enumerator
|
||
|
- values. */
|
||
|
- ENUM_UNDERLYING_TYPE (enumtype) = copy_node (underlying_type);
|
||
|
- set_min_and_max_values_for_integral_type
|
||
|
+ /* Compute the minimum and maximum values for the type.
|
||
|
+
|
||
|
+ [dcl.enum]
|
||
|
+
|
||
|
+ For an enumeration where emin is the smallest enumerator and emax
|
||
|
+ is the largest, the values of the enumeration are the values of the
|
||
|
+ underlying type in the range bmin to bmax, where bmin and bmax are,
|
||
|
+ respectively, the smallest and largest values of the smallest bit-
|
||
|
+ field that can store emin and emax. */
|
||
|
+
|
||
|
+ /* The middle-end currently assumes that types with TYPE_PRECISION
|
||
|
+ narrower than their underlying type are suitably zero or sign
|
||
|
+ extended to fill their mode. Similarly, it assumes that the front
|
||
|
+ end assures that a value of a particular type must be within
|
||
|
+ TYPE_MIN_VALUE and TYPE_MAX_VALUE.
|
||
|
+
|
||
|
+ We used to set these fields based on bmin and bmax, but that led
|
||
|
+ to invalid assumptions like optimizing away bounds checking. So
|
||
|
+ now we just set the TYPE_PRECISION, TYPE_MIN_VALUE, and
|
||
|
+ TYPE_MAX_VALUE to the values for the mode above and only restrict
|
||
|
+ the ENUM_UNDERLYING_TYPE for the benefit of diagnostics. */
|
||
|
+ ENUM_UNDERLYING_TYPE (enumtype)
|
||
|
+ = build_distinct_type_copy (underlying_type);
|
||
|
+ TYPE_PRECISION (ENUM_UNDERLYING_TYPE (enumtype)) = precision;
|
||
|
+ set_min_and_max_values_for_integral_type
|
||
|
(ENUM_UNDERLYING_TYPE (enumtype), precision, unsignedp);
|
||
|
+
|
||
|
+ /* If -fstrict-enums, still constrain TYPE_MIN/MAX_VALUE. */
|
||
|
+ if (flag_strict_enums)
|
||
|
+ set_min_and_max_values_for_integral_type (enumtype, precision,
|
||
|
+ unsignedp);
|
||
|
}
|
||
|
else
|
||
|
underlying_type = ENUM_UNDERLYING_TYPE (enumtype);
|
||
|
|
||
|
- /* Compute the minimum and maximum values for the type.
|
||
|
-
|
||
|
- [dcl.enum]
|
||
|
-
|
||
|
- For an enumeration where emin is the smallest enumerator and emax
|
||
|
- is the largest, the values of the enumeration are the values of the
|
||
|
- underlying type in the range bmin to bmax, where bmin and bmax are,
|
||
|
- respectively, the smallest and largest values of the smallest bit-
|
||
|
- field that can store emin and emax. */
|
||
|
-
|
||
|
- /* The middle-end currently assumes that types with TYPE_PRECISION
|
||
|
- narrower than their underlying type are suitably zero or sign
|
||
|
- extended to fill their mode. g++ doesn't make these guarantees.
|
||
|
- Until the middle-end can represent such paradoxical types, we
|
||
|
- set the TYPE_PRECISION to the width of the underlying type. */
|
||
|
- TYPE_PRECISION (enumtype) = TYPE_PRECISION (underlying_type);
|
||
|
-
|
||
|
- set_min_and_max_values_for_integral_type (enumtype, precision, unsignedp);
|
||
|
-
|
||
|
/* Convert each of the enumerators to the type of the underlying
|
||
|
type of the enumeration. */
|
||
|
for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN (values))
|
||
|
--- gcc/doc/invoke.texi
|
||
|
+++ gcc/doc/invoke.texi
|
||
|
@@ -1877,6 +1877,15 @@ unambiguous base classes.
|
||
|
Emit statistics about front-end processing at the end of the compilation.
|
||
|
This information is generally only useful to the G++ development team.
|
||
|
|
||
|
+@item -fstrict-enums
|
||
|
+@opindex fstrict-enums
|
||
|
+Allow the compiler to optimize using the assumption that a value of
|
||
|
+enumeration type can only be one of the values of the enumeration (as
|
||
|
+defined in the C++ standard; basically, a value which can be
|
||
|
+represented in the minimum number of bits needed to represent all the
|
||
|
+enumerators). This assumption may not be valid if the program uses a
|
||
|
+cast to convert an arbitrary integer value to the enumeration type.
|
||
|
+
|
||
|
@item -ftemplate-depth-@var{n}
|
||
|
@opindex ftemplate-depth
|
||
|
Set the maximum instantiation depth for template classes to @var{n}.
|
||
|
--- gcc/tree-vrp.c
|
||
|
+++ gcc/tree-vrp.c
|
||
|
@@ -130,7 +130,7 @@ vrp_val_max (const_tree type)
|
||
|
return NULL_TREE;
|
||
|
|
||
|
/* For integer sub-types the values for the base type are relevant. */
|
||
|
- if (TREE_TYPE (type))
|
||
|
+ if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type))
|
||
|
type = TREE_TYPE (type);
|
||
|
|
||
|
return TYPE_MAX_VALUE (type);
|
||
|
@@ -145,7 +145,7 @@ vrp_val_min (const_tree type)
|
||
|
return NULL_TREE;
|
||
|
|
||
|
/* For integer sub-types the values for the base type are relevant. */
|
||
|
- if (TREE_TYPE (type))
|
||
|
+ if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type))
|
||
|
type = TREE_TYPE (type);
|
||
|
|
||
|
return TYPE_MIN_VALUE (type);
|
||
|
@@ -192,7 +192,8 @@ needs_overflow_infinity (const_tree type)
|
||
|
&& !TYPE_OVERFLOW_WRAPS (type)
|
||
|
/* Integer sub-types never overflow as they are never
|
||
|
operands of arithmetic operators. */
|
||
|
- && !(TREE_TYPE (type) && TREE_TYPE (type) != type));
|
||
|
+ && !(TREE_CODE (type) == INTEGER_TYPE
|
||
|
+ && TREE_TYPE (type) && TREE_TYPE (type) != type));
|
||
|
}
|
||
|
|
||
|
/* Return whether TYPE can support our overflow infinity
|
||
|
@@ -2720,9 +2721,9 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
|
||
|
|
||
|
/* Always use base-types here. This is important for the
|
||
|
correct signedness. */
|
||
|
- if (TREE_TYPE (inner_type))
|
||
|
+ if (TREE_CODE (inner_type) == INTEGER_TYPE && TREE_TYPE (inner_type))
|
||
|
inner_type = TREE_TYPE (inner_type);
|
||
|
- if (TREE_TYPE (outer_type))
|
||
|
+ if (TREE_CODE (outer_type) == INTEGER_TYPE && TREE_TYPE (outer_type))
|
||
|
outer_type = TREE_TYPE (outer_type);
|
||
|
|
||
|
/* If VR0 is varying and we increase the type precision, assume
|
||
|
--- gcc/testsuite/g++.dg/opt/enum2.C
|
||
|
+++ gcc/testsuite/g++.dg/opt/enum2.C
|
||
|
@@ -0,0 +1,21 @@
|
||
|
+// PR c++/43680
|
||
|
+// Test that we don't make excessively aggressive assumptions about what
|
||
|
+// values an enum variable can have.
|
||
|
+// { dg-options "-O2 -fPIC" }
|
||
|
+// { dg-do run }
|
||
|
+
|
||
|
+extern "C" void abort ();
|
||
|
+
|
||
|
+enum E { A, B, C, D };
|
||
|
+
|
||
|
+void
|
||
|
+CheckE(const E value)
|
||
|
+{
|
||
|
+ long v = value;
|
||
|
+ if (v <= D)
|
||
|
+ abort ();
|
||
|
+}
|
||
|
+
|
||
|
+int main() {
|
||
|
+ CheckE(static_cast<E>(5));
|
||
|
+}
|
||
|
--- gcc/testsuite/g++.dg/warn/Wswitch-1.C
|
||
|
+++ gcc/testsuite/g++.dg/warn/Wswitch-1.C
|
||
|
@@ -50,13 +50,13 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el,
|
||
|
{
|
||
|
case e1: return 1;
|
||
|
case e2: return 2;
|
||
|
- case 3: return 3; /* { dg-warning "exceeds maximum value" } */
|
||
|
+ case 3: return 3; /* { dg-warning "case value" } */
|
||
|
}
|
||
|
switch (ep)
|
||
|
{
|
||
|
case e1: return 1;
|
||
|
case e2: return 2;
|
||
|
- case 3: return 3; /* { dg-warning "exceeds maximum value" } */
|
||
|
+ case 3: return 3;
|
||
|
default: break;
|
||
|
}
|
||
|
return 0;
|
||
|
--- gcc/testsuite/g++.dg/warn/pr33738.C
|
||
|
+++ gcc/testsuite/g++.dg/warn/pr33738.C
|
||
|
@@ -1,5 +1,5 @@
|
||
|
// { dg-do run }
|
||
|
-// { dg-options "-O2 -Wtype-limits" }
|
||
|
+// { dg-options "-O2 -Wtype-limits -fstrict-enums" }
|
||
|
extern void link_error (void);
|
||
|
|
||
|
enum Alpha {
|
||
|
|