struct op
{
- cpp_num value; /* The value logically "right" of op. */
+ const cpp_token *token; /* The token forming op (for diagnostics). */
+ cpp_num value; /* The value logically "right" of op. */
enum cpp_ttype op;
};
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_mul PARAMS ((cpp_reader *, cpp_num, cpp_num));
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 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)
result.low = 0;
result.high = 0;
- result.unsignedp = type & CPP_N_UNSIGNED;
- result.overflow = 0;
+ result.unsignedp = !!(type & CPP_N_UNSIGNED);
+ result.overflow = false;
p = token->val.str.text;
end = p + token->val.str.len;
if (base == 10)
cpp_error (pfile, DL_WARNING,
"integer constant is so large that it is unsigned");
- result.unsignedp = 1;
+ result.unsignedp = true;
}
}
/* 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);
+ overflow = !!(num.high >> (PART_PRECISION - shift));
result.high = num.high << shift;
result.low = num.low << shift;
result.high |= num.low >> (PART_PRECISION - shift);
cpp_error (pfile, DL_WARNING,
"this use of \"defined\" may not be portable");
+ _cpp_mark_macro_used (node);
+
/* 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--;
- result.unsignedp = 0;
+ result.unsignedp = false;
result.high = 0;
- result.overflow = 0;
+ result.overflow = false;
result.low = node && node->type == NT_MACRO;
return result;
}
result.low = temp;
}
- result.unsignedp = unsignedp;
- result.overflow = 0;
+ result.unsignedp = !!unsignedp;
+ result.overflow = false;
return result;
}
\f
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)
-/* 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, 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}
+ /* EQ */ {0, 0}, /* Shouldn't happen. */
+ /* NOT */ {16, NO_L_OPERAND},
+ /* 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 | 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 | 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 | CHECK_PROMOTION},
+ /* LESS_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION},
+ /* UPLUS */ {16, NO_L_OPERAND},
+ /* UMINUS */ {16, NO_L_OPERAND}
};
/* Parse and evaluate a C expression, reading from 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;
{
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)
{
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:
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;
}
{
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)
{
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);
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
prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0);
while (prio < optab[top->op].prio)
{
- if (optab[top->op].arity == UNARY)
- {
- 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)
+ if (CPP_OPTION (pfile, warn_num_sign_change)
+ && optab[top->op].flags & CHECK_PROMOTION)
+ check_promotion (pfile, top);
+
+ switch (top->op)
{
+ case CPP_UPLUS:
+ case CPP_UMINUS:
+ case CPP_NOT:
+ case CPP_COMPL:
+ top[-1].value = num_unary_op (pfile, top->value, top->op);
+ break;
+
+ case CPP_PLUS:
+ case CPP_MINUS:
+ case CPP_RSHIFT:
+ case CPP_LSHIFT:
+ case CPP_MIN:
+ case CPP_MAX:
+ case CPP_COMMA:
+ top[-1].value = num_binary_op (pfile, top[-1].value,
+ top->value, top->op);
+ break;
+
+ case CPP_GREATER:
+ case CPP_LESS:
+ case CPP_GREATER_EQ:
+ case CPP_LESS_EQ:
+ top[-1].value
+ = num_inequality_op (pfile, top[-1].value, top->value, top->op);
+ break;
+
+ case CPP_EQ_EQ:
+ case CPP_NOT_EQ:
+ top[-1].value
+ = num_equality_op (pfile, top[-1].value, top->value, top->op);
+ break;
+
+ case CPP_AND:
+ case CPP_OR:
+ case CPP_XOR:
+ top[-1].value
+ = num_bitwise_op (pfile, top[-1].value, top->value, top->op);
+ break;
+
+ case CPP_MULT:
+ top[-1].value = num_mul (pfile, top[-1].value, top->value);
+ break;
+
+ case CPP_DIV:
+ case CPP_MOD:
+ top[-1].value = num_div_op (pfile, top[-1].value,
+ top->value, top->op);
+ break;
+
case CPP_OR_OR:
+ top--;
if (!num_zerop (top->value))
pfile->state.skip_eval--;
- top->value.low = !num_zerop (top->value) || !num_zerop (top[1].value);
+ 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;
+ continue;
case CPP_AND_AND:
+ top--;
if (num_zerop (top->value))
pfile->state.skip_eval--;
- top->value.low = !num_zerop (top->value) && !num_zerop (top[1].value);
+ 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;
+ continue;
case CPP_OPEN_PAREN:
if (op != CPP_CLOSE_PAREN)
cpp_error (pfile, DL_ERROR, "missing ')' in expression");
return 0;
}
+ top--;
top->value = top[1].value;
return top;
case CPP_COLON:
- top--;
+ top -= 2;
if (!num_zerop (top->value))
{
pfile->state.skip_eval--;
top->value = top[2].value;
top->value.unsignedp = (top[1].value.unsignedp
|| top[2].value.unsignedp);
- break;
+ continue;
case CPP_QUERY:
cpp_error (pfile, DL_ERROR, "'?' without following ':'");
goto bad_op;
}
+ top--;
if (top->value.overflow && !pfile->state.skip_eval)
cpp_error (pfile, DL_PEDWARN,
"integer overflow in preprocessor expression");
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)
switch (op)
{
case CPP_UPLUS:
- if (CPP_WTRADITIONAL (pfile))
+ if (CPP_WTRADITIONAL (pfile) && !pfile->state.skip_eval)
cpp_error (pfile, DL_WARNING,
"traditional C rejects the unary plus operator");
num.overflow = false;
/* Comma. */
default: /* case CPP_COMMA: */
- if (CPP_PEDANTIC (pfile))
+ if (CPP_PEDANTIC (pfile) && !pfile->state.skip_eval)
cpp_error (pfile, DL_PEDWARN,
"comma operator in operand of #if");
lhs = rhs;
/* Multiply two preprocessing numbers. */
static cpp_num
-num_mul (pfile, lhs, rhs, op)
+num_mul (pfile, lhs, rhs)
cpp_reader *pfile;
cpp_num lhs, rhs;
- enum cpp_ttype op ATTRIBUTE_UNUSED;
{
cpp_num result, temp;
bool unsignedp = lhs.unsignedp || rhs.unsignedp;
}
else
{
- cpp_error (pfile, DL_ERROR, "division by zero in #if");
+ if (!pfile->state.skip_eval)
+ cpp_error (pfile, DL_ERROR, "division by zero in #if");
return lhs;
}