cpplib: Add sign promotion warning
Neil Booth
neil@daikokuya.co.uk
Fri Jul 19 14:09:00 GMT 2002
As discussed recently.
Neil.
* 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.
Index: cppexp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cppexp.c,v
retrieving revision 1.128
diff -u -p -r1.128 cppexp.c
--- cppexp.c 19 Jul 2002 19:24:42 -0000 1.128
+++ cppexp.c 19 Jul 2002 19:47:34 -0000
@@ -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_r
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
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:
@@ -992,6 +1000,29 @@ _cpp_expand_op_stack (pfile)
pfile->op_limit = pfile->op_stack + new_size;
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. */
Index: cppinit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cppinit.c,v
retrieving revision 1.243
diff -u -p -r1.243 cppinit.c
--- cppinit.c 2 Jul 2002 22:28:18 -0000 1.243
+++ cppinit.c 19 Jul 2002 19:47:35 -0000
@@ -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:
Index: cpplib.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpplib.h,v
retrieving revision 1.225
diff -u -p -r1.225 cpplib.h
--- cpplib.h 17 Jul 2002 17:27:13 -0000 1.225
+++ cpplib.h 19 Jul 2002 19:47:35 -0000
@@ -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;
Index: testsuite/gcc.dg/cpp/Wsignprom.c
===================================================================
RCS file: testsuite/gcc.dg/cpp/Wsignprom.c
diff -N testsuite/gcc.dg/cpp/Wsignprom.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/cpp/Wsignprom.c 19 Jul 2002 19:47:38 -0000
@@ -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
More information about the Gcc-patches
mailing list