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
This commit is contained in:
parent
7a56114260
commit
68e6527569
|
@ -1,3 +1,13 @@
|
||||||
|
2002-07-20 Neil Booth <neil@daikokuya.co.uk>
|
||||||
|
|
||||||
|
* 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 <edelsohn@gnu.org>
|
2002-07-19 David Edelsohn <edelsohn@gnu.org>
|
||||||
|
|
||||||
* config/rs6000/rs6000.md: Remove ppc630 fpcompare from single
|
* config/rs6000/rs6000.md: Remove ppc630 fpcompare from single
|
||||||
|
|
87
gcc/cppexp.c
87
gcc/cppexp.c
|
@ -30,6 +30,7 @@ Boston, MA 02111-1307, USA. */
|
||||||
|
|
||||||
struct op
|
struct op
|
||||||
{
|
{
|
||||||
|
const cpp_token *token; /* The token forming op (for diagnostics). */
|
||||||
cpp_num value; /* The value logically "right" of op. */
|
cpp_num value; /* The value logically "right" of op. */
|
||||||
enum cpp_ttype 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 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_float_suffix PARAMS ((const uchar *, size_t));
|
||||||
static unsigned int interpret_int_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. */
|
/* Token type abuse to create unary plus and minus operators. */
|
||||||
#define CPP_UPLUS (CPP_LAST_CPP_OP + 1)
|
#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
|
the flag NO_L_OPERAND is set. These semantics are automatic; any
|
||||||
extra semantics need to be handled with operator-specific code. */
|
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 NO_L_OPERAND (1 << 0)
|
||||||
#define LEFT_ASSOC (1 << 1)
|
#define LEFT_ASSOC (1 << 1)
|
||||||
|
#define CHECK_PROMOTION (1 << 2)
|
||||||
|
|
||||||
/* Operator to priority map. Must be in the same order as the first
|
/* Operator to priority map. Must be in the same order as the first
|
||||||
N entries of enum cpp_ttype. */
|
N entries of enum cpp_ttype. */
|
||||||
|
@ -644,35 +648,35 @@ static const struct operator
|
||||||
{
|
{
|
||||||
/* EQ */ {0, 0}, /* Shouldn't happen. */
|
/* EQ */ {0, 0}, /* Shouldn't happen. */
|
||||||
/* NOT */ {16, NO_L_OPERAND},
|
/* NOT */ {16, NO_L_OPERAND},
|
||||||
/* GREATER */ {12, LEFT_ASSOC},
|
/* GREATER */ {12, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* LESS */ {12, LEFT_ASSOC},
|
/* LESS */ {12, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* PLUS */ {14, LEFT_ASSOC},
|
/* PLUS */ {14, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* MINUS */ {14, LEFT_ASSOC},
|
/* MINUS */ {14, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* MULT */ {15, LEFT_ASSOC},
|
/* MULT */ {15, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* DIV */ {15, LEFT_ASSOC},
|
/* DIV */ {15, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* MOD */ {15, LEFT_ASSOC},
|
/* MOD */ {15, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* AND */ {9, LEFT_ASSOC},
|
/* AND */ {9, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* OR */ {7, LEFT_ASSOC},
|
/* OR */ {7, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* XOR */ {8, LEFT_ASSOC},
|
/* XOR */ {8, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* RSHIFT */ {13, LEFT_ASSOC},
|
/* RSHIFT */ {13, LEFT_ASSOC},
|
||||||
/* LSHIFT */ {13, LEFT_ASSOC},
|
/* LSHIFT */ {13, LEFT_ASSOC},
|
||||||
|
|
||||||
/* MIN */ {10, LEFT_ASSOC},
|
/* MIN */ {10, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* MAX */ {10, LEFT_ASSOC},
|
/* MAX */ {10, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
|
|
||||||
/* COMPL */ {16, NO_L_OPERAND},
|
/* COMPL */ {16, NO_L_OPERAND},
|
||||||
/* AND_AND */ {6, LEFT_ASSOC},
|
/* AND_AND */ {6, LEFT_ASSOC},
|
||||||
/* OR_OR */ {5, LEFT_ASSOC},
|
/* OR_OR */ {5, LEFT_ASSOC},
|
||||||
/* QUERY */ {3, 0},
|
/* QUERY */ {3, 0},
|
||||||
/* COLON */ {4, LEFT_ASSOC},
|
/* COLON */ {4, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* COMMA */ {2, LEFT_ASSOC},
|
/* COMMA */ {2, LEFT_ASSOC},
|
||||||
/* OPEN_PAREN */ {1, NO_L_OPERAND},
|
/* OPEN_PAREN */ {1, NO_L_OPERAND},
|
||||||
/* CLOSE_PAREN */ {0, 0},
|
/* CLOSE_PAREN */ {0, 0},
|
||||||
/* EOF */ {0, 0},
|
/* EOF */ {0, 0},
|
||||||
/* EQ_EQ */ {11, LEFT_ASSOC},
|
/* EQ_EQ */ {11, LEFT_ASSOC},
|
||||||
/* NOT_EQ */ {11, LEFT_ASSOC},
|
/* NOT_EQ */ {11, LEFT_ASSOC},
|
||||||
/* GREATER_EQ */ {12, LEFT_ASSOC},
|
/* GREATER_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* LESS_EQ */ {12, LEFT_ASSOC},
|
/* LESS_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION},
|
||||||
/* UPLUS */ {16, NO_L_OPERAND},
|
/* UPLUS */ {16, NO_L_OPERAND},
|
||||||
/* UMINUS */ {16, NO_L_OPERAND}
|
/* UMINUS */ {16, NO_L_OPERAND}
|
||||||
};
|
};
|
||||||
|
@ -693,7 +697,6 @@ _cpp_parse_expr (pfile)
|
||||||
cpp_reader *pfile;
|
cpp_reader *pfile;
|
||||||
{
|
{
|
||||||
struct op *top = pfile->op_stack;
|
struct op *top = pfile->op_stack;
|
||||||
const cpp_token *token = NULL, *prev_token;
|
|
||||||
unsigned int lex_count;
|
unsigned int lex_count;
|
||||||
bool saw_leading_not, want_value = true;
|
bool saw_leading_not, want_value = true;
|
||||||
|
|
||||||
|
@ -711,10 +714,9 @@ _cpp_parse_expr (pfile)
|
||||||
{
|
{
|
||||||
struct op op;
|
struct op op;
|
||||||
|
|
||||||
prev_token = token;
|
|
||||||
token = cpp_get_token (pfile);
|
|
||||||
lex_count++;
|
lex_count++;
|
||||||
op.op = token->type;
|
op.token = cpp_get_token (pfile);
|
||||||
|
op.op = op.token->type;
|
||||||
|
|
||||||
switch (op.op)
|
switch (op.op)
|
||||||
{
|
{
|
||||||
|
@ -726,9 +728,9 @@ _cpp_parse_expr (pfile)
|
||||||
case CPP_HASH:
|
case CPP_HASH:
|
||||||
if (!want_value)
|
if (!want_value)
|
||||||
SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
|
SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
|
||||||
cpp_token_as_text (pfile, token));
|
cpp_token_as_text (pfile, op.token));
|
||||||
want_value = false;
|
want_value = false;
|
||||||
top->value = eval_token (pfile, token);
|
top->value = eval_token (pfile, op.token);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case CPP_NOT:
|
case CPP_NOT:
|
||||||
|
@ -743,15 +745,16 @@ _cpp_parse_expr (pfile)
|
||||||
op.op = CPP_UMINUS;
|
op.op = CPP_UMINUS;
|
||||||
break;
|
break;
|
||||||
case CPP_OTHER:
|
case CPP_OTHER:
|
||||||
if (ISGRAPH (token->val.c))
|
if (ISGRAPH (op.token->val.c))
|
||||||
SYNTAX_ERROR2 ("invalid character '%c' in #if", token->val.c);
|
SYNTAX_ERROR2 ("invalid character '%c' in #if", op.token->val.c);
|
||||||
else
|
else
|
||||||
SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", token->val.c);
|
SYNTAX_ERROR2 ("invalid character '\\%03o' in #if",
|
||||||
|
op.token->val.c);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ)
|
if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ)
|
||||||
SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions",
|
SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions",
|
||||||
cpp_token_as_text (pfile, token));
|
cpp_token_as_text (pfile, op.token));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -760,7 +763,7 @@ _cpp_parse_expr (pfile)
|
||||||
{
|
{
|
||||||
if (!want_value)
|
if (!want_value)
|
||||||
SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
|
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)
|
else if (want_value)
|
||||||
{
|
{
|
||||||
|
@ -775,7 +778,7 @@ _cpp_parse_expr (pfile)
|
||||||
SYNTAX_ERROR ("#if with no expression");
|
SYNTAX_ERROR ("#if with no expression");
|
||||||
if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN)
|
if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN)
|
||||||
SYNTAX_ERROR2 ("operator '%s' has no right operand",
|
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);
|
top = reduce (pfile, top, op.op);
|
||||||
|
@ -816,6 +819,7 @@ _cpp_parse_expr (pfile)
|
||||||
top = _cpp_expand_op_stack (pfile);
|
top = _cpp_expand_op_stack (pfile);
|
||||||
|
|
||||||
top->op = op.op;
|
top->op = op.op;
|
||||||
|
top->token = op.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The controlling macro expression is only valid if we called lex 3
|
/* 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);
|
prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0);
|
||||||
while (prio < optab[top->op].prio)
|
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)
|
switch (top->op)
|
||||||
{
|
{
|
||||||
case CPP_UPLUS:
|
case CPP_UPLUS:
|
||||||
|
@ -994,6 +1002,29 @@ _cpp_expand_op_stack (pfile)
|
||||||
return pfile->op_stack + old_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. */
|
/* Clears the unused high order bits of the number pointed to by PNUM. */
|
||||||
static cpp_num
|
static cpp_num
|
||||||
num_trim (num, precision)
|
num_trim (num, precision)
|
||||||
|
|
|
@ -1672,6 +1672,7 @@ cpp_handle_option (pfile, argc, argv)
|
||||||
case OPT_Wall:
|
case OPT_Wall:
|
||||||
CPP_OPTION (pfile, warn_trigraphs) = 1;
|
CPP_OPTION (pfile, warn_trigraphs) = 1;
|
||||||
CPP_OPTION (pfile, warn_comments) = 1;
|
CPP_OPTION (pfile, warn_comments) = 1;
|
||||||
|
CPP_OPTION (pfile, warn_num_sign_change) = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_Wtraditional:
|
case OPT_Wtraditional:
|
||||||
|
|
|
@ -333,6 +333,10 @@ struct cpp_options
|
||||||
/* Nonzero means warn about text after an #endif (or #else). */
|
/* Nonzero means warn about text after an #endif (or #else). */
|
||||||
unsigned char warn_endif_labels;
|
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. */
|
/* Nonzero means turn warnings into errors. */
|
||||||
unsigned char warnings_are_errors;
|
unsigned char warnings_are_errors;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
2002-07-20 Neil Booth <neil@daikokuya.co.uk>
|
||||||
|
|
||||||
|
* gcc.dg/cpp/Wsignprom.c: New tests.
|
||||||
|
|
||||||
2002-07-20 Alan Modra <amodra@bigpond.net.au>
|
2002-07-20 Alan Modra <amodra@bigpond.net.au>
|
||||||
|
|
||||||
* gcc.c-torture/execute/loop-13.c: New test.
|
* gcc.c-torture/execute/loop-13.c: New test.
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue