From: Neil Booth Date: Sat, 20 Jul 2002 13:31:56 +0000 (+0000) Subject: cppexp.c (struct op): Add token pointer. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=68e6527569f6ec0f520a53bcf786103a0f9b3fa4;p=gcc.git cppexp.c (struct op): Add token pointer. * cppexp.c (struct op): Add token pointer. (check_promotion, CHECK_PROMOTION): New. (optab): Update. (_cpp_parse_expr): Update, use token pointer of struct op. (reduce): Warn about change of sign owing to promotion. * cppinit.c (cpp_handle_option): New warning if -Wall. * cpplib.h (struct cpp_options): New member. testsuite: * gcc.dg/cpp/Wsignprom.c: New tests. From-SVN: r55611 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6720f50f2b2..b20c1b6e98a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2002-07-20 Neil Booth + + * cppexp.c (struct op): Add token pointer. + (check_promotion, CHECK_PROMOTION): New. + (optab): Update. + (_cpp_parse_expr): Update, use token pointer of struct op. + (reduce): Warn about change of sign owing to promotion. + * cppinit.c (cpp_handle_option): New warning if -Wall. + * cpplib.h (struct cpp_options): New member. + 2002-07-19 David Edelsohn * config/rs6000/rs6000.md: Remove ppc630 fpcompare from single diff --git a/gcc/cppexp.c b/gcc/cppexp.c index 58538444d08..b66fea925e7 100644 --- a/gcc/cppexp.c +++ b/gcc/cppexp.c @@ -30,6 +30,7 @@ Boston, MA 02111-1307, USA. */ struct op { + const cpp_token *token; /* The token forming op (for diagnostics). */ cpp_num value; /* The value logically "right" of op. */ enum cpp_ttype op; }; @@ -64,6 +65,7 @@ static cpp_num eval_token PARAMS ((cpp_reader *, const cpp_token *)); static struct op *reduce PARAMS ((cpp_reader *, struct op *, enum cpp_ttype)); static unsigned int interpret_float_suffix PARAMS ((const uchar *, size_t)); static unsigned int interpret_int_suffix PARAMS ((const uchar *, size_t)); +static void check_promotion PARAMS ((cpp_reader *, const struct op *)); /* Token type abuse to create unary plus and minus operators. */ #define CPP_UPLUS (CPP_LAST_CPP_OP + 1) @@ -630,9 +632,11 @@ The parser assumes all shifted operators require a left operand unless the flag NO_L_OPERAND is set. These semantics are automatic; any extra semantics need to be handled with operator-specific code. */ -/* Flags. */ +/* Flags. If CHECK_PROMOTION, we warn if the effective sign of an + operand changes because of integer promotions. */ #define NO_L_OPERAND (1 << 0) #define LEFT_ASSOC (1 << 1) +#define CHECK_PROMOTION (1 << 2) /* Operator to priority map. Must be in the same order as the first N entries of enum cpp_ttype. */ @@ -644,35 +648,35 @@ static const struct operator { /* 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}, + /* GREATER */ {12, LEFT_ASSOC | CHECK_PROMOTION}, + /* LESS */ {12, LEFT_ASSOC | CHECK_PROMOTION}, + /* PLUS */ {14, LEFT_ASSOC | CHECK_PROMOTION}, + /* MINUS */ {14, LEFT_ASSOC | CHECK_PROMOTION}, + /* MULT */ {15, LEFT_ASSOC | CHECK_PROMOTION}, + /* DIV */ {15, LEFT_ASSOC | CHECK_PROMOTION}, + /* MOD */ {15, LEFT_ASSOC | CHECK_PROMOTION}, + /* AND */ {9, LEFT_ASSOC | CHECK_PROMOTION}, + /* OR */ {7, LEFT_ASSOC | CHECK_PROMOTION}, + /* XOR */ {8, LEFT_ASSOC | CHECK_PROMOTION}, /* RSHIFT */ {13, LEFT_ASSOC}, /* LSHIFT */ {13, LEFT_ASSOC}, - /* MIN */ {10, LEFT_ASSOC}, - /* MAX */ {10, LEFT_ASSOC}, + /* MIN */ {10, LEFT_ASSOC | CHECK_PROMOTION}, + /* MAX */ {10, LEFT_ASSOC | CHECK_PROMOTION}, /* COMPL */ {16, NO_L_OPERAND}, /* AND_AND */ {6, LEFT_ASSOC}, /* OR_OR */ {5, LEFT_ASSOC}, /* QUERY */ {3, 0}, - /* COLON */ {4, LEFT_ASSOC}, + /* COLON */ {4, LEFT_ASSOC | CHECK_PROMOTION}, /* 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}, + /* GREATER_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION}, + /* LESS_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION}, /* UPLUS */ {16, NO_L_OPERAND}, /* UMINUS */ {16, NO_L_OPERAND} }; @@ -693,7 +697,6 @@ _cpp_parse_expr (pfile) cpp_reader *pfile; { struct op *top = pfile->op_stack; - const cpp_token *token = NULL, *prev_token; unsigned int lex_count; bool saw_leading_not, want_value = true; @@ -711,10 +714,9 @@ _cpp_parse_expr (pfile) { struct op op; - prev_token = token; - token = cpp_get_token (pfile); lex_count++; - op.op = token->type; + op.token = cpp_get_token (pfile); + op.op = op.token->type; switch (op.op) { @@ -726,9 +728,9 @@ _cpp_parse_expr (pfile) case CPP_HASH: if (!want_value) SYNTAX_ERROR2 ("missing binary operator before token \"%s\"", - cpp_token_as_text (pfile, token)); + cpp_token_as_text (pfile, op.token)); want_value = false; - top->value = eval_token (pfile, token); + top->value = eval_token (pfile, op.token); continue; case CPP_NOT: @@ -743,15 +745,16 @@ _cpp_parse_expr (pfile) op.op = CPP_UMINUS; break; case CPP_OTHER: - if (ISGRAPH (token->val.c)) - SYNTAX_ERROR2 ("invalid character '%c' in #if", token->val.c); + if (ISGRAPH (op.token->val.c)) + SYNTAX_ERROR2 ("invalid character '%c' in #if", op.token->val.c); else - SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", token->val.c); + SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", + op.token->val.c); default: if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ) SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions", - cpp_token_as_text (pfile, token)); + cpp_token_as_text (pfile, op.token)); break; } @@ -760,7 +763,7 @@ _cpp_parse_expr (pfile) { if (!want_value) SYNTAX_ERROR2 ("missing binary operator before token \"%s\"", - cpp_token_as_text (pfile, token)); + cpp_token_as_text (pfile, op.token)); } else if (want_value) { @@ -775,7 +778,7 @@ _cpp_parse_expr (pfile) SYNTAX_ERROR ("#if with no expression"); if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN) SYNTAX_ERROR2 ("operator '%s' has no right operand", - cpp_token_as_text (pfile, prev_token)); + cpp_token_as_text (pfile, top->token)); } top = reduce (pfile, top, op.op); @@ -816,6 +819,7 @@ _cpp_parse_expr (pfile) top = _cpp_expand_op_stack (pfile); top->op = op.op; + top->token = op.token; } /* The controlling macro expression is only valid if we called lex 3 @@ -860,6 +864,10 @@ reduce (pfile, top, op) prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0); while (prio < optab[top->op].prio) { + if (CPP_OPTION (pfile, warn_num_sign_change) + && optab[top->op].flags & CHECK_PROMOTION) + check_promotion (pfile, top); + switch (top->op) { case CPP_UPLUS: @@ -994,6 +1002,29 @@ _cpp_expand_op_stack (pfile) return pfile->op_stack + old_size; } +/* Emits a warning if the effective sign of either operand of OP + changes because of integer promotions. */ +static void +check_promotion (pfile, op) + cpp_reader *pfile; + const struct op *op; +{ + if (op->value.unsignedp == op[-1].value.unsignedp) + return; + + if (op->value.unsignedp) + { + if (!num_positive (op[-1].value, CPP_OPTION (pfile, precision))) + cpp_error (pfile, DL_WARNING, + "the left operand of \"%s\" changes sign when promoted", + cpp_token_as_text (pfile, op->token)); + } + else if (!num_positive (op->value, CPP_OPTION (pfile, precision))) + cpp_error (pfile, DL_WARNING, + "the right operand of \"%s\" changes sign when promoted", + cpp_token_as_text (pfile, op->token)); +} + /* Clears the unused high order bits of the number pointed to by PNUM. */ static cpp_num num_trim (num, precision) diff --git a/gcc/cppinit.c b/gcc/cppinit.c index db1314dd8f3..72e26ce87de 100644 --- a/gcc/cppinit.c +++ b/gcc/cppinit.c @@ -1672,6 +1672,7 @@ cpp_handle_option (pfile, argc, argv) case OPT_Wall: CPP_OPTION (pfile, warn_trigraphs) = 1; CPP_OPTION (pfile, warn_comments) = 1; + CPP_OPTION (pfile, warn_num_sign_change) = 1; break; case OPT_Wtraditional: diff --git a/gcc/cpplib.h b/gcc/cpplib.h index 7c1fe854658..c407321ff43 100644 --- a/gcc/cpplib.h +++ b/gcc/cpplib.h @@ -333,6 +333,10 @@ struct cpp_options /* Nonzero means warn about text after an #endif (or #else). */ unsigned char warn_endif_labels; + /* Nonzero means warn about implicit sign changes owing to integer + promotions. */ + unsigned char warn_num_sign_change; + /* Nonzero means turn warnings into errors. */ unsigned char warnings_are_errors; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 16655099ab2..91c63ea5700 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2002-07-20 Neil Booth + + * gcc.dg/cpp/Wsignprom.c: New tests. + 2002-07-20 Alan Modra * gcc.c-torture/execute/loop-13.c: New test. diff --git a/gcc/testsuite/gcc.dg/cpp/Wsignprom.c b/gcc/testsuite/gcc.dg/cpp/Wsignprom.c new file mode 100644 index 00000000000..44b5667b3f2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/Wsignprom.c @@ -0,0 +1,26 @@ +/* { dg-do preprocess } */ +/* { dg-options "-Wall" } */ + +/* Test that -Wall emits the warnings about integer promotion changing + the sign of an operand. */ + +#if -1 > 0U /* { dg-warning "changes sign when promoted" } */ +#endif + +#if 0U + -1 /* { dg-warning "changes sign when promoted" } */ +#endif + +#if 0U * -1 /* { dg-warning "changes sign when promoted" } */ +#endif + +#if 1U / -2 /* { dg-warning "changes sign when promoted" } */ +#endif + +#if -1 % 1U /* { dg-warning "changes sign when promoted" } */ +#endif + +#if 1 ? 0U : -1 /* { dg-warning "changes sign when promoted" } */ +#endif + +#if 1 ? -1 : 0U /* { dg-warning "changes sign when promoted" } */ +#endif