* [PATCH] c++: Excess precision for ? int : float or int == float [PR107097, PR82071, PR87390]
@ 2022-10-13 16:45 Jakub Jelinek
0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2022-10-13 16:45 UTC (permalink / raw)
To: Jason Merrill, Joseph S. Myers; +Cc: gcc-patches
Hi!
The following incremental patch implements the C11 behavior (for all C++
versions) for
cond ? int : float
cond ? float : int
int cmp float
float cmp int
where int is any integral type, float any floating point type with
excess precision and cmp ==, !=, >, <, >=, <= and <=>.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2022-10-13 Jakub Jelinek <jakub@redhat.com>
PR c/82071
PR c/87390
PR c++/107097
gcc/cp/
* cp-tree.h (cp_ep_convert_and_check): Remove.
* cvt.cc (cp_ep_convert_and_check): Remove.
* call.cc (build_conditional_expr): Use excess precision for ?: with
one arm floating and another integral. Don't convert first to
semantic result type from integral types.
(convert_like_internal): Don't call cp_ep_convert_and_check, instead
just strip EXCESS_PRECISION_EXPR before calling cp_convert_and_check
or cp_convert.
* typeck.cc (cp_build_binary_op): Set may_need_excess_precision
for comparisons or SPACESHIP_EXPR with at least one operand integral.
Don't compute semantic_result_type if build_type is non-NULL. Call
cp_convert_and_check instead of cp_ep_convert_and_check.
gcc/testsuite/
* gcc.target/i386/excess-precision-8.c: For C++ wrap abort and
exit declarations into extern "C" block.
* gcc.target/i386/excess-precision-10.c: Likewise.
* g++.target/i386/excess-precision-7.C: Remove.
* g++.target/i386/excess-precision-8.C: New test.
* g++.target/i386/excess-precision-9.C: Remove.
* g++.target/i386/excess-precision-10.C: New test.
* g++.target/i386/excess-precision-12.C: New test.
--- gcc/cp/cp-tree.h.jj 2022-10-13 09:35:27.999241554 +0200
+++ gcc/cp/cp-tree.h 2022-10-13 15:43:57.124884379 +0200
@@ -6793,8 +6793,6 @@ extern tree ocp_convert (tree, tree,
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);
--- gcc/cp/cvt.cc.jj 2022-10-13 09:35:27.956242146 +0200
+++ gcc/cp/cvt.cc 2022-10-13 14:09:29.612758165 +0200
@@ -684,33 +684,6 @@ cp_convert_and_check (tree type, tree ex
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. */
--- gcc/cp/call.cc.jj 2022-10-13 09:50:41.248658097 +0200
+++ gcc/cp/call.cc 2022-10-13 16:11:34.901325768 +0200
@@ -5895,11 +5895,53 @@ build_conditional_expr (const op_locatio
&& (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;
if (TREE_CODE (t1) == COMPLEX_TYPE)
@@ -5976,10 +6018,6 @@ build_conditional_expr (const op_locatio
}
}
- 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
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);
--- gcc/cp/typeck.cc.jj 2022-10-13 09:48:03.259835071 +0200
+++ gcc/cp/typeck.cc 2022-10-13 15:36:57.911534008 +0200
@@ -5227,6 +5227,18 @@ cp_build_binary_op (const op_location_t
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;
@@ -6149,7 +6161,8 @@ cp_build_binary_op (const op_location_t
}
}
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);
@@ -6446,11 +6459,9 @@ cp_build_binary_op (const op_location_t
{
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;
--- gcc/testsuite/gcc.target/i386/excess-precision-8.c.jj 2020-01-12 11:54:37.941390355 +0100
+++ gcc/testsuite/gcc.target/i386/excess-precision-8.c 2022-10-13 14:21:30.161695474 +0200
@@ -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)
--- gcc/testsuite/gcc.target/i386/excess-precision-10.c.jj 2020-01-12 11:54:37.941390355 +0100
+++ gcc/testsuite/gcc.target/i386/excess-precision-10.c 2022-10-13 15:11:09.679536633 +0200
@@ -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)
--- gcc/testsuite/g++.target/i386/excess-precision-7.C.jj 2022-10-13 09:35:28.080240438 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-7.C 2022-10-13 14:22:50.824562894 +0200
@@ -1,7 +0,0 @@
-// Excess precision tests. Test C99 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"
--- gcc/testsuite/g++.target/i386/excess-precision-8.C.jj 2022-10-13 14:22:29.573861273 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-8.C 2022-10-13 14:22:44.198655927 +0200
@@ -0,0 +1,7 @@
+// 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-8.c"
--- gcc/testsuite/g++.target/i386/excess-precision-9.C.jj 2022-10-13 09:35:28.080240438 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-9.C 2022-10-13 15:12:06.931756106 +0200
@@ -1,6 +0,0 @@
-// Excess precision tests. Test implicit conversions in comparisons:
-// no excess precision in C++.
-// { dg-do run }
-// { dg-options "-mfpmath=387 -fexcess-precision=standard" }
-
-#include "../../gcc.target/i386/excess-precision-9.c"
--- gcc/testsuite/g++.target/i386/excess-precision-10.C.jj 2022-10-13 15:12:11.348695892 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-10.C 2022-10-13 15:12:41.309287429 +0200
@@ -0,0 +1,6 @@
+// Excess precision tests. Test implicit conversions in comparisons:
+// excess precision in C++.
+// { dg-do run }
+// { dg-options "-mfpmath=387 -fexcess-precision=standard" }
+
+#include "../../gcc.target/i386/excess-precision-10.c"
--- gcc/testsuite/g++.target/i386/excess-precision-12.C.jj 2022-10-13 15:26:44.956822134 +0200
+++ gcc/testsuite/g++.target/i386/excess-precision-12.C 2022-10-13 15:31:02.847335047 +0200
@@ -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 <compare>
+#include <cstdlib>
+
+int
+main (void)
+{
+ float f = 0x1p63f;
+ unsigned long long int u = (1ULL << 63) + 1;
+
+ if ((f <=> u) >= 0)
+ abort ();
+
+ if ((u <=> f) <= 0)
+ abort ();
+}
Jakub
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-10-13 16:45 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-13 16:45 [PATCH] c++: Excess precision for ? int : float or int == float [PR107097, PR82071, PR87390] Jakub Jelinek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).