From: Neil Booth Date: Sun, 26 May 2002 18:42:21 +0000 (+0000) Subject: cppexp.c (possible_sum_sign, [...]): Remove. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=913189081f3bc7eebcf6bd13b9e344ba9cd2f9a3;p=gcc.git cppexp.c (possible_sum_sign, [...]): Remove. * 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 55ffba40302..1a028a95b7f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2002-05-26 Neil Booth + + * 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 * config/avr/avr.c (avr_asm_only_p): New variable. diff --git a/gcc/cppexp.c b/gcc/cppexp.c index 2d2ce489c03..7aa350d49bd 100644 --- a/gcc/cppexp.c +++ b/gcc/cppexp.c @@ -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; } /* 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; +} diff --git a/gcc/cpplib.c b/gcc/cpplib.c index ba6924d08ec..e819ffca4d0 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -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; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3dc427f4b70..51e46fb12f0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2002-05-26 Neil Booth + + * gcc.dg/cpp/arith-1.c: New semantic tests. + * gcc.dg/cpp/if-1.c: Update. + 2002-05-24 Ben Elliston * 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 index 00000000000..85d5848d800 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/arith-1.c @@ -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) - 4 >= 0 || (3 >? 2U) - 4 <= 0 +# error /* { dg-bogus "error" } */ +#endif + +#if (3 = 0 || (3 = 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 diff --git a/gcc/testsuite/gcc.dg/cpp/if-1.c b/gcc/testsuite/gcc.dg/cpp/if-1.c index 863fa904753..c08fd2393d7 100644 --- a/gcc/testsuite/gcc.dg/cpp/if-1.c +++ b/gcc/testsuite/gcc.dg/cpp/if-1.c @@ -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