public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-3291] c++: Excess precision for ? int : float or int == float [PR107097, PR82071, PR87390]
@ 2022-10-14  7:34 Jakub Jelinek
  0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2022-10-14  7:34 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:16ec267063c8ce60769888d4097bcd158410adc8

commit r13-3291-g16ec267063c8ce60769888d4097bcd158410adc8
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Fri Oct 14 09:33:23 2022 +0200

    c++: Excess precision for ? int : float or int == float [PR107097, PR82071, PR87390]
    
    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 <=>.
    
    2022-10-14  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.

Diff:
---
 gcc/cp/call.cc                                     | 62 ++++++++++++++++------
 gcc/cp/cp-tree.h                                   |  2 -
 gcc/cp/cvt.cc                                      | 27 ----------
 gcc/cp/typeck.cc                                   | 21 ++++++--
 ...{excess-precision-9.C => excess-precision-10.C} |  4 +-
 .../g++.target/i386/excess-precision-12.C          | 20 +++++++
 .../{excess-precision-7.C => excess-precision-8.C} |  4 +-
 .../gcc.target/i386/excess-precision-10.c          |  6 +++
 gcc/testsuite/gcc.target/i386/excess-precision-8.c |  6 +++
 9 files changed, 99 insertions(+), 53 deletions(-)

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 <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 ();
+}
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)

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-10-14  7:34 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-14  7:34 [gcc r13-3291] 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).