]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/43680 ([DR 1022] G++ is too aggressive in optimizing away bounds checking...
authorJason Merrill <jason@redhat.com>
Mon, 3 May 2010 21:16:40 +0000 (17:16 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 3 May 2010 21:16:40 +0000 (17:16 -0400)
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

gcc/ChangeLog
gcc/c.opt
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/opt/enum2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wswitch-1.C
gcc/testsuite/g++.dg/warn/pr33738.C

index f7fffbd9a468a6934ca3d93890192eb8c0e25d1d..30f3ea13fd9d06a4c85fd06531bc28f7c7f82be8 100644 (file)
@@ -1,3 +1,8 @@
+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>
            James E. Wilson  <wilson@codesourcery.com>
 
index 2e1933cd0d1717321860701ef85c6f26c9732e2a..3ab29830886a38327830dac9b36737ca63f770cc 100644 (file)
--- a/gcc/c.opt
+++ b/gcc/c.opt
@@ -783,6 +783,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++
 
index 51559e8aee605acd82989ea65141ab6275a4ac5b..8175f146aa1eb40eafa5e950d0a30e7dab2eafc8 100644 (file)
@@ -1,3 +1,13 @@
+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>
 
        PR c++/43951
index c640af4d5b64d7ee83778a56462c58e023e978b3..87f8111f15fece47d6cf46819ef21fb50584a108 100644 (file)
@@ -2786,14 +2786,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);
     }
 
index 1f87c5f8c263f623c1e4f277f3dc077fe7ed915a..5be0b8d8f305641772d4f9f433a194110dc4dbb9 100644 (file)
@@ -682,7 +682,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",
@@ -1311,6 +1312,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);
index 346b7b43646abc890b433eb2ff0741646ae9d00a..563628287174374a40f0829813de664cd5746f8e 100644 (file)
@@ -11255,12 +11255,6 @@ finish_enum (tree enumtype)
   tree maxnode;
   tree value;
   tree t;
-  bool unsignedp;
-  bool use_short_enum;
-  int lowprec;
-  int highprec;
-  int precision;
-  unsigned int itk;
   tree underlying_type = NULL_TREE;
   bool fixed_underlying_type_p 
     = ENUM_UNDERLYING_TYPE (enumtype) != NULL_TREE;
@@ -11323,17 +11317,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]
@@ -11380,43 +11376,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. */
+      /* 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);
-      set_min_and_max_values_for_integral_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))
index fefb0abd1d55e974c355ce5b261d1572c4528927..b2fbd48becdfd854aaa4632d68fa024ed4265519 100644 (file)
@@ -1982,6 +1982,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}.
index 1f7fe55be5729c62817b1a6546ec0140546e7295..722ee1e46a9837115b4855f75aad0002b02f5687 100644 (file)
@@ -1,3 +1,10 @@
+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>
 
        * g++.dg/cdce3.C: Skip on alpha*-dec-osf5*.
diff --git a/gcc/testsuite/g++.dg/opt/enum2.C b/gcc/testsuite/g++.dg/opt/enum2.C
new file mode 100644 (file)
index 0000000..6300896
--- /dev/null
@@ -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));
+}
index 6a2094466cf5c2984bb0ba6cfc1e526b3aec63cd..1da7180ec79c068aef2d35d5205be188b31eb0c9 100644 (file)
@@ -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; /* { dg-warning "case value" } */
     default: break;
     }
   return 0;
index 8847b6e342cd6449ffef548bcb2e5e454412c5d6..e84fece13f669bb2e9e16a876892b3a9af4f6a5a 100644 (file)
@@ -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 {