This patch fixes PR 55715, bogus cpplib diagnostics for subtraction involving the most negative integer arising from the implementation of subtraction as negation followed by falling through into the addition case. The fix is simply to separate the subtraction implementation from that of addition so the overflow check can be done using the signs of the original operands.
Bootstrapped with no regressions on x86_64-unknown-linux-gnu. Applied to mainline. libcpp: 2013-12-09 Joseph Myers <jos...@codesourcery.com> PR preprocessor/55715 * expr.c (num_binary_op): Implement subtraction directly rather than with negation and falling through into addition case. gcc/testsuite: 2013-12-09 Joseph Myers <jos...@codesourcery.com> PR preprocessor/55715 * gcc.dg/cpp/expr-overflow-1.c: New test. Index: libcpp/expr.c =================================================================== --- libcpp/expr.c (revision 205803) +++ libcpp/expr.c (working copy) @@ -1836,7 +1836,22 @@ num_binary_op (cpp_reader *pfile, cpp_num lhs, cpp /* Arithmetic. */ case CPP_MINUS: - rhs = num_negate (rhs, precision); + result.low = lhs.low - rhs.low; + result.high = lhs.high - rhs.high; + if (result.low > lhs.low) + result.high--; + result.unsignedp = lhs.unsignedp || rhs.unsignedp; + result.overflow = false; + + result = num_trim (result, precision); + if (!result.unsignedp) + { + bool lhsp = num_positive (lhs, precision); + result.overflow = (lhsp != num_positive (rhs, precision) + && lhsp != num_positive (result, precision)); + } + return result; + case CPP_PLUS: result.low = lhs.low + rhs.low; result.high = lhs.high + rhs.high; Index: gcc/testsuite/gcc.dg/cpp/expr-overflow-1.c =================================================================== --- gcc/testsuite/gcc.dg/cpp/expr-overflow-1.c (revision 0) +++ gcc/testsuite/gcc.dg/cpp/expr-overflow-1.c (revision 0) @@ -0,0 +1,44 @@ +/* Test overflow in preprocessor arithmetic. PR 55715. */ +/* { dg-do preprocess } */ +/* { dg-options "-std=c99" } */ + +#include <stdint.h> + +#if -1 - INTMAX_MIN +#endif + +#if 0 - INTMAX_MIN /* { dg-warning "overflow" } */ +#endif + +#if 1 * INTMAX_MIN +#endif + +#if -1 * INTMAX_MIN /* { dg-warning "overflow" } */ +#endif + +#if 0 * INTMAX_MIN +#endif + +#if -INTMAX_MIN /* { dg-warning "overflow" } */ +#endif + +#if +INTMAX_MIN +#endif + +#if INTMAX_MIN / 1 +#endif + +#if INTMAX_MIN / -1 /* { dg-warning "overflow" } */ +#endif + +#if UINTMAX_MAX * UINTMAX_MAX +#endif + +#if UINTMAX_MAX / -1 +#endif + +#if UINTMAX_MAX + INTMAX_MAX +#endif + +#if UINTMAX_MAX - INTMAX_MIN +#endif -- Joseph S. Myers jos...@codesourcery.com