Blame SOURCES/gcc44-pr43680.patch

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