From: eggert@bi.TWinsun.COM (Paul Eggert)
Subject: more overflow warnings for GCC 2.3.1
Organization: GNUs Not Usenet
Distribution: gnu
Date: Thu, 12 Nov 1992 06:57:12 GMT

Please ignore this message unless you're using my earlier overflow checking
patches.  (rms writes that he doesn't have time to check these changes, which
are not strictly required by ANSI C.)

Here are further patches for improved checking for arithmetic overflow at
compile-time.  They add warnings for problematic code like the following
(sparc, SunOS 4.1.2).

  int f() { return 4294967296LL; }
  int g() { switch (0) { case 4294967296LL: return 0; } return 1; }
  char a = (0 ? 256 : 257);
  unsigned char b = 256;
  unsigned char c = -129;

They also warn about lines like the following if -Wconversion is specified.

  unsigned d = -1;
  unsigned e = d | -1;
  int h() { switch (e) { case -1: return 0; } return 1; }
  unsigned i() { return -1; }


===================================================================
RCS file: c-common.c,v
retrieving revision 2.3.1.1
retrieving revision 2.3.1.3
diff -c -r2.3.1.1 -r2.3.1.3
*** c-common.c	1992/11/05 01:27:21	2.3.1.1
--- c-common.c	1992/11/11 21:37:19	2.3.1.3
***************
*** 300,305 ****
--- 300,335 ----
        TREE_CONSTANT_OVERFLOW (value) = 0;
      }
  }
+ 
+ void
+ unsigned_conversion_warning (result, operand)
+      tree result, operand;
+ {
+   if (TREE_CODE (operand) == INTEGER_CST
+       && TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
+       && TREE_UNSIGNED (TREE_TYPE (result))
+       && !int_fits_type_p (operand, TREE_TYPE (result)))
+     if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result))))
+       pedwarn ("large integer implicitly truncated to unsigned type");
+     else if (warn_conversion)
+       pedwarn ("negative integer implicitly converted to unsigned type");
+ }
+ 
+ tree
+ convert_and_check (type, expr)
+      tree type, expr;
+ {
+   tree t = convert (type, expr);
+   if (TREE_CODE (t) == INTEGER_CST)
+     if (TREE_CONSTANT_OVERFLOW (t))
+       {
+ 	pedwarn ("overflow in implicit constant conversion");
+ 	TREE_CONSTANT_OVERFLOW (t) = 0;
+       }
+     else
+       unsigned_conversion_warning (t, expr);
+   return t;
+ }
  
  void
  c_expand_expr_stmt (expr)
===================================================================
RCS file: c-tree.h,v
retrieving revision 2.3.1.1
retrieving revision 2.3.1.2
diff -c -r2.3.1.1 -r2.3.1.2
*** c-tree.h	1992/11/06 00:23:10	2.3.1.1
--- c-tree.h	1992/11/11 03:13:13	2.3.1.2
***************
*** 144,150 ****
  extern tree digest_init ();
  extern tree c_expand_start_case ();
  extern tree default_conversion ();
- extern void constant_expression_warning ();
  
  /* Given two integer or real types, return the type for their sum.
     Given two compatible ANSI C types, returns the merged type.  */
--- 144,149 ----
***************
*** 188,193 ****
--- 187,196 ----
  
  /* Functions in c-common.c: */
  
+ extern tree convert_and_check ();
+ extern void constant_expression_warning ();
+ extern void unsigned_conversion_warning ();
+ 
  /* Concatenate a list of STRING_CST nodes into one STRING_CST.  */
  extern tree combine_strings ();
  
===================================================================
RCS file: c-typeck.c,v
retrieving revision 2.3.1.2
retrieving revision 2.3.1.4
diff -c -r2.3.1.2 -r2.3.1.4
*** c-typeck.c	1992/11/05 01:27:21	2.3.1.2
--- c-typeck.c	1992/11/11 07:54:24	2.3.1.4
***************
*** 2136,2141 ****
--- 2136,2143 ----
        && (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<'))
      warning ("comparisons like X<=Y<=Z do not have their mathematical meaning");
  
+   unsigned_conversion_warning (result, arg1);
+   unsigned_conversion_warning (result, arg2);
    constant_expression_warning (result);
  
    class = TREE_CODE_CLASS (TREE_CODE (result));
***************
*** 3563,3572 ****
  			  TREE_READONLY (op1) || TREE_READONLY (op2),
  			  TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
      
    if (result_type != TREE_TYPE (op1))
!     op1 = convert (result_type, op1);
    if (result_type != TREE_TYPE (op2))
!     op2 = convert (result_type, op2);
      
  #if 0
    if (code1 == RECORD_TYPE || code1 == UNION_TYPE)
--- 3565,3577 ----
  			  TREE_READONLY (op1) || TREE_READONLY (op2),
  			  TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
      
+   if (TREE_CODE (ifexp) == INTEGER_CST)
+     return convert_and_check (result_type, integer_zerop (ifexp) ? op2 : op1);
+ 
    if (result_type != TREE_TYPE (op1))
!     op1 = convert_and_check (result_type, op1);
    if (result_type != TREE_TYPE (op2))
!     op2 = convert_and_check (result_type, op2);
      
  #if 0
    if (code1 == RECORD_TYPE || code1 == UNION_TYPE)
***************
*** 3605,3612 ****
      }
  #endif /* 0 */
  
-   if (TREE_CODE (ifexp) == INTEGER_CST)
-     return (integer_zerop (ifexp) ? op2 : op1);
    return fold (build (COND_EXPR, result_type, ifexp, op1, op2));
  }
  
--- 3610,3615 ----
***************
*** 3985,3991 ****
      return error_mark_node;
  
    if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
!     return rhs;
  
    if (coder == VOID_TYPE)
      {
--- 3988,3997 ----
      return error_mark_node;
  
    if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
!     {
!       constant_expression_warning (rhs);
!       return rhs;
!     }
  
    if (coder == VOID_TYPE)
      {
***************
*** 3996,4006 ****
    if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == ENUMERAL_TYPE)
         &&
        (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE))
!     {
!       tree t = convert (type, rhs);
!       constant_expression_warning (t);
!       return t;
!     }
    /* Conversions among pointers */
    else if (codel == POINTER_TYPE && coder == POINTER_TYPE)
      {
--- 4002,4008 ----
    if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == ENUMERAL_TYPE)
         &&
        (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE))
!     return convert_and_check (type, rhs);
    /* Conversions among pointers */
    else if (codel == POINTER_TYPE && coder == POINTER_TYPE)
      {
===================================================================
RCS file: invoke.texi,v
retrieving revision 2.3
retrieving revision 2.3.1.1
diff -c -r2.3 -r2.3.1.1
*** invoke.texi	1992/10/31 20:54:13	2.3
--- invoke.texi	1992/11/11 22:00:56	2.3.1.1
***************
*** 927,932 ****
--- 927,937 ----
  conversions changing the width or signedness of a fixed point argument
  except when the same as the default promotion.
  
+ Also, warn if a negative integer constant expression is implicitly
+ converted to an unsigned type.  For example, warn about the assignment
+ @code{x = -1} if @code{x} is unsigned.  But do not warn about explicit
+ casts like @code{(unsigned) -1}.
+ 
  @item -Waggregate-return
  Warn if any functions that return structures or unions are defined or
  called.  (In languages where you can return an array, this also elicits
===================================================================
RCS file: stmt.c,v
retrieving revision 2.3
retrieving revision 2.3.1.1
diff -c -r2.3 -r2.3.1.1
*** stmt.c	1992/10/09 16:59:03	2.3
--- stmt.c	1992/11/11 03:13:13	2.3.1.1
***************
*** 49,54 ****
--- 49,55 ----
  #include "obstack.h"
  #include "loop.h"
  #include "recog.h"
+ #include "c-tree.h"
  
  #define obstack_chunk_alloc xmalloc
  #define obstack_chunk_free free
***************
*** 3328,3334 ****
  
    /* Convert VALUE to the type in which the comparisons are nominally done.  */
    if (value != 0)
!     value = convert (nominal_type, value);
  
    /* If this is the first label, warn if any insns have been emitted.  */
    if (case_stack->data.case_stmt.seenlabel == 0)
--- 3329,3335 ----
  
    /* Convert VALUE to the type in which the comparisons are nominally done.  */
    if (value != 0)
!     value = convert_and_check (nominal_type, value);
  
    /* If this is the first label, warn if any insns have been emitted.  */
    if (case_stack->data.case_stmt.seenlabel == 0)
***************
*** 3458,3468 ****
    /* Convert VALUEs to type in which the comparisons are nominally done.  */
    if (value1 == 0)  /* Negative infinity. */
      value1 = TYPE_MIN_VALUE(index_type);
!   value1 = convert (nominal_type, value1);
  
    if (value2 == 0)  /* Positive infinity. */
      value2 = TYPE_MAX_VALUE(index_type);
!   value2 = convert (nominal_type, value2);
  
    /* Fail if these values are out of range.  */
    if (! int_fits_type_p (value1, index_type))
--- 3459,3469 ----
    /* Convert VALUEs to type in which the comparisons are nominally done.  */
    if (value1 == 0)  /* Negative infinity. */
      value1 = TYPE_MIN_VALUE(index_type);
!   value1 = convert_and_check (nominal_type, value1);
  
    if (value2 == 0)  /* Positive infinity. */
      value2 = TYPE_MAX_VALUE(index_type);
!   value2 = convert_and_check (nominal_type, value2);
  
    /* Fail if these values are out of range.  */
    if (! int_fits_type_p (value1, index_type))