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.
This commit is contained in:
parent
98e341130f
commit
16ec267063
9 changed files with 99 additions and 53 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
20
gcc/testsuite/g++.target/i386/excess-precision-12.C
Normal file
20
gcc/testsuite/g++.target/i386/excess-precision-12.C
Normal file
|
@ -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 ();
|
||||
}
|
|
@ -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"
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue