Index: gcc/libcpp/expr.c |
diff --git a/gcc/libcpp/expr.c b/gcc/libcpp/expr.c |
index edefd389cc75e3c63c2d689664eb9ddceac3e307..60cb2816a7ab9d3fed07c567362e62dea5ef24c0 100644 |
--- a/gcc/libcpp/expr.c |
+++ b/gcc/libcpp/expr.c |
@@ -1,6 +1,6 @@ |
/* Parse C expressions for cpplib. |
Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001, |
- 2002, 2004, 2008, 2009 Free Software Foundation. |
+ 2002, 2004, 2008, 2009, 2010 Free Software Foundation. |
Contributed by Per Bothner, 1994. |
This program is free software; you can redistribute it and/or modify it |
@@ -52,7 +52,8 @@ static cpp_num num_inequality_op (cpp_reader *, cpp_num, cpp_num, |
static cpp_num num_equality_op (cpp_reader *, cpp_num, cpp_num, |
enum cpp_ttype); |
static cpp_num num_mul (cpp_reader *, cpp_num, cpp_num); |
-static cpp_num num_div_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype); |
+static cpp_num num_div_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype, |
+ source_location); |
static cpp_num num_lshift (cpp_num, size_t, size_t); |
static cpp_num num_rshift (cpp_num, size_t, size_t); |
@@ -82,89 +83,106 @@ static void check_promotion (cpp_reader *, const struct op *); |
static unsigned int |
interpret_float_suffix (const uchar *s, size_t len) |
{ |
- size_t f, l, w, q, i, d; |
- size_t r, k, u, h; |
+ size_t flags; |
+ size_t f, d, l, w, q, i; |
- f = l = w = q = i = d = 0; |
- r = k = u = h = 0; |
+ flags = 0; |
+ f = d = l = w = q = i = 0; |
- while (len--) |
- switch (s[len]) |
+ /* Process decimal float suffixes, which are two letters starting |
+ with d or D. Order and case are significant. */ |
+ if (len == 2 && (*s == 'd' || *s == 'D')) |
+ { |
+ bool uppercase = (*s == 'D'); |
+ switch (s[1]) |
{ |
- case 'r': case 'R': r++; break; |
- case 'k': case 'K': k++; break; |
- case 'u': case 'U': u++; break; |
- case 'h': case 'H': h++; break; |
- case 'f': case 'F': |
- if (d > 0) |
- return 0; |
- f++; |
- break; |
- case 'l': case 'L': |
- if (d > 0) |
- return 0; |
- l++; |
- /* If there are two Ls, they must be adjacent and the same case. */ |
- if (l == 2 && s[len] != s[len + 1]) |
- return 0; |
- break; |
- case 'w': case 'W': |
- if (d > 0) |
- return 0; |
- w++; |
- break; |
- case 'q': case 'Q': |
- if (d > 0) |
- return 0; |
- q++; |
- break; |
- case 'i': case 'I': |
- case 'j': case 'J': i++; break; |
- case 'd': case 'D': d++; break; |
+ case 'f': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL): 0); break; |
+ case 'F': return (uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL) : 0); break; |
+ case 'd': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM): 0); break; |
+ case 'D': return (uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM) : 0); break; |
+ case 'l': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break; |
+ case 'L': return (uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break; |
default: |
- return 0; |
+ /* Additional two-character suffixes beginning with D are not |
+ for decimal float constants. */ |
+ break; |
} |
+ } |
- if (r + k > 1 || h > 1 || l > 2 || u > 1) |
- return 0; |
- |
- if (r == 1) |
+ /* Recognize a fixed-point suffix. */ |
+ switch (s[len-1]) |
{ |
- if (f || i || d || w || q) |
- return 0; |
- |
- return (CPP_N_FRACT |
- | (u ? CPP_N_UNSIGNED : 0) |
- | (h ? CPP_N_SMALL : |
- l == 2 ? CPP_N_LARGE : |
- l == 1 ? CPP_N_MEDIUM : 0)); |
+ case 'k': case 'K': flags = CPP_N_ACCUM; break; |
+ case 'r': case 'R': flags = CPP_N_FRACT; break; |
+ default: break; |
} |
- if (k == 1) |
+ /* Continue processing a fixed-point suffix. The suffix is case |
+ insensitive except for ll or LL. Order is significant. */ |
+ if (flags) |
{ |
- if (f || i || d || w || q) |
- return 0; |
+ if (len == 1) |
+ return flags; |
+ len--; |
+ |
+ if (*s == 'u' || *s == 'U') |
+ { |
+ flags |= CPP_N_UNSIGNED; |
+ if (len == 1) |
+ return flags; |
+ len--; |
+ s++; |
+ } |
- return (CPP_N_ACCUM |
- | (u ? CPP_N_UNSIGNED : 0) |
- | (h ? CPP_N_SMALL : |
- l == 2 ? CPP_N_LARGE : |
- l == 1 ? CPP_N_MEDIUM : 0)); |
+ switch (*s) |
+ { |
+ case 'h': case 'H': |
+ if (len == 1) |
+ return flags |= CPP_N_SMALL; |
+ break; |
+ case 'l': |
+ if (len == 1) |
+ return flags |= CPP_N_MEDIUM; |
+ if (len == 2 && s[1] == 'l') |
+ return flags |= CPP_N_LARGE; |
+ break; |
+ case 'L': |
+ if (len == 1) |
+ return flags |= CPP_N_MEDIUM; |
+ if (len == 2 && s[1] == 'L') |
+ return flags |= CPP_N_LARGE; |
+ break; |
+ default: |
+ break; |
+ } |
+ /* Anything left at this point is invalid. */ |
+ return 0; |
} |
- if (f + l + w + q > 1 || i > 1 || h + u > 0) |
- return 0; |
+ /* In any remaining valid suffix, the case and order don't matter. */ |
+ while (len--) |
+ switch (s[len]) |
+ { |
+ case 'f': case 'F': f++; break; |
+ case 'd': case 'D': d++; break; |
+ case 'l': case 'L': l++; break; |
+ case 'w': case 'W': w++; break; |
+ case 'q': case 'Q': q++; break; |
+ case 'i': case 'I': |
+ case 'j': case 'J': i++; break; |
+ default: |
+ return 0; |
+ } |
- /* Allow dd, df, dl suffixes for decimal float constants. */ |
- if (d && ((d + f + l != 2) || i)) |
+ if (f + d + l + w + q > 1 || i > 1) |
return 0; |
return ((i ? CPP_N_IMAGINARY : 0) |
| (f ? CPP_N_SMALL : |
+ d ? CPP_N_MEDIUM : |
l ? CPP_N_LARGE : |
w ? CPP_N_MD_W : |
- q ? CPP_N_MD_Q : CPP_N_MEDIUM) |
- | (d ? CPP_N_DFLOAT : 0)); |
+ q ? CPP_N_MD_Q : CPP_N_DEFAULT)); |
} |
/* Subroutine of cpp_classify_number. S points to an integer suffix |
@@ -211,6 +229,7 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token) |
const uchar *limit; |
unsigned int max_digit, result, radix; |
enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag; |
+ bool seen_digit; |
/* If the lexer has done its job, length one can only be a single |
digit. Fast-path this very common case. */ |
@@ -221,6 +240,7 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token) |
float_flag = NOT_FLOAT; |
max_digit = 0; |
radix = 10; |
+ seen_digit = false; |
/* First, interpret the radix. */ |
if (*str == '0') |
@@ -249,6 +269,7 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token) |
if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16)) |
{ |
+ seen_digit = true; |
c = hex_value (c); |
if (c > max_digit) |
max_digit = c; |
@@ -314,6 +335,9 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token) |
return CPP_N_INVALID; |
} |
+ if (radix == 16 && !seen_digit) |
+ SYNTAX_ERROR ("no digits in hexadecimal floating constant"); |
+ |
if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99)) |
cpp_error (pfile, CPP_DL_PEDWARN, |
"use of C99 hexadecimal floating constant"); |
@@ -351,6 +375,13 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token) |
"traditional C rejects the \"%.*s\" suffix", |
(int) (limit - str), str); |
+ /* A suffix for double is a GCC extension via decimal float support. |
+ If the suffix also specifies an imaginary value we'll catch that |
+ later. */ |
+ if ((result == CPP_N_MEDIUM) && CPP_PEDANTIC (pfile)) |
+ cpp_error (pfile, CPP_DL_PEDWARN, |
+ "suffix for double constant is a GCC extension"); |
+ |
/* Radix must be 10 for decimal floats. */ |
if ((result & CPP_N_DFLOAT) && radix != 10) |
{ |
@@ -395,10 +426,12 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token) |
} |
if ((result & CPP_N_WIDTH) == CPP_N_LARGE |
- && ! CPP_OPTION (pfile, c99) |
&& CPP_OPTION (pfile, warn_long_long)) |
- cpp_error (pfile, CPP_DL_PEDWARN, |
- "use of C99 long long integer constant"); |
+ cpp_error (pfile, |
+ CPP_OPTION (pfile, c99) ? CPP_DL_WARNING : CPP_DL_PEDWARN, |
+ CPP_OPTION (pfile, cplusplus) |
+ ? "use of C++0x long long integer constant" |
+ : "use of C99 long long integer constant"); |
result |= CPP_N_INTEGER; |
} |
@@ -512,8 +545,27 @@ cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token, |
&& pfile->state.in_directive) |
&& !num_positive (result, precision)) |
{ |
+ /* This is for constants within the range of uintmax_t but |
+ not that of intmax_t. For such decimal constants, a |
+ diagnostic is required for C99 as the selected type must |
+ be signed and not having a type is a constraint violation |
+ (DR#298, TC3), so this must be a pedwarn. For C90, |
+ unsigned long is specified to be used for a constant that |
+ does not fit in signed long; if uintmax_t has the same |
+ range as unsigned long this means only a warning is |
+ appropriate here. C90 permits the preprocessor to use a |
+ wider range than unsigned long in the compiler, so if |
+ uintmax_t is wider than unsigned long no diagnostic is |
+ required for such constants in preprocessor #if |
+ expressions and the compiler will pedwarn for such |
+ constants outside the range of unsigned long that reach |
+ the compiler so a diagnostic is not required there |
+ either; thus, pedwarn for C99 but use a plain warning for |
+ C90. */ |
if (base == 10) |
- cpp_error (pfile, CPP_DL_WARNING, |
+ cpp_error (pfile, (CPP_OPTION (pfile, c99) |
+ ? CPP_DL_PEDWARN |
+ : CPP_DL_WARNING), |
"integer constant is so large that it is unsigned"); |
result.unsignedp = true; |
} |
@@ -606,7 +658,7 @@ parse_defined (cpp_reader *pfile) |
if (token->type == CPP_NAME) |
{ |
- node = token->val.node; |
+ node = token->val.node.node; |
if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN) |
{ |
cpp_error (pfile, CPP_DL_ERROR, "missing ')' after \"defined\""); |
@@ -726,14 +778,14 @@ eval_token (cpp_reader *pfile, const cpp_token *token) |
break; |
case CPP_NAME: |
- if (token->val.node == pfile->spec_nodes.n_defined) |
+ if (token->val.node.node == pfile->spec_nodes.n_defined) |
return parse_defined (pfile); |
else if (CPP_OPTION (pfile, cplusplus) |
- && (token->val.node == pfile->spec_nodes.n_true |
- || token->val.node == pfile->spec_nodes.n_false)) |
+ && (token->val.node.node == pfile->spec_nodes.n_true |
+ || token->val.node.node == pfile->spec_nodes.n_false)) |
{ |
result.high = 0; |
- result.low = (token->val.node == pfile->spec_nodes.n_true); |
+ result.low = (token->val.node.node == pfile->spec_nodes.n_true); |
} |
else |
{ |
@@ -741,7 +793,7 @@ eval_token (cpp_reader *pfile, const cpp_token *token) |
result.low = 0; |
if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval) |
cpp_error (pfile, CPP_DL_WARNING, "\"%s\" is not defined", |
- NODE_NAME (token->val.node)); |
+ NODE_NAME (token->val.node.node)); |
} |
break; |
@@ -1078,7 +1130,7 @@ reduce (cpp_reader *pfile, struct op *top, enum cpp_ttype op) |
case CPP_DIV: |
case CPP_MOD: |
top[-1].value = num_div_op (pfile, top[-1].value, |
- top->value, top->op); |
+ top->value, top->op, top->loc); |
top[-1].loc = top->loc; |
break; |
@@ -1623,10 +1675,13 @@ num_mul (cpp_reader *pfile, cpp_num lhs, cpp_num rhs) |
return result; |
} |
-/* Divide two preprocessing numbers, returning the answer or the |
- remainder depending upon OP. */ |
+/* Divide two preprocessing numbers, LHS and RHS, returning the answer |
+ or the remainder depending upon OP. LOCATION is the source location |
+ of this operator (for diagnostics). */ |
+ |
static cpp_num |
-num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op) |
+num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op, |
+ source_location location) |
{ |
cpp_num result, sub; |
cpp_num_part mask; |
@@ -1666,7 +1721,8 @@ num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op) |
else |
{ |
if (!pfile->state.skip_eval) |
- cpp_error (pfile, CPP_DL_ERROR, "division by zero in #if"); |
+ cpp_error_with_line (pfile, CPP_DL_ERROR, location, 0, |
+ "division by zero in #if"); |
return lhs; |
} |