diff options
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/c/c-decl.c | 115 | ||||
-rw-r--r-- | gcc/c/c-parser.c | 5 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 4 | ||||
-rw-r--r-- | gcc/c/c-typeck.c | 62 |
5 files changed, 188 insertions, 12 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 522da71..8d9d4aa 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,17 @@ +2016-08-19 Joseph Myers <joseph@codesourcery.com> + + PR c/32187 + * 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. + 2016-08-12 Jakub Jelinek <jakub@redhat.com> Martin Liska <mliska@suse.cz> diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 9ad473c..0fb2d20 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -9804,6 +9804,14 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, error_at (loc, ("both %<long%> and %<float%> in " "declaration specifiers")); + else if (specs->typespec_word == cts_floatn_nx) + error_at (loc, + ("both %<long%> and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); else if (specs->typespec_word == cts_dfloat32) error_at (loc, ("both %<long%> and %<_Decimal32%> in " @@ -9857,6 +9865,14 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, error_at (loc, ("both %<short%> and %<double%> in " "declaration specifiers")); + else if (specs->typespec_word == cts_floatn_nx) + error_at (loc, + ("both %<short%> and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); else if (specs->typespec_word == cts_dfloat32) error_at (loc, ("both %<short%> and %<_Decimal32%> in " @@ -9901,6 +9917,14 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, error_at (loc, ("both %<signed%> and %<double%> in " "declaration specifiers")); + else if (specs->typespec_word == cts_floatn_nx) + error_at (loc, + ("both %<signed%> and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); else if (specs->typespec_word == cts_dfloat32) error_at (loc, ("both %<signed%> and %<_Decimal32%> in " @@ -9945,6 +9969,14 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, error_at (loc, ("both %<unsigned%> and %<double%> in " "declaration specifiers")); + else if (specs->typespec_word == cts_floatn_nx) + error_at (loc, + ("both %<unsigned%> and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); else if (specs->typespec_word == cts_dfloat32) error_at (loc, ("both %<unsigned%> and %<_Decimal32%> in " @@ -10049,6 +10081,14 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, error_at (loc, ("both %<_Sat%> and %<double%> in " "declaration specifiers")); + else if (specs->typespec_word == cts_floatn_nx) + error_at (loc, + ("both %<_Sat%> and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); else if (specs->typespec_word == cts_dfloat32) error_at (loc, ("both %<_Sat%> and %<_Decimal32%> in " @@ -10082,8 +10122,9 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, } else { - /* "void", "_Bool", "char", "int", "float", "double", "_Decimal32", - "__intN", "_Decimal64", "_Decimal128", "_Fract", "_Accum" or + /* "void", "_Bool", "char", "int", "float", "double", + "_FloatN", "_FloatNx", "_Decimal32", "__intN", + "_Decimal64", "_Decimal128", "_Fract", "_Accum" or "__auto_type". */ if (specs->typespec_word != cts_none) { @@ -10308,6 +10349,69 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, specs->locations[cdw_typespec] = loc; } return specs; + CASE_RID_FLOATN_NX: + specs->floatn_nx_idx = i - RID_FLOATN_NX_FIRST; + if (!in_system_header_at (input_location)) + pedwarn (loc, OPT_Wpedantic, + "ISO C does not support the %<_Float%d%s%> type", + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + + if (specs->long_p) + error_at (loc, + ("both %<long%> and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->short_p) + error_at (loc, + ("both %<short%> and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->signed_p) + error_at (loc, + ("both %<signed%> and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->unsigned_p) + error_at (loc, + ("both %<unsigned%> and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (specs->saturating_p) + error_at (loc, + ("both %<_Sat%> and %<_Float%d%s%> in " + "declaration specifiers"), + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else if (FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) == NULL_TREE) + error_at (loc, + "%<_Float%d%s%> is not supported on this target", + floatn_nx_types[specs->floatn_nx_idx].n, + (floatn_nx_types[specs->floatn_nx_idx].extended + ? "x" + : "")); + else + { + specs->typespec_word = cts_floatn_nx; + specs->locations[cdw_typespec] = loc; + } + return specs; case RID_DFLOAT32: case RID_DFLOAT64: case RID_DFLOAT128: @@ -10785,6 +10889,13 @@ finish_declspecs (struct c_declspecs *specs) : double_type_node); } break; + case cts_floatn_nx: + gcc_assert (!specs->long_p && !specs->short_p + && !specs->signed_p && !specs->unsigned_p); + specs->type = (specs->complex_p + ? COMPLEX_FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) + : FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx)); + break; case cts_dfloat32: case cts_dfloat64: case cts_dfloat128: diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index c050f64..fe0c95f 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -540,6 +540,7 @@ c_keyword_starts_typename (enum rid keyword) case RID_DFLOAT32: case RID_DFLOAT64: case RID_DFLOAT128: + CASE_RID_FLOATN_NX: case RID_BOOL: case RID_ENUM: case RID_STRUCT: @@ -727,6 +728,7 @@ c_token_starts_declspecs (c_token *token) case RID_DFLOAT32: case RID_DFLOAT64: case RID_DFLOAT128: + CASE_RID_FLOATN_NX: case RID_BOOL: case RID_ENUM: case RID_STRUCT: @@ -2536,6 +2538,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, case RID_DFLOAT32: case RID_DFLOAT64: case RID_DFLOAT128: + CASE_RID_FLOATN_NX: case RID_BOOL: case RID_FRACT: case RID_ACCUM: @@ -4009,6 +4012,7 @@ c_parser_attribute_any_word (c_parser *parser) case RID_DFLOAT32: case RID_DFLOAT64: case RID_DFLOAT128: + CASE_RID_FLOATN_NX: case RID_BOOL: case RID_FRACT: case RID_ACCUM: @@ -9638,6 +9642,7 @@ c_parser_objc_selector (c_parser *parser) case RID_CHAR: case RID_FLOAT: case RID_DOUBLE: + CASE_RID_FLOATN_NX: case RID_VOID: case RID_BOOL: case RID_ATOMIC: diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 46be53e..5a8ab6d 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -230,6 +230,7 @@ enum c_typespec_keyword { cts_dfloat32, cts_dfloat64, cts_dfloat128, + cts_floatn_nx, cts_fract, cts_accum, cts_auto_type @@ -295,6 +296,9 @@ struct c_declspecs { int align_log; /* For the __intN declspec, this stores the index into the int_n_* arrays. */ int int_n_idx; + /* For the _FloatN and _FloatNx declspec, this stores the index into + the floatn_nx_types array. */ + int floatn_nx_idx; /* The storage class specifier, or csc_none if none. */ enum c_storage_class storage_class; /* Any type specifier keyword used such as "int", not reflecting diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 2e1e09d..bc8728a 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -927,18 +927,41 @@ c_common_type (tree t1, tree t2) return long_integer_type_node; } + /* For floating types of the same TYPE_PRECISION (which we here + assume means either the same set of values, or sets of values + neither a subset of the other, with behavior being undefined in + the latter case), follow the rules from TS 18661-3: prefer + interchange types _FloatN, then standard types long double, + double, float, then extended types _FloatNx. For extended types, + check them starting with _Float128x as that seems most consistent + in spirit with preferring long double to double; for interchange + types, also check in that order for consistency although it's not + possible for more than one of them to have the same + precision. */ + tree mv1 = TYPE_MAIN_VARIANT (t1); + tree mv2 = TYPE_MAIN_VARIANT (t2); + + for (int i = NUM_FLOATN_TYPES - 1; i >= 0; i--) + if (mv1 == FLOATN_TYPE_NODE (i) || mv2 == FLOATN_TYPE_NODE (i)) + return FLOATN_TYPE_NODE (i); + /* Likewise, prefer long double to double even if same size. */ - if (TYPE_MAIN_VARIANT (t1) == long_double_type_node - || TYPE_MAIN_VARIANT (t2) == long_double_type_node) + if (mv1 == long_double_type_node || mv2 == long_double_type_node) return long_double_type_node; /* Likewise, prefer double to float even if same size. We got a couple of embedded targets with 32 bit doubles, and the pdp11 might have 64 bit floats. */ - if (TYPE_MAIN_VARIANT (t1) == double_type_node - || TYPE_MAIN_VARIANT (t2) == double_type_node) + if (mv1 == double_type_node || mv2 == double_type_node) return double_type_node; + if (mv1 == float_type_node || mv2 == float_type_node) + return float_type_node; + + for (int i = NUM_FLOATNX_TYPES - 1; i >= 0; i--) + if (mv1 == FLOATNX_TYPE_NODE (i) || mv2 == FLOATNX_TYPE_NODE (i)) + return FLOATNX_TYPE_NODE (i); + /* Otherwise prefer the unsigned one. */ if (TYPE_UNSIGNED (t1)) @@ -3284,6 +3307,30 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, val = require_complete_type (ploc, val); + /* Some floating-point arguments must be promoted to double when + no type is specified by a prototype. This applies to + arguments of type float, and to architecture-specific types + (ARM __fp16), but not to _FloatN or _FloatNx types. */ + bool promote_float_arg = false; + if (type == NULL_TREE + && TREE_CODE (valtype) == REAL_TYPE + && (TYPE_PRECISION (valtype) + <= TYPE_PRECISION (double_type_node)) + && TYPE_MAIN_VARIANT (valtype) != double_type_node + && TYPE_MAIN_VARIANT (valtype) != long_double_type_node + && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype))) + { + /* Promote this argument, unless it has a _FloatN or + _FloatNx type. */ + promote_float_arg = true; + for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++) + if (TYPE_MAIN_VARIANT (valtype) == FLOATN_NX_TYPE_NODE (i)) + { + promote_float_arg = false; + break; + } + } + if (type != 0) { /* Formal parm type is specified by a function prototype. */ @@ -3450,12 +3497,7 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, parmval = default_conversion (parmval); } } - else if (TREE_CODE (valtype) == REAL_TYPE - && (TYPE_PRECISION (valtype) - <= TYPE_PRECISION (double_type_node)) - && TYPE_MAIN_VARIANT (valtype) != double_type_node - && TYPE_MAIN_VARIANT (valtype) != long_double_type_node - && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype))) + else if (promote_float_arg) { if (type_generic) parmval = val; |