cppexp.c (possible_sum_sign, [...]): Remove.
authorNeil Booth <neil@daikokuya.demon.co.uk>
Sun, 26 May 2002 18:42:21 +0000 (18:42 +0000)
committerNeil Booth <neil@gcc.gnu.org>
Sun, 26 May 2002 18:42:21 +0000 (18:42 +0000)
* cppexp.c (possible_sum_sign, integer_overflow, left_shift,
right_shift): Remove.
(cpp_num, cpp_num_part, PART_PRECISION, HALF_MASK, LOW_PART,
HIGH_PART): New.
(struct op): Use cpp_num.
(num_zerop, num_eq, num_positive, num_greater_freq, num_trim,
num_part_mul, num_unary_op, num_binary_op, num_negate,
num_bitwise_op, num_inequality_op, num_equality_op, num_mul,
num_div_op, num_lshift, num_rshift, append_digit): New.
(interpret_number, parse_defined, eval_token, reduce): Update
for two-integer arithmetic.
(binary_handler): New typedef.
(optab): Update.
(COMPARE, EQUALITY, BITWISE, MINMAX, UNARY, SHIFT): Delete.
(_cpp_parse_expr, reduce): Update to handle two-integers.
* cpplib.c (_cpp_test_assertion): Back up on CPP_EOF.
testsuite:
* gcc.dg/cpp/arith-1.c: New semantic tests.
* gcc.dg/cpp/if-1.c: Update.

From-SVN: r53900

gcc/ChangeLog
gcc/cppexp.c
gcc/cpplib.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cpp/arith-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cpp/if-1.c

index 55ffba4030218a9f4a08cc212f41e0593ca2eade..1a028a95b7f4f114439b37815b87a0ef79ccfcb0 100644 (file)
@@ -1,3 +1,22 @@
+2002-05-26  Neil Booth  <neil@daikokuya.demon.co.uk>
+
+       * cppexp.c (possible_sum_sign, integer_overflow, left_shift,
+       right_shift): Remove.
+       (cpp_num, cpp_num_part, PART_PRECISION, HALF_MASK, LOW_PART,
+       HIGH_PART): New.
+       (struct op): Use cpp_num.
+       (num_zerop, num_eq, num_positive, num_greater_freq, num_trim,
+       num_part_mul, num_unary_op, num_binary_op, num_negate,
+       num_bitwise_op, num_inequality_op, num_equality_op, num_mul,
+       num_div_op, num_lshift, num_rshift, append_digit): New.
+       (interpret_number, parse_defined, eval_token, reduce): Update
+       for two-integer arithmetic.
+       (binary_handler): New typedef.
+       (optab): Update.
+       (COMPARE, EQUALITY, BITWISE, MINMAX, UNARY, SHIFT): Delete.
+       (_cpp_parse_expr, reduce): Update to handle two-integers.
+       * cpplib.c (_cpp_test_assertion): Back up on CPP_EOF.
+
 2002-05-26  Marek Michalkiewicz  <marekm@amelek.gda.pl>
 
        * config/avr/avr.c (avr_asm_only_p): New variable.
index 2d2ce489c0330cc2377b03ade1ca370ded86d9b9..7aa350d49bdbc82cbac2f7d89f8b7522cf7960be 100644 (file)
@@ -23,29 +23,61 @@ Boston, MA 02111-1307, USA.  */
 #include "cpplib.h"
 #include "cpphash.h"
 
-/* Yield nonzero if adding two numbers with A's and B's signs can yield a
-   number with SUM's sign, where A, B, and SUM are all C integers.  */
-#define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
-
-static void integer_overflow PARAMS ((cpp_reader *));
-static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
-                                          unsigned int,
-                                          unsigned HOST_WIDEST_INT));
-static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
-                                           unsigned int,
-                                           unsigned HOST_WIDEST_INT));
-static struct op parse_number PARAMS ((cpp_reader *, const cpp_token *));
-static struct op parse_defined PARAMS ((cpp_reader *));
-static struct op eval_token PARAMS ((cpp_reader *, const cpp_token *));
-static struct op *reduce PARAMS ((cpp_reader *, struct op *, enum cpp_ttype));
+typedef unsigned long cpp_num_part;
+typedef struct cpp_num cpp_num;
+
+#define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT)
+#define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2))
+#define LOW_PART(num_part) (num_part & HALF_MASK)
+#define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2))
+
+/* A preprocessing number.  Code assumes that any unused high bits of
+   the double integer are set to zero.  */
+struct cpp_num
+{
+  cpp_num_part high;
+  cpp_num_part low;
+  bool unsignedp;  /* True if value should be treated as unsigned.  */
+  bool overflow;   /* True if the most recent calculation overflowed.  */
+};
 
 struct op
 {
+  cpp_num value;                    /* The value logically "right" of op.  */
   enum cpp_ttype op;
-  uchar unsignedp;    /* True if value should be treated as unsigned.  */
-  HOST_WIDEST_INT value; /* The value logically "right" of op.  */
 };
 
+/* Some simple utility routines on double integers.  */
+#define num_zerop(num) ((num.low | num.high) == 0)
+#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high)
+static bool num_positive PARAMS ((cpp_num, size_t));
+static bool num_greater_eq PARAMS ((cpp_num, cpp_num, size_t));
+static cpp_num num_trim PARAMS ((cpp_num, size_t));
+static cpp_num num_part_mul PARAMS ((cpp_num_part, cpp_num_part));
+
+static cpp_num num_unary_op PARAMS ((cpp_reader *, cpp_num, enum cpp_ttype));
+static cpp_num num_binary_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
+                                     enum cpp_ttype));
+static cpp_num num_negate PARAMS ((cpp_num, size_t));
+static cpp_num num_bitwise_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
+                                      enum cpp_ttype));
+static cpp_num num_inequality_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
+                                         enum cpp_ttype));
+static cpp_num num_equality_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
+                                       enum cpp_ttype));
+static cpp_num num_mul PARAMS ((cpp_reader *, cpp_num, cpp_num,
+                               enum cpp_ttype));
+static cpp_num num_div_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
+                                  enum cpp_ttype));
+static cpp_num num_lshift PARAMS ((cpp_num, size_t, size_t));
+static cpp_num num_rshift PARAMS ((cpp_num, size_t, size_t));
+
+static cpp_num append_digit PARAMS ((cpp_num, int, int, size_t));
+static cpp_num interpret_number PARAMS ((cpp_reader *, const cpp_token *));
+static cpp_num parse_defined PARAMS ((cpp_reader *));
+static cpp_num eval_token PARAMS ((cpp_reader *, const cpp_token *));
+static struct op *reduce PARAMS ((cpp_reader *, struct op *, enum cpp_ttype));
+
 /* Token type abuse.  There is no "error" token, but we can't get
    comments in #if, so we can abuse that token type.  Similarly,
    create unary plus and minus operators.  */
@@ -83,26 +115,79 @@ static const struct suffix vsuf_3[] = {
   { "llu", 1, 2 }, { "LLU", 1, 2 }, { "LLu", 1, 2 }, { "llU", 1, 2 }
 };
 
+/* Append DIGIT to NUM, a number of PRECISION bits being read in base
+   BASE.  */
+static cpp_num
+append_digit (num, digit, base, precision)
+     cpp_num num;
+     int digit, base;
+     size_t precision;
+{
+  cpp_num result;
+  unsigned int shift = 3 + (base == 16);
+  bool overflow;
+  cpp_num_part add_high, add_low;
+
+  /* Multiply by 8 or 16.  Catching this overflow here means we don't
+     need to worry about add_high overflowing.  */
+  overflow = num.high >> (PART_PRECISION - shift);
+  result.high = num.high << shift;
+  result.low = num.low << shift;
+  result.high |= num.low >> (PART_PRECISION - shift);
+
+  if (base == 10)
+    {
+      add_low = num.low << 1;
+      add_high = (num.high << 1) + (num.low >> (PART_PRECISION - 1));
+    }
+  else
+    add_high = add_low = 0;
+
+  if (add_low + digit < add_low)
+    add_high++;
+  add_low += digit;
+    
+  if (result.low + add_low < result.low)
+    add_high++;
+  if (result.high + add_high < result.high)
+    overflow = true;
+
+  result.low += add_low;
+  result.high += add_high;
+
+  /* The above code catches overflow of a cpp_num type.  This catches
+     overflow of the (possibly shorter) target precision.  */
+  num.low = result.low;
+  num.high = result.high;
+  result = num_trim (result, precision);
+  if (!num_eq (result, num))
+    overflow = true;
+
+  result.unsignedp = num.unsignedp;
+  result.overflow = overflow;
+  return result;
+}
+
 /* Parse and convert what is presumably an integer in TOK.  Accepts
    decimal, hex, or octal with or without size suffixes.  Returned op
    is CPP_ERROR on error, otherwise it is a CPP_NUMBER.  */
-static struct op
-parse_number (pfile, tok)
+static cpp_num
+interpret_number (pfile, tok)
      cpp_reader *pfile;
      const cpp_token *tok;
 {
-  struct op op;
+  cpp_num result;
   const uchar *start = tok->val.str.text;
   const uchar *end = start + tok->val.str.len;
   const uchar *p = start;
-  int c = 0, i, nsuff;
-  unsigned HOST_WIDEST_INT n = 0, nd, MAX_over_base;
-  int base = 10;
-  int overflow = 0;
-  int digit, largest_digit = 0;
   const struct suffix *sufftab;
+  size_t precision = CPP_OPTION (pfile, precision);
+  unsigned int i, nsuff, base = 10, c = 0, largest_digit = 0;
+  bool overflow = false;
 
-  op.unsignedp = 0;
+  result.low = result.high = 0;
+  result.unsignedp = 0;
+  result.overflow = 0;
 
   if (p[0] == '0')
     {
@@ -118,25 +203,19 @@ parse_number (pfile, tok)
        }
     }
 
-  /* Some buggy compilers (e.g. MPW C) seem to need both casts.  */
-  MAX_over_base = (((unsigned HOST_WIDEST_INT) -1)
-                  / ((unsigned HOST_WIDEST_INT) base));
-
   for(; p < end; p++)
     {
       c = *p;
 
-      if (ISDIGIT (c)
-         || (base == 16 && ISXDIGIT (c)))
-       digit = hex_value (c);
+      if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
+       c = hex_value (c);
       else
        break;
 
-      if (largest_digit < digit)
-       largest_digit = digit;
-      nd = n * base + digit;
-      overflow |= MAX_over_base < n || nd < n;
-      n = nd;
+      result = append_digit (result, c, base, precision);
+      overflow |= result.overflow;
+      if (largest_digit < c)
+       largest_digit = c;
     }
 
   if (p < end)
@@ -166,7 +245,7 @@ parse_number (pfile, tok)
          break;
       if (i == nsuff)
        goto invalid_suffix;
-      op.unsignedp = sufftab[i].u;
+      result.unsignedp = sufftab[i].u;
 
       if (CPP_WTRADITIONAL (pfile)
          && sufftab[i].u
@@ -183,38 +262,34 @@ parse_number (pfile, tok)
               "integer constant contains digits beyond the radix");
 
   if (overflow)
-    cpp_error (pfile, DL_PEDWARN, "integer constant out of range");
-
+    cpp_error (pfile, DL_PEDWARN, "integer constant too large for its type");
   /* If too big to be signed, consider it unsigned.  */
-  else if ((HOST_WIDEST_INT) n < 0 && ! op.unsignedp)
+  else if (!result.unsignedp && !num_positive (result, precision))
     {
       if (base == 10)
        cpp_error (pfile, DL_WARNING,
                   "integer constant is so large that it is unsigned");
-      op.unsignedp = 1;
+      result.unsignedp = 1;
     }
 
-  op.value = n;
-  op.op = CPP_NUMBER;
-  return op;
+  return result;
 
  invalid_suffix:
   cpp_error (pfile, DL_ERROR, "invalid suffix '%.*s' on integer constant",
             (int) (end - p), p);
  syntax_error:
-  op.op = CPP_ERROR;
-  return op;
+  return result;
 }
 
 /* Handle meeting "defined" in a preprocessor expression.  */
-static struct op
+static cpp_num
 parse_defined (pfile)
      cpp_reader *pfile;
 {
+  cpp_num result;
   int paren = 0;
   cpp_hashnode *node = 0;
   const cpp_token *token;
-  struct op op;
   cpp_context *initial_context = pfile->context;
 
   /* Don't expand macros.  */
@@ -253,57 +328,60 @@ parse_defined (pfile)
        }
     }
 
-  if (!node)
-    op.op = CPP_ERROR;
-  else
+  if (node)
     {
       if (pfile->context != initial_context)
        cpp_error (pfile, DL_WARNING,
                   "this use of \"defined\" may not be portable");
 
-      op.value = node->type == NT_MACRO;
-      op.unsignedp = 0;
-      op.op = CPP_NUMBER;
-
       /* A possible controlling macro of the form #if !defined ().
         _cpp_parse_expr checks there was no other junk on the line.  */
       pfile->mi_ind_cmacro = node;
     }
 
   pfile->state.prevent_expansion--;
-  return op;
+
+  result.unsignedp = 0;
+  result.high = 0;
+  result.overflow = 0;
+  result.low = node && node->type == NT_MACRO;
+  return result;
 }
 
 /* Convert a token into a CPP_NUMBER (an interpreted preprocessing
    number or character constant, or the result of the "defined" or "#"
    operators), or CPP_ERROR on error.  */
-static struct op
+static cpp_num
 eval_token (pfile, token)
      cpp_reader *pfile;
      const cpp_token *token;
 {
+  cpp_num result;
   unsigned int temp;
   int unsignedp = 0;
-  struct op op;
-
-  op.op = CPP_NUMBER;
 
   switch (token->type)
     {
     case CPP_NUMBER:
-      return parse_number (pfile, token);
+      return interpret_number (pfile, token);
 
     case CPP_WCHAR:
     case CPP_CHAR:
       {
-       cppchar_t result = cpp_interpret_charconst (pfile, token,
-                                                   &temp, &unsignedp);
-       op.value = result;
+       cppchar_t cc = cpp_interpret_charconst (pfile, token,
+                                               &temp, &unsignedp);
+
+       result.high = 0;
+       result.low = cc;
        /* Sign-extend the result if necessary.  */
-       if (!unsignedp && (cppchar_signed_t) result < 0
-           && sizeof (HOST_WIDEST_INT) > sizeof (cppchar_t))
-         op.value |= ~(((unsigned HOST_WIDEST_INT) 1 << BITS_PER_CPPCHAR_T)
-                       - 1);
+       if (!unsignedp && (cppchar_signed_t) cc < 0)
+         {
+           if (PART_PRECISION > BITS_PER_CPPCHAR_T)
+             result.low |= ~(~(cpp_num_part) 0
+                             >> (PART_PRECISION - BITS_PER_CPPCHAR_T));
+           result.high = ~(cpp_num_part) 0;
+           result = num_trim (result, CPP_OPTION (pfile, precision));
+         }
       }
       break;
 
@@ -314,7 +392,8 @@ eval_token (pfile, token)
               && (token->val.node == pfile->spec_nodes.n_true
                   || token->val.node == pfile->spec_nodes.n_false))
        {
-         op.value = (token->val.node == pfile->spec_nodes.n_true);
+         result.high = 0;
+         result.low = (token->val.node == pfile->spec_nodes.n_true);
 
          /* Warn about use of true or false in #if when pedantic
             and stdbool.h has not been included.  */
@@ -326,7 +405,8 @@ eval_token (pfile, token)
        }
       else
        {
-         op.value = 0;
+         result.high = 0;
+         result.low = 0;
          if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
            cpp_error (pfile, DL_WARNING, "\"%s\" is not defined",
                       NODE_NAME (token->val.node));
@@ -334,66 +414,14 @@ eval_token (pfile, token)
       break;
 
     default: /* CPP_HASH */
-      if (_cpp_test_assertion (pfile, &temp))
-       op.op = CPP_ERROR;
-      op.value = temp;
+      _cpp_test_assertion (pfile, &temp);
+      result.high = 0;
+      result.low = temp;
     }
 
-  op.unsignedp = unsignedp;
-  return op;
-}
-
-/* Warn if appropriate on overflow.  */
-static void
-integer_overflow (pfile)
-     cpp_reader *pfile;
-{
-  if (CPP_PEDANTIC (pfile))
-    cpp_error (pfile, DL_PEDWARN,
-              "integer overflow in preprocessor expression");
-}
-
-/* Handle shifting A left by B bits.  UNSIGNEDP is non-zero if A is
-   unsigned.  */
-static HOST_WIDEST_INT
-left_shift (pfile, a, unsignedp, b)
-     cpp_reader *pfile;
-     HOST_WIDEST_INT a;
-     unsigned int unsignedp;
-     unsigned HOST_WIDEST_INT b;
-{
-  if (b >= HOST_BITS_PER_WIDEST_INT)
-    {
-      if (! unsignedp && a != 0)
-       integer_overflow (pfile);
-      return 0;
-    }
-  else if (unsignedp)
-    return (unsigned HOST_WIDEST_INT) a << b;
-  else
-    {
-      HOST_WIDEST_INT l = a << b;
-      if (l >> b != a)
-       integer_overflow (pfile);
-      return l;
-    }
-}
-
-/* Handle shifting A right by B bits.  UNSIGNEDP is non-zero if A is
-   unsigned.  */
-static HOST_WIDEST_INT
-right_shift (pfile, a, unsignedp, b)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-     HOST_WIDEST_INT a;
-     unsigned int unsignedp;
-     unsigned HOST_WIDEST_INT b;
-{
-  if (b >= HOST_BITS_PER_WIDEST_INT)
-    return unsignedp ? 0 : a >> (HOST_BITS_PER_WIDEST_INT - 1);
-  else if (unsignedp)
-    return (unsigned HOST_WIDEST_INT) a >> b;
-  else
-    return a >> b;
+  result.unsignedp = unsignedp;
+  result.overflow = 0;
+  return result;
 }
 \f
 /* Operator precedence and flags table.
@@ -422,74 +450,58 @@ extra semantics need to be handled with operator-specific code.  */
 #define NO_L_OPERAND   (1 << 0)
 #define LEFT_ASSOC     (1 << 1)
 
+/* Arity. */
+#define UNARY          (1 << 0)
+#define BINARY         (1 << 1)
+#define OTHER          (1 << 2)
+
+typedef cpp_num (*binary_handler) PARAMS ((cpp_reader *, cpp_num, cpp_num,
+                                          enum cpp_ttype));
 /* Operator to priority map.  Must be in the same order as the first
    N entries of enum cpp_ttype.  */
 static const struct operator
 {
   uchar prio;
   uchar flags;
+  uchar arity;
+  binary_handler handler;
 } optab[] =
 {
-  /* EQ */             {0, 0},         /* Shouldn't happen.  */
-  /* NOT */            {16, NO_L_OPERAND},
-  /* GREATER */                {12, LEFT_ASSOC},
-  /* LESS */           {12, LEFT_ASSOC},
-  /* PLUS */           {14, LEFT_ASSOC},
-  /* MINUS */          {14, LEFT_ASSOC},
-  /* MULT */           {15, LEFT_ASSOC},
-  /* DIV */            {15, LEFT_ASSOC},
-  /* MOD */            {15, LEFT_ASSOC},
-  /* AND */            {9, LEFT_ASSOC},
-  /* OR */             {7, LEFT_ASSOC},
-  /* XOR */            {8, LEFT_ASSOC},
-  /* RSHIFT */         {13, LEFT_ASSOC},
-  /* LSHIFT */         {13, LEFT_ASSOC},
-  /* MIN */            {10, LEFT_ASSOC},       /* C++ specific */
-  /* MAX */            {10, LEFT_ASSOC},       /* extensions */
-
-  /* COMPL */          {16, NO_L_OPERAND},
-  /* AND_AND */                {6, LEFT_ASSOC},
-  /* OR_OR */          {5, LEFT_ASSOC},
-  /* QUERY */          {3, 0},
-  /* COLON */          {4, LEFT_ASSOC},
-  /* COMMA */          {2, LEFT_ASSOC},
-  /* OPEN_PAREN */     {1, NO_L_OPERAND},
-  /* CLOSE_PAREN */    {0, 0},
-  /* EOF */            {0, 0},
-  /* EQ_EQ */          {11, LEFT_ASSOC},
-  /* NOT_EQ */         {11, LEFT_ASSOC},
-  /* GREATER_EQ */     {12, LEFT_ASSOC},
-  /* LESS_EQ */                {12, LEFT_ASSOC},
-  /* UPLUS */          {16, NO_L_OPERAND},
-  /* UMINUS */         {16, NO_L_OPERAND}
+  /* EQ */             {0, 0, OTHER, NULL},    /* Shouldn't happen.  */
+  /* NOT */            {16, NO_L_OPERAND, UNARY, NULL},
+  /* GREATER */                {12, LEFT_ASSOC, BINARY, num_inequality_op},
+  /* LESS */           {12, LEFT_ASSOC, BINARY, num_inequality_op},
+  /* PLUS */           {14, LEFT_ASSOC, BINARY, num_binary_op},
+  /* MINUS */          {14, LEFT_ASSOC, BINARY, num_binary_op},
+  /* MULT */           {15, LEFT_ASSOC, BINARY, num_mul},
+  /* DIV */            {15, LEFT_ASSOC, BINARY, num_div_op},
+  /* MOD */            {15, LEFT_ASSOC, BINARY, num_div_op},
+  /* AND */            {9, LEFT_ASSOC, BINARY, num_bitwise_op},
+  /* OR */             {7, LEFT_ASSOC, BINARY, num_bitwise_op},
+  /* XOR */            {8, LEFT_ASSOC, BINARY, num_bitwise_op},
+  /* RSHIFT */         {13, LEFT_ASSOC, BINARY, num_binary_op},
+  /* LSHIFT */         {13, LEFT_ASSOC, BINARY, num_binary_op},
+
+  /* MIN */            {10, LEFT_ASSOC, BINARY, num_binary_op},
+  /* MAX */            {10, LEFT_ASSOC, BINARY, num_binary_op},
+
+  /* COMPL */          {16, NO_L_OPERAND, UNARY, NULL},
+  /* AND_AND */                {6, LEFT_ASSOC, OTHER, NULL},
+  /* OR_OR */          {5, LEFT_ASSOC, OTHER, NULL},
+  /* QUERY */          {3, 0, OTHER, NULL},
+  /* COLON */          {4, LEFT_ASSOC, OTHER, NULL},
+  /* COMMA */          {2, LEFT_ASSOC, BINARY, num_binary_op},
+  /* OPEN_PAREN */     {1, NO_L_OPERAND, OTHER, NULL},
+  /* CLOSE_PAREN */    {0, 0, OTHER, NULL},
+  /* EOF */            {0, 0, OTHER, NULL},
+  /* EQ_EQ */          {11, LEFT_ASSOC, BINARY, num_equality_op},
+  /* NOT_EQ */         {11, LEFT_ASSOC, BINARY, num_equality_op},
+  /* GREATER_EQ */     {12, LEFT_ASSOC, BINARY, num_inequality_op},
+  /* LESS_EQ */                {12, LEFT_ASSOC, BINARY, num_inequality_op},
+  /* UPLUS */          {16, NO_L_OPERAND, UNARY, NULL},
+  /* UMINUS */         {16, NO_L_OPERAND, UNARY, NULL}
 };
 
-#define COMPARE(OP) \
-  top->unsignedp = 0; \
-  top->value = (unsigned1 | unsigned2) \
-  ? (unsigned HOST_WIDEST_INT) v1 OP (unsigned HOST_WIDEST_INT) v2 \
-  : (v1 OP v2)
-#define EQUALITY(OP) \
-  top->value = v1 OP v2; \
-  top->unsignedp = 0;
-#define BITWISE(OP) \
-  top->value = v1 OP v2; \
-  top->unsignedp = unsigned1 | unsigned2;
-#define MINMAX(OP) \
-  top->value = (v1 OP v2) ? v1 : v2; \
-  top->unsignedp = unsigned1 | unsigned2;
-#define UNARY(OP) \
-  top->value = OP v2; \
-  top->unsignedp = unsigned2;
-#define SHIFT(PSH, MSH) \
-  if (pfile->state.skip_eval)  \
-    break;             \
-  top->unsignedp = unsigned1; \
-  if (v2 < 0 && ! unsigned2)  \
-    top->value = MSH (pfile, v1, unsigned1, -v2); \
-  else \
-    top->value = PSH (pfile, v1, unsigned1, v2);
-
 /* Parse and evaluate a C expression, reading from PFILE.
    Returns the truth value of the expression.
 
@@ -541,11 +553,7 @@ _cpp_parse_expr (pfile)
            SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
                           cpp_token_as_text (pfile, token));
          want_value = false;
-         op = eval_token (pfile, token);
-         if (op.op == CPP_ERROR)
-           goto syntax_error;
-         top->value = op.value;
-         top->unsignedp = op.unsignedp;
+         top->value = eval_token (pfile, token);
          continue;
 
        case CPP_NOT:
@@ -607,18 +615,18 @@ _cpp_parse_expr (pfile)
        case CPP_CLOSE_PAREN:
          continue;
        case CPP_OR_OR:
-         if (top->value)
+         if (!num_zerop (top->value))
            pfile->state.skip_eval++;
          break;
        case CPP_AND_AND:
        case CPP_QUERY:
-         if (!top->value)
+         if (num_zerop (top->value))
            pfile->state.skip_eval++;
          break;
        case CPP_COLON:
          if (top->op != CPP_QUERY)
            SYNTAX_ERROR (" ':' without preceding '?'");
-         if (top[-1].value) /* Was '?' condition true?  */
+         if (!num_zerop (top[-1].value)) /* Was '?' condition true?  */
            pfile->state.skip_eval++;
          else
            pfile->state.skip_eval--;
@@ -648,7 +656,7 @@ _cpp_parse_expr (pfile)
       return false;  /* Return false on syntax error.  */
     }
 
-  return top->value != 0;
+  return !num_zerop (top->value);
 }
 
 /* Reduce the operator / value stack if possible, in preparation for
@@ -662,6 +670,13 @@ reduce (pfile, top, op)
 {
   unsigned int prio;
 
+  if (top->op <= CPP_EQ || top->op > CPP_LAST_CPP_OP + 2)
+    {
+    bad_op:
+      cpp_error (pfile, DL_ICE, "impossible operator '%u'", top->op);
+      return 0;
+    }
+
   if (op == CPP_OPEN_PAREN)
     return top;
 
@@ -670,144 +685,73 @@ reduce (pfile, top, op)
   prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0);
   while (prio < optab[top->op].prio)
     {
-      HOST_WIDEST_INT v1, v2;
-      unsigned int unsigned1, unsigned2;
-
-      unsigned2 = top->unsignedp, v2 = top->value;
-      top--;
-      unsigned1 = top->unsignedp, v1 = top->value;
-
-      /* Now set top->value = (top[1].op)(v1, v2); */
-      switch (top[1].op)
+      if (optab[top->op].arity == UNARY)
        {
-       default:
-         cpp_error (pfile, DL_ICE, "impossible operator '%u'", top[1].op);
-         return 0;
-
-       case CPP_NOT:    UNARY(!);      break;
-       case CPP_COMPL:  UNARY(~);      break;
-       case CPP_LESS:   COMPARE(<);    break;
-       case CPP_GREATER: COMPARE(>);   break;
-       case CPP_LESS_EQ: COMPARE(<=);  break;
-       case CPP_GREATER_EQ: COMPARE(>=); break;
-       case CPP_EQ_EQ:  EQUALITY(==);  break;
-       case CPP_NOT_EQ: EQUALITY(!=);  break;
-       case CPP_AND:    BITWISE(&);    break;
-       case CPP_XOR:    BITWISE(^);    break;
-       case CPP_OR:     BITWISE(|);    break;
-       case CPP_LSHIFT: SHIFT(left_shift, right_shift); break;
-       case CPP_RSHIFT: SHIFT(right_shift, left_shift); break;
-       case CPP_MIN:    MINMAX(<);     break;
-       case CPP_MAX:    MINMAX(>);     break;
-
-       case CPP_UPLUS:
-         /* Can't use UNARY(+) because K+R C did not have unary
-            plus.  Can't use UNARY() because some compilers object
-            to the empty argument.  */
-         top->value = v2;
-         top->unsignedp = unsigned2;
-         if (CPP_WTRADITIONAL (pfile))
-           cpp_error (pfile, DL_WARNING,
-                      "traditional C rejects the unary plus operator");
-         break;
-       case CPP_UMINUS:
-         UNARY(-);
-         if (!pfile->state.skip_eval && (top->value & v2) < 0 && !unsigned2)
-           integer_overflow (pfile);
+         if (!pfile->state.skip_eval)
+           top[-1].value = num_unary_op (pfile, top->value, top->op);
+         top--;
+       }
+      else if (optab[top->op].arity == BINARY)
+       {
+         if (!pfile->state.skip_eval)
+           top[-1].value = (* (binary_handler) optab[top->op].handler)
+             (pfile, top[-1].value, top->value, top->op);
+         top--;
+       }
+      /* Anything changing skip_eval has to be handled here.  */
+      else switch (top--->op)
+       {
+       case CPP_OR_OR:
+         if (!num_zerop (top->value))
+           pfile->state.skip_eval--;
+         top->value.low = !num_zerop (top->value) || !num_zerop (top[1].value);
+         top->value.high = 0;
+         top->value.unsignedp = false;
+         top->value.overflow = false;
          break;
 
-       case CPP_PLUS:
-         top->value = v1 + v2;
-         top->unsignedp = unsigned1 | unsigned2;
-         if (! top->unsignedp && ! pfile->state.skip_eval
-             && ! possible_sum_sign (v1, v2, top->value))
-           integer_overflow (pfile);
-         break;
-       case CPP_MINUS:
-         top->value = v1 - v2;
-         top->unsignedp = unsigned1 | unsigned2;
-         if (! top->unsignedp && ! pfile->state.skip_eval
-             && ! possible_sum_sign (top->value, v2, v1))
-           integer_overflow (pfile);
-         break;
-       case CPP_MULT:
-         top->unsignedp = unsigned1 | unsigned2;
-         if (top->unsignedp)
-           top->value = (unsigned HOST_WIDEST_INT) v1 * v2;
-         else if (!pfile->state.skip_eval)
-           {
-             top->value = v1 * v2;
-             if (v1 && (top->value / v1 != v2
-                        || (top->value & v1 & v2) < 0))
-               integer_overflow (pfile);
-           }
+       case CPP_AND_AND:
+         if (num_zerop (top->value))
+           pfile->state.skip_eval--;
+         top->value.low = !num_zerop (top->value) && !num_zerop (top[1].value);
+         top->value.high = 0;
+         top->value.unsignedp = false;
+         top->value.overflow = false;
          break;
-       case CPP_DIV:
-       case CPP_MOD:
-         if (pfile->state.skip_eval)
-           break;
-         if (v2 == 0)
+
+       case CPP_OPEN_PAREN:
+         if (op != CPP_CLOSE_PAREN)
            {
-             cpp_error (pfile, DL_ERROR, "division by zero in #if");
+             cpp_error (pfile, DL_ERROR, "missing ')' in expression");
              return 0;
            }
-         top->unsignedp = unsigned1 | unsigned2;
-         if (top[1].op == CPP_DIV)
+         top->value = top[1].value;
+         return top;
+
+       case CPP_COLON:
+         top--;
+         if (!num_zerop (top->value))
            {
-             if (top->unsignedp)
-               top->value = (unsigned HOST_WIDEST_INT) v1 / v2;
-             else
-               {
-                 top->value = v1 / v2;
-                 if ((top->value & v1 & v2) < 0)
-                   integer_overflow (pfile);
-               }
+             pfile->state.skip_eval--;
+             top->value = top[1].value;
            }
          else
-           {
-             if (top->unsignedp)
-               top->value = (unsigned HOST_WIDEST_INT) v1 % v2;
-             else
-               top->value = v1 % v2;
-           }
+           top->value = top[2].value;
+         top->value.unsignedp = (top[1].value.unsignedp
+                                 || top[2].value.unsignedp);
          break;
 
-       case CPP_OR_OR:
-         top->value = v1 || v2;
-         top->unsignedp = 0;
-         if (v1) pfile->state.skip_eval--;
-         break;
-       case CPP_AND_AND:
-         top->value = v1 && v2;
-         top->unsignedp = 0;
-         if (!v1) pfile->state.skip_eval--;
-         break;
-       case CPP_COMMA:
-         if (CPP_PEDANTIC (pfile))
-           cpp_error (pfile, DL_PEDWARN,
-                      "comma operator in operand of #if");
-         top->value = v2;
-         top->unsignedp = unsigned2;
-         break;
        case CPP_QUERY:
          cpp_error (pfile, DL_ERROR, "'?' without following ':'");
          return 0;
-       case CPP_COLON:
-         top--;
-         if (top->value) pfile->state.skip_eval--;
-         top->value = top->value ? v1 : v2;
-         top->unsignedp = unsigned1 | unsigned2;
-         break;
-       case CPP_OPEN_PAREN:
-         if (op != CPP_CLOSE_PAREN)
-           {
-             cpp_error (pfile, DL_ERROR, "missing ')' in expression");
-             return 0;
-           }
-         top->value = v2;
-         top->unsignedp = unsigned2;
-         return top;
+
+       default:
+         goto bad_op;
        }
+
+      if (top->value.overflow && !pfile->state.skip_eval)
+       cpp_error (pfile, DL_PEDWARN,
+                  "integer overflow in preprocessor expression");
     }
 
   if (op == CPP_CLOSE_PAREN)
@@ -833,3 +777,545 @@ _cpp_expand_op_stack (pfile)
 
   return pfile->op_stack + old_size;
 }
+
+/* Clears the unused high order bits of the number pointed to by PNUM.  */
+static cpp_num
+num_trim (num, precision)
+     cpp_num num;
+     size_t precision;
+{
+  if (precision > PART_PRECISION)
+    {
+      precision -= PART_PRECISION;
+      if (precision < PART_PRECISION)
+       num.high &= (1 << precision) - 1;
+    }
+  else
+    {
+      if (precision < PART_PRECISION)
+       num.low &= (1 << precision) - 1;
+      num.high = 0;
+    }
+
+  return num;
+}
+
+/* True iff A (presumed signed) >= 0.  */
+static bool
+num_positive (num, precision)
+     cpp_num num;
+     size_t precision;
+{
+  if (precision > PART_PRECISION)
+    {
+      precision -= PART_PRECISION;
+      return (num.high & (1 << (precision - 1))) == 0;
+    }
+
+  return (num.low & (1 << (precision - 1))) == 0;
+}
+
+/* Returns the negative of NUM.  */
+static cpp_num
+num_negate (num, precision)
+     cpp_num num;
+     size_t precision;
+{
+  cpp_num copy;
+
+  copy = num;
+  num.high = ~num.high;
+  num.low = ~num.low;
+  if (++num.low == 0)
+    num.high++;
+  num = num_trim (num, precision);
+  num.overflow = (!num.unsignedp && num_eq (num, copy) && !num_zerop (num));
+
+  return num;
+}
+
+/* Returns true if A >= B.  */
+static bool
+num_greater_eq (pa, pb, precision)
+     cpp_num pa, pb;
+     size_t precision;
+{
+  bool unsignedp;
+
+  unsignedp = pa.unsignedp || pb.unsignedp;
+
+  if (!unsignedp)
+    {
+      /* Both numbers have signed type.  If they are of different
+       sign, the answer is the sign of A.  */
+      unsignedp = num_positive (pa, precision);
+
+      if (unsignedp != num_positive (pb, precision))
+       return unsignedp;
+
+      /* Otherwise we can do an unsigned comparison.  */
+    }
+
+  return (pa.high > pb.high) || (pa.high == pb.high && pa.low >= pb.low);
+}
+
+/* Returns LHS OP RHS, where OP is a bit-wise operation.  */
+static cpp_num
+num_bitwise_op (pfile, lhs, rhs, op)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     cpp_num lhs, rhs;
+     enum cpp_ttype op;
+{
+  lhs.overflow = false;
+  lhs.unsignedp = lhs.unsignedp || rhs.unsignedp;
+
+  /* As excess precision is zeroed, there is no need to num_trim () as
+     these operations cannot introduce a set bit there.  */
+  if (op == CPP_AND)
+    {
+      lhs.low &= rhs.low;
+      lhs.high &= rhs.high;
+    }
+  else if (op == CPP_OR)
+    {
+      lhs.low |= rhs.low;
+      lhs.high |= rhs.high;
+    }
+  else
+    {
+      lhs.low ^= rhs.low;
+      lhs.high ^= rhs.high;
+    }
+
+  return lhs;
+}
+
+/* Returns LHS OP RHS, where OP is an inequality.  */
+static cpp_num
+num_inequality_op (pfile, lhs, rhs, op)
+     cpp_reader *pfile;
+     cpp_num lhs, rhs;
+     enum cpp_ttype op;
+{
+  bool gte = num_greater_eq (lhs, rhs, CPP_OPTION (pfile, precision));
+
+  if (op == CPP_GREATER_EQ)
+    lhs.low = gte;
+  else if (op == CPP_LESS)
+    lhs.low = !gte;
+  else if (op == CPP_GREATER)
+    lhs.low = gte && !num_eq (lhs, rhs);
+  else /* CPP_LESS_EQ.  */
+    lhs.low = !gte || num_eq (lhs, rhs);
+
+  lhs.high = 0;
+  lhs.overflow = false;
+  lhs.unsignedp = false;
+  return lhs;
+}
+
+/* Returns LHS OP RHS, where OP is == or !=.  */
+static cpp_num
+num_equality_op (pfile, lhs, rhs, op)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+     cpp_num lhs, rhs;
+     enum cpp_ttype op;
+{
+  lhs.low = num_eq (lhs, rhs);
+  if (op == CPP_NOT_EQ)
+    lhs.low = !lhs.low;
+  lhs.high = 0;
+  lhs.overflow = false;
+  lhs.unsignedp = false;
+  return lhs;
+}
+
+/* Shift NUM, of width PRECISION, right by N bits.  */
+static cpp_num
+num_rshift (num, precision, n)
+     cpp_num num;
+     size_t precision, n;
+{
+  cpp_num_part sign_mask;
+
+  if (num.unsignedp || num_positive (num, precision))
+    sign_mask = 0;
+  else
+    sign_mask = ~(cpp_num_part) 0;
+
+  if (n >= precision)
+    num.high = num.low = sign_mask;
+  else
+    {
+      /* Sign-extend.  */
+      if (precision < PART_PRECISION)
+       num.high = sign_mask, num.low |= sign_mask << precision;
+      else if (precision < 2 * PART_PRECISION)
+       num.high |= sign_mask << (precision - PART_PRECISION);
+
+      if (n >= PART_PRECISION)
+       {
+         n -= PART_PRECISION;
+         num.low = num.high;
+         num.high = sign_mask;
+       }
+
+      if (n)
+       {
+         num.low = (num.low >> n) | (num.high << (PART_PRECISION - n));
+         num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n));
+       }
+    }
+
+  num = num_trim (num, precision);
+  num.overflow = false;
+  return num;
+}
+
+/* Shift NUM, of width PRECISION, left by N bits.  */
+static cpp_num
+num_lshift (num, precision, n)
+     cpp_num num;
+     size_t precision, n;
+{
+  if (n >= precision)
+    {
+      num.overflow = !num.unsignedp && !num_zerop (num);
+      num.high = num.low = 0;
+    }
+  else
+    {
+      cpp_num orig, maybe_orig;
+      size_t m = n;
+
+      orig = num;
+      if (m >= PART_PRECISION)
+       {
+         m -= PART_PRECISION;
+         num.high = num.low;
+         num.low = 0;
+       }
+      if (m)
+       {
+         num.high = (num.high << m) | (num.low >> (PART_PRECISION - m));
+         num.low <<= m;
+       }
+      num = num_trim (num, precision);
+
+      if (num.unsignedp)
+       num.overflow = false;
+      else
+       {
+         maybe_orig = num_rshift (num, precision, n);
+         num.overflow = !num_eq (orig, maybe_orig);
+       }
+    }
+
+  return num;
+}
+
+/* The four unary operators: +, -, ! and ~.  */
+static cpp_num
+num_unary_op (pfile, num, op)
+     cpp_reader *pfile;
+     cpp_num num;
+     enum cpp_ttype op;
+{
+  switch (op)
+    {
+    case CPP_UPLUS:
+      if (CPP_WTRADITIONAL (pfile))
+       cpp_error (pfile, DL_WARNING,
+                  "traditional C rejects the unary plus operator");
+      num.overflow = false;
+      break;
+
+    case CPP_UMINUS:
+      num = num_negate (num, CPP_OPTION (pfile, precision));
+      break;
+
+    case CPP_COMPL:
+      num.high = ~num.high;
+      num.low = ~num.low;
+      num = num_trim (num, CPP_OPTION (pfile, precision));
+      num.overflow = false;
+      break;
+
+    default: /* case CPP_NOT: */
+      num.low = num_zerop (num);
+      num.high = 0;
+      num.overflow = false;
+      num.unsignedp = false;
+      break;
+    }
+
+  return num;
+}
+
+/* The various binary operators.  */
+static cpp_num
+num_binary_op (pfile, lhs, rhs, op)
+     cpp_reader *pfile;
+     cpp_num lhs, rhs;
+     enum cpp_ttype op;
+{
+  cpp_num result;
+  size_t precision = CPP_OPTION (pfile, precision);
+  bool gte;
+  size_t n;
+
+  switch (op)
+    {
+      /* Shifts.  */
+    case CPP_LSHIFT:
+    case CPP_RSHIFT:
+      if (!rhs.unsignedp && !num_positive (rhs, precision))
+       {
+         /* A negative shift is a positive shift the other way.  */
+         if (op == CPP_LSHIFT)
+           op = CPP_RSHIFT;
+         else
+           op = CPP_LSHIFT;
+         rhs = num_negate (rhs, precision);
+       }
+      if (rhs.high)
+       n = ~0;                 /* Maximal.  */
+      else
+       n = rhs.low;
+      if (op == CPP_LSHIFT)
+       lhs = num_lshift (lhs, precision, n);
+      else
+       lhs = num_rshift (lhs, precision, n);
+      break;
+
+      /* Min / Max.  */
+    case CPP_MIN:
+    case CPP_MAX:
+      {
+       bool unsignedp = lhs.unsignedp || rhs.unsignedp;
+
+       gte = num_greater_eq (lhs, rhs, precision);
+       if (op == CPP_MIN)
+         gte = !gte;
+       if (!gte)
+         lhs = rhs;
+       lhs.unsignedp = unsignedp;
+      }
+      break;
+
+      /* Arithmetic.  */
+    case CPP_MINUS:
+      rhs = num_negate (rhs, precision);
+    case CPP_PLUS:
+      result.low = lhs.low + rhs.low;
+      result.high = lhs.high + rhs.high;
+      if (result.low < lhs.low)
+       result.high++;
+
+      result = num_trim (result, precision);
+      result.unsignedp = lhs.unsignedp || rhs.unsignedp;
+      if (result.unsignedp)
+       result.overflow = false;
+      else
+       {
+         bool lhsp = num_positive (lhs, precision);
+         result.overflow = (lhsp == num_positive (rhs, precision)
+                            && lhsp != num_positive (result, precision));
+       }
+      return result;
+
+      /* Comma.  */
+    default: /* case CPP_COMMA: */
+      if (CPP_PEDANTIC (pfile))
+       cpp_error (pfile, DL_PEDWARN,
+                  "comma operator in operand of #if");
+      lhs = rhs;
+      break;
+    }
+
+  return lhs;
+}
+
+/* Multiplies two unsigned cpp_num_parts to give a cpp_num.  This
+   cannot overflow.  */
+static cpp_num
+num_part_mul (lhs, rhs)
+     cpp_num_part lhs, rhs;
+{
+  cpp_num result;
+  cpp_num_part middle[2], temp;
+
+  result.low = LOW_PART (lhs) * LOW_PART (rhs);
+  result.high = HIGH_PART (lhs) * HIGH_PART (rhs);
+
+  middle[0] = LOW_PART (lhs) * HIGH_PART (rhs);
+  middle[1] = HIGH_PART (lhs) * LOW_PART (rhs);
+
+  temp = result.low;
+  result.low += LOW_PART (middle[0]) << (PART_PRECISION / 2);
+  if (result.low < temp)
+    result.high++;
+
+  temp = result.low;
+  result.low += LOW_PART (middle[1]) << (PART_PRECISION / 2);
+  if (result.low < temp)
+    result.high++;
+
+  result.high += HIGH_PART (middle[0]);
+  result.high += HIGH_PART (middle[1]);
+
+  return result;
+}
+
+/* Multiply two preprocessing numbers.  */
+static cpp_num
+num_mul (pfile, lhs, rhs, op)
+     cpp_reader *pfile;
+     cpp_num lhs, rhs;
+     enum cpp_ttype op ATTRIBUTE_UNUSED;
+{
+  cpp_num result, temp;
+  bool unsignedp = lhs.unsignedp || rhs.unsignedp;
+  bool overflow, negate = false;
+  size_t precision = CPP_OPTION (pfile, precision);
+
+  /* Prepare for unsigned multiplication.  */
+  if (!unsignedp)
+    {
+      if (!num_positive (lhs, precision))
+       negate = !negate, lhs = num_negate (lhs, precision);
+      if (!num_positive (rhs, precision))
+       negate = !negate, rhs = num_negate (rhs, precision);
+    }
+
+  overflow = lhs.high && rhs.high;
+  result = num_part_mul (lhs.low, rhs.low);
+
+  temp = num_part_mul (lhs.high, rhs.low);
+  result.high += temp.low;
+  if (temp.high)
+    overflow = true;
+
+  temp = num_part_mul (lhs.low, rhs.high);
+  result.high += temp.low;
+  if (temp.high)
+    overflow = true;
+
+  temp.low = result.low, temp.high = result.high;
+  result = num_trim (result, precision);
+  if (!num_eq (result, temp))
+    overflow = true;
+
+  if (negate)
+    result = num_negate (result, precision);
+
+  if (unsignedp)
+    result.overflow = false;
+  else
+    result.overflow = overflow || (num_positive (result, precision) ^ !negate
+                                  && !num_zerop (result));
+  result.unsignedp = unsignedp;
+
+  return result;
+}
+
+/* Divide two preprocessing numbers, returning the answer or the
+   remainder depending upon OP.  */
+static cpp_num
+num_div_op (pfile, lhs, rhs, op)
+     cpp_reader *pfile;
+     cpp_num lhs, rhs;
+     enum cpp_ttype op;
+{
+  cpp_num result, sub;
+  cpp_num_part mask;
+  bool unsignedp = lhs.unsignedp || rhs.unsignedp;
+  bool negate = false, lhs_neg = false;
+  size_t i, precision = CPP_OPTION (pfile, precision);
+
+  /* Prepare for unsigned division.  */
+  if (!unsignedp)
+    {
+      if (!num_positive (lhs, precision))
+       negate = !negate, lhs_neg = true, lhs = num_negate (lhs, precision);
+      if (!num_positive (rhs, precision))
+       negate = !negate, rhs = num_negate (rhs, precision);
+    }
+
+  /* Find the high bit.  */
+  if (rhs.high)
+    {
+      i = precision - 1;
+      mask = 1 << (i - PART_PRECISION);
+      for (; ; i--, mask >>= 1)
+       if (rhs.high & mask)
+         break;
+    }
+  else if (rhs.low)
+    {
+      if (precision > PART_PRECISION)
+       i = precision - PART_PRECISION - 1;
+      else
+       i = precision - 1;
+      mask = 1 << i;
+      for (; ; i--, mask >>= 1)
+       if (rhs.low & mask)
+         break;
+    }
+  else
+    {
+      cpp_error (pfile, DL_ERROR, "division by zero in #if");
+      return lhs;
+    }
+
+  /* First non-zero bit of RHS is bit I.  Do naive division by
+     shifting the RHS fully left, and subtracting from LHS if LHS is
+     at least as big, and then repeating but with one less shift.
+     This is not very efficient, but is easy to understand.  */
+
+  rhs.unsignedp = true;
+  lhs.unsignedp = true;
+  i = precision - i - 1;
+  sub = num_lshift (rhs, precision, i);
+
+  result.high = result.low = 0;
+  for (;;)
+    {
+      if (num_greater_eq (lhs, sub, precision))
+       {
+         lhs = num_binary_op (pfile, lhs, sub, CPP_MINUS);
+         if (i >= PART_PRECISION)
+           result.high |= 1 << (i - PART_PRECISION);
+         else
+           result.low |= 1 << i;
+       }
+      if (i-- == 0)
+       break;
+      sub.low = (sub.low >> 1) | (sub.high << (PART_PRECISION - 1));
+      sub.high >>= 1;
+    }
+
+  /* We divide so that the remainder has the sign of the LHS.  */
+  if (op == CPP_DIV)
+    {
+      result.unsignedp = unsignedp;
+      if (unsignedp)
+       result.overflow = false;
+      else
+       {
+         if (negate)
+           result = num_negate (result, precision);
+         result.overflow = num_positive (result, precision) ^ !negate;
+       }
+
+      return result;
+    }
+
+  /* CPP_MOD.  */
+  lhs.unsignedp = unsignedp;
+  lhs.overflow = false;
+  if (lhs_neg)
+    lhs = num_negate (lhs, precision);
+
+  return lhs;
+}
index ba6924d08ec6f0b009cc6f0c9f659b6242ba38bb..e819ffca4d0920f96fadc2f1e2a13216f09c6f32 100644 (file)
@@ -1652,6 +1652,8 @@ _cpp_test_assertion (pfile, value)
   if (node)
     *value = (node->type == NT_ASSERTION &&
              (answer == 0 || *find_answer (node, answer) != 0));
+  else if (pfile->cur_token[-1].type == CPP_EOF)
+    _cpp_backup_tokens (pfile, 1);
 
   /* We don't commit the memory for the answer - it's temporary only.  */
   return node == 0;
index 3dc427f4b7033ea8eae3157733ec194873a49c4d..51e46fb12f029bc09a6af2ff860849fa9c504792 100644 (file)
@@ -1,3 +1,8 @@
+2002-05-26  Neil Booth  <neil@daikokuya.demon.co.uk>
+
+       * gcc.dg/cpp/arith-1.c: New semantic tests.
+       * gcc.dg/cpp/if-1.c: Update.
+
 2002-05-24  Ben Elliston  <bje@redhat.com>
 
        * lib/c-torture.exp (c-torture-execute): Handle multiple sources.
diff --git a/gcc/testsuite/gcc.dg/cpp/arith-1.c b/gcc/testsuite/gcc.dg/cpp/arith-1.c
new file mode 100644 (file)
index 0000000..85d5848
--- /dev/null
@@ -0,0 +1,257 @@
+/* Preprocessor arithmetic semantic tests.  */
+
+/* Copyright (C) 2002 Free Software Foundation, Inc.  */
+/* Source: Neil Booth, 25 May 2002.  */
+
+/* The file tests all aspects of preprocessor arithmetic that are
+   independent of target precision.  */
+
+/* { dg-do preprocess } */
+/* { dg-options -fno-show-column } */
+
+/* Test || operator and its short circuiting.  */
+#if 0 || 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 5 || 0
+#else
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 0 || 1
+#else
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 1 || 4
+#else
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 1 || (8 / 0) /* { dg-bogus "division by zero" }  */
+#else
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 1 || (1 << 256) /* { dg-bogus "overflow" }  */
+#endif
+
+/* Test && operator and its short circuiting.  */
+#if (0 && 0) || (0 && 1) || (1 && 0)
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 1 && 2
+#else
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 0 && (8 / 0)/* { dg-bogus "division by zero" }  */
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 0 && (1 << 256) /* { dg-bogus "overflow" }  */
+#endif
+
+/* Test == and != operators, and their signedness.  */
+#if 1 == 0 || 0 == 1 || 20 != 0x014 || 142 != 0216
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (1 == 1) - 2 > 0 || (1U != 1U) - 2 > 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+/* Test ? : operator, its short circuiting, and its signedness.  */
+#if (1 ? 3: 5) != 3 || (0 ? 3: 5) != 5
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 1 ? 0: 1 / 0 /* { dg-bogus "division by zero" }  */
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 0 ? 1 / 0: 0 /* { dg-bogus "division by zero" }  */
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 0 ? (1 << 256): 0 /* { dg-bogus "overflow" }  */
+#endif
+
+#if 1 ? 0: (1 << 256) /* { dg-bogus "overflow" }  */
+#endif
+
+/* Test unary + and its signedness.  */
+
+#if 23 != +23 || 23 != + +23
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (+1 - 2) > 0 || (+1U - 2) < 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+/* Test unary - and its signedness.  */
+
+#if -1 + 1 != 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if -1 >= 0 || -1U <= 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+/* Test unary ! and its signedness.  */
+#if !5 != 0 || !1 != 0 || !0 != 1
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if !5 - 1 > 0 || !5U - 1 > 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+/* Test unary ~ and its signedness.  */
+#if ~0 != -1 || ~~5 != 5 || ~-2 != 1
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if ~5 > 0 || ~5U < 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+/* Test comparison operators and their signedness.  */
+#if 1 >= 1 && 2 >= 1 && -1 >= -1 && -1 >= -2 && 1 >= -1 && 1 >= -2 \
+    && !(-2 >= -1) && !(2 >= 3) && -1U >= 2 && !(-1 >= 1)
+#else
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if ((1 > 0) - 2) > 0 || ((1U > 0) - 2) > 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if !(1 > 1) && 2 > 1 && !(-1 > -1) && -1 > -2 && 1 > -1 && 1 > -2 \
+    && !(-2 > -1) && !(2 > 3) && -1U > 2 && !(-1 > 1)
+#else
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if ((1 >= 0) - 2) > 0 || ((1U >= 0) - 2) > 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 1 <= 1 && !(2 <= 1) && -1 <= -1 && !(-1 <= -2) && !(1 <= -1) && !(1 <= -2) \
+    && -2 <= -1 && 2 <= 3 && !(-1U <= 2) && -1 <= 1
+#else
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if ((1 <= 0) - 2) > 0 || ((1U <= 0) - 2) > 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if !(1 < 1) && !(2 < 1) && !(-1 < -1) && !(-1 < -2) && !(1 < -1) && !(1 < -2) \
+    && -2 < -1 && 2 < 3 && !(-1U < 2) && -1 < 1
+#else
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if ((1 < 0) - 2) > 0 || ((1U < 0) - 2) > 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+/* Test bitwise operators and their signedness.  */
+#if (3 & 7) != 3 || (-1 & 34) != 34
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (3 & 7) - 20 > 0 || (3 & 7U) - 20 < 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (3 | 5) != 7 || (-1 | 34) != -1
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (3 | 7) - 20 > 0 || (3 | 7U) - 20 < 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (7 ^ 5) != 2 || (-1 ^ 34) != ~34
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (3 ^ 7) - 20 > 0 || (3 ^ 7U) - 20 < 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+/* Test shifts and their signedness.  */
+#if 3 << 2 != 12 || 3 << -2 != 0 || -1 << 1 != -2
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 5 >> 1 != 2 || 5 >> -2 != 20 || -5 >> 1 != -3
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (5 >> 2) - 2 >= 0 || (5U >> 2) - 2 <= 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (5 << 1) - 20 >= 0 || (5U << 1) - 20 <= 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 0
+/* Test min / max and their signedness.  */
+#if (3 >? 2) != 3 || (-3 >? -2) != -2
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (3 <? 2) != 2 || (-3 <? -2) != -3
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (3 >? 2) - 4 >= 0 || (3 >? 2U) - 4 <= 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (3 <? 2) - 4 >= 0 || (3 <? 2U) - 4 <= 0
+# error                /* { dg-bogus "error" }  */
+#endif
+#endif
+
+/* Test *, / and % and their signedness.  */
+#if 3 * 2 != 6 || 3 * -2 != -6 || -2 * 3 != -6 || -2 * -3 != 6
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 3 * 2 - 7 >= 0 || 3 * 2U - 7 < 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 5 / 2 != 2 || -325 / 50 != -6 || 53 / -4 != -13 || -55 / -12 != 4
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 3 / 2 - 7 >= 0 || 3 / 2U - 7 < 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 5 % 2 != 1 || -325 % 50 != -25 || 53 % -4 != 1 || -55 % -12 != -7
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if 3 % 2 - 7 >= 0 || 3U % 2 - 7 < 0
+# error                /* { dg-bogus "error" }  */
+#endif
+
+/* Test , and its signedness.  */
+#if (1, 2) != 2 || (2, 1) != 1
+# error                /* { dg-bogus "error" }  */
+#endif
+
+#if (1, 2) - 3 >= 0 || (1, 2U) - 3 <= 0 || (1U, 2) - 3 >= 0
+# error                /* { dg-bogus "error" }  */
+#endif
index 863fa904753ef63ad6365710116262140feb39a3..c08fd2393d7b5bd964e40c7145e1118a2af16f44 100644 (file)
@@ -37,5 +37,5 @@
 #if 099 /* { dg-error "digits beyond the radix" "decimal in octal constant" } */
 #endif
 
-#if 0xfffffffffffffffff /* { dg-error "integer constant out of range" "range error" } */
+#if 0xfffffffffffffffff /* { dg-error "integer constant" "range error" } */
 #endif