diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 709afc63eb7..6a34e9c2ae1 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -5895,10 +5895,52 @@ build_conditional_expr (const op_location_t &loc, && (ARITHMETIC_TYPE_P (arg3_type) || UNSCOPED_ENUM_P (arg3_type))) { - /* In this case, there is always a common type. */ - result_type = type_after_usual_arithmetic_conversions (arg2_type, - arg3_type); + /* A conditional expression between a floating-point + type and an integer type should convert the integer type to + the evaluation format of the floating-point type, with + possible excess precision. */ + tree eptype2 = arg2_type; + tree eptype3 = arg3_type; + tree eptype; + if (ANY_INTEGRAL_TYPE_P (arg2_type) + && (eptype = excess_precision_type (arg3_type)) != NULL_TREE) + { + eptype3 = eptype; + if (!semantic_result_type) + semantic_result_type + = type_after_usual_arithmetic_conversions (arg2_type, arg3_type); + } + else if (ANY_INTEGRAL_TYPE_P (arg3_type) + && (eptype = excess_precision_type (arg2_type)) != NULL_TREE) + { + eptype2 = eptype; + if (!semantic_result_type) + semantic_result_type + = type_after_usual_arithmetic_conversions (arg2_type, arg3_type); + } + result_type = type_after_usual_arithmetic_conversions (eptype2, + eptype3); if (result_type == error_mark_node) + { + tree t1 = eptype2; + tree t2 = eptype3; + if (TREE_CODE (t1) == COMPLEX_TYPE) + t1 = TREE_TYPE (t1); + if (TREE_CODE (t2) == COMPLEX_TYPE) + t2 = TREE_TYPE (t2); + gcc_checking_assert (TREE_CODE (t1) == REAL_TYPE + && TREE_CODE (t2) == REAL_TYPE + && (extended_float_type_p (t1) + || extended_float_type_p (t2)) + && cp_compare_floating_point_conversion_ranks + (t1, t2) == 3); + if (complain & tf_error) + error_at (loc, "operands to % of types %qT and %qT " + "have unordered conversion rank", + eptype2, eptype3); + return error_mark_node; + } + if (semantic_result_type == error_mark_node) { tree t1 = arg2_type; tree t2 = arg3_type; @@ -5976,10 +6018,6 @@ build_conditional_expr (const op_location_t &loc, } } - if (semantic_result_type && INTEGRAL_TYPE_P (arg2_type)) - arg2 = perform_implicit_conversion (semantic_result_type, arg2, complain); - else if (semantic_result_type && INTEGRAL_TYPE_P (arg3_type)) - arg3 = perform_implicit_conversion (semantic_result_type, arg3, complain); arg2 = perform_implicit_conversion (result_type, arg2, complain); arg3 = perform_implicit_conversion (result_type, arg3, complain); } @@ -8546,14 +8584,8 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, warning_sentinel w (warn_zero_as_null_pointer_constant); if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR) - { - if (issue_conversion_warnings) - expr = cp_ep_convert_and_check (totype, TREE_OPERAND (expr, 0), - TREE_TYPE (expr), complain); - else - expr = cp_convert (totype, TREE_OPERAND (expr, 0), complain); - } - else if (issue_conversion_warnings) + expr = TREE_OPERAND (expr, 0); + if (issue_conversion_warnings) expr = cp_convert_and_check (totype, expr, complain); else expr = cp_convert (totype, expr, complain); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ceaadba33fa..1534c875693 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6793,8 +6793,6 @@ extern tree ocp_convert (tree, tree, int, int, tsubst_flags_t); extern tree cp_convert (tree, tree, tsubst_flags_t); extern tree cp_convert_and_check (tree, tree, tsubst_flags_t); -extern tree cp_ep_convert_and_check (tree, tree, tree, - tsubst_flags_t); extern tree cp_fold_convert (tree, tree); extern tree cp_get_callee (tree); extern tree cp_get_callee_fndecl (tree); diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc index 4da04e1cad7..434d306961f 100644 --- a/gcc/cp/cvt.cc +++ b/gcc/cp/cvt.cc @@ -684,33 +684,6 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain) return result; } -/* Similarly, but deal with excess precision. SEMANTIC_TYPE is the type this - conversion would use without excess precision. If SEMANTIC_TYPE is NULL, - this function is equivalent to cp_convert_and_check. This function is - a wrapper that handles conversions that may be different than the usual - ones because of excess precision. */ - -tree -cp_ep_convert_and_check (tree type, tree expr, tree semantic_type, - tsubst_flags_t complain) -{ - if (TREE_TYPE (expr) == type) - return expr; - if (expr == error_mark_node) - return expr; - if (!semantic_type) - return cp_convert_and_check (type, expr, complain); - - if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE - && TREE_TYPE (expr) != semantic_type) - /* For integers, we need to check the real conversion, not - the conversion to the excess precision type. */ - expr = cp_convert_and_check (semantic_type, expr, complain); - /* Result type is the excess precision type, which should be - large enough, so do not check. */ - return cp_convert (type, expr, complain); -} - /* Conversion... FLAGS indicates how we should behave. */ diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index c3503b69f77..634f60c1a96 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -5229,6 +5229,18 @@ cp_build_binary_op (const op_location_t &location, case EXACT_DIV_EXPR: may_need_excess_precision = true; break; + case EQ_EXPR: + case NE_EXPR: + case LE_EXPR: + case GE_EXPR: + case LT_EXPR: + case GT_EXPR: + case SPACESHIP_EXPR: + /* Excess precision for implicit conversions of integers to + floating point. */ + may_need_excess_precision = (ANY_INTEGRAL_TYPE_P (type0) + || ANY_INTEGRAL_TYPE_P (type1)); + break; default: may_need_excess_precision = false; break; @@ -6157,7 +6169,8 @@ cp_build_binary_op (const op_location_t &location, } } if (may_need_excess_precision - && (orig_type0 != type0 || orig_type1 != type1)) + && (orig_type0 != type0 || orig_type1 != type1) + && build_type == NULL_TREE) { gcc_assert (common); semantic_result_type = cp_common_type (orig_type0, orig_type1); @@ -6460,11 +6473,9 @@ cp_build_binary_op (const op_location_t &location, { warning_sentinel w (warn_sign_conversion, short_compare); if (!same_type_p (TREE_TYPE (op0), result_type)) - op0 = cp_ep_convert_and_check (result_type, op0, - semantic_result_type, complain); + op0 = cp_convert_and_check (result_type, op0, complain); if (!same_type_p (TREE_TYPE (op1), result_type)) - op1 = cp_ep_convert_and_check (result_type, op1, - semantic_result_type, complain); + op1 = cp_convert_and_check (result_type, op1, complain); if (op0 == error_mark_node || op1 == error_mark_node) return error_mark_node; diff --git a/gcc/testsuite/g++.target/i386/excess-precision-9.C b/gcc/testsuite/g++.target/i386/excess-precision-10.C similarity index 63% rename from gcc/testsuite/g++.target/i386/excess-precision-9.C rename to gcc/testsuite/g++.target/i386/excess-precision-10.C index 1fcadb94c1f..9dbe25e0934 100644 --- a/gcc/testsuite/g++.target/i386/excess-precision-9.C +++ b/gcc/testsuite/g++.target/i386/excess-precision-10.C @@ -1,6 +1,6 @@ // Excess precision tests. Test implicit conversions in comparisons: -// no excess precision in C++. +// excess precision in C++. // { dg-do run } // { dg-options "-mfpmath=387 -fexcess-precision=standard" } -#include "../../gcc.target/i386/excess-precision-9.c" +#include "../../gcc.target/i386/excess-precision-10.c" diff --git a/gcc/testsuite/g++.target/i386/excess-precision-12.C b/gcc/testsuite/g++.target/i386/excess-precision-12.C new file mode 100644 index 00000000000..dff48c07c8b --- /dev/null +++ b/gcc/testsuite/g++.target/i386/excess-precision-12.C @@ -0,0 +1,20 @@ +// Excess precision tests. Test implicit conversions in 3-way comparisons: +// excess precision in C++. +// { dg-do run { target c++20 } } +// { dg-options "-mfpmath=387 -fexcess-precision=standard" } + +#include +#include + +int +main (void) +{ + float f = 0x1p63f; + unsigned long long int u = (1ULL << 63) + 1; + + if ((f <=> u) >= 0) + abort (); + + if ((u <=> f) <= 0) + abort (); +} diff --git a/gcc/testsuite/g++.target/i386/excess-precision-7.C b/gcc/testsuite/g++.target/i386/excess-precision-8.C similarity index 60% rename from gcc/testsuite/g++.target/i386/excess-precision-7.C rename to gcc/testsuite/g++.target/i386/excess-precision-8.C index 5df0d9d8c1f..c170c004b69 100644 --- a/gcc/testsuite/g++.target/i386/excess-precision-7.C +++ b/gcc/testsuite/g++.target/i386/excess-precision-8.C @@ -1,7 +1,7 @@ -// Excess precision tests. Test C99 semantics for conversions from +// Excess precision tests. Test C++ semantics for conversions from // integers to floating point: no excess precision for either explicit // or implicit conversions. // { dg-do run } // { dg-options "-mfpmath=387 -fexcess-precision=standard" } -#include "../../gcc.target/i386/excess-precision-7.c" +#include "../../gcc.target/i386/excess-precision-8.c" diff --git a/gcc/testsuite/gcc.target/i386/excess-precision-10.c b/gcc/testsuite/gcc.target/i386/excess-precision-10.c index f1b9b7e1980..1dd3e7a424c 100644 --- a/gcc/testsuite/gcc.target/i386/excess-precision-10.c +++ b/gcc/testsuite/gcc.target/i386/excess-precision-10.c @@ -3,8 +3,14 @@ /* { dg-do run } */ /* { dg-options "-std=c11 -mfpmath=387 -fexcess-precision=standard" } */ +#ifdef __cplusplus +extern "C" { +#endif extern void abort (void); extern void exit (int); +#ifdef __cplusplus +} +#endif int main (void) diff --git a/gcc/testsuite/gcc.target/i386/excess-precision-8.c b/gcc/testsuite/gcc.target/i386/excess-precision-8.c index c0a31ed5f4e..8dd04585180 100644 --- a/gcc/testsuite/gcc.target/i386/excess-precision-8.c +++ b/gcc/testsuite/gcc.target/i386/excess-precision-8.c @@ -4,8 +4,14 @@ /* { dg-do run } */ /* { dg-options "-std=c11 -mfpmath=387 -fexcess-precision=standard" } */ +#ifdef __cplusplus +extern "C" { +#endif extern void abort (void); extern void exit (int); +#ifdef __cplusplus +} +#endif int main (void)