Commit cbb4feb3 by Jason Merrill Committed by Jason Merrill

re PR c++/43680 ([DR 1022] G++ is too aggressive in optimizing away bounds checking with enums)

	PR c++/43680
gcc:
	* c.opt (-fstrict-enums): New.
	* doc/invoke.texi (C++ Dialect Options): Document -fstrict-enums.
gcc/cp:
	* 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.

From-SVN: r159006
parent e492f63b
2010-04-26 Jason Merrill <jason@redhat.com>
* c.opt (-fstrict-enums): New.
* doc/invoke.texi (C++ Dialect Options): Document -fstrict-enums.
2010-05-03 David Ung <davidu@mips.com> 2010-05-03 David Ung <davidu@mips.com>
James E. Wilson <wilson@codesourcery.com> James E. Wilson <wilson@codesourcery.com>
......
...@@ -783,6 +783,10 @@ fstats ...@@ -783,6 +783,10 @@ fstats
C++ ObjC++ C++ ObjC++
Display statistics accumulated during compilation 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 fstrict-prototype
C++ ObjC++ C++ ObjC++
......
2010-05-03 Jason Merrill <jason@redhat.com>
PR c++/42810
PR c++/43680
* 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.
2010-05-01 H.J. Lu <hongjiu.lu@intel.com> 2010-05-01 H.J. Lu <hongjiu.lu@intel.com>
PR c++/43951 PR c++/43951
......
...@@ -2786,14 +2786,8 @@ check_bitfield_decl (tree field) ...@@ -2786,14 +2786,8 @@ check_bitfield_decl (tree field)
&& TREE_CODE (type) != BOOLEAN_TYPE) && TREE_CODE (type) != BOOLEAN_TYPE)
warning (0, "width of %q+D exceeds its type", field); warning (0, "width of %q+D exceeds its type", field);
else if (TREE_CODE (type) == ENUMERAL_TYPE else if (TREE_CODE (type) == ENUMERAL_TYPE
&& (0 > compare_tree_int (w, && (0 > (compare_tree_int
tree_int_cst_min_precision (w, TYPE_PRECISION (ENUM_UNDERLYING_TYPE (type))))))
(TYPE_MIN_VALUE (type),
TYPE_UNSIGNED (type)))
|| 0 > compare_tree_int (w,
tree_int_cst_min_precision
(TYPE_MAX_VALUE (type),
TYPE_UNSIGNED (type)))))
warning (0, "%q+D is too small to hold all values of %q#T", field, type); warning (0, "%q+D is too small to hold all values of %q#T", field, type);
} }
......
...@@ -682,7 +682,8 @@ ocp_convert (tree type, tree expr, int convtype, int flags) ...@@ -682,7 +682,8 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
the original value is within the range of the enumeration the original value is within the range of the enumeration
values. Otherwise, the resulting enumeration value is values. Otherwise, the resulting enumeration value is
unspecified. */ 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, warning (OPT_Wconversion,
"the result of the conversion is unspecified because " "the result of the conversion is unspecified because "
"%qE is outside the range of type %qT", "%qE is outside the range of type %qT",
...@@ -1311,6 +1312,8 @@ type_promotes_to (tree type) ...@@ -1311,6 +1312,8 @@ type_promotes_to (tree type)
int precision = MAX (TYPE_PRECISION (type), int precision = MAX (TYPE_PRECISION (type),
TYPE_PRECISION (integer_type_node)); TYPE_PRECISION (integer_type_node));
tree totype = c_common_type_for_size (precision, 0); tree totype = c_common_type_for_size (precision, 0);
if (TREE_CODE (type) == ENUMERAL_TYPE)
type = ENUM_UNDERLYING_TYPE (type);
if (TYPE_UNSIGNED (type) if (TYPE_UNSIGNED (type)
&& ! int_fits_type_p (TYPE_MAX_VALUE (type), totype)) && ! int_fits_type_p (TYPE_MAX_VALUE (type), totype))
type = c_common_type_for_size (precision, 1); type = c_common_type_for_size (precision, 1);
......
...@@ -11255,12 +11255,6 @@ finish_enum (tree enumtype) ...@@ -11255,12 +11255,6 @@ finish_enum (tree enumtype)
tree maxnode; tree maxnode;
tree value; tree value;
tree t; tree t;
bool unsignedp;
bool use_short_enum;
int lowprec;
int highprec;
int precision;
unsigned int itk;
tree underlying_type = NULL_TREE; tree underlying_type = NULL_TREE;
bool fixed_underlying_type_p bool fixed_underlying_type_p
= ENUM_UNDERLYING_TYPE (enumtype) != NULL_TREE; = ENUM_UNDERLYING_TYPE (enumtype) != NULL_TREE;
...@@ -11323,17 +11317,19 @@ finish_enum (tree enumtype) ...@@ -11323,17 +11317,19 @@ finish_enum (tree enumtype)
the enumeration had a single enumerator with value 0. */ the enumeration had a single enumerator with value 0. */
minnode = maxnode = integer_zero_node; minnode = maxnode = integer_zero_node;
if (!fixed_underlying_type_p)
{
/* Compute the number of bits require to represent all values of the /* Compute the number of bits require to represent all values of the
enumeration. We must do this before the type of MINNODE and enumeration. We must do this before the type of MINNODE and
MAXNODE are transformed, since tree_int_cst_min_precision relies MAXNODE are transformed, since tree_int_cst_min_precision relies
on the TREE_TYPE of the value it is passed. */ on the TREE_TYPE of the value it is passed. */
unsignedp = tree_int_cst_sgn (minnode) >= 0; bool unsignedp = tree_int_cst_sgn (minnode) >= 0;
lowprec = tree_int_cst_min_precision (minnode, unsignedp); int lowprec = tree_int_cst_min_precision (minnode, unsignedp);
highprec = tree_int_cst_min_precision (maxnode, unsignedp); int highprec = tree_int_cst_min_precision (maxnode, unsignedp);
precision = MAX (lowprec, highprec); int precision = MAX (lowprec, highprec);
unsigned int itk;
bool use_short_enum;
if (!fixed_underlying_type_p)
{
/* Determine the underlying type of the enumeration. /* Determine the underlying type of the enumeration.
[dcl.enum] [dcl.enum]
...@@ -11380,24 +11376,16 @@ finish_enum (tree enumtype) ...@@ -11380,24 +11376,16 @@ finish_enum (tree enumtype)
The value of sizeof() applied to an enumeration type, an object The value of sizeof() applied to an enumeration type, an object
of an enumeration type, or an enumerator, is the value of sizeof() of an enumeration type, or an enumerator, is the value of sizeof()
applied to the underlying type. */ 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 (enumtype) = TYPE_SIZE (underlying_type);
TYPE_SIZE_UNIT (enumtype) = TYPE_SIZE_UNIT (underlying_type); TYPE_SIZE_UNIT (enumtype) = TYPE_SIZE_UNIT (underlying_type);
SET_TYPE_MODE (enumtype, TYPE_MODE (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_ALIGN (enumtype) = TYPE_ALIGN (underlying_type);
TYPE_USER_ALIGN (enumtype) = TYPE_USER_ALIGN (underlying_type); TYPE_USER_ALIGN (enumtype) = TYPE_USER_ALIGN (underlying_type);
TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (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)
= build_distinct_type_copy (underlying_type);
set_min_and_max_values_for_integral_type
(ENUM_UNDERLYING_TYPE (enumtype), precision, unsignedp);
}
else
underlying_type = ENUM_UNDERLYING_TYPE (enumtype);
/* Compute the minimum and maximum values for the type. /* Compute the minimum and maximum values for the type.
[dcl.enum] [dcl.enum]
...@@ -11410,12 +11398,28 @@ finish_enum (tree enumtype) ...@@ -11410,12 +11398,28 @@ finish_enum (tree enumtype)
/* The middle-end currently assumes that types with TYPE_PRECISION /* The middle-end currently assumes that types with TYPE_PRECISION
narrower than their underlying type are suitably zero or sign narrower than their underlying type are suitably zero or sign
extended to fill their mode. g++ doesn't make these guarantees. extended to fill their mode. Similarly, it assumes that the front
Until the middle-end can represent such paradoxical types, we end assures that a value of a particular type must be within
set the TYPE_PRECISION to the width of the underlying type. */ TYPE_MIN_VALUE and TYPE_MAX_VALUE.
TYPE_PRECISION (enumtype) = TYPE_PRECISION (underlying_type);
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);
set_min_and_max_values_for_integral_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);
/* Convert each of the enumerators to the type of the underlying /* Convert each of the enumerators to the type of the underlying
type of the enumeration. */ type of the enumeration. */
......
...@@ -1982,6 +1982,15 @@ unambiguous base classes. ...@@ -1982,6 +1982,15 @@ unambiguous base classes.
Emit statistics about front-end processing at the end of the compilation. Emit statistics about front-end processing at the end of the compilation.
This information is generally only useful to the G++ development team. 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} @item -ftemplate-depth=@var{n}
@opindex ftemplate-depth @opindex ftemplate-depth
Set the maximum instantiation depth for template classes to @var{n}. Set the maximum instantiation depth for template classes to @var{n}.
......
2010-05-03 Jason Merrill <jason@redhat.com>
PR c++/43680
* g++.dg/opt/enum2.C: New.
* g++.dg/warn/pr33738.C: Use -fstrict-enums.
* g++.dg/warn/Wswitch-1.C: Adjust message.
2010-05-03 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> 2010-05-03 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* g++.dg/cdce3.C: Skip on alpha*-dec-osf5*. * g++.dg/cdce3.C: Skip on alpha*-dec-osf5*.
......
// 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));
}
...@@ -50,13 +50,13 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, ...@@ -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 e1: return 1;
case e2: return 2; case e2: return 2;
case 3: return 3; /* { dg-warning "exceeds maximum value" } */ case 3: return 3; /* { dg-warning "case value" } */
} }
switch (ep) switch (ep)
{ {
case e1: return 1; case e1: return 1;
case e2: return 2; case e2: return 2;
case 3: return 3; /* { dg-warning "exceeds maximum value" } */ case 3: return 3; /* { dg-warning "case value" } */
default: break; default: break;
} }
return 0; return 0;
......
// { dg-do run } // { dg-do run }
// { dg-options "-O2 -Wtype-limits" } // { dg-options "-O2 -Wtype-limits -fstrict-enums" }
extern void link_error (void); extern void link_error (void);
enum Alpha { enum Alpha {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment