aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/ChangeLog14
-rw-r--r--gcc/c/c-decl.c115
-rw-r--r--gcc/c/c-parser.c5
-rw-r--r--gcc/c/c-tree.h4
-rw-r--r--gcc/c/c-typeck.c62
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;