mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-11 12:54:00 +08:00
c65699efcc
ISO/IEC TS 18661-3:2015 defines C bindings to IEEE interchange and extended types, in the form of _FloatN and _FloatNx type names with corresponding fN/FN and fNx/FNx constant suffixes and FLTN_* / FLTNX_* <float.h> macros. This patch implements support for this feature in GCC. The _FloatN types, for N = 16, 32, 64 or >= 128 and a multiple of 32, are types encoded according to the corresponding IEEE interchange format (endianness unspecified; may use either the NaN conventions recommended in IEEE 754-2008, or the MIPS NaN conventions, since the choice of convention is only an IEEE recommendation, not a requirement). The _FloatNx types, for N = 32, 64 and 128, are IEEE "extended" types: types extending a narrower format with range and precision at least as big as those specified in IEEE 754 for each extended type (and with unspecified representation, but still following IEEE semantics for their values and operations - and with the set of values being determined by the precision and the maximum exponent, which means that while Intel "extended" is suitable for _Float64x, m68k "extended" is not). These types are always distinct from and not compatible with each other and the standard floating types float, double, long double; thus, double, _Float64 and _Float32x may all have the same ABI, but they are three still distinct types. The type names may be used with _Complex to construct corresponding complex types (unlike __float128, which acts more like a typedef name than a keyword - thus, this patch may be considered to fix PR c/32187). The new suffixes can be combined with GNU "i" and "j" suffixes for constants of complex types (e.g. 1.0if128, 2.0f64i). The set of types supported is implementation-defined. In this GCC patch, _Float32 is SFmode if that is suitable; _Float32x and _Float64 are DFmode if that is suitable; _Float128 is TFmode if that is suitable; _Float64x is XFmode if that is suitable, and otherwise TFmode if that is suitable. There is a target hook to override the choices if necessary. "Suitable" means both conforming to the requirements of that type, and supported as a scalar type including in libgcc. The ABI is whatever the back end does for scalars of that mode (but note that _Float32 is passed without promotion in variable arguments, unlike float). All the existing issues with exceptions and rounding modes for existing types apply equally to the new type names. No GCC port supports a floating-point format suitable for _Float128x. Although there is HFmode support for ARM and AArch64, use of that for _Float16 is not enabled. Supporting _Float16 would require additional work on the excess precision aspects of TS 18661-3: there are new values of FLT_EVAL_METHOD, which are not currently supported in GCC, and FLT_EVAL_METHOD == 0 now means that operations and constants on types narrower than float are evaluated to the range and precision of float. Implementing that, so that _Float16 gets evaluated with excess range and precision, would involve changes to the excess precision infrastructure so that the _Float16 case is enabled by default, unlike the x87 case which is only enabled for -fexcess-precision=standard. Other differences between _Float16 and __fp16 would also need to be disentangled. GCC has some prior support for nonstandard floating-point types in the form of __float80 and __float128. Where these were previously types distinct from long double, they are made by this patch into aliases for _Float64x / _Float128 if those types have the required properties. In principle the set of possible _FloatN types is infinite. This patch hardcodes the four such types for N <= 128, but with as much code as possible using loops over types to minimize the number of places with such hardcoding. I don't think it's likely any further such types will be of use in future (or indeed that formats suitable for _Float128x will actually be implemented). There is a corner case that all _FloatN, for N >= 128 and a multiple of 32, should be treated as keywords even when the corresponding type is not supported; I intend to deal with that in a followup patch. Tests are added for various functionality of the new types, mostly using type-generic headers. The tests use dg-add-options to pass any extra options needed to enable the types; this is wired up to use the same options as for __float128 on powerpc to enable _Float128 and _Float64x, and effective-target keywords for runtime support do the same hardware test as for __float128 to make sure the VSX instructions generated by those options are supported. (Corresponding additions would be needed for _Float16 on ARM as well if that were enabled with -mfp16-format=ieee required to use it rather than unconditionally available. Of course, -mfp16-format=alternative enables use of a format which is not compatible with the requirements of the _Float16 type.) C++ note: no support for the new types or constant suffixes is added for C++. C++ decimal floating-point support was very different from the C support, using class types, and the same may well apply to any future C++ bindings for IEEE interchange and extended types. There is a case, however, for supporting at least *f128 constants in C++, so that code using __float128 can use the newer style for constants throughout rather than needing to use the older *q constants in C++. Also, if built-in functions are added that may provide a way in which the types could leak into C++ code. Fortran note: the float128_type_node used in the Fortran front end is renamed to gfc_float128_type_node, since the semantics are different: in particular, if long double has binary128 format, then the new language-independent float128_type_node is a distinct type that also has binary128 format, but the Fortran node is expected to be NULL in that case. Likewise, Fortran's complex_float128_type_node is renamed to gfc_complex_float128_type_node. PowerPC note: the back end had an inconsistency that if TFmode was binary128, *q constants were TFmode instead of KFmode but __float128 was KFmode. This patch follows the same logic as for *q constants, so that _Float128 prefers TFmode (and __float128 becomes an alias for _Float128). ARM note: __fp16 is promoted to double (by convert_arguments) when passed without a prototype / in variable arguments. But this is only about the argument promotion; it is not handled as promoting in c-common.c:self_promoting_args_p / c-typeck.c:c_type_promotes_to, meaning that a K&R function definition for an argument of type __fp16 corresponds to a prototype with an argument of that type, not to one with an argument of type double, whereas a float argument in a K&R function definition corresponds to a double prototype argument - and the same functions are also what's involved in making va_arg give a warning and generate a call to abort when called with type float. This is preserved by this patch, while arranging for _Float16 not to be promoted when passed without a prototype / in variable arguments (the promotion of float being considered a legacy feature, not applied to any new types in C99 or later). TS 18661-3 extends the set of decimal floating-point types similarly, and adds new constant suffixes for the existing types, but this patch does not do anything regarding that extension. This patch does nothing regarding built-in functions, although type-generic functions such as __builtin_isinf work for the new types and associated tests are included. There are at least two levels of built-in function support possible for these types. The minimal level, implemented in <https://gcc.gnu.org/ml/gcc-patches/2016-06/msg01702.html> (which needs updating to use dg-add-options), adds built-in functions similar to those x86 has for __float128: __builtin_inf* __builtin_huge_val*, __builtin_nan*, __builtin_nans*, __builtin_fabs*, __builtin_copysign*. That would be sufficient for glibc to use the *f128 names for built-in functions by default with *q used only for backwards compatibility when using older GCC versions. That would also allow c_cpp_builtins's flag_building_libgcc code, defining __LIBGCC_%s_FUNC_EXT__, to use such suffixes rather than the present code hardcoding logic about target-specific constant suffixes and how those relate to function suffixes. Full built-in function support would cover the full range of built-in functions for existing floating-point types, adding variants for all the new types, except for a few obsolescent functions and non-type-generic variants of type-generic functions. Some but not all references to such functions in GCC use macros such as CASE_FLT_FN to be type-generic; a fair amount of work would be needed to identify all places to update. Adding all those functions would enable optimizations (for constant arguments and otherwise) for TS 18661-3 functions, but it would also substantially expand the enum listing built-in functions (and we've had problems with the size of that enum in the past), and increase the amount of built-in function initialization to do - I don't know what the startup cost involved in built-in function initialization is, but it would be something to consider when adding such a large set of functions. There are also a range of optimizations, in match.pd and elsewhere, that only operate on the three standard floating-point types. Ideally those would be made generic to all floating-point types, but this patch does nothing in that regard. Special care would be needed regarding making sure library functions to which calls are generated actually exist. For example, if sqrt is called on an argument of type _Float32, and the result converted to _Float32, this is equivalent to doing a square root operation directly on _Float32. But if the user's libm does not have the sqrtf32 function, or the name is not reserved because __STDC_WANT_IEC_60559_TYPES_EXT__ was not defined before including <math.h>, you can only do that optimization if you convert to a call to sqrtf instead. DECIMAL_DIG now relates to all supported floating-point formats, not just float, double and long double; I've raised the question with WG14 of how this relates to the formula for DECIMAL_DIG in C11 not considering this. TS 18661-3 says it also covers non-arithmetic formats only supported by library conversion functions; this patch does not add any target hooks to allow for the case where there are such formats wider than any supported for arithmetic types (where e.g. libc supports conversions involving the binary128 representation, but the _Float128 type is not supported). GCC provides its own <tgmath.h> for some targets. No attempt is made to adapt this to handle the new types. Nothing is done regarding debug info for the new types (see the "Debugger support for __float128 type?" thread on gcc@, Sep/Oct 2015). No __SIZEOF_*__ macros are added for the new types. Nothing is done with do_warn_double_promotion. Nothing is done to include the new types in those determining max_align_t, although properly it should be sufficiently aligned for any of those types. The logic for usual arithmetic conversions in c_common_type relies on TYPE_PRECISION for floating-point types, which is less than ideal (doesn't necessarily correspond to whether one type's values are subset of another); looking in more detail at the formats might be better. But since I included code in build_common_tree_nodes to work around rs6000 KFmode having precision 113 not 128, I think it should work. Ideally one might have errors in generic code for the case where the two types do not have one type's values a subset of the other (which is undefined behavior). But the only case where this can actually occur is mixing IBM long double with binary128 on powerpc, and rs6000_invalid_binary_op deals with that at present. TS 18661-3 does not fully specify the type resulting from the usual arithmetic conversions in the case where two _FloatNx types have the same set of values; I arranged the code to prefer the greater value of N in that case. The __FP_FAST_FMA* macros are not extended to cover the new types, since there are no corresponding built-in functions (if built-in fmafN, fmafNx are added, the macros should be extended, and the new macros documented). Also, only a limited set of modes is handled in mode_has_fma. Diagnostics relating to the use of the new types with -pedantic do not try to distinguish them from purely nonstandard types such as __int128 and constant suffixes such as *q. If you use an unsupported _FloatN / _FloatNx type you get a warning about the type defaulting to int after the warning about the type not being supported. That's less than ideal, but it's also a pre-existing condition if you use __int128 on a 32-bit system where it's unsupported. Bootstrapped with no regressions on x86_64-pc-linux-gnu. Other back-end changes minimally tested by building cc1 for ia64-linux-gnu, powerpc64le-linux-gnu, pdp11-none (the last failed for unrelated reasons). PR c/32187 gcc: * tree-core.h (TI_COMPLEX_FLOAT16_TYPE) (TI_COMPLEX_FLOATN_NX_TYPE_FIRST, TI_COMPLEX_FLOAT32_TYPE) (TI_COMPLEX_FLOAT64_TYPE, TI_COMPLEX_FLOAT128_TYPE) (TI_COMPLEX_FLOAT32X_TYPE, TI_COMPLEX_FLOAT64X_TYPE) (TI_COMPLEX_FLOAT128X_TYPE, TI_FLOAT16_TYPE, TI_FLOATN_TYPE_FIRST) (TI_FLOATN_NX_TYPE_FIRST, TI_FLOAT32_TYPE, TI_FLOAT64_TYPE) (TI_FLOAT128_TYPE, TI_FLOATN_TYPE_LAST, TI_FLOAT32X_TYPE) (TI_FLOATNX_TYPE_FIRST, TI_FLOAT64X_TYPE, TI_FLOAT128X_TYPE) (TI_FLOATNX_TYPE_LAST, TI_FLOATN_NX_TYPE_LAST): New enum tree_index values. (NUM_FLOATN_TYPES, NUM_FLOATNX_TYPES, NUM_FLOATN_NX_TYPES): New macros. (struct floatn_type_info): New structure type. (floatn_nx_types): New variable declaration. * tree.h (FLOATN_TYPE_NODE, FLOATN_NX_TYPE_NODE) (FLOATNX_TYPE_NODE, float128_type_node, float64x_type_node) (COMPLEX_FLOATN_NX_TYPE_NODE): New macros. * tree.c (floatn_nx_types): New variable. (build_common_tree_nodes): Initialize _FloatN, _FloatNx and corresponding complex types. * target.def (floatn_mode): New hook. * targhooks.c: Include "real.h". (default_floatn_mode): New function. * targhooks.h (default_floatn_mode): New prototype. * doc/extend.texi (Floating Types): Document _FloatN and _FloatNx types. * doc/sourcebuild.texi (float@var{n}, float@var{n}x): Document new effective-target and dg-add-options keywords. (float@var{n}_runtime, float@var{n}x_runtime, floatn_nx_runtime): Document new effective-target keywords. * doc/tm.texi.in (TARGET_FLOATN_MODE): New @hook. * doc/tm.texi: Regenerate. * ginclude/float.h (LDBL_DECIMAL_DIG): Define to __LDBL_DECIMAL_DIG__, not __DECIMAL_DIG__. [__STDC_WANT_IEC_60559_TYPES_EXT__]: Define macros from TS 18661-3. * real.h (struct real_format): Add field ieee_bits. * real.c (ieee_single_format, mips_single_format) (motorola_single_format, spu_single_format, ieee_double_format) (mips_double_format, motorola_double_format) (ieee_extended_motorola_format, ieee_extended_intel_96_format) (ieee_extended_intel_128_format) (ieee_extended_intel_96_round_53_format, ibm_extended_format) (mips_extended_format, ieee_quad_format, mips_quad_format) (vax_f_format, vax_d_format, vax_g_format, decimal_single_format) (decimal_double_format, decimal_quad_format, ieee_half_format) (arm_half_format, real_internal_format: Initialize ieee_bits field. * config/i386/i386.c (ix86_init_builtin_types): Do not initialize float128_type_node. Set float80_type_node to float64x_type_node if appropriate and long_double_type_node not appropriate. * config/ia64/ia64.c (ia64_init_builtins): Likewise. * config/pdp11/pdp11.c (pdp11_f_format, pdp11_d_format): Initialize ieee_bits field. * config/rs6000/rs6000.c (TARGET_FLOATN_MODE): New macro. (rs6000_init_builtins): Set ieee128_float_type_node to float128_type_node. (rs6000_floatn_mode): New function. gcc/c: * c-tree.h (cts_floatn_nx): New enum c_typespec_keyword value. (struct c_declspecs): Add field floatn_nx_idx. * c-decl.c (declspecs_add_type, finish_declspecs): Handle _FloatN and _FloatNx type specifiers. * c-parser.c (c_keyword_starts_typename, c_token_starts_declspecs) (c_parser_declspecs, c_parser_attribute_any_word) (c_parser_objc_selector): Use CASE_RID_FLOATN_NX. * c-typeck.c (c_common_type): Handle _FloatN and _FloatNx types. (convert_arguments): Avoid promoting _FloatN and _FloatNx types narrower than double. gcc/c-family: * c-common.h (RID_FLOAT16, RID_FLOATN_NX_FIRST, RID_FLOAT32) (RID_FLOAT64, RID_FLOAT128, RID_FLOAT32X, RID_FLOAT64X) (RID_FLOAT128X): New enum rid values. (CASE_RID_FLOATN_NX): New macro. * c-common.c (c_common_reswords): Add _FloatN and _FloatNx keywords. (c_common_type_for_mode): Check for _FloatN and _FloatNx and corresponding complex types. (c_common_nodes_and_builtins): For non-C++, register _FloatN and _FloatNx and corresponding complex types. (keyword_begins_type_specifier): Use CASE_RID_FLOATN_NX. * c-cppbuiltin.c (builtin_define_float_constants): Check _FloatN and _FloatNx types for the widest type for determining DECIMAL_DIG. Define __LDBL_DECIMAL_DIG__ as well as __DECIMAL_DIG__ for long double. Handle FMA_SUFFIX being NULL. (c_cpp_builtins): Call builtin_define_float_constants for _FloatN and _FloatNx types. * c-lex.c (interpret_float): Handle _FloatN and _FloatNx constants. * c-pretty-print.c (pp_c_floating_constant): Handle _FloatN and _FloatNx types. gcc/fortran: * trans-types.h (float128_type_node): Rename to gfc_float128_type_node. (complex_float128_type_node): Rename to gfc_complex_float128_type_node. * iso-c-binding.def, trans-intrinsic.c, trans-types.c: All users changed. gcc/testsuite: * lib/target-supports.exp (check_effective_target_float16) (check_effective_target_float32, check_effective_target_float64) (check_effective_target_float128, check_effective_target_float32x) (check_effective_target_float64x) (check_effective_target_float128x) (check_effective_target_float16_runtime) (check_effective_target_float32_runtime) (check_effective_target_float64_runtime) (check_effective_target_float128_runtime) (check_effective_target_float32x_runtime) (check_effective_target_float64x_runtime) (check_effective_target_float128x_runtime) (check_effective_target_floatn_nx_runtime) (add_options_for_float16, add_options_for_float32) (add_options_for_float64, add_options_for_float128) (add_options_for_float32x, add_options_for_float64x) (add_options_for_float128x): New procedures. * gcc.dg/dfp/floatn.c, gcc.dg/float128-typeof.c, gcc.dg/float128x-typeof.c, gcc.dg/float16-typeof.c, gcc.dg/float32-typeof.c, gcc.dg/float32x-typeof.c, gcc.dg/float64-typeof.c, gcc.dg/float64x-typeof.c, gcc.dg/floatn-arithconv.c, gcc.dg/floatn-errs.c, gcc.dg/floatn-typeof.h, gcc.dg/torture/float128-basic.c, gcc.dg/torture/float128-complex.c, gcc.dg/torture/float128-floath.c, gcc.dg/torture/float128-tg.c, gcc.dg/torture/float128x-basic.c, gcc.dg/torture/float128x-complex.c, gcc.dg/torture/float128x-floath.c, gcc.dg/torture/float128x-tg.c, gcc.dg/torture/float16-basic.c, gcc.dg/torture/float16-complex.c, gcc.dg/torture/float16-floath.c, gcc.dg/torture/float16-tg.c, gcc.dg/torture/float32-basic.c, gcc.dg/torture/float32-complex.c, gcc.dg/torture/float32-floath.c, gcc.dg/torture/float32-tg.c, gcc.dg/torture/float32x-basic.c, gcc.dg/torture/float32x-complex.c, gcc.dg/torture/float32x-floath.c, gcc.dg/torture/float32x-tg.c, gcc.dg/torture/float64-basic.c, gcc.dg/torture/float64-complex.c, gcc.dg/torture/float64-floath.c, gcc.dg/torture/float64-tg.c, gcc.dg/torture/float64x-basic.c, gcc.dg/torture/float64x-complex.c, gcc.dg/torture/float64x-floath.c, gcc.dg/torture/float64x-tg.c, gcc.dg/torture/floatn-basic.h, gcc.dg/torture/floatn-complex.h, gcc.dg/torture/floatn-convert.c, gcc.dg/torture/floatn-floath.h, gcc.dg/torture/floatn-tg.h, gcc.dg/torture/fp-int-convert-float128-ieee-timode.c, gcc.dg/torture/fp-int-convert-float128-ieee.c, gcc.dg/torture/fp-int-convert-float128x-timode.c, gcc.dg/torture/fp-int-convert-float128x.c, gcc.dg/torture/fp-int-convert-float16-timode.c, gcc.dg/torture/fp-int-convert-float16.c, gcc.dg/torture/fp-int-convert-float32-timode.c, gcc.dg/torture/fp-int-convert-float32.c, gcc.dg/torture/fp-int-convert-float32x-timode.c, gcc.dg/torture/fp-int-convert-float32x.c, gcc.dg/torture/fp-int-convert-float64-timode.c, gcc.dg/torture/fp-int-convert-float64.c, gcc.dg/torture/fp-int-convert-float64x-timode.c, gcc.dg/torture/fp-int-convert-float64x.c: New tests. * gcc.dg/torture/fp-int-convert.h (TEST_I_F): Add argument for maximum exponent of floating-point type. Use it in testing whether 0x8...0 fits in the floating-point type. Always treat -1 (signed 0xf...f) as fitting in the floating-point type. (M_OK1): New macro. * gcc.dg/torture/fp-int-convert-double.c, gcc.dg/torture/fp-int-convert-float.c, gcc.dg/torture/fp-int-convert-float128-timode.c, gcc.dg/torture/fp-int-convert-float128.c, gcc.dg/torture/fp-int-convert-float80-timode.c, gcc.dg/torture/fp-int-convert-float80.c, gcc.dg/torture/fp-int-convert-long-double.c, gcc.dg/torture/fp-int-convert-timode.c: Update calls to TEST_I_F. libcpp: * include/cpplib.h (CPP_N_FLOATN, CPP_N_FLOATNX) (CPP_N_WIDTH_FLOATN_NX, CPP_FLOATN_SHIFT, CPP_FLOATN_MAX): New macros. * expr.c (interpret_float_suffix): Handle fN, fNx, FN and FNx suffixes. From-SVN: r239625
2241 lines
61 KiB
C
2241 lines
61 KiB
C
/* Parse C expressions for cpplib.
|
||
Copyright (C) 1987-2016 Free Software Foundation, Inc.
|
||
Contributed by Per Bothner, 1994.
|
||
|
||
This program is free software; you can redistribute it and/or modify it
|
||
under the terms of the GNU General Public License as published by the
|
||
Free Software Foundation; either version 3, or (at your option) any
|
||
later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program; see the file COPYING3. If not see
|
||
<http://www.gnu.org/licenses/>. */
|
||
|
||
#include "config.h"
|
||
#include "system.h"
|
||
#include "cpplib.h"
|
||
#include "internal.h"
|
||
|
||
#define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT)
|
||
#define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2))
|
||
#define LOW_PART(num_part) (num_part & HALF_MASK)
|
||
#define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2))
|
||
|
||
struct op
|
||
{
|
||
const cpp_token *token; /* The token forming op (for diagnostics). */
|
||
cpp_num value; /* The value logically "right" of op. */
|
||
source_location loc; /* The location of this value. */
|
||
enum cpp_ttype op;
|
||
};
|
||
|
||
/* Some simple utility routines on double integers. */
|
||
#define num_zerop(num) ((num.low | num.high) == 0)
|
||
#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high)
|
||
static bool num_positive (cpp_num, size_t);
|
||
static bool num_greater_eq (cpp_num, cpp_num, size_t);
|
||
static cpp_num num_trim (cpp_num, size_t);
|
||
static cpp_num num_part_mul (cpp_num_part, cpp_num_part);
|
||
|
||
static cpp_num num_unary_op (cpp_reader *, cpp_num, enum cpp_ttype);
|
||
static cpp_num num_binary_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
|
||
static cpp_num num_negate (cpp_num, size_t);
|
||
static cpp_num num_bitwise_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
|
||
static cpp_num num_inequality_op (cpp_reader *, cpp_num, cpp_num,
|
||
enum cpp_ttype);
|
||
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,
|
||
source_location);
|
||
static cpp_num num_lshift (cpp_num, size_t, size_t);
|
||
static cpp_num num_rshift (cpp_num, size_t, size_t);
|
||
|
||
static cpp_num append_digit (cpp_num, int, int, size_t);
|
||
static cpp_num parse_defined (cpp_reader *);
|
||
static cpp_num eval_token (cpp_reader *, const cpp_token *, source_location);
|
||
static struct op *reduce (cpp_reader *, struct op *, enum cpp_ttype);
|
||
static unsigned int interpret_float_suffix (cpp_reader *, const uchar *, size_t);
|
||
static unsigned int interpret_int_suffix (cpp_reader *, const uchar *, size_t);
|
||
static void check_promotion (cpp_reader *, const struct op *);
|
||
|
||
static cpp_num parse_has_include (cpp_reader *, enum include_type);
|
||
|
||
/* Token type abuse to create unary plus and minus operators. */
|
||
#define CPP_UPLUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1))
|
||
#define CPP_UMINUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 2))
|
||
|
||
/* With -O2, gcc appears to produce nice code, moving the error
|
||
message load and subsequent jump completely out of the main path. */
|
||
#define SYNTAX_ERROR(msgid) \
|
||
do { cpp_error (pfile, CPP_DL_ERROR, msgid); goto syntax_error; } while(0)
|
||
#define SYNTAX_ERROR2(msgid, arg) \
|
||
do { cpp_error (pfile, CPP_DL_ERROR, msgid, arg); goto syntax_error; } \
|
||
while(0)
|
||
#define SYNTAX_ERROR_AT(loc, msgid) \
|
||
do { cpp_error_with_line (pfile, CPP_DL_ERROR, (loc), 0, msgid); goto syntax_error; } \
|
||
while(0)
|
||
#define SYNTAX_ERROR2_AT(loc, msgid, arg) \
|
||
do { cpp_error_with_line (pfile, CPP_DL_ERROR, (loc), 0, msgid, arg); goto syntax_error; } \
|
||
while(0)
|
||
|
||
/* Subroutine of cpp_classify_number. S points to a float suffix of
|
||
length LEN, possibly zero. Returns 0 for an invalid suffix, or a
|
||
flag vector (of CPP_N_* bits) describing the suffix. */
|
||
static unsigned int
|
||
interpret_float_suffix (cpp_reader *pfile, const uchar *s, size_t len)
|
||
{
|
||
size_t flags;
|
||
size_t f, d, l, w, q, i, fn, fnx, fn_bits;
|
||
|
||
flags = 0;
|
||
f = d = l = w = q = i = fn = fnx = fn_bits = 0;
|
||
|
||
/* The following decimal float suffixes, from TR 24732:2009 and TS
|
||
18661-2:2015, are supported:
|
||
|
||
df, DF - _Decimal32.
|
||
dd, DD - _Decimal64.
|
||
dl, DL - _Decimal128.
|
||
|
||
The dN and DN suffixes for _DecimalN, and dNx and DNx for
|
||
_DecimalNx, defined in TS 18661-3:2015, are not supported.
|
||
|
||
Fixed-point suffixes, from TR 18037:2008, are supported. They
|
||
consist of three parts, in order:
|
||
|
||
(i) An optional u or U, for unsigned types.
|
||
|
||
(ii) An optional h or H, for short types, or l or L, for long
|
||
types, or ll or LL, for long long types. Use of ll or LL is a
|
||
GNU extension.
|
||
|
||
(iii) r or R, for _Fract types, or k or K, for _Accum types.
|
||
|
||
Otherwise the suffix is for a binary or standard floating-point
|
||
type. Such a suffix, or the absence of a suffix, may be preceded
|
||
or followed by i, I, j or J, to indicate an imaginary number with
|
||
the corresponding complex type. The following suffixes for
|
||
binary or standard floating-point types are supported:
|
||
|
||
f, F - float (ISO C and C++).
|
||
l, L - long double (ISO C and C++).
|
||
d, D - double, even with the FLOAT_CONST_DECIMAL64 pragma in
|
||
operation (from TR 24732:2009; the pragma and the suffix
|
||
are not included in TS 18661-2:2015).
|
||
w, W - machine-specific type such as __float80 (GNU extension).
|
||
q, Q - machine-specific type such as __float128 (GNU extension).
|
||
fN, FN - _FloatN (TS 18661-3:2015).
|
||
fNx, FNx - _FloatNx (TS 18661-3:2015). */
|
||
|
||
/* 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 '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:
|
||
/* Additional two-character suffixes beginning with D are not
|
||
for decimal float constants. */
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (CPP_OPTION (pfile, ext_numeric_literals))
|
||
{
|
||
/* Recognize a fixed-point suffix. */
|
||
if (len != 0)
|
||
switch (s[len-1])
|
||
{
|
||
case 'k': case 'K': flags = CPP_N_ACCUM; break;
|
||
case 'r': case 'R': flags = CPP_N_FRACT; break;
|
||
default: break;
|
||
}
|
||
|
||
/* Continue processing a fixed-point suffix. The suffix is case
|
||
insensitive except for ll or LL. Order is significant. */
|
||
if (flags)
|
||
{
|
||
if (len == 1)
|
||
return flags;
|
||
len--;
|
||
|
||
if (*s == 'u' || *s == 'U')
|
||
{
|
||
flags |= CPP_N_UNSIGNED;
|
||
if (len == 1)
|
||
return flags;
|
||
len--;
|
||
s++;
|
||
}
|
||
|
||
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;
|
||
}
|
||
}
|
||
|
||
/* In any remaining valid suffix, the case and order don't matter. */
|
||
while (len--)
|
||
{
|
||
switch (s[0])
|
||
{
|
||
case 'f': case 'F':
|
||
f++;
|
||
if (len > 0
|
||
&& !CPP_OPTION (pfile, cplusplus)
|
||
&& s[1] >= '1'
|
||
&& s[1] <= '9'
|
||
&& fn_bits == 0)
|
||
{
|
||
f--;
|
||
while (len > 0
|
||
&& s[1] >= '0'
|
||
&& s[1] <= '9'
|
||
&& fn_bits < CPP_FLOATN_MAX)
|
||
{
|
||
fn_bits = fn_bits * 10 + (s[1] - '0');
|
||
len--;
|
||
s++;
|
||
}
|
||
if (len > 0 && s[1] == 'x')
|
||
{
|
||
fnx++;
|
||
len--;
|
||
s++;
|
||
}
|
||
else
|
||
fn++;
|
||
}
|
||
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;
|
||
}
|
||
s++;
|
||
}
|
||
|
||
/* Reject any case of multiple suffixes specifying types, multiple
|
||
suffixes specifying an imaginary constant, _FloatN or _FloatNx
|
||
suffixes for invalid values of N, and _FloatN suffixes for values
|
||
of N larger than can be represented in the return value. The
|
||
caller is responsible for rejecting _FloatN suffixes where
|
||
_FloatN is not supported on the chosen target. */
|
||
if (f + d + l + w + q + fn + fnx > 1 || i > 1)
|
||
return 0;
|
||
if (fn_bits > CPP_FLOATN_MAX)
|
||
return 0;
|
||
if (fnx && fn_bits != 32 && fn_bits != 64 && fn_bits != 128)
|
||
return 0;
|
||
if (fn && fn_bits != 16 && fn_bits % 32 != 0)
|
||
return 0;
|
||
if (fn && fn_bits == 96)
|
||
return 0;
|
||
|
||
if (i && !CPP_OPTION (pfile, ext_numeric_literals))
|
||
return 0;
|
||
|
||
if ((w || q) && !CPP_OPTION (pfile, ext_numeric_literals))
|
||
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 :
|
||
fn ? CPP_N_FLOATN | (fn_bits << CPP_FLOATN_SHIFT) :
|
||
fnx ? CPP_N_FLOATNX | (fn_bits << CPP_FLOATN_SHIFT) :
|
||
CPP_N_DEFAULT));
|
||
}
|
||
|
||
/* Return the classification flags for a float suffix. */
|
||
unsigned int
|
||
cpp_interpret_float_suffix (cpp_reader *pfile, const char *s, size_t len)
|
||
{
|
||
return interpret_float_suffix (pfile, (const unsigned char *)s, len);
|
||
}
|
||
|
||
/* Subroutine of cpp_classify_number. S points to an integer suffix
|
||
of length LEN, possibly zero. Returns 0 for an invalid suffix, or a
|
||
flag vector describing the suffix. */
|
||
static unsigned int
|
||
interpret_int_suffix (cpp_reader *pfile, const uchar *s, size_t len)
|
||
{
|
||
size_t u, l, i;
|
||
|
||
u = l = i = 0;
|
||
|
||
while (len--)
|
||
switch (s[len])
|
||
{
|
||
case 'u': case 'U': u++; break;
|
||
case 'i': case 'I':
|
||
case 'j': case 'J': i++; break;
|
||
case 'l': case 'L': 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;
|
||
default:
|
||
return 0;
|
||
}
|
||
|
||
if (l > 2 || u > 1 || i > 1)
|
||
return 0;
|
||
|
||
if (i && !CPP_OPTION (pfile, ext_numeric_literals))
|
||
return 0;
|
||
|
||
return ((i ? CPP_N_IMAGINARY : 0)
|
||
| (u ? CPP_N_UNSIGNED : 0)
|
||
| ((l == 0) ? CPP_N_SMALL
|
||
: (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE));
|
||
}
|
||
|
||
/* Return the classification flags for an int suffix. */
|
||
unsigned int
|
||
cpp_interpret_int_suffix (cpp_reader *pfile, const char *s, size_t len)
|
||
{
|
||
return interpret_int_suffix (pfile, (const unsigned char *)s, len);
|
||
}
|
||
|
||
/* Return the string type corresponding to the the input user-defined string
|
||
literal type. If the input type is not a user-defined string literal
|
||
type return the input type. */
|
||
enum cpp_ttype
|
||
cpp_userdef_string_remove_type (enum cpp_ttype type)
|
||
{
|
||
if (type == CPP_STRING_USERDEF)
|
||
return CPP_STRING;
|
||
else if (type == CPP_WSTRING_USERDEF)
|
||
return CPP_WSTRING;
|
||
else if (type == CPP_STRING16_USERDEF)
|
||
return CPP_STRING16;
|
||
else if (type == CPP_STRING32_USERDEF)
|
||
return CPP_STRING32;
|
||
else if (type == CPP_UTF8STRING_USERDEF)
|
||
return CPP_UTF8STRING;
|
||
else
|
||
return type;
|
||
}
|
||
|
||
/* Return the user-defined string literal type corresponding to the input
|
||
string type. If the input type is not a string type return the input
|
||
type. */
|
||
enum cpp_ttype
|
||
cpp_userdef_string_add_type (enum cpp_ttype type)
|
||
{
|
||
if (type == CPP_STRING)
|
||
return CPP_STRING_USERDEF;
|
||
else if (type == CPP_WSTRING)
|
||
return CPP_WSTRING_USERDEF;
|
||
else if (type == CPP_STRING16)
|
||
return CPP_STRING16_USERDEF;
|
||
else if (type == CPP_STRING32)
|
||
return CPP_STRING32_USERDEF;
|
||
else if (type == CPP_UTF8STRING)
|
||
return CPP_UTF8STRING_USERDEF;
|
||
else
|
||
return type;
|
||
}
|
||
|
||
/* Return the char type corresponding to the the input user-defined char
|
||
literal type. If the input type is not a user-defined char literal
|
||
type return the input type. */
|
||
enum cpp_ttype
|
||
cpp_userdef_char_remove_type (enum cpp_ttype type)
|
||
{
|
||
if (type == CPP_CHAR_USERDEF)
|
||
return CPP_CHAR;
|
||
else if (type == CPP_WCHAR_USERDEF)
|
||
return CPP_WCHAR;
|
||
else if (type == CPP_CHAR16_USERDEF)
|
||
return CPP_CHAR16;
|
||
else if (type == CPP_CHAR32_USERDEF)
|
||
return CPP_CHAR32;
|
||
else if (type == CPP_UTF8CHAR_USERDEF)
|
||
return CPP_UTF8CHAR;
|
||
else
|
||
return type;
|
||
}
|
||
|
||
/* Return the user-defined char literal type corresponding to the input
|
||
char type. If the input type is not a char type return the input
|
||
type. */
|
||
enum cpp_ttype
|
||
cpp_userdef_char_add_type (enum cpp_ttype type)
|
||
{
|
||
if (type == CPP_CHAR)
|
||
return CPP_CHAR_USERDEF;
|
||
else if (type == CPP_WCHAR)
|
||
return CPP_WCHAR_USERDEF;
|
||
else if (type == CPP_CHAR16)
|
||
return CPP_CHAR16_USERDEF;
|
||
else if (type == CPP_CHAR32)
|
||
return CPP_CHAR32_USERDEF;
|
||
else if (type == CPP_UTF8CHAR)
|
||
return CPP_UTF8CHAR_USERDEF;
|
||
else
|
||
return type;
|
||
}
|
||
|
||
/* Return true if the token type is a user-defined string literal. */
|
||
bool
|
||
cpp_userdef_string_p (enum cpp_ttype type)
|
||
{
|
||
if (type == CPP_STRING_USERDEF
|
||
|| type == CPP_WSTRING_USERDEF
|
||
|| type == CPP_STRING16_USERDEF
|
||
|| type == CPP_STRING32_USERDEF
|
||
|| type == CPP_UTF8STRING_USERDEF)
|
||
return true;
|
||
else
|
||
return false;
|
||
}
|
||
|
||
/* Return true if the token type is a user-defined char literal. */
|
||
bool
|
||
cpp_userdef_char_p (enum cpp_ttype type)
|
||
{
|
||
if (type == CPP_CHAR_USERDEF
|
||
|| type == CPP_WCHAR_USERDEF
|
||
|| type == CPP_CHAR16_USERDEF
|
||
|| type == CPP_CHAR32_USERDEF
|
||
|| type == CPP_UTF8CHAR_USERDEF)
|
||
return true;
|
||
else
|
||
return false;
|
||
}
|
||
|
||
/* Extract the suffix from a user-defined literal string or char. */
|
||
const char *
|
||
cpp_get_userdef_suffix (const cpp_token *tok)
|
||
{
|
||
unsigned int len = tok->val.str.len;
|
||
const char *text = (const char *)tok->val.str.text;
|
||
char delim;
|
||
unsigned int i;
|
||
for (i = 0; i < len; ++i)
|
||
if (text[i] == '\'' || text[i] == '"')
|
||
break;
|
||
if (i == len)
|
||
return text + len;
|
||
delim = text[i];
|
||
for (i = len; i > 0; --i)
|
||
if (text[i - 1] == delim)
|
||
break;
|
||
return text + i;
|
||
}
|
||
|
||
/* Categorize numeric constants according to their field (integer,
|
||
floating point, or invalid), radix (decimal, octal, hexadecimal),
|
||
and type suffixes.
|
||
|
||
TOKEN is the token that represents the numeric constant to
|
||
classify.
|
||
|
||
In C++0X if UD_SUFFIX is non null it will be assigned
|
||
any unrecognized suffix for a user-defined literal.
|
||
|
||
VIRTUAL_LOCATION is the virtual location for TOKEN. */
|
||
unsigned int
|
||
cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
|
||
const char **ud_suffix, source_location virtual_location)
|
||
{
|
||
const uchar *str = token->val.str.text;
|
||
const uchar *limit;
|
||
unsigned int max_digit, result, radix;
|
||
enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag;
|
||
bool seen_digit;
|
||
bool seen_digit_sep;
|
||
|
||
if (ud_suffix)
|
||
*ud_suffix = NULL;
|
||
|
||
/* If the lexer has done its job, length one can only be a single
|
||
digit. Fast-path this very common case. */
|
||
if (token->val.str.len == 1)
|
||
return CPP_N_INTEGER | CPP_N_SMALL | CPP_N_DECIMAL;
|
||
|
||
limit = str + token->val.str.len;
|
||
float_flag = NOT_FLOAT;
|
||
max_digit = 0;
|
||
radix = 10;
|
||
seen_digit = false;
|
||
seen_digit_sep = false;
|
||
|
||
/* First, interpret the radix. */
|
||
if (*str == '0')
|
||
{
|
||
radix = 8;
|
||
str++;
|
||
|
||
/* Require at least one hex digit to classify it as hex. */
|
||
if (*str == 'x' || *str == 'X')
|
||
{
|
||
if (str[1] == '.' || ISXDIGIT (str[1]))
|
||
{
|
||
radix = 16;
|
||
str++;
|
||
}
|
||
else if (DIGIT_SEP (str[1]))
|
||
SYNTAX_ERROR_AT (virtual_location,
|
||
"digit separator after base indicator");
|
||
}
|
||
else if (*str == 'b' || *str == 'B')
|
||
{
|
||
if (str[1] == '0' || str[1] == '1')
|
||
{
|
||
radix = 2;
|
||
str++;
|
||
}
|
||
else if (DIGIT_SEP (str[1]))
|
||
SYNTAX_ERROR_AT (virtual_location,
|
||
"digit separator after base indicator");
|
||
}
|
||
}
|
||
|
||
/* Now scan for a well-formed integer or float. */
|
||
for (;;)
|
||
{
|
||
unsigned int c = *str++;
|
||
|
||
if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16))
|
||
{
|
||
seen_digit_sep = false;
|
||
seen_digit = true;
|
||
c = hex_value (c);
|
||
if (c > max_digit)
|
||
max_digit = c;
|
||
}
|
||
else if (DIGIT_SEP (c))
|
||
{
|
||
if (seen_digit_sep)
|
||
SYNTAX_ERROR_AT (virtual_location, "adjacent digit separators");
|
||
seen_digit_sep = true;
|
||
}
|
||
else if (c == '.')
|
||
{
|
||
if (seen_digit_sep || DIGIT_SEP (*str))
|
||
SYNTAX_ERROR_AT (virtual_location,
|
||
"digit separator adjacent to decimal point");
|
||
seen_digit_sep = false;
|
||
if (float_flag == NOT_FLOAT)
|
||
float_flag = AFTER_POINT;
|
||
else
|
||
SYNTAX_ERROR_AT (virtual_location,
|
||
"too many decimal points in number");
|
||
}
|
||
else if ((radix <= 10 && (c == 'e' || c == 'E'))
|
||
|| (radix == 16 && (c == 'p' || c == 'P')))
|
||
{
|
||
if (seen_digit_sep || DIGIT_SEP (*str))
|
||
SYNTAX_ERROR_AT (virtual_location,
|
||
"digit separator adjacent to exponent");
|
||
float_flag = AFTER_EXPON;
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
/* Start of suffix. */
|
||
str--;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (seen_digit_sep && float_flag != AFTER_EXPON)
|
||
SYNTAX_ERROR_AT (virtual_location,
|
||
"digit separator outside digit sequence");
|
||
|
||
/* The suffix may be for decimal fixed-point constants without exponent. */
|
||
if (radix != 16 && float_flag == NOT_FLOAT)
|
||
{
|
||
result = interpret_float_suffix (pfile, str, limit - str);
|
||
if ((result & CPP_N_FRACT) || (result & CPP_N_ACCUM))
|
||
{
|
||
result |= CPP_N_FLOATING;
|
||
/* We need to restore the radix to 10, if the radix is 8. */
|
||
if (radix == 8)
|
||
radix = 10;
|
||
|
||
if (CPP_PEDANTIC (pfile))
|
||
cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
|
||
"fixed-point constants are a GCC extension");
|
||
goto syntax_ok;
|
||
}
|
||
else
|
||
result = 0;
|
||
}
|
||
|
||
if (float_flag != NOT_FLOAT && radix == 8)
|
||
radix = 10;
|
||
|
||
if (max_digit >= radix)
|
||
{
|
||
if (radix == 2)
|
||
SYNTAX_ERROR2_AT (virtual_location,
|
||
"invalid digit \"%c\" in binary constant", '0' + max_digit);
|
||
else
|
||
SYNTAX_ERROR2_AT (virtual_location,
|
||
"invalid digit \"%c\" in octal constant", '0' + max_digit);
|
||
}
|
||
|
||
if (float_flag != NOT_FLOAT)
|
||
{
|
||
if (radix == 2)
|
||
{
|
||
cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0,
|
||
"invalid prefix \"0b\" for floating constant");
|
||
return CPP_N_INVALID;
|
||
}
|
||
|
||
if (radix == 16 && !seen_digit)
|
||
SYNTAX_ERROR_AT (virtual_location,
|
||
"no digits in hexadecimal floating constant");
|
||
|
||
if (radix == 16 && CPP_PEDANTIC (pfile)
|
||
&& !CPP_OPTION (pfile, extended_numbers))
|
||
{
|
||
if (CPP_OPTION (pfile, cplusplus))
|
||
cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
|
||
"use of C++1z hexadecimal floating constant");
|
||
else
|
||
cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
|
||
"use of C99 hexadecimal floating constant");
|
||
}
|
||
|
||
if (float_flag == AFTER_EXPON)
|
||
{
|
||
if (*str == '+' || *str == '-')
|
||
str++;
|
||
|
||
/* Exponent is decimal, even if string is a hex float. */
|
||
if (!ISDIGIT (*str))
|
||
{
|
||
if (DIGIT_SEP (*str))
|
||
SYNTAX_ERROR_AT (virtual_location,
|
||
"digit separator adjacent to exponent");
|
||
else
|
||
SYNTAX_ERROR_AT (virtual_location, "exponent has no digits");
|
||
}
|
||
do
|
||
{
|
||
seen_digit_sep = DIGIT_SEP (*str);
|
||
str++;
|
||
}
|
||
while (ISDIGIT (*str) || DIGIT_SEP (*str));
|
||
}
|
||
else if (radix == 16)
|
||
SYNTAX_ERROR_AT (virtual_location,
|
||
"hexadecimal floating constants require an exponent");
|
||
|
||
if (seen_digit_sep)
|
||
SYNTAX_ERROR_AT (virtual_location,
|
||
"digit separator outside digit sequence");
|
||
|
||
result = interpret_float_suffix (pfile, str, limit - str);
|
||
if (result == 0)
|
||
{
|
||
if (CPP_OPTION (pfile, user_literals))
|
||
{
|
||
if (ud_suffix)
|
||
*ud_suffix = (const char *) str;
|
||
result = CPP_N_LARGE | CPP_N_USERDEF;
|
||
}
|
||
else
|
||
{
|
||
cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0,
|
||
"invalid suffix \"%.*s\" on floating constant",
|
||
(int) (limit - str), str);
|
||
return CPP_N_INVALID;
|
||
}
|
||
}
|
||
|
||
/* Traditional C didn't accept any floating suffixes. */
|
||
if (limit != str
|
||
&& CPP_WTRADITIONAL (pfile)
|
||
&& ! cpp_sys_macro_p (pfile))
|
||
cpp_warning_with_line (pfile, CPP_W_TRADITIONAL, virtual_location, 0,
|
||
"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_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
|
||
"suffix for double constant is a GCC extension");
|
||
|
||
/* Radix must be 10 for decimal floats. */
|
||
if ((result & CPP_N_DFLOAT) && radix != 10)
|
||
{
|
||
cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0,
|
||
"invalid suffix \"%.*s\" with hexadecimal floating constant",
|
||
(int) (limit - str), str);
|
||
return CPP_N_INVALID;
|
||
}
|
||
|
||
if ((result & (CPP_N_FRACT | CPP_N_ACCUM)) && CPP_PEDANTIC (pfile))
|
||
cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
|
||
"fixed-point constants are a GCC extension");
|
||
|
||
if ((result & CPP_N_DFLOAT) && CPP_PEDANTIC (pfile))
|
||
cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
|
||
"decimal float constants are a GCC extension");
|
||
|
||
result |= CPP_N_FLOATING;
|
||
}
|
||
else
|
||
{
|
||
result = interpret_int_suffix (pfile, str, limit - str);
|
||
if (result == 0)
|
||
{
|
||
if (CPP_OPTION (pfile, user_literals))
|
||
{
|
||
if (ud_suffix)
|
||
*ud_suffix = (const char *) str;
|
||
result = CPP_N_UNSIGNED | CPP_N_LARGE | CPP_N_USERDEF;
|
||
}
|
||
else
|
||
{
|
||
cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0,
|
||
"invalid suffix \"%.*s\" on integer constant",
|
||
(int) (limit - str), str);
|
||
return CPP_N_INVALID;
|
||
}
|
||
}
|
||
|
||
/* Traditional C only accepted the 'L' suffix.
|
||
Suppress warning about 'LL' with -Wno-long-long. */
|
||
if (CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile))
|
||
{
|
||
int u_or_i = (result & (CPP_N_UNSIGNED|CPP_N_IMAGINARY));
|
||
int large = (result & CPP_N_WIDTH) == CPP_N_LARGE
|
||
&& CPP_OPTION (pfile, cpp_warn_long_long);
|
||
|
||
if (u_or_i || large)
|
||
cpp_warning_with_line (pfile, large ? CPP_W_LONG_LONG : CPP_W_TRADITIONAL,
|
||
virtual_location, 0,
|
||
"traditional C rejects the \"%.*s\" suffix",
|
||
(int) (limit - str), str);
|
||
}
|
||
|
||
if ((result & CPP_N_WIDTH) == CPP_N_LARGE
|
||
&& CPP_OPTION (pfile, cpp_warn_long_long))
|
||
{
|
||
const char *message = CPP_OPTION (pfile, cplusplus)
|
||
? N_("use of C++11 long long integer constant")
|
||
: N_("use of C99 long long integer constant");
|
||
|
||
if (CPP_OPTION (pfile, c99))
|
||
cpp_warning_with_line (pfile, CPP_W_LONG_LONG, virtual_location,
|
||
0, message);
|
||
else
|
||
cpp_pedwarning_with_line (pfile, CPP_W_LONG_LONG,
|
||
virtual_location, 0, message);
|
||
}
|
||
|
||
result |= CPP_N_INTEGER;
|
||
}
|
||
|
||
syntax_ok:
|
||
if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile))
|
||
cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
|
||
"imaginary constants are a GCC extension");
|
||
if (radix == 2
|
||
&& !CPP_OPTION (pfile, binary_constants)
|
||
&& CPP_PEDANTIC (pfile))
|
||
cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
|
||
CPP_OPTION (pfile, cplusplus)
|
||
? N_("binary constants are a C++14 feature "
|
||
"or GCC extension")
|
||
: N_("binary constants are a GCC extension"));
|
||
|
||
if (radix == 10)
|
||
result |= CPP_N_DECIMAL;
|
||
else if (radix == 16)
|
||
result |= CPP_N_HEX;
|
||
else if (radix == 2)
|
||
result |= CPP_N_BINARY;
|
||
else
|
||
result |= CPP_N_OCTAL;
|
||
|
||
return result;
|
||
|
||
syntax_error:
|
||
return CPP_N_INVALID;
|
||
}
|
||
|
||
/* cpp_interpret_integer converts an integer constant into a cpp_num,
|
||
of precision options->precision.
|
||
|
||
We do not provide any interface for decimal->float conversion,
|
||
because the preprocessor doesn't need it and we don't want to
|
||
drag in GCC's floating point emulator. */
|
||
cpp_num
|
||
cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token,
|
||
unsigned int type)
|
||
{
|
||
const uchar *p, *end;
|
||
cpp_num result;
|
||
|
||
result.low = 0;
|
||
result.high = 0;
|
||
result.unsignedp = !!(type & CPP_N_UNSIGNED);
|
||
result.overflow = false;
|
||
|
||
p = token->val.str.text;
|
||
end = p + token->val.str.len;
|
||
|
||
/* Common case of a single digit. */
|
||
if (token->val.str.len == 1)
|
||
result.low = p[0] - '0';
|
||
else
|
||
{
|
||
cpp_num_part max;
|
||
size_t precision = CPP_OPTION (pfile, precision);
|
||
unsigned int base = 10, c = 0;
|
||
bool overflow = false;
|
||
|
||
if ((type & CPP_N_RADIX) == CPP_N_OCTAL)
|
||
{
|
||
base = 8;
|
||
p++;
|
||
}
|
||
else if ((type & CPP_N_RADIX) == CPP_N_HEX)
|
||
{
|
||
base = 16;
|
||
p += 2;
|
||
}
|
||
else if ((type & CPP_N_RADIX) == CPP_N_BINARY)
|
||
{
|
||
base = 2;
|
||
p += 2;
|
||
}
|
||
|
||
/* We can add a digit to numbers strictly less than this without
|
||
needing the precision and slowness of double integers. */
|
||
max = ~(cpp_num_part) 0;
|
||
if (precision < PART_PRECISION)
|
||
max >>= PART_PRECISION - precision;
|
||
max = (max - base + 1) / base + 1;
|
||
|
||
for (; p < end; p++)
|
||
{
|
||
c = *p;
|
||
|
||
if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
|
||
c = hex_value (c);
|
||
else if (DIGIT_SEP (c))
|
||
continue;
|
||
else
|
||
break;
|
||
|
||
/* Strict inequality for when max is set to zero. */
|
||
if (result.low < max)
|
||
result.low = result.low * base + c;
|
||
else
|
||
{
|
||
result = append_digit (result, c, base, precision);
|
||
overflow |= result.overflow;
|
||
max = 0;
|
||
}
|
||
}
|
||
|
||
if (overflow && !(type & CPP_N_USERDEF))
|
||
cpp_error (pfile, CPP_DL_PEDWARN,
|
||
"integer constant is too large for its type");
|
||
/* If too big to be signed, consider it unsigned. Only warn for
|
||
decimal numbers. Traditional numbers were always signed (but
|
||
we still honor an explicit U suffix); but we only have
|
||
traditional semantics in directives. */
|
||
else if (!result.unsignedp
|
||
&& !(CPP_OPTION (pfile, traditional)
|
||
&& 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_OPTION (pfile, c99)
|
||
? CPP_DL_PEDWARN
|
||
: CPP_DL_WARNING),
|
||
"integer constant is so large that it is unsigned");
|
||
result.unsignedp = true;
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/* Append DIGIT to NUM, a number of PRECISION bits being read in base BASE. */
|
||
static cpp_num
|
||
append_digit (cpp_num num, int digit, int base, size_t precision)
|
||
{
|
||
cpp_num result;
|
||
unsigned int shift;
|
||
bool overflow;
|
||
cpp_num_part add_high, add_low;
|
||
|
||
/* Multiply by 2, 8 or 16. Catching this overflow here means we don't
|
||
need to worry about add_high overflowing. */
|
||
switch (base)
|
||
{
|
||
case 2:
|
||
shift = 1;
|
||
break;
|
||
|
||
case 16:
|
||
shift = 4;
|
||
break;
|
||
|
||
default:
|
||
shift = 3;
|
||
}
|
||
overflow = !!(num.high >> (PART_PRECISION - shift));
|
||
result.high = num.high << shift;
|
||
result.low = num.low << shift;
|
||
result.high |= num.low >> (PART_PRECISION - shift);
|
||
result.unsignedp = num.unsignedp;
|
||
|
||
if (base == 10)
|
||
{
|
||
add_low = num.low << 1;
|
||
add_high = (num.high << 1) + (num.low >> (PART_PRECISION - 1));
|
||
}
|
||
else
|
||
add_high = add_low = 0;
|
||
|
||
if (add_low + digit < add_low)
|
||
add_high++;
|
||
add_low += digit;
|
||
|
||
if (result.low + add_low < result.low)
|
||
add_high++;
|
||
if (result.high + add_high < result.high)
|
||
overflow = true;
|
||
|
||
result.low += add_low;
|
||
result.high += add_high;
|
||
result.overflow = overflow;
|
||
|
||
/* The above code catches overflow of a cpp_num type. This catches
|
||
overflow of the (possibly shorter) target precision. */
|
||
num.low = result.low;
|
||
num.high = result.high;
|
||
result = num_trim (result, precision);
|
||
if (!num_eq (result, num))
|
||
result.overflow = true;
|
||
|
||
return result;
|
||
}
|
||
|
||
/* Handle meeting "defined" in a preprocessor expression. */
|
||
static cpp_num
|
||
parse_defined (cpp_reader *pfile)
|
||
{
|
||
cpp_num result;
|
||
int paren = 0;
|
||
cpp_hashnode *node = 0;
|
||
const cpp_token *token;
|
||
cpp_context *initial_context = pfile->context;
|
||
|
||
/* Don't expand macros. */
|
||
pfile->state.prevent_expansion++;
|
||
|
||
token = cpp_get_token (pfile);
|
||
if (token->type == CPP_OPEN_PAREN)
|
||
{
|
||
paren = 1;
|
||
token = cpp_get_token (pfile);
|
||
}
|
||
|
||
if (token->type == CPP_NAME)
|
||
{
|
||
node = token->val.node.node;
|
||
if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
|
||
{
|
||
cpp_error (pfile, CPP_DL_ERROR, "missing ')' after \"defined\"");
|
||
node = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
cpp_error (pfile, CPP_DL_ERROR,
|
||
"operator \"defined\" requires an identifier");
|
||
if (token->flags & NAMED_OP)
|
||
{
|
||
cpp_token op;
|
||
|
||
op.flags = 0;
|
||
op.type = token->type;
|
||
cpp_error (pfile, CPP_DL_ERROR,
|
||
"(\"%s\" is an alternative token for \"%s\" in C++)",
|
||
cpp_token_as_text (pfile, token),
|
||
cpp_token_as_text (pfile, &op));
|
||
}
|
||
}
|
||
|
||
if (node)
|
||
{
|
||
if (pfile->context != initial_context && CPP_PEDANTIC (pfile))
|
||
cpp_error (pfile, CPP_DL_WARNING,
|
||
"this use of \"defined\" may not be portable");
|
||
|
||
_cpp_mark_macro_used (node);
|
||
if (!(node->flags & NODE_USED))
|
||
{
|
||
node->flags |= NODE_USED;
|
||
if (node->type == NT_MACRO)
|
||
{
|
||
if ((node->flags & NODE_BUILTIN)
|
||
&& pfile->cb.user_builtin_macro)
|
||
pfile->cb.user_builtin_macro (pfile, node);
|
||
if (pfile->cb.used_define)
|
||
pfile->cb.used_define (pfile, pfile->directive_line, node);
|
||
}
|
||
else
|
||
{
|
||
if (pfile->cb.used_undef)
|
||
pfile->cb.used_undef (pfile, pfile->directive_line, 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--;
|
||
|
||
/* Do not treat conditional macros as being defined. This is due to the
|
||
powerpc and spu ports using conditional macros for 'vector', 'bool', and
|
||
'pixel' to act as conditional keywords. This messes up tests like #ifndef
|
||
bool. */
|
||
result.unsignedp = false;
|
||
result.high = 0;
|
||
result.overflow = false;
|
||
result.low = (node && node->type == NT_MACRO
|
||
&& (node->flags & NODE_CONDITIONAL) == 0);
|
||
return result;
|
||
}
|
||
|
||
/* Convert a token into a CPP_NUMBER (an interpreted preprocessing
|
||
number or character constant, or the result of the "defined" or "#"
|
||
operators). */
|
||
static cpp_num
|
||
eval_token (cpp_reader *pfile, const cpp_token *token,
|
||
source_location virtual_location)
|
||
{
|
||
cpp_num result;
|
||
unsigned int temp;
|
||
int unsignedp = 0;
|
||
|
||
result.unsignedp = false;
|
||
result.overflow = false;
|
||
|
||
switch (token->type)
|
||
{
|
||
case CPP_NUMBER:
|
||
temp = cpp_classify_number (pfile, token, NULL, virtual_location);
|
||
if (temp & CPP_N_USERDEF)
|
||
cpp_error (pfile, CPP_DL_ERROR,
|
||
"user-defined literal in preprocessor expression");
|
||
switch (temp & CPP_N_CATEGORY)
|
||
{
|
||
case CPP_N_FLOATING:
|
||
cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0,
|
||
"floating constant in preprocessor expression");
|
||
break;
|
||
case CPP_N_INTEGER:
|
||
if (!(temp & CPP_N_IMAGINARY))
|
||
return cpp_interpret_integer (pfile, token, temp);
|
||
cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0,
|
||
"imaginary number in preprocessor expression");
|
||
break;
|
||
|
||
case CPP_N_INVALID:
|
||
/* Error already issued. */
|
||
break;
|
||
}
|
||
result.high = result.low = 0;
|
||
break;
|
||
|
||
case CPP_WCHAR:
|
||
case CPP_CHAR:
|
||
case CPP_CHAR16:
|
||
case CPP_CHAR32:
|
||
case CPP_UTF8CHAR:
|
||
{
|
||
cppchar_t cc = cpp_interpret_charconst (pfile, token,
|
||
&temp, &unsignedp);
|
||
|
||
result.high = 0;
|
||
result.low = cc;
|
||
/* Sign-extend the result if necessary. */
|
||
if (!unsignedp && (cppchar_signed_t) cc < 0)
|
||
{
|
||
if (PART_PRECISION > BITS_PER_CPPCHAR_T)
|
||
result.low |= ~(~(cpp_num_part) 0
|
||
>> (PART_PRECISION - BITS_PER_CPPCHAR_T));
|
||
result.high = ~(cpp_num_part) 0;
|
||
result = num_trim (result, CPP_OPTION (pfile, precision));
|
||
}
|
||
}
|
||
break;
|
||
|
||
case CPP_NAME:
|
||
if (token->val.node.node == pfile->spec_nodes.n_defined)
|
||
return parse_defined (pfile);
|
||
else if (token->val.node.node == pfile->spec_nodes.n__has_include__)
|
||
return parse_has_include (pfile, IT_INCLUDE);
|
||
else if (token->val.node.node == pfile->spec_nodes.n__has_include_next__)
|
||
return parse_has_include (pfile, IT_INCLUDE_NEXT);
|
||
else if (CPP_OPTION (pfile, cplusplus)
|
||
&& (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.node == pfile->spec_nodes.n_true);
|
||
}
|
||
else
|
||
{
|
||
result.high = 0;
|
||
result.low = 0;
|
||
if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
|
||
cpp_warning_with_line (pfile, CPP_W_UNDEF, virtual_location, 0,
|
||
"\"%s\" is not defined, evaluates to 0",
|
||
NODE_NAME (token->val.node.node));
|
||
}
|
||
break;
|
||
|
||
case CPP_HASH:
|
||
if (!pfile->state.skipping)
|
||
{
|
||
/* A pedantic warning takes precedence over a deprecated
|
||
warning here. */
|
||
if (CPP_PEDANTIC (pfile))
|
||
cpp_error_with_line (pfile, CPP_DL_PEDWARN,
|
||
virtual_location, 0,
|
||
"assertions are a GCC extension");
|
||
else if (CPP_OPTION (pfile, cpp_warn_deprecated))
|
||
cpp_warning_with_line (pfile, CPP_W_DEPRECATED, virtual_location, 0,
|
||
"assertions are a deprecated extension");
|
||
}
|
||
_cpp_test_assertion (pfile, &temp);
|
||
result.high = 0;
|
||
result.low = temp;
|
||
break;
|
||
|
||
default:
|
||
abort ();
|
||
}
|
||
|
||
result.unsignedp = !!unsignedp;
|
||
return result;
|
||
}
|
||
|
||
/* Operator precedence and flags table.
|
||
|
||
After an operator is returned from the lexer, if it has priority less
|
||
than the operator on the top of the stack, we reduce the stack by one
|
||
operator and repeat the test. Since equal priorities do not reduce,
|
||
this is naturally right-associative.
|
||
|
||
We handle left-associative operators by decrementing the priority of
|
||
just-lexed operators by one, but retaining the priority of operators
|
||
already on the stack.
|
||
|
||
The remaining cases are '(' and ')'. We handle '(' by skipping the
|
||
reduction phase completely. ')' is given lower priority than
|
||
everything else, including '(', effectively forcing a reduction of the
|
||
parenthesized expression. If there is a matching '(', the routine
|
||
reduce() exits immediately. If the normal exit route sees a ')', then
|
||
there cannot have been a matching '(' and an error message is output.
|
||
|
||
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. 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. */
|
||
static const struct cpp_operator
|
||
{
|
||
uchar prio;
|
||
uchar flags;
|
||
} optab[] =
|
||
{
|
||
/* 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},
|
||
|
||
/* COMPL */ {16, NO_L_OPERAND},
|
||
/* AND_AND */ {6, LEFT_ASSOC},
|
||
/* OR_OR */ {5, LEFT_ASSOC},
|
||
/* Note that QUERY, COLON, and COMMA must have the same precedence.
|
||
However, there are some special cases for these in reduce(). */
|
||
/* QUERY */ {4, 0},
|
||
/* COLON */ {4, LEFT_ASSOC | CHECK_PROMOTION},
|
||
/* COMMA */ {4, 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.
|
||
Returns the truth value of the expression.
|
||
|
||
The implementation is an operator precedence parser, i.e. a
|
||
bottom-up parser, using a stack for not-yet-reduced tokens.
|
||
|
||
The stack base is op_stack, and the current stack pointer is 'top'.
|
||
There is a stack element for each operator (only), and the most
|
||
recently pushed operator is 'top->op'. An operand (value) is
|
||
stored in the 'value' field of the stack element of the operator
|
||
that precedes it. */
|
||
bool
|
||
_cpp_parse_expr (cpp_reader *pfile, bool is_if)
|
||
{
|
||
struct op *top = pfile->op_stack;
|
||
unsigned int lex_count;
|
||
bool saw_leading_not, want_value = true;
|
||
source_location virtual_location = 0;
|
||
|
||
pfile->state.skip_eval = 0;
|
||
|
||
/* Set up detection of #if ! defined(). */
|
||
pfile->mi_ind_cmacro = 0;
|
||
saw_leading_not = false;
|
||
lex_count = 0;
|
||
|
||
/* Lowest priority operator prevents further reductions. */
|
||
top->op = CPP_EOF;
|
||
|
||
for (;;)
|
||
{
|
||
struct op op;
|
||
|
||
lex_count++;
|
||
op.token = cpp_get_token_with_location (pfile, &virtual_location);
|
||
op.op = op.token->type;
|
||
op.loc = virtual_location;
|
||
|
||
switch (op.op)
|
||
{
|
||
/* These tokens convert into values. */
|
||
case CPP_NUMBER:
|
||
case CPP_CHAR:
|
||
case CPP_WCHAR:
|
||
case CPP_CHAR16:
|
||
case CPP_CHAR32:
|
||
case CPP_UTF8CHAR:
|
||
case CPP_NAME:
|
||
case CPP_HASH:
|
||
if (!want_value)
|
||
SYNTAX_ERROR2_AT (op.loc,
|
||
"missing binary operator before token \"%s\"",
|
||
cpp_token_as_text (pfile, op.token));
|
||
want_value = false;
|
||
top->value = eval_token (pfile, op.token, op.loc);
|
||
continue;
|
||
|
||
case CPP_NOT:
|
||
saw_leading_not = lex_count == 1;
|
||
break;
|
||
case CPP_PLUS:
|
||
if (want_value)
|
||
op.op = CPP_UPLUS;
|
||
break;
|
||
case CPP_MINUS:
|
||
if (want_value)
|
||
op.op = CPP_UMINUS;
|
||
break;
|
||
|
||
default:
|
||
if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ)
|
||
SYNTAX_ERROR2_AT (op.loc,
|
||
"token \"%s\" is not valid in preprocessor expressions",
|
||
cpp_token_as_text (pfile, op.token));
|
||
break;
|
||
}
|
||
|
||
/* Check we have a value or operator as appropriate. */
|
||
if (optab[op.op].flags & NO_L_OPERAND)
|
||
{
|
||
if (!want_value)
|
||
SYNTAX_ERROR2_AT (op.loc,
|
||
"missing binary operator before token \"%s\"",
|
||
cpp_token_as_text (pfile, op.token));
|
||
}
|
||
else if (want_value)
|
||
{
|
||
/* We want a number (or expression) and haven't got one.
|
||
Try to emit a specific diagnostic. */
|
||
if (op.op == CPP_CLOSE_PAREN && top->op == CPP_OPEN_PAREN)
|
||
SYNTAX_ERROR_AT (op.loc,
|
||
"missing expression between '(' and ')'");
|
||
|
||
if (op.op == CPP_EOF && top->op == CPP_EOF)
|
||
SYNTAX_ERROR2_AT (op.loc,
|
||
"%s with no expression", is_if ? "#if" : "#elif");
|
||
|
||
if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN)
|
||
SYNTAX_ERROR2_AT (op.loc,
|
||
"operator '%s' has no right operand",
|
||
cpp_token_as_text (pfile, top->token));
|
||
else if (op.op == CPP_CLOSE_PAREN || op.op == CPP_EOF)
|
||
/* Complain about missing paren during reduction. */;
|
||
else
|
||
SYNTAX_ERROR2_AT (op.loc,
|
||
"operator '%s' has no left operand",
|
||
cpp_token_as_text (pfile, op.token));
|
||
}
|
||
|
||
top = reduce (pfile, top, op.op);
|
||
if (!top)
|
||
goto syntax_error;
|
||
|
||
if (op.op == CPP_EOF)
|
||
break;
|
||
|
||
switch (op.op)
|
||
{
|
||
case CPP_CLOSE_PAREN:
|
||
continue;
|
||
case CPP_OR_OR:
|
||
if (!num_zerop (top->value))
|
||
pfile->state.skip_eval++;
|
||
break;
|
||
case CPP_AND_AND:
|
||
case CPP_QUERY:
|
||
if (num_zerop (top->value))
|
||
pfile->state.skip_eval++;
|
||
break;
|
||
case CPP_COLON:
|
||
if (top->op != CPP_QUERY)
|
||
SYNTAX_ERROR_AT (op.loc,
|
||
" ':' without preceding '?'");
|
||
if (!num_zerop (top[-1].value)) /* Was '?' condition true? */
|
||
pfile->state.skip_eval++;
|
||
else
|
||
pfile->state.skip_eval--;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
want_value = true;
|
||
|
||
/* Check for and handle stack overflow. */
|
||
if (++top == pfile->op_limit)
|
||
top = _cpp_expand_op_stack (pfile);
|
||
|
||
top->op = op.op;
|
||
top->token = op.token;
|
||
top->loc = op.loc;
|
||
}
|
||
|
||
/* The controlling macro expression is only valid if we called lex 3
|
||
times: <!> <defined expression> and <EOF>. push_conditional ()
|
||
checks that we are at top-of-file. */
|
||
if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3))
|
||
pfile->mi_ind_cmacro = 0;
|
||
|
||
if (top != pfile->op_stack)
|
||
{
|
||
cpp_error_with_line (pfile, CPP_DL_ICE, top->loc, 0,
|
||
"unbalanced stack in %s",
|
||
is_if ? "#if" : "#elif");
|
||
syntax_error:
|
||
return false; /* Return false on syntax error. */
|
||
}
|
||
|
||
return !num_zerop (top->value);
|
||
}
|
||
|
||
/* Reduce the operator / value stack if possible, in preparation for
|
||
pushing operator OP. Returns NULL on error, otherwise the top of
|
||
the stack. */
|
||
static struct op *
|
||
reduce (cpp_reader *pfile, struct op *top, enum cpp_ttype op)
|
||
{
|
||
unsigned int prio;
|
||
|
||
if (top->op <= CPP_EQ || top->op > CPP_LAST_CPP_OP + 2)
|
||
{
|
||
bad_op:
|
||
cpp_error (pfile, CPP_DL_ICE, "impossible operator '%u'", top->op);
|
||
return 0;
|
||
}
|
||
|
||
if (op == CPP_OPEN_PAREN)
|
||
return top;
|
||
|
||
/* Decrement the priority of left-associative operators to force a
|
||
reduction with operators of otherwise equal priority. */
|
||
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:
|
||
case CPP_UMINUS:
|
||
case CPP_NOT:
|
||
case CPP_COMPL:
|
||
top[-1].value = num_unary_op (pfile, top->value, top->op);
|
||
top[-1].loc = top->loc;
|
||
break;
|
||
|
||
case CPP_PLUS:
|
||
case CPP_MINUS:
|
||
case CPP_RSHIFT:
|
||
case CPP_LSHIFT:
|
||
case CPP_COMMA:
|
||
top[-1].value = num_binary_op (pfile, top[-1].value,
|
||
top->value, top->op);
|
||
top[-1].loc = top->loc;
|
||
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);
|
||
top[-1].loc = top->loc;
|
||
break;
|
||
|
||
case CPP_EQ_EQ:
|
||
case CPP_NOT_EQ:
|
||
top[-1].value
|
||
= num_equality_op (pfile, top[-1].value, top->value, top->op);
|
||
top[-1].loc = top->loc;
|
||
break;
|
||
|
||
case CPP_AND:
|
||
case CPP_OR:
|
||
case CPP_XOR:
|
||
top[-1].value
|
||
= num_bitwise_op (pfile, top[-1].value, top->value, top->op);
|
||
top[-1].loc = top->loc;
|
||
break;
|
||
|
||
case CPP_MULT:
|
||
top[-1].value = num_mul (pfile, top[-1].value, top->value);
|
||
top[-1].loc = top->loc;
|
||
break;
|
||
|
||
case CPP_DIV:
|
||
case CPP_MOD:
|
||
top[-1].value = num_div_op (pfile, top[-1].value,
|
||
top->value, top->op, top->loc);
|
||
top[-1].loc = top->loc;
|
||
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.high = 0;
|
||
top->value.unsignedp = false;
|
||
top->value.overflow = false;
|
||
top->loc = top[1].loc;
|
||
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.high = 0;
|
||
top->value.unsignedp = false;
|
||
top->value.overflow = false;
|
||
top->loc = top[1].loc;
|
||
continue;
|
||
|
||
case CPP_OPEN_PAREN:
|
||
if (op != CPP_CLOSE_PAREN)
|
||
{
|
||
cpp_error_with_line (pfile, CPP_DL_ERROR,
|
||
top->token->src_loc,
|
||
0, "missing ')' in expression");
|
||
return 0;
|
||
}
|
||
top--;
|
||
top->value = top[1].value;
|
||
top->loc = top[1].loc;
|
||
return top;
|
||
|
||
case CPP_COLON:
|
||
top -= 2;
|
||
if (!num_zerop (top->value))
|
||
{
|
||
pfile->state.skip_eval--;
|
||
top->value = top[1].value;
|
||
top->loc = top[1].loc;
|
||
}
|
||
else
|
||
{
|
||
top->value = top[2].value;
|
||
top->loc = top[2].loc;
|
||
}
|
||
top->value.unsignedp = (top[1].value.unsignedp
|
||
|| top[2].value.unsignedp);
|
||
continue;
|
||
|
||
case CPP_QUERY:
|
||
/* COMMA and COLON should not reduce a QUERY operator. */
|
||
if (op == CPP_COMMA || op == CPP_COLON)
|
||
return top;
|
||
cpp_error (pfile, CPP_DL_ERROR, "'?' without following ':'");
|
||
return 0;
|
||
|
||
default:
|
||
goto bad_op;
|
||
}
|
||
|
||
top--;
|
||
if (top->value.overflow && !pfile->state.skip_eval)
|
||
cpp_error (pfile, CPP_DL_PEDWARN,
|
||
"integer overflow in preprocessor expression");
|
||
}
|
||
|
||
if (op == CPP_CLOSE_PAREN)
|
||
{
|
||
cpp_error (pfile, CPP_DL_ERROR, "missing '(' in expression");
|
||
return 0;
|
||
}
|
||
|
||
return top;
|
||
}
|
||
|
||
/* Returns the position of the old top of stack after expansion. */
|
||
struct op *
|
||
_cpp_expand_op_stack (cpp_reader *pfile)
|
||
{
|
||
size_t old_size = (size_t) (pfile->op_limit - pfile->op_stack);
|
||
size_t new_size = old_size * 2 + 20;
|
||
|
||
pfile->op_stack = XRESIZEVEC (struct op, pfile->op_stack, new_size);
|
||
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 (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_with_line (pfile, CPP_DL_WARNING, op[-1].loc, 0,
|
||
"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_with_line (pfile, CPP_DL_WARNING, op->loc, 0,
|
||
"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 (cpp_num num, size_t precision)
|
||
{
|
||
if (precision > PART_PRECISION)
|
||
{
|
||
precision -= PART_PRECISION;
|
||
if (precision < PART_PRECISION)
|
||
num.high &= ((cpp_num_part) 1 << precision) - 1;
|
||
}
|
||
else
|
||
{
|
||
if (precision < PART_PRECISION)
|
||
num.low &= ((cpp_num_part) 1 << precision) - 1;
|
||
num.high = 0;
|
||
}
|
||
|
||
return num;
|
||
}
|
||
|
||
/* True iff A (presumed signed) >= 0. */
|
||
static bool
|
||
num_positive (cpp_num num, size_t precision)
|
||
{
|
||
if (precision > PART_PRECISION)
|
||
{
|
||
precision -= PART_PRECISION;
|
||
return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0;
|
||
}
|
||
|
||
return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0;
|
||
}
|
||
|
||
/* Sign extend a number, with PRECISION significant bits and all
|
||
others assumed clear, to fill out a cpp_num structure. */
|
||
cpp_num
|
||
cpp_num_sign_extend (cpp_num num, size_t precision)
|
||
{
|
||
if (!num.unsignedp)
|
||
{
|
||
if (precision > PART_PRECISION)
|
||
{
|
||
precision -= PART_PRECISION;
|
||
if (precision < PART_PRECISION
|
||
&& (num.high & (cpp_num_part) 1 << (precision - 1)))
|
||
num.high |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
|
||
}
|
||
else if (num.low & (cpp_num_part) 1 << (precision - 1))
|
||
{
|
||
if (precision < PART_PRECISION)
|
||
num.low |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
|
||
num.high = ~(cpp_num_part) 0;
|
||
}
|
||
}
|
||
|
||
return num;
|
||
}
|
||
|
||
/* Returns the negative of NUM. */
|
||
static cpp_num
|
||
num_negate (cpp_num num, size_t precision)
|
||
{
|
||
cpp_num copy;
|
||
|
||
copy = num;
|
||
num.high = ~num.high;
|
||
num.low = ~num.low;
|
||
if (++num.low == 0)
|
||
num.high++;
|
||
num = num_trim (num, precision);
|
||
num.overflow = (!num.unsignedp && num_eq (num, copy) && !num_zerop (num));
|
||
|
||
return num;
|
||
}
|
||
|
||
/* Returns true if A >= B. */
|
||
static bool
|
||
num_greater_eq (cpp_num pa, cpp_num pb, size_t precision)
|
||
{
|
||
bool unsignedp;
|
||
|
||
unsignedp = pa.unsignedp || pb.unsignedp;
|
||
|
||
if (!unsignedp)
|
||
{
|
||
/* Both numbers have signed type. If they are of different
|
||
sign, the answer is the sign of A. */
|
||
unsignedp = num_positive (pa, precision);
|
||
|
||
if (unsignedp != num_positive (pb, precision))
|
||
return unsignedp;
|
||
|
||
/* Otherwise we can do an unsigned comparison. */
|
||
}
|
||
|
||
return (pa.high > pb.high) || (pa.high == pb.high && pa.low >= pb.low);
|
||
}
|
||
|
||
/* Returns LHS OP RHS, where OP is a bit-wise operation. */
|
||
static cpp_num
|
||
num_bitwise_op (cpp_reader *pfile ATTRIBUTE_UNUSED,
|
||
cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
|
||
{
|
||
lhs.overflow = false;
|
||
lhs.unsignedp = lhs.unsignedp || rhs.unsignedp;
|
||
|
||
/* As excess precision is zeroed, there is no need to num_trim () as
|
||
these operations cannot introduce a set bit there. */
|
||
if (op == CPP_AND)
|
||
{
|
||
lhs.low &= rhs.low;
|
||
lhs.high &= rhs.high;
|
||
}
|
||
else if (op == CPP_OR)
|
||
{
|
||
lhs.low |= rhs.low;
|
||
lhs.high |= rhs.high;
|
||
}
|
||
else
|
||
{
|
||
lhs.low ^= rhs.low;
|
||
lhs.high ^= rhs.high;
|
||
}
|
||
|
||
return lhs;
|
||
}
|
||
|
||
/* Returns LHS OP RHS, where OP is an inequality. */
|
||
static cpp_num
|
||
num_inequality_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs,
|
||
enum cpp_ttype op)
|
||
{
|
||
bool gte = num_greater_eq (lhs, rhs, CPP_OPTION (pfile, precision));
|
||
|
||
if (op == CPP_GREATER_EQ)
|
||
lhs.low = gte;
|
||
else if (op == CPP_LESS)
|
||
lhs.low = !gte;
|
||
else if (op == CPP_GREATER)
|
||
lhs.low = gte && !num_eq (lhs, rhs);
|
||
else /* CPP_LESS_EQ. */
|
||
lhs.low = !gte || num_eq (lhs, rhs);
|
||
|
||
lhs.high = 0;
|
||
lhs.overflow = false;
|
||
lhs.unsignedp = false;
|
||
return lhs;
|
||
}
|
||
|
||
/* Returns LHS OP RHS, where OP is == or !=. */
|
||
static cpp_num
|
||
num_equality_op (cpp_reader *pfile ATTRIBUTE_UNUSED,
|
||
cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
|
||
{
|
||
/* Work around a 3.0.4 bug; see PR 6950. */
|
||
bool eq = num_eq (lhs, rhs);
|
||
if (op == CPP_NOT_EQ)
|
||
eq = !eq;
|
||
lhs.low = eq;
|
||
lhs.high = 0;
|
||
lhs.overflow = false;
|
||
lhs.unsignedp = false;
|
||
return lhs;
|
||
}
|
||
|
||
/* Shift NUM, of width PRECISION, right by N bits. */
|
||
static cpp_num
|
||
num_rshift (cpp_num num, size_t precision, size_t n)
|
||
{
|
||
cpp_num_part sign_mask;
|
||
bool x = num_positive (num, precision);
|
||
|
||
if (num.unsignedp || x)
|
||
sign_mask = 0;
|
||
else
|
||
sign_mask = ~(cpp_num_part) 0;
|
||
|
||
if (n >= precision)
|
||
num.high = num.low = sign_mask;
|
||
else
|
||
{
|
||
/* Sign-extend. */
|
||
if (precision < PART_PRECISION)
|
||
num.high = sign_mask, num.low |= sign_mask << precision;
|
||
else if (precision < 2 * PART_PRECISION)
|
||
num.high |= sign_mask << (precision - PART_PRECISION);
|
||
|
||
if (n >= PART_PRECISION)
|
||
{
|
||
n -= PART_PRECISION;
|
||
num.low = num.high;
|
||
num.high = sign_mask;
|
||
}
|
||
|
||
if (n)
|
||
{
|
||
num.low = (num.low >> n) | (num.high << (PART_PRECISION - n));
|
||
num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n));
|
||
}
|
||
}
|
||
|
||
num = num_trim (num, precision);
|
||
num.overflow = false;
|
||
return num;
|
||
}
|
||
|
||
/* Shift NUM, of width PRECISION, left by N bits. */
|
||
static cpp_num
|
||
num_lshift (cpp_num num, size_t precision, size_t n)
|
||
{
|
||
if (n >= precision)
|
||
{
|
||
num.overflow = !num.unsignedp && !num_zerop (num);
|
||
num.high = num.low = 0;
|
||
}
|
||
else
|
||
{
|
||
cpp_num orig, maybe_orig;
|
||
size_t m = n;
|
||
|
||
orig = num;
|
||
if (m >= PART_PRECISION)
|
||
{
|
||
m -= PART_PRECISION;
|
||
num.high = num.low;
|
||
num.low = 0;
|
||
}
|
||
if (m)
|
||
{
|
||
num.high = (num.high << m) | (num.low >> (PART_PRECISION - m));
|
||
num.low <<= m;
|
||
}
|
||
num = num_trim (num, precision);
|
||
|
||
if (num.unsignedp)
|
||
num.overflow = false;
|
||
else
|
||
{
|
||
maybe_orig = num_rshift (num, precision, n);
|
||
num.overflow = !num_eq (orig, maybe_orig);
|
||
}
|
||
}
|
||
|
||
return num;
|
||
}
|
||
|
||
/* The four unary operators: +, -, ! and ~. */
|
||
static cpp_num
|
||
num_unary_op (cpp_reader *pfile, cpp_num num, enum cpp_ttype op)
|
||
{
|
||
switch (op)
|
||
{
|
||
case CPP_UPLUS:
|
||
if (CPP_WTRADITIONAL (pfile) && !pfile->state.skip_eval)
|
||
cpp_warning (pfile, CPP_W_TRADITIONAL,
|
||
"traditional C rejects the unary plus operator");
|
||
num.overflow = false;
|
||
break;
|
||
|
||
case CPP_UMINUS:
|
||
num = num_negate (num, CPP_OPTION (pfile, precision));
|
||
break;
|
||
|
||
case CPP_COMPL:
|
||
num.high = ~num.high;
|
||
num.low = ~num.low;
|
||
num = num_trim (num, CPP_OPTION (pfile, precision));
|
||
num.overflow = false;
|
||
break;
|
||
|
||
default: /* case CPP_NOT: */
|
||
num.low = num_zerop (num);
|
||
num.high = 0;
|
||
num.overflow = false;
|
||
num.unsignedp = false;
|
||
break;
|
||
}
|
||
|
||
return num;
|
||
}
|
||
|
||
/* The various binary operators. */
|
||
static cpp_num
|
||
num_binary_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
|
||
{
|
||
cpp_num result;
|
||
size_t precision = CPP_OPTION (pfile, precision);
|
||
size_t n;
|
||
|
||
switch (op)
|
||
{
|
||
/* Shifts. */
|
||
case CPP_LSHIFT:
|
||
case CPP_RSHIFT:
|
||
if (!rhs.unsignedp && !num_positive (rhs, precision))
|
||
{
|
||
/* A negative shift is a positive shift the other way. */
|
||
if (op == CPP_LSHIFT)
|
||
op = CPP_RSHIFT;
|
||
else
|
||
op = CPP_LSHIFT;
|
||
rhs = num_negate (rhs, precision);
|
||
}
|
||
if (rhs.high)
|
||
n = ~0; /* Maximal. */
|
||
else
|
||
n = rhs.low;
|
||
if (op == CPP_LSHIFT)
|
||
lhs = num_lshift (lhs, precision, n);
|
||
else
|
||
lhs = num_rshift (lhs, precision, n);
|
||
break;
|
||
|
||
/* Arithmetic. */
|
||
case CPP_MINUS:
|
||
result.low = lhs.low - rhs.low;
|
||
result.high = lhs.high - rhs.high;
|
||
if (result.low > lhs.low)
|
||
result.high--;
|
||
result.unsignedp = lhs.unsignedp || rhs.unsignedp;
|
||
result.overflow = false;
|
||
|
||
result = num_trim (result, precision);
|
||
if (!result.unsignedp)
|
||
{
|
||
bool lhsp = num_positive (lhs, precision);
|
||
result.overflow = (lhsp != num_positive (rhs, precision)
|
||
&& lhsp != num_positive (result, precision));
|
||
}
|
||
return result;
|
||
|
||
case CPP_PLUS:
|
||
result.low = lhs.low + rhs.low;
|
||
result.high = lhs.high + rhs.high;
|
||
if (result.low < lhs.low)
|
||
result.high++;
|
||
result.unsignedp = lhs.unsignedp || rhs.unsignedp;
|
||
result.overflow = false;
|
||
|
||
result = num_trim (result, precision);
|
||
if (!result.unsignedp)
|
||
{
|
||
bool lhsp = num_positive (lhs, precision);
|
||
result.overflow = (lhsp == num_positive (rhs, precision)
|
||
&& lhsp != num_positive (result, precision));
|
||
}
|
||
return result;
|
||
|
||
/* Comma. */
|
||
default: /* case CPP_COMMA: */
|
||
if (CPP_PEDANTIC (pfile) && (!CPP_OPTION (pfile, c99)
|
||
|| !pfile->state.skip_eval))
|
||
cpp_pedwarning (pfile, CPP_W_PEDANTIC,
|
||
"comma operator in operand of #if");
|
||
lhs = rhs;
|
||
break;
|
||
}
|
||
|
||
return lhs;
|
||
}
|
||
|
||
/* Multiplies two unsigned cpp_num_parts to give a cpp_num. This
|
||
cannot overflow. */
|
||
static cpp_num
|
||
num_part_mul (cpp_num_part lhs, cpp_num_part rhs)
|
||
{
|
||
cpp_num result;
|
||
cpp_num_part middle[2], temp;
|
||
|
||
result.low = LOW_PART (lhs) * LOW_PART (rhs);
|
||
result.high = HIGH_PART (lhs) * HIGH_PART (rhs);
|
||
|
||
middle[0] = LOW_PART (lhs) * HIGH_PART (rhs);
|
||
middle[1] = HIGH_PART (lhs) * LOW_PART (rhs);
|
||
|
||
temp = result.low;
|
||
result.low += LOW_PART (middle[0]) << (PART_PRECISION / 2);
|
||
if (result.low < temp)
|
||
result.high++;
|
||
|
||
temp = result.low;
|
||
result.low += LOW_PART (middle[1]) << (PART_PRECISION / 2);
|
||
if (result.low < temp)
|
||
result.high++;
|
||
|
||
result.high += HIGH_PART (middle[0]);
|
||
result.high += HIGH_PART (middle[1]);
|
||
result.unsignedp = true;
|
||
result.overflow = false;
|
||
|
||
return result;
|
||
}
|
||
|
||
/* Multiply two preprocessing numbers. */
|
||
static cpp_num
|
||
num_mul (cpp_reader *pfile, cpp_num lhs, cpp_num rhs)
|
||
{
|
||
cpp_num result, temp;
|
||
bool unsignedp = lhs.unsignedp || rhs.unsignedp;
|
||
bool overflow, negate = false;
|
||
size_t precision = CPP_OPTION (pfile, precision);
|
||
|
||
/* Prepare for unsigned multiplication. */
|
||
if (!unsignedp)
|
||
{
|
||
if (!num_positive (lhs, precision))
|
||
negate = !negate, lhs = num_negate (lhs, precision);
|
||
if (!num_positive (rhs, precision))
|
||
negate = !negate, rhs = num_negate (rhs, precision);
|
||
}
|
||
|
||
overflow = lhs.high && rhs.high;
|
||
result = num_part_mul (lhs.low, rhs.low);
|
||
|
||
temp = num_part_mul (lhs.high, rhs.low);
|
||
result.high += temp.low;
|
||
if (temp.high)
|
||
overflow = true;
|
||
|
||
temp = num_part_mul (lhs.low, rhs.high);
|
||
result.high += temp.low;
|
||
if (temp.high)
|
||
overflow = true;
|
||
|
||
temp.low = result.low, temp.high = result.high;
|
||
result = num_trim (result, precision);
|
||
if (!num_eq (result, temp))
|
||
overflow = true;
|
||
|
||
if (negate)
|
||
result = num_negate (result, precision);
|
||
|
||
if (unsignedp)
|
||
result.overflow = false;
|
||
else
|
||
result.overflow = overflow || (num_positive (result, precision) ^ !negate
|
||
&& !num_zerop (result));
|
||
result.unsignedp = unsignedp;
|
||
|
||
return result;
|
||
}
|
||
|
||
/* 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,
|
||
source_location location)
|
||
{
|
||
cpp_num result, sub;
|
||
cpp_num_part mask;
|
||
bool unsignedp = lhs.unsignedp || rhs.unsignedp;
|
||
bool negate = false, lhs_neg = false;
|
||
size_t i, precision = CPP_OPTION (pfile, precision);
|
||
|
||
/* Prepare for unsigned division. */
|
||
if (!unsignedp)
|
||
{
|
||
if (!num_positive (lhs, precision))
|
||
negate = !negate, lhs_neg = true, lhs = num_negate (lhs, precision);
|
||
if (!num_positive (rhs, precision))
|
||
negate = !negate, rhs = num_negate (rhs, precision);
|
||
}
|
||
|
||
/* Find the high bit. */
|
||
if (rhs.high)
|
||
{
|
||
i = precision - 1;
|
||
mask = (cpp_num_part) 1 << (i - PART_PRECISION);
|
||
for (; ; i--, mask >>= 1)
|
||
if (rhs.high & mask)
|
||
break;
|
||
}
|
||
else if (rhs.low)
|
||
{
|
||
if (precision > PART_PRECISION)
|
||
i = precision - PART_PRECISION - 1;
|
||
else
|
||
i = precision - 1;
|
||
mask = (cpp_num_part) 1 << i;
|
||
for (; ; i--, mask >>= 1)
|
||
if (rhs.low & mask)
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
if (!pfile->state.skip_eval)
|
||
cpp_error_with_line (pfile, CPP_DL_ERROR, location, 0,
|
||
"division by zero in #if");
|
||
return lhs;
|
||
}
|
||
|
||
/* First nonzero bit of RHS is bit I. Do naive division by
|
||
shifting the RHS fully left, and subtracting from LHS if LHS is
|
||
at least as big, and then repeating but with one less shift.
|
||
This is not very efficient, but is easy to understand. */
|
||
|
||
rhs.unsignedp = true;
|
||
lhs.unsignedp = true;
|
||
i = precision - i - 1;
|
||
sub = num_lshift (rhs, precision, i);
|
||
|
||
result.high = result.low = 0;
|
||
for (;;)
|
||
{
|
||
if (num_greater_eq (lhs, sub, precision))
|
||
{
|
||
lhs = num_binary_op (pfile, lhs, sub, CPP_MINUS);
|
||
if (i >= PART_PRECISION)
|
||
result.high |= (cpp_num_part) 1 << (i - PART_PRECISION);
|
||
else
|
||
result.low |= (cpp_num_part) 1 << i;
|
||
}
|
||
if (i-- == 0)
|
||
break;
|
||
sub.low = (sub.low >> 1) | (sub.high << (PART_PRECISION - 1));
|
||
sub.high >>= 1;
|
||
}
|
||
|
||
/* We divide so that the remainder has the sign of the LHS. */
|
||
if (op == CPP_DIV)
|
||
{
|
||
result.unsignedp = unsignedp;
|
||
result.overflow = false;
|
||
if (!unsignedp)
|
||
{
|
||
if (negate)
|
||
result = num_negate (result, precision);
|
||
result.overflow = (num_positive (result, precision) ^ !negate
|
||
&& !num_zerop (result));
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/* CPP_MOD. */
|
||
lhs.unsignedp = unsignedp;
|
||
lhs.overflow = false;
|
||
if (lhs_neg)
|
||
lhs = num_negate (lhs, precision);
|
||
|
||
return lhs;
|
||
}
|
||
|
||
/* Handle meeting "__has_include__" in a preprocessor expression. */
|
||
static cpp_num
|
||
parse_has_include (cpp_reader *pfile, enum include_type type)
|
||
{
|
||
cpp_num result;
|
||
bool paren = false;
|
||
cpp_hashnode *node = 0;
|
||
const cpp_token *token;
|
||
bool bracket = false;
|
||
char *fname = 0;
|
||
|
||
result.unsignedp = false;
|
||
result.high = 0;
|
||
result.overflow = false;
|
||
result.low = 0;
|
||
|
||
pfile->state.in__has_include__++;
|
||
|
||
token = cpp_get_token (pfile);
|
||
if (token->type == CPP_OPEN_PAREN)
|
||
{
|
||
paren = true;
|
||
token = cpp_get_token (pfile);
|
||
}
|
||
|
||
if (token->type == CPP_STRING || token->type == CPP_HEADER_NAME)
|
||
{
|
||
if (token->type == CPP_HEADER_NAME)
|
||
bracket = true;
|
||
fname = XNEWVEC (char, token->val.str.len - 1);
|
||
memcpy (fname, token->val.str.text + 1, token->val.str.len - 2);
|
||
fname[token->val.str.len - 2] = '\0';
|
||
node = token->val.node.node;
|
||
}
|
||
else if (token->type == CPP_LESS)
|
||
{
|
||
bracket = true;
|
||
fname = _cpp_bracket_include (pfile);
|
||
}
|
||
else
|
||
cpp_error (pfile, CPP_DL_ERROR,
|
||
"operator \"__has_include__\" requires a header string");
|
||
|
||
if (fname)
|
||
{
|
||
int angle_brackets = (bracket ? 1 : 0);
|
||
|
||
if (_cpp_has_header (pfile, fname, angle_brackets, type))
|
||
result.low = 1;
|
||
else
|
||
result.low = 0;
|
||
|
||
XDELETEVEC (fname);
|
||
}
|
||
|
||
if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
|
||
cpp_error (pfile, CPP_DL_ERROR,
|
||
"missing ')' after \"__has_include__\"");
|
||
|
||
/* A possible controlling macro of the form #if !__has_include__ ().
|
||
_cpp_parse_expr checks there was no other junk on the line. */
|
||
if (node)
|
||
pfile->mi_ind_cmacro = node;
|
||
|
||
pfile->state.in__has_include__--;
|
||
|
||
return result;
|
||
}
|