OSDN Git Service

Correct conversion/overflow behavior.
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 8 Nov 2010 20:17:42 +0000 (20:17 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 8 Nov 2010 20:17:42 +0000 (20:17 +0000)
* cvt.c (ignore_overflows): Move here from typeck.c.
(ocp_convert): Use it.
(cp_fold_convert): Use it.  Don't call rvalue.
* typeck.c (build_static_cast_1): Don't use it.  Do call rvalue.
* error.c (location_of): Handle expressions, too.
* class.c (check_bitfield_decl): Set input_location around call to
cxx_constant_value.
* semantics.c (cxx_eval_outermost_constant_expr): Don't
print the expression if it already had TREE_OVERFLOW set.
(reduced_constant_expression_p): Check TREE_OVERFLOW_P for C++98, too.
(verify_constant): Allow overflow with a permerror if we're
enforcing.
(cxx_eval_outermost_constant_expr): Use verify_constant.
(adjust_temp_type): Use cp_fold_convert.
* decl.c (build_enumerator): Don't call constant_expression_warning.
* decl2.c (grokbitfield): Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@166453 138bc75d-0d04-0410-961f-82ee72b054a4

16 files changed:
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/error.c
gcc/cp/semantics.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/expr/overflow1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/overflow-warn-1.C
gcc/testsuite/g++.dg/warn/overflow-warn-3.C
gcc/testsuite/g++.dg/warn/overflow-warn-4.C
gcc/testsuite/g++.dg/warn/overflow-warn-5.C
libstdc++-v3/ChangeLog
libstdc++-v3/testsuite/20_util/ratio/cons/cons_overflow_neg.cc

index 1a40ee0..4f08ec3 100644 (file)
@@ -1,3 +1,23 @@
+2010-11-08  Jason Merrill  <jason@redhat.com>
+
+       Correct conversion/overflow behavior.
+       * cvt.c (ignore_overflows): Move here from typeck.c.
+       (ocp_convert): Use it.
+       (cp_fold_convert): Use it.  Don't call rvalue.
+       * typeck.c (build_static_cast_1): Don't use it.  Do call rvalue.
+       * error.c (location_of): Handle expressions, too.
+       * class.c (check_bitfield_decl): Set input_location around call to
+       cxx_constant_value.
+       * semantics.c (cxx_eval_outermost_constant_expr): Don't
+       print the expression if it already had TREE_OVERFLOW set.
+       (reduced_constant_expression_p): Check TREE_OVERFLOW_P for C++98, too.
+       (verify_constant): Allow overflow with a permerror if we're
+       enforcing.
+       (cxx_eval_outermost_constant_expr): Use verify_constant.
+       (adjust_temp_type): Use cp_fold_convert.
+       * decl.c (build_enumerator): Don't call constant_expression_warning.
+       * decl2.c (grokbitfield): Likewise.
+
 2010-11-06  Jason Merrill  <jason@redhat.com>
 
        PR c++/46348
index 435fa71..03951cf 100644 (file)
@@ -2797,11 +2797,14 @@ check_bitfield_decl (tree field)
     }
   else
     {
+      location_t loc = input_location;
       /* Avoid the non_lvalue wrapper added by fold for PLUS_EXPRs.  */
       STRIP_NOPS (w);
 
       /* detect invalid field size.  */
+      input_location = DECL_SOURCE_LOCATION (field);
       w = cxx_constant_value (w);
+      input_location = loc;
 
       if (TREE_CODE (w) != INTEGER_CST)
        {
index d2d6f4a..2f7823f 100644 (file)
@@ -543,12 +543,35 @@ force_rvalue (tree expr)
 }
 
 \f
-/* Fold away simple conversions, but make sure the result is an rvalue.  */
+/* If EXPR and ORIG are INTEGER_CSTs, return a version of EXPR that has
+   TREE_OVERFLOW set only if it is set in ORIG.  Otherwise, return EXPR
+   unchanged.  */
+
+static tree
+ignore_overflows (tree expr, tree orig)
+{
+  if (TREE_CODE (expr) == INTEGER_CST
+      && TREE_CODE (orig) == INTEGER_CST
+      && TREE_OVERFLOW (expr) != TREE_OVERFLOW (orig))
+    {
+      gcc_assert (!TREE_OVERFLOW (orig));
+      /* Ensure constant sharing.  */
+      expr = build_int_cst_wide (TREE_TYPE (expr),
+                                TREE_INT_CST_LOW (expr),
+                                TREE_INT_CST_HIGH (expr));
+    }
+  return expr;
+}
+
+/* Fold away simple conversions, but make sure TREE_OVERFLOW is set
+   properly.  */
 
 tree
 cp_fold_convert (tree type, tree expr)
 {
-  return rvalue (fold_convert (type, expr));
+  tree conv = fold_convert (type, expr);
+  conv = ignore_overflows (conv, expr);
+  return conv;
 }
 
 /* C++ conversions, preference to static cast conversions.  */
@@ -661,6 +684,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
   if (INTEGRAL_CODE_P (code))
     {
       tree intype = TREE_TYPE (e);
+      tree converted;
 
       if (TREE_CODE (type) == ENUMERAL_TYPE)
        {
@@ -705,7 +729,10 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
       if (code == BOOLEAN_TYPE)
        return cp_truthvalue_conversion (e);
 
-      return fold_if_not_in_template (convert_to_integer (type, e));
+      converted = fold_if_not_in_template (convert_to_integer (type, e));
+
+      /* Ignore any integer overflow caused by the conversion.  */
+      return ignore_overflows (converted, e);
     }
   if (NULLPTR_TYPE_P (type) && e && null_ptr_cst_p (e))
     return nullptr_node;
index fb5ca7f..c372840 100644 (file)
@@ -11823,7 +11823,6 @@ build_enumerator (tree name, tree value, tree enumtype, location_t loc)
          if (TREE_CODE (value) == INTEGER_CST)
            {
              value = perform_integral_promotions (value);
-             constant_expression_warning (value);
            }
          else
            {
index a805c6b..e00549e 100644 (file)
@@ -1054,7 +1054,6 @@ grokbitfield (const cp_declarator *declarator,
       if (!INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (width)))
        error ("width of bit-field %qD has non-integral type %qT", value,
               TREE_TYPE (width));
-      constant_expression_warning (width);
       DECL_INITIAL (value) = width;
       SET_DECL_C_BIT_FIELD (value);
     }
index 6f60c06..1560fc6 100644 (file)
@@ -2469,7 +2469,9 @@ location_of (tree t)
   else if (TREE_CODE (t) == OVERLOAD)
     t = OVL_FUNCTION (t);
 
-  return DECL_SOURCE_LOCATION (t);
+  if (DECL_P (t))
+    return DECL_SOURCE_LOCATION (t);
+  return EXPR_LOC_OR_HERE (t);
 }
 
 /* Now the interfaces from error et al to dump_type et al. Each takes an
index fd7da34..494247e 100644 (file)
@@ -5789,7 +5789,7 @@ adjust_temp_type (tree type, tree temp)
   if (TREE_CODE (temp) == CONSTRUCTOR)
     return build_constructor (type, CONSTRUCTOR_ELTS (temp));
   gcc_assert (SCALAR_TYPE_P (type));
-  return fold_convert (type, temp);
+  return cp_fold_convert (type, temp);
 }
 
 /* Subroutine of cxx_eval_call_expression.
@@ -6003,13 +6003,13 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
   return result;
 }
 
+/* FIXME speed this up, it's taking 16% of compile time on sieve testcase.  */
+
 bool
 reduced_constant_expression_p (tree t)
 {
-  /* FIXME speed this up, it's taking 16% of compile time on sieve testcase.  */
-  if (cxx_dialect >= cxx0x && TREE_OVERFLOW_P (t))
-    /* In C++0x, integer overflow makes this not a constant expression.
-       FIXME arithmetic overflow is different from conversion truncation */
+  if (TREE_OVERFLOW_P (t))
+    /* Integer overflow makes this not a constant expression.  */
     return false;
   /* FIXME are we calling this too much?  */
   return initializer_constant_valid_p (t, TREE_TYPE (t)) != NULL_TREE;
@@ -6030,7 +6030,20 @@ verify_constant (tree t, bool allow_non_constant, bool *non_constant_p)
   if (!*non_constant_p && !reduced_constant_expression_p (t))
     {
       if (!allow_non_constant)
-       error ("%qE is not a constant expression", t);
+       {
+         /* If T was already folded to a _CST with TREE_OVERFLOW set,
+            printing the folded constant isn't helpful.  */
+         if (TREE_OVERFLOW_P (t))
+           {
+             permerror (input_location, "overflow in constant expression");
+             /* If we're being permissive (and are in an enforcing
+                context), consider this constant.  */
+             if (flag_permissive)
+               return false;
+           }
+         else
+           error ("%q+E is not a constant expression", t);
+       }
       *non_constant_p = true;
     }
   return *non_constant_p;
@@ -6895,12 +6908,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant)
   tree r = cxx_eval_constant_expression (NULL, t, allow_non_constant,
                                         false, &non_constant_p);
 
-  if (!non_constant_p && !reduced_constant_expression_p (r))
-    {
-      if (!allow_non_constant)
-       error ("%qE is not a constant expression", t);
-      non_constant_p = true;
-    }
+  verify_constant (r, allow_non_constant, &non_constant_p);
 
   if (non_constant_p && !allow_non_constant)
     return error_mark_node;
index 6a52fc4..cad8817 100644 (file)
@@ -5717,33 +5717,6 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
                             allow_inverse_p, c_cast_p, complain);
 }
 
-/* If EXPR is an INTEGER_CST and ORIG is an arithmetic constant, return
-   a version of EXPR that has TREE_OVERFLOW set if it is set in ORIG.
-   Otherwise, return EXPR unchanged.  */
-
-static tree
-ignore_overflows (tree expr, tree orig)
-{
-  if (TREE_CODE (expr) == INTEGER_CST
-      && CONSTANT_CLASS_P (orig)
-      && TREE_CODE (orig) != STRING_CST
-      && TREE_OVERFLOW (expr) != TREE_OVERFLOW (orig))
-    {
-      if (!TREE_OVERFLOW (orig))
-       /* Ensure constant sharing.  */
-       expr = build_int_cst_wide (TREE_TYPE (expr),
-                                  TREE_INT_CST_LOW (expr),
-                                  TREE_INT_CST_HIGH (expr));
-      else
-       {
-         /* Avoid clobbering a shared constant.  */
-         expr = copy_node (expr);
-         TREE_OVERFLOW (expr) = TREE_OVERFLOW (orig);
-       }
-    }
-  return expr;
-}
-
 /* Perform a static_cast from EXPR to TYPE.  When C_CAST_P is true,
    this static_cast is being attempted as one of the possible casts
    allowed by a C-style cast.  (In that case, accessibility of base
@@ -5757,7 +5730,6 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
 {
   tree intype;
   tree result;
-  tree orig;
 
   /* Assume the cast is valid.  */
   *valid_p = true;
@@ -5814,8 +5786,14 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
       expr = build_base_path (MINUS_EXPR, build_address (expr),
                              base, /*nonnull=*/false);
       /* Convert the pointer to a reference -- but then remember that
-        there are no expressions with reference type in C++.  */
-      return convert_from_reference (cp_fold_convert (type, expr));
+        there are no expressions with reference type in C++.
+
+         We call rvalue so that there's an actual tree code
+         (NON_LVALUE_EXPR) for the static_cast; otherwise, if the operand
+         is a variable with the same type, the conversion would get folded
+         away, leaving just the variable and causing lvalue_kind to give
+         the wrong answer.  */
+      return convert_from_reference (rvalue (cp_fold_convert (type, expr)));
     }
 
   /* "An lvalue of type cv1 T1 can be cast to type rvalue reference to
@@ -5830,8 +5808,6 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
       return convert_from_reference (expr);
     }
 
-  orig = expr;
-
   /* Resolve overloaded address here rather than once in
      implicit_conversion and again in the inverse code below.  */
   if (TYPE_PTRMEMFUNC_P (type) && type_unknown_p (expr))
@@ -5852,9 +5828,6 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
     {
       result = convert_from_reference (result);
 
-      /* Ignore any integer overflow caused by the cast.  */
-      result = ignore_overflows (result, orig);
-
       /* [expr.static.cast]
 
         If T is a reference type, the result is an lvalue; otherwise,
@@ -5894,13 +5867,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
        || SCALAR_FLOAT_TYPE_P (type))
       && (INTEGRAL_OR_ENUMERATION_TYPE_P (intype)
          || SCALAR_FLOAT_TYPE_P (intype)))
-    {
-      expr = ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
-
-      /* Ignore any integer overflow caused by the cast.  */
-      expr = ignore_overflows (expr, orig);
-      return expr;
-    }
+    return ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
 
   if (TYPE_PTR_P (type) && TYPE_PTR_P (intype)
       && CLASS_TYPE_P (TREE_TYPE (type))
index 74d974b..7d2688e 100644 (file)
@@ -1,3 +1,11 @@
+2010-11-08  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/expr/overflow1.C: New.
+       * g++.dg/warn/overflow-warn-1.C: Add expected diagnostics.
+       * g++.dg/warn/overflow-warn-3.C: Remove unnecessary line number.
+       * g++.dg/warn/overflow-warn-4.C: Add expected diagnostics.
+       * g++.dg/warn/overflow-warn-5.C: Don't expect wrong warning.
+
 2010-11-08  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * gcc.dg/pr35442.c: Adapt warning.
diff --git a/gcc/testsuite/g++.dg/expr/overflow1.C b/gcc/testsuite/g++.dg/expr/overflow1.C
new file mode 100644 (file)
index 0000000..b67b4e4
--- /dev/null
@@ -0,0 +1,8 @@
+#include <limits.h>
+
+enum E {
+  A = (unsigned char)-1,       /* OK */
+  B = (signed char)UCHAR_MAX,  /* implementation-defined */
+  C = INT_MAX+1,     /* undefined (C)/ill-formed (C++) { dg-message "" } */
+  D = UINT_MAX+1     /* OK */
+};
index 17bd067..22c512a 100644 (file)
@@ -1,7 +1,7 @@
 /* Test for diagnostics for constant overflow.  */
 /* Origin: Joseph Myers <joseph@codesourcery.com> */
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-fpermissive" } */
 
 #include <limits.h>
 
@@ -19,8 +19,10 @@ enum e {
   E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
   /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
   E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
+  /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */
   /* Again, overflow in evaluated subexpression.  */
   E6 = 0 * (INT_MAX + 1), /* { dg-warning "integer overflow in expression" } */
+  /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 24 } */
   /* A cast does not constitute overflow in conversion.  */
   E7 = (char) INT_MAX
 };
@@ -29,6 +31,7 @@ struct s {
   int a;
   int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
   int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
+  /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 33 } */
 };
 
 void
@@ -49,10 +52,10 @@ void *n = 0;
    constants.  The third has the overflow in an unevaluated
    subexpression, so is a null pointer constant.  */
 void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
-/* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 51 } */
+/* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* } 54 } */
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 53 } */
-void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } 55 } */
+/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 56 } */
+void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */
 
 void
 g (int i)
@@ -62,6 +65,7 @@ g (int i)
     case 0 * (1/0): /* { dg-warning "division by zero" } */
       ;
     case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
+      /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 67 } */
       ;
     }
 }
index ce03a97..d88c87a 100644 (file)
@@ -57,7 +57,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" }
 
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
 /* { dg-warning "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 58 } */
-void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } 60 } */
+void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */
 
 void
 g (int i)
index 0c916d0..374d294 100644 (file)
@@ -11,7 +11,7 @@ enum e {
   E1 = UINT_MAX + 1,
   /* Overflow in an unevaluated part of an expression is OK (example
      in the standard).  */
-  E2 = 2 || 1 / 0, /* { dg-bogus "warning: division by zero" "" { xfail *-*-* } 14 } */
+  E2 = 2 || 1 / 0, /* { dg-bogus "warning: division by zero" "" { xfail *-*-* } } */
   E3 = 1 / 0, /* { dg-warning "division by zero" } */
   /* { dg-error "enumerator value for 'E3' is not an integer constant|not a constant expression" "enum error" { target *-*-* } 15 } */
   /* But as in DR#031, the 1/0 in an evaluated subexpression means the
@@ -20,9 +20,11 @@ enum e {
   /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
   E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
   /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
+  /* { dg-error "enumerator value for 'E5' is not an integer constant" "enum error" { target *-*-* } 21 } */
   /* Again, overflow in evaluated subexpression.  */
   E6 = 0 * (INT_MAX + 1), /* { dg-warning "integer overflow in expression" } */
-  /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 24 } */
+  /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 25 } */
+  /* { dg-error "enumerator value for 'E6' is not an integer constant" "enum error" { target *-*-* } 25 } */
   /* A cast does not constitute overflow in conversion.  */
   E7 = (char) INT_MAX
 };
@@ -31,7 +33,8 @@ struct s {
   int a;
   int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
   int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
-  /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 33 } */
+  /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 35 } */
+  /* { dg-error "bit-field .* width not an integer constant" "" { target *-*-* } 35 } */
 };
 
 void
@@ -53,11 +56,11 @@ void *n = 0;
    constants.  The third has the overflow in an unevaluated
    subexpression, so is a null pointer constant.  */
 void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
-/* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 55 } */
+/* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 58 } */
 
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 58 } */
-void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } 60 } */
+/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 61 } */
+void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */
 
 void
 g (int i)
@@ -67,7 +70,7 @@ g (int i)
     case 0 * (1/0): /* { dg-warning "division by zero" } */
       ;
     case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
-      /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 69 } */
+      /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 72 } */
       ;
     }
 }
index 472d4a7..bdfec4a 100644 (file)
@@ -1,7 +1,11 @@
 /* PR c/27273 */
 /* { dg-do compile } */
-/* { dg-options "-Woverflow" } */
+
+// This used to warn about "overflow in implicit constant conversion",
+// which was wrong; 512 is never converted to unsigned char.  Rather, an
+// appropriate warning would be that the & expression always evaluates to 0
+// because of the limited range of unsigned char.
 
 unsigned char rx_async(unsigned char p) {
-    return p & 512; /* { dg-warning "overflow in implicit constant conversion" } */
+    return p & 512; /* { dg-warning "" "" { xfail *-*-* } } */
 }
index 4a5d630..d49f970 100644 (file)
@@ -1,3 +1,8 @@
+2010-11-08  Jason Merrill  <jason@redhat.com>
+
+       * testsuite/20_util/ratio/cons/cons_overflow_neg.cc: Adjust
+       expected error.
+
 2010-11-08  Benjamin Kosnik  <bkoz@redhat.com>
 
         * include/std/complex (operator==, !=): Mark constexpr.
index fa4c85e..e7f448d 100644 (file)
@@ -52,6 +52,6 @@ test04()
 // { dg-error "denominator cannot be zero" "" { target *-*-* } 153 }
 // { dg-error "out of range" "" { target *-*-* } 154 }
 // { dg-error "non-constant expression" "" { target *-*-* } 59 }
-// { dg-error "is not a constant expression" "" { target *-*-* } 59 }
+// { dg-error "overflow in constant expression" "" { target *-*-* } 59 }
 // { dg-error "not a member" "" { target *-*-* } 162 }
 // { dg-error "not a valid template argument" "" { target *-*-* } 164 }