Standards compliant preprocessor arithmetic

Neil Booth neil@daikokuya.demon.co.uk
Sun May 26 14:51:00 GMT 2002


In a private message Zack said he had no problems with the
previous patch, so I applied it.  Finally, that means we can
get CPP arithmetic correct.  This patch has the preprocessor
do arithmetic to the correct precision, depending upon the
standard selected.

I've included very comprehensive tests of all overflow conditions,
some other diagnostics, and numerical correctness.  These make
many existing tests redundant; I'll clean up the duplication in a
follow-up patch sometime.  I used these tests to ensure
CPP had the correct semantics for 16, 32 and 64 bit target
precision from a 32-bit x86 linux host.  Previously, doing things
like using "65536" in CPP arithmetic would not give any
diagnostics about an overly large number when target
arithmetic is 16-bit; they now happen properly (does the
compiler proper get narrowing semantics correct, in general?
I suspect it doesn't).

There are a couple of small issues I've skirted around here.
I'm sticking to using "unsigned long" as the half-integer.
This really should become "unsigned long long" in some
circumstances, so we can get enhanced precision.  In fact,
I'd really like to use the unsigned version of HOST_WIDE_INT,
but I want to understand better why this was changed last
year to be target-dependent and "long long" in some cases,
as using that would kill performance.  Why is "long" not
enough for a 32->64 bit cross?

I've added run-time sanity checks that CPP is capable of the
necessary precision; this might cause some cross-compilers
to fail (correctly) where they previously succeeded silently.

I'm bootstrapping this; I'll apply it if it succeeds as expected.

There is room for improving CPP arithmetic efficiency; I just
did enough preivously to get things "obviously correct" (ahem)
but still be reasonably efficient.  In particular, interpreting
the value of textual number could be done a lot more efficiently.
This is particularly important as that must be just about the
most common operation.  I'll make some performance improvements
in follow-up patches.

Neil.

	* c-common.c (c_common_init): Set CPP arithmetic precision.
	* cppexp.c (cpp_num_part): Move typedef ...
	* cpphash.h: ...here.
	* cppinit.c (cpp_create_reader): Default to host long arithmetic.
	(sanity_checks): Update.
testsuite:
	* gcc.dg/cpp/arith-2.c, gcc.dg/cpp/arith-3.c: New tests.

============================================================
Index: gcc/c-common.c
--- gcc/c-common.c	25 May 2002 22:01:41 -0000	1.332
+++ gcc/c-common.c	26 May 2002 19:40:34 -0000
@@ -4488,6 +4488,10 @@ c_common_init (filename)
 
   /* Set up preprocessor arithmetic.  Must be done after call to
      c_common_nodes_and_builtins for wchar_type_node to be good.  */
+  if (flag_isoc99)
+    options->precision = TYPE_PRECISION (intmax_type_node);
+  else
+    options->precision = TYPE_PRECISION (long_integer_type_node);
   options->char_precision = TYPE_PRECISION (char_type_node);
   options->int_precision = TYPE_PRECISION (integer_type_node);
   options->wchar_precision = TYPE_PRECISION (wchar_type_node);
============================================================
Index: gcc/cppexp.c
--- gcc/cppexp.c	26 May 2002 18:42:06 -0000	1.116
+++ gcc/cppexp.c	26 May 2002 19:40:37 -0000
@@ -23,7 +23,6 @@ Boston, MA 02111-1307, USA.  */
 #include "cpplib.h"
 #include "cpphash.h"
 
-typedef unsigned long cpp_num_part;
 typedef struct cpp_num cpp_num;
 
 #define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT)
============================================================
Index: gcc/cpphash.h
--- gcc/cpphash.h	22 May 2002 22:02:12 -0000	1.152
+++ gcc/cpphash.h	26 May 2002 19:40:39 -0000
@@ -29,6 +29,7 @@ struct directive;		/* Deliberately incom
 struct pending_option;
 struct op;
 
+typedef unsigned long cpp_num_part;
 typedef unsigned char uchar;
 #define U (const uchar *)  /* Intended use: U"string" */
 
============================================================
Index: gcc/cppinit.c
--- gcc/cppinit.c	23 May 2002 18:55:05 -0000	1.233
+++ gcc/cppinit.c	26 May 2002 19:40:43 -0000
@@ -496,8 +496,7 @@ cpp_create_reader (lang)
 
   /* Default CPP arithmetic to something sensible for the host for the
      benefit of dumb users like fix-header.  */
-#define BITS_PER_HOST_WIDEST_INT (CHAR_BIT * sizeof (HOST_WIDEST_INT))
-  CPP_OPTION (pfile, precision) = BITS_PER_HOST_WIDEST_INT;
+  CPP_OPTION (pfile, precision) = CHAR_BIT * sizeof (long);
   CPP_OPTION (pfile, char_precision) = CHAR_BIT;
   CPP_OPTION (pfile, wchar_precision) = CHAR_BIT * sizeof (int);
   CPP_OPTION (pfile, int_precision) = CHAR_BIT * sizeof (int);
@@ -848,6 +847,7 @@ static void sanity_checks (pfile)
      cpp_reader *pfile;
 {
   cppchar_t test = 0;
+  size_t max_precision = 2 * CHAR_BIT * sizeof (cpp_num_part);
 
   /* Sanity checks for assumptions about CPP arithmetic and target
      type precisions made by cpplib.  */
@@ -855,11 +855,11 @@ static void sanity_checks (pfile)
   if (test < 1)
     cpp_error (pfile, DL_ICE, "cppchar_t must be an unsigned type");
 
-  if (CPP_OPTION (pfile, precision) > BITS_PER_HOST_WIDEST_INT)
+  if (CPP_OPTION (pfile, precision) > max_precision)
     cpp_error (pfile, DL_ICE,
 	       "preprocessor arithmetic has maximum precision of %lu bits; target requires %lu bits",
-	       (unsigned long)BITS_PER_HOST_WIDEST_INT,
-	       (unsigned long)CPP_OPTION (pfile, precision));
+	       (unsigned long) max_precision,
+	       (unsigned long) CPP_OPTION (pfile, precision));
 
   if (CPP_OPTION (pfile, precision) < CPP_OPTION (pfile, int_precision))
     cpp_error (pfile, DL_ICE,
@@ -879,8 +879,8 @@ static void sanity_checks (pfile)
   if (CPP_OPTION (pfile, wchar_precision) > BITS_PER_CPPCHAR_T)
     cpp_error (pfile, DL_ICE,
 	       "CPP on this host cannot handle wide character constants over %lu bits, but the target requires %lu bits",
-	       (unsigned long)BITS_PER_CPPCHAR_T,
-	       (unsigned long)CPP_OPTION (pfile, wchar_precision));
+	       (unsigned long) BITS_PER_CPPCHAR_T,
+	       (unsigned long) CPP_OPTION (pfile, wchar_precision));
 }
 #else
 # define sanity_checks(PFILE)
============================================================
Index: gcc/testsuite/gcc.dg/cpp/arith-2.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.dg/cpp/arith-2.c	26 May 2002 19:40:43 -0000
@@ -0,0 +1,447 @@
+/* Preprocessor arithmetic semantic tests.  */
+
+/* Copyright (C) 2002 Free Software Foundation, Inc.  */
+/* Source: Neil Booth, 26 May 2002.  */
+
+/* The file tests overflow warnings for, and values of, preprocessor
+   arithmetic that are dependent on target precision.  
+
+   Please keep changes to arith-2.c and arith-3.c in sync.  */
+
+/* { dg-do preprocess } */
+/* { dg-options "-std=c89 -fno-show-column" } */
+
+#include <limits.h>
+
+#define APPEND2(NUM, SUFF) NUM ## SUFF
+#define APPEND(NUM, SUFF) APPEND2(NUM, SUFF)
+
+#define TARGET_UTYPE_MAX ULONG_MAX
+
+/* The tests in this file depend only on the macros defined in this
+   #if block.  Note that it is no good calculating these values, as
+   the intent is to test both the preprocessor's number parser and
+   arithmetic.  */
+#if TARGET_UTYPE_MAX == 65535UL
+
+#  define TARG_PRECISION 16
+#  define MAX_INT  32767
+#  define MAX_UINT 65535
+
+#  define TARG_MAX_HEX 0x7fff
+#  define TARG_MAX_OCT 077777
+#  define TARG_MAX_PLUS_1 32768L
+#  define TARG_MAX_PLUS_1_U 32768UL
+#  define TARG_MAX_PLUS_1_HEX 0x8000
+#  define TARG_MAX_PLUS_1_OCT 0100000
+#  define UTARG_MAX_HEX 0xffff
+#  define UTARG_MAX_OCT 0177777
+#  define UTARG_MAX_PLUS_1 65536L
+#  define UTARG_MAX_PLUS_1_HEX 0x10000
+#  define UTARG_MAX_PLUS_1_OCT 0200000
+
+#  define TARG_LOWPART_PLUS_1 256L
+#  define TARG_LOWPART_PLUS_1_U 256UL
+
+  /* Division and modulo; anything that uses the high half in both
+     dividend and divisor.  */
+#  define LONG_UDIVISION 61234UL / 260L
+#  define LONG_UDIVISION_ANSWER 235
+#  define LONG_SDIVISION -15000L / 299L
+#  define LONG_SDIVISION_ANSWER -50
+#  define LONG_UMODULO 61234UL % 260L
+#  define LONG_UMODULO_ANSWER 134
+#  define LONG_SMODULO -15000L % 299L
+#  define LONG_SMODULO_ANSWER -50
+
+#elif TARGET_UTYPE_MAX == 4294967295UL
+
+#  define TARG_PRECISION 32
+#  define MAX_INT  2147483647
+#  define MAX_UINT 4294967295
+
+#  define TARG_MAX_HEX 0x7fffffff
+#  define TARG_MAX_OCT 017777777777
+#  define TARG_MAX_PLUS_1 2147483648L
+#  define TARG_MAX_PLUS_1_U 2147483648UL
+#  define TARG_MAX_PLUS_1_HEX 0x80000000
+#  define TARG_MAX_PLUS_1_OCT 020000000000
+#  define UTARG_MAX_HEX 0xffffffff
+#  define UTARG_MAX_OCT 037777777777
+#  define UTARG_MAX_PLUS_1 4294967296L
+#  define UTARG_MAX_PLUS_1_HEX 0x100000000
+#  define UTARG_MAX_PLUS_1_OCT 040000000000
+
+#  define TARG_LOWPART_PLUS_1 65536
+#  define TARG_LOWPART_PLUS_1_U 65536UL
+
+  /* Division and modulo; anything that uses the high half in both
+     dividend and divisor.  */
+#  define LONG_UDIVISION 268335456UL / 70000L
+#  define LONG_UDIVISION_ANSWER 3833
+#  define LONG_SDIVISION -368335456L / 123456L
+#  define LONG_SDIVISION_ANSWER -2983
+#  define LONG_UMODULO 268335456UL % 70000L
+#  define LONG_UMODULO_ANSWER 25456
+#  define LONG_SMODULO -368335456L % 123456L
+#  define LONG_SMODULO_ANSWER -66208
+
+#elif TARGET_UTYPE_MAX == 18446744073709551615UL
+
+#  define TARG_PRECISION 64
+#  define MAX_INT  9223372036854775807
+#  define MAX_UINT 18446744073709551615
+
+#  define TARG_MAX_HEX 0x7fffffffffffffff
+#  define TARG_MAX_OCT 0777777777777777777777
+#  define TARG_MAX_PLUS_1 9223372036854775808L
+#  define TARG_MAX_PLUS_1_U 9223372036854775808UL
+#  define TARG_MAX_PLUS_1_HEX 0x8000000000000000
+#  define TARG_MAX_PLUS_1_OCT 01000000000000000000000
+#  define UTARG_MAX_HEX 0xffffffffffffffff
+#  define UTARG_MAX_OCT 01777777777777777777777
+#  define UTARG_MAX_PLUS_1 18446744073709551616L
+#  define UTARG_MAX_PLUS_1_HEX 0x10000000000000000
+#  define UTARG_MAX_PLUS_1_OCT 02000000000000000000000
+
+#  define TARG_LOWPART_PLUS_1 4294967296
+#  define TARG_LOWPART_PLUS_1_U 4294967296U
+
+  /* Division and modulo; anything that uses the high half in both
+     dividend and divisor.  */
+#  define LONG_UDIVISION 235184372088832UL / 17279869184L
+#  define LONG_UDIVISION_ANSWER 13610
+#  define LONG_SDIVISION -234582345927345L / 12345678901L
+#  define LONG_SDIVISION_ANSWER -19001
+#  define LONG_UMODULO 235184372088832UL % 17279869184L
+#  define LONG_UMODULO_ANSWER 5352494592L
+#  define LONG_SMODULO -234582345927345L % 12345678901L
+#  define LONG_SMODULO_ANSWER -2101129444L
+
+#else
+
+#  error Please extend the macros here so that this file tests your target
+
+#endif
+
+/* Create more macros based on the above.  */
+#define TARG_PART_BITS (TARG_PRECISION / 2)
+#define TARG_MIN (-TARG_MAX - 1)
+#define TARG_MAX APPEND (MAX_INT, L)
+#define TARG_MAX_U APPEND (MAX_INT, UL)
+#define UTARG_MAX APPEND (MAX_UINT, L)
+#define UTARG_MAX_U APPEND (MAX_UINT, UL)
+
+/* And now the tests.  */
+
+#if TARG_MAX			/* { dg-bogus "so large" }  */
+#endif
+#if TARG_MAX_PLUS_1_HEX		/* { dg-bogus "so large" }  */
+#endif
+#if TARG_MAX_PLUS_1_OCT		/* { dg-bogus "so large" }  */
+#endif
+
+#if UTARG_MAX			/* { dg-warning "so large" }  */
+#endif
+#if UTARG_MAX_PLUS_1		/* { dg-error "too large" }  */
+#endif
+#if UTARG_MAX_PLUS_1_HEX	/* { dg-error "too large" }  */
+#endif
+#if UTARG_MAX_HEX		/* { dg-bogus "too large" }  */
+#endif
+#if UTARG_MAX_PLUS_1_OCT	/* { dg-error "too large" }  */
+#endif
+#if UTARG_MAX_OCT		/* { dg-bogus "too large" }  */
+#endif
+
+#if TARG_MAX < 0 || TARG_MAX_PLUS_1 < 0	/* { dg-warning "so large" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if UTARG_MAX_HEX < 0 || TARG_MAX_HEX < 0
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if UTARG_MAX_OCT < 0 || TARG_MAX_OCT < 0
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -1 != UTARG_MAX_U
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Test each operator correctly warns of overflow conditions, and
+   gives the right answer.  */
+
+/* Binary +.  */
+#if TARG_MAX + 1 != TARG_MIN	/* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX + -2 != TARG_MAX	/* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX + -1 != TARG_MIN	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX_U + 1 != TARG_MIN	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX_U + -2 != TARG_MAX /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Binary -.  */
+#if TARG_MAX - -1 != TARG_MIN	/* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX - 2 != TARG_MAX	/* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX - 1 != TARG_MIN	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX_U - -1 != TARG_MIN	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX_U - 2 != TARG_MAX /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+
+/* Binary *.  */
+#if TARG_LOWPART_PLUS_1 * (TARG_LOWPART_PLUS_1 >> 1) != TARG_MIN /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_LOWPART_PLUS_1 >> 1) * TARG_LOWPART_PLUS_1 != TARG_MIN /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_LOWPART_PLUS_1 << 1) * (TARG_LOWPART_PLUS_1 + 1) != (TARG_LOWPART_PLUS_1 << 1) /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX * 1 != TARG_MAX	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_MAX >> 1) * 2	!= TARG_MAX - 1 /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_LOWPART_PLUS_1_U + 61) * (TARG_LOWPART_PLUS_1 << 1) != 61 * (TARG_LOWPART_PLUS_1 << 1) /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_LOWPART_PLUS_1 >> 1) * TARG_LOWPART_PLUS_1_U != TARG_MIN /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if 1 * TARG_MIN != TARG_MIN	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Binary /.  */
+#if TARG_MIN / -1 != TARG_MIN	/* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MIN / 1 != TARG_MIN	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX_PLUS_1_U / -1 != 0 /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -5 / (2 - 2) /* { dg-error "division by zero" } */
+#endif
+
+#if LONG_UDIVISION != LONG_UDIVISION_ANSWER
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if LONG_SDIVISION != LONG_SDIVISION_ANSWER
+# error		/* { dg-bogus "error" }  */
+#endif
+
+/* Binary %.  Cannot overflow.  */
+#if -5 % (2 - 2) /* { dg-error "division by zero" } */
+#endif
+
+#if TARG_MIN % 1 /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if LONG_UMODULO != LONG_UMODULO_ANSWER
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if LONG_SMODULO != LONG_SMODULO_ANSWER
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if 234 % -1U != 234
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MIN % -1U != TARG_MIN
+# error		/* { dg-bogus "error" }  */
+#endif
+
+/* Binary << and Binary >>, the latter cannot overflow.  */
+#if -1 >> 3 != -1     /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX >> 3 != TARG_MAX / 8     /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if 0 << 256 != 0  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if 1 << 256 != 0 /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if 1U << 256 != 0  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX << 1 != -2  /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX_U << 1 != -2  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_LOWPART_PLUS_1 << TARG_PART_BITS != 0  /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_LOWPART_PLUS_1 << (TARG_PART_BITS - 1) != TARG_MIN  /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_LOWPART_PLUS_1_U << (TARG_PART_BITS - 1) != TARG_MIN  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_LOWPART_PLUS_1 << (TARG_PART_BITS - 2) != (TARG_MAX_PLUS_1_U >> 1)  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+/* Test how the sign bit is handled.  */
+#if (TARG_MIN << 1) != 0    /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_MAX_PLUS_1_U << 1) != 0    /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_MIN >> 1) != 3U << (TARG_PRECISION - 2)    /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_MAX_PLUS_1_U >> 1) != 1 << (TARG_PRECISION - 2)    /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+/* Unary -.  It can overflow in just one case.  */
+#if -TARG_MIN != TARG_MIN  /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if - -TARG_MAX != TARG_MAX   /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Unary +, ~, and !.  They cannot overflow.  */
+#if +TARG_MAX != TARG_MAX  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if !TARG_MAX + !TARG_MIN != 0   /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if ~TARG_MAX , ~TARG_MIN != TARG_MAX  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Bitwise &, ^, |.  They cannot overflow.  */
+#if (TARG_MAX & -1), (TARG_MIN & -1) != TARG_MIN  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX | -1, (TARG_MIN | -1) != -1  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX ^ -1, (TARG_MIN ^ -1) != TARG_MAX  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Comparison operators.  They cannot overflow.  */
+#if -1 <= TARG_MAX, (TARG_MIN <= 1) != 1  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -1 >= TARG_MAX, (TARG_MIN >= 1) != 0  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -1 < TARG_MAX, (TARG_MIN < 1) != 1  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -1 > TARG_MAX, (TARG_MIN > 1) != 0  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Comma and ? : operators.  They cannot overflow.  */
+#if -1, TARG_MAX, TARG_MIN != TARG_MIN  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -1 ? TARG_MAX: TARG_MAX, 0 ? 1: TARG_MIN != TARG_MIN /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
============================================================
Index: gcc/testsuite/gcc.dg/cpp/arith-3.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.dg/cpp/arith-3.c	26 May 2002 19:40:43 -0000
@@ -0,0 +1,447 @@
+/* Preprocessor arithmetic semantic tests.  */
+
+/* Copyright (C) 2002 Free Software Foundation, Inc.  */
+/* Source: Neil Booth, 26 May 2002.  */
+
+/* The file tests overflow warnings for, and values of, preprocessor
+   arithmetic that are dependent on target precision.
+
+   Please keep changes to arith-2.c and arith-3.c in sync.  */
+
+/* { dg-do preprocess } */
+/* { dg-options "-std=c99 -fno-show-column" } */
+
+#include <limits.h>
+
+#define APPEND2(NUM, SUFF) NUM ## SUFF
+#define APPEND(NUM, SUFF) APPEND2(NUM, SUFF)
+
+#define TARGET_UTYPE_MAX  ULONG_LONG_MAX
+
+/* The tests in this file depend only on the macros defined in this
+   #if block.  Note that it is no good calculating these values, as
+   the intent is to test both the preprocessor's number parser and
+   arithmetic.  */
+#if TARGET_UTYPE_MAX == 65535ULL
+
+#  define TARG_PRECISION 16
+#  define MAX_INT  32767
+#  define MAX_UINT 65535
+
+#  define TARG_MAX_HEX 0x7fff
+#  define TARG_MAX_OCT 077777
+#  define TARG_MAX_PLUS_1 32768L
+#  define TARG_MAX_PLUS_1_U 32768UL
+#  define TARG_MAX_PLUS_1_HEX 0x8000
+#  define TARG_MAX_PLUS_1_OCT 0100000
+#  define UTARG_MAX_HEX 0xffff
+#  define UTARG_MAX_OCT 0177777
+#  define UTARG_MAX_PLUS_1 65536L
+#  define UTARG_MAX_PLUS_1_HEX 0x10000
+#  define UTARG_MAX_PLUS_1_OCT 0200000
+
+#  define TARG_LOWPART_PLUS_1 256L
+#  define TARG_LOWPART_PLUS_1_U 256UL
+
+  /* Division and modulo; anything that uses the high half in both
+     dividend and divisor.  */
+#  define LONG_UDIVISION 61234UL / 260L
+#  define LONG_UDIVISION_ANSWER 235
+#  define LONG_SDIVISION -15000L / 299L
+#  define LONG_SDIVISION_ANSWER -50
+#  define LONG_UMODULO 61234UL % 260L
+#  define LONG_UMODULO_ANSWER 134
+#  define LONG_SMODULO -15000L % 299L
+#  define LONG_SMODULO_ANSWER -50
+
+#elif TARGET_UTYPE_MAX == 4294967295ULL
+
+#  define TARG_PRECISION 32
+#  define MAX_INT  2147483647
+#  define MAX_UINT 4294967295
+
+#  define TARG_MAX_HEX 0x7fffffff
+#  define TARG_MAX_OCT 017777777777
+#  define TARG_MAX_PLUS_1 2147483648L
+#  define TARG_MAX_PLUS_1_U 2147483648UL
+#  define TARG_MAX_PLUS_1_HEX 0x80000000
+#  define TARG_MAX_PLUS_1_OCT 020000000000
+#  define UTARG_MAX_HEX 0xffffffff
+#  define UTARG_MAX_OCT 037777777777
+#  define UTARG_MAX_PLUS_1 4294967296L
+#  define UTARG_MAX_PLUS_1_HEX 0x100000000
+#  define UTARG_MAX_PLUS_1_OCT 040000000000
+
+#  define TARG_LOWPART_PLUS_1 65536
+#  define TARG_LOWPART_PLUS_1_U 65536UL
+
+  /* Division and modulo; anything that uses the high half in both
+     dividend and divisor.  */
+#  define LONG_UDIVISION 268335456UL / 70000L
+#  define LONG_UDIVISION_ANSWER 3833
+#  define LONG_SDIVISION -368335456L / 123456L
+#  define LONG_SDIVISION_ANSWER -2983
+#  define LONG_UMODULO 268335456UL % 70000L
+#  define LONG_UMODULO_ANSWER 25456
+#  define LONG_SMODULO -368335456L % 123456L
+#  define LONG_SMODULO_ANSWER -66208
+
+#elif TARGET_UTYPE_MAX == 18446744073709551615ULL
+
+#  define TARG_PRECISION 64
+#  define MAX_INT  9223372036854775807
+#  define MAX_UINT 18446744073709551615
+
+#  define TARG_MAX_HEX 0x7fffffffffffffff
+#  define TARG_MAX_OCT 0777777777777777777777
+#  define TARG_MAX_PLUS_1 9223372036854775808L
+#  define TARG_MAX_PLUS_1_U 9223372036854775808UL
+#  define TARG_MAX_PLUS_1_HEX 0x8000000000000000
+#  define TARG_MAX_PLUS_1_OCT 01000000000000000000000
+#  define UTARG_MAX_HEX 0xffffffffffffffff
+#  define UTARG_MAX_OCT 01777777777777777777777
+#  define UTARG_MAX_PLUS_1 18446744073709551616L
+#  define UTARG_MAX_PLUS_1_HEX 0x10000000000000000
+#  define UTARG_MAX_PLUS_1_OCT 02000000000000000000000
+
+#  define TARG_LOWPART_PLUS_1 4294967296
+#  define TARG_LOWPART_PLUS_1_U 4294967296U
+
+  /* Division and modulo; anything that uses the high half in both
+     dividend and divisor.  */
+#  define LONG_UDIVISION 235184372088832UL / 17279869184L
+#  define LONG_UDIVISION_ANSWER 13610
+#  define LONG_SDIVISION -234582345927345L / 12345678901L
+#  define LONG_SDIVISION_ANSWER -19001
+#  define LONG_UMODULO 235184372088832UL % 17279869184L
+#  define LONG_UMODULO_ANSWER 5352494592L
+#  define LONG_SMODULO -234582345927345L % 12345678901L
+#  define LONG_SMODULO_ANSWER -2101129444L
+
+#else
+
+#  error Please extend the macros here so that this file tests your target
+
+#endif
+
+/* Create more macros based on the above.  */
+#define TARG_PART_BITS (TARG_PRECISION / 2)
+#define TARG_MIN (-TARG_MAX - 1)
+#define TARG_MAX APPEND (MAX_INT, L)
+#define TARG_MAX_U APPEND (MAX_INT, UL)
+#define UTARG_MAX APPEND (MAX_UINT, L)
+#define UTARG_MAX_U APPEND (MAX_UINT, UL)
+
+/* And now the tests.  */
+
+#if TARG_MAX			/* { dg-bogus "so large" }  */
+#endif
+#if TARG_MAX_PLUS_1_HEX		/* { dg-bogus "so large" }  */
+#endif
+#if TARG_MAX_PLUS_1_OCT		/* { dg-bogus "so large" }  */
+#endif
+
+#if UTARG_MAX			/* { dg-warning "so large" }  */
+#endif
+#if UTARG_MAX_PLUS_1		/* { dg-error "too large" }  */
+#endif
+#if UTARG_MAX_PLUS_1_HEX	/* { dg-error "too large" }  */
+#endif
+#if UTARG_MAX_HEX		/* { dg-bogus "too large" }  */
+#endif
+#if UTARG_MAX_PLUS_1_OCT	/* { dg-error "too large" }  */
+#endif
+#if UTARG_MAX_OCT		/* { dg-bogus "too large" }  */
+#endif
+
+#if TARG_MAX < 0 || TARG_MAX_PLUS_1 < 0	/* { dg-warning "so large" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if UTARG_MAX_HEX < 0 || TARG_MAX_HEX < 0
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if UTARG_MAX_OCT < 0 || TARG_MAX_OCT < 0
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -1 != UTARG_MAX_U
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Test each operator correctly warns of overflow conditions, and
+   gives the right answer.  */
+
+/* Binary +.  */
+#if TARG_MAX + 1 != TARG_MIN	/* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX + -2 != TARG_MAX	/* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX + -1 != TARG_MIN	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX_U + 1 != TARG_MIN	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX_U + -2 != TARG_MAX /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Binary -.  */
+#if TARG_MAX - -1 != TARG_MIN	/* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX - 2 != TARG_MAX	/* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX - 1 != TARG_MIN	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX_U - -1 != TARG_MIN	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX_U - 2 != TARG_MAX /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+
+/* Binary *.  */
+#if TARG_LOWPART_PLUS_1 * (TARG_LOWPART_PLUS_1 >> 1) != TARG_MIN /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_LOWPART_PLUS_1 >> 1) * TARG_LOWPART_PLUS_1 != TARG_MIN /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_LOWPART_PLUS_1 << 1) * (TARG_LOWPART_PLUS_1 + 1) != (TARG_LOWPART_PLUS_1 << 1) /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX * 1 != TARG_MAX	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_MAX >> 1) * 2	!= TARG_MAX - 1 /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_LOWPART_PLUS_1_U + 61) * (TARG_LOWPART_PLUS_1 << 1) != 61 * (TARG_LOWPART_PLUS_1 << 1) /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_LOWPART_PLUS_1 >> 1) * TARG_LOWPART_PLUS_1_U != TARG_MIN /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if 1 * TARG_MIN != TARG_MIN	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Binary /.  */
+#if TARG_MIN / -1 != TARG_MIN	/* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MIN / 1 != TARG_MIN	/* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -TARG_MAX_PLUS_1_U / -1 != 0 /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -5 / (2 - 2) /* { dg-error "division by zero" } */
+#endif
+
+#if LONG_UDIVISION != LONG_UDIVISION_ANSWER
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if LONG_SDIVISION != LONG_SDIVISION_ANSWER
+# error		/* { dg-bogus "error" }  */
+#endif
+
+/* Binary %.  Cannot overflow.  */
+#if -5 % (2 - 2) /* { dg-error "division by zero" } */
+#endif
+
+#if TARG_MIN % 1 /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if LONG_UMODULO != LONG_UMODULO_ANSWER
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if LONG_SMODULO != LONG_SMODULO_ANSWER
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if 234 % -1U != 234
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MIN % -1U != TARG_MIN
+# error		/* { dg-bogus "error" }  */
+#endif
+
+/* Binary << and Binary >>, the latter cannot overflow.  */
+#if -1 >> 3 != -1     /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX >> 3 != TARG_MAX / 8     /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if 0 << 256 != 0  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if 1 << 256 != 0 /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if 1U << 256 != 0  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX << 1 != -2  /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX_U << 1 != -2  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_LOWPART_PLUS_1 << TARG_PART_BITS != 0  /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_LOWPART_PLUS_1 << (TARG_PART_BITS - 1) != TARG_MIN  /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_LOWPART_PLUS_1_U << (TARG_PART_BITS - 1) != TARG_MIN  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_LOWPART_PLUS_1 << (TARG_PART_BITS - 2) != (TARG_MAX_PLUS_1_U >> 1)  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+/* Test how the sign bit is handled.  */
+#if (TARG_MIN << 1) != 0    /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_MAX_PLUS_1_U << 1) != 0    /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_MIN >> 1) != 3U << (TARG_PRECISION - 2)    /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if (TARG_MAX_PLUS_1_U >> 1) != 1 << (TARG_PRECISION - 2)    /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+/* Unary -.  It can overflow in just one case.  */
+#if -TARG_MIN != TARG_MIN  /* { dg-warning "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if - -TARG_MAX != TARG_MAX   /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Unary +, ~, and !.  They cannot overflow.  */
+#if +TARG_MAX != TARG_MAX  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if !TARG_MAX + !TARG_MIN != 0   /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if ~TARG_MAX , ~TARG_MIN != TARG_MAX  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Bitwise &, ^, |.  They cannot overflow.  */
+#if (TARG_MAX & -1), (TARG_MIN & -1) != TARG_MIN  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX | -1, (TARG_MIN | -1) != -1  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if TARG_MAX ^ -1, (TARG_MIN ^ -1) != TARG_MAX  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Comparison operators.  They cannot overflow.  */
+#if -1 <= TARG_MAX, (TARG_MIN <= 1) != 1  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -1 >= TARG_MAX, (TARG_MIN >= 1) != 0  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -1 < TARG_MAX, (TARG_MIN < 1) != 1  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -1 > TARG_MAX, (TARG_MIN > 1) != 0  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+
+
+
+/* Comma and ? : operators.  They cannot overflow.  */
+#if -1, TARG_MAX, TARG_MIN != TARG_MIN  /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif
+
+#if -1 ? TARG_MAX: TARG_MAX, 0 ? 1: TARG_MIN != TARG_MIN /* { dg-bogus "overflow" } */
+# error		/* { dg-bogus "error" }  */
+#endif



More information about the Gcc-patches mailing list