From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 2F2FA3858401 for ; Tue, 11 Oct 2022 13:33:32 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2F2FA3858401 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1665495211; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=nLTh26+N4jOjzkjel12hp+HJyZrbHRRFjcMCfB4o5gI=; b=VnD/I2yU26vXnsvfXV8f0Rp5BZNMTF3iU+OnwcHrhL+eU7WTEcYQeHNETB8pd3V1Ihak8c Ttrmn083Gg83oHPIeUuU2I7NV+nfl/eAaAGJszqXjtJPDNAnXxr5N7OTe+UtrRj6UjmPbQ +VqT7387KiBFN+tfvDIx9f/zHcUANsE= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-674-ghHH84ftMo6MSVcXgOIFLA-1; Tue, 11 Oct 2022 09:33:28 -0400 X-MC-Unique: ghHH84ftMo6MSVcXgOIFLA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 54859185A78F; Tue, 11 Oct 2022 13:33:28 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.192.55]) by smtp.corp.redhat.com (Postfix) with ESMTPS id B720E1111C60; Tue, 11 Oct 2022 13:33:27 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 29BDXPJi2968443 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Tue, 11 Oct 2022 15:33:25 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 29BDXOtv2968442; Tue, 11 Oct 2022 15:33:24 +0200 Date: Tue, 11 Oct 2022 15:33:23 +0200 From: Jakub Jelinek To: Jason Merrill , "Joseph S. Myers" Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: Implement excess precision support for C++ [PR107097, PR323] Message-ID: Reply-To: Jakub Jelinek MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3.6 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Hi! The following patch implements excess precision support for C++. Like for C, it uses EXCESS_PRECISION_EXPR tree to say that its operand is evaluated in excess precision and what the semantic type of the expression is. In most places I've followed what the C FE does in similar spots, so e.g. for binary ops if one or both operands are already EXCESS_PRECISION_EXPR, strip those away or for operations that might need excess precision (+, -, *, /) check if the operands should use excess precision and convert to that type and at the end wrap into EXCESS_PRECISION_EXPR with the common semantic type. In general I've tried to follow the C99 handling, C11+ relies on the C standard saying that in case of integral conversions excess precision can be used (see PR87390 for more details), but I don't see anything similar on the C++ standard side. There are some cases which needed to be handled differently, the C FE can just strip EXCESS_PRECISION_EXPR (replace it with its operand) when handling explicit cast, but that IMHO isn't right for C++ - the discovery what exact conversion should be used (e.g. if user conversion or standard or their sequence) should be decided based on the semantic type (i.e. type of EXCESS_PRECISION_EXPR), and that decision continues in convert_like* where we pick the right user conversion, again, if say some class has ctor from double and long double and we are on ia32 with standard excess precision promoting float/double to long double, then we should pick the ctor from double. Or when some other class has ctor from just double, and EXCESS_PRECISION_EXPR semantic type is float, we should choose the user ctor from double, but actually just convert the long double excess precision to double and not to float first. We need to make sure even identity conversion converts from excess precision to the semantic one though, but if identity is chained with other conversions, we don't want the identity next_conversion to drop to semantic precision only to widen afterwards. The existing testcases tweaks were for cases on i686-linux where excess precision breaks those tests, e.g. if we have double d = 4.2; if (d == 4.2) then it does the expected thing only with -fexcess-precision=fast, because with -fexcess-precision=standard it is actually double d = 4.2; if ((long double) d == 4.2L) where 4.2L is different from 4.2. I've added -fexcess-precision=fast to some tests and changed other tests to use constants that are exactly representable and don't suffer from these excess precision issues. There is one exception, pr68180.C looks like a bug in the patch which is also present in the C FE (so I'd like to get it resolved incrementally in both). Reduced testcase: typedef float __attribute__((vector_size (16))) float32x4_t; float32x4_t foo(float32x4_t x, float y) { return x + y; } with -m32 -std=c11 -Wno-psabi or -m32 -std=c++17 -Wno-psabi it is rejected with: pr68180.c:2:52: error: conversion of scalar ‘long double’ to vector ‘float32x4_t’ {aka ‘__vector(4) float’} involves truncation but without excess precision (say just -std=c11 -Wno-psabi or -std=c++17 -Wno-psabi) it is accepted. Perhaps we should pass down the semantic type to scalar_to_vector and use the semantic type rather than excess precision type in the diagnostics. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2022-10-11 Jakub Jelinek PR middle-end/323 PR c++/107097 gcc/c-family/ * c-opts.cc (c_common_post_options): Handle flag_excess_precision in C++ the same as in C. * c-lex.cc (interpret_float): Set const_type to excess_precision () even for C++. gcc/cp/ * parser.cc (cp_parser_primary_expression): Handle EXCESS_PRECISION_EXPR with REAL_CST operand the same as REAL_CST. * cvt.cc (cp_ep_convert_and_check): New function. * call.cc (build_conditional_expr): Add excess precision support. (convert_like_internal): Likewise. Add NESTED_P argument, pass true to recursive calls to convert_like. (convert_like): Add NESTED_P argument, pass it through to convert_like_internal. For other overload pass false to it. (convert_like_with_context): Pass false to NESTED_P. (convert_arg_to_ellipsis): Add excess precision support. (magic_varargs_p): For __builtin_is{finite,inf,inf_sign,nan,normal} and __builtin_fpclassify return 2 instead of 1, document what it means. (build_over_call): Don't handle former magic 2 which is no longer used, instead for magic 1 remove EXCESS_PRECISION_EXPR. (perform_direct_initialization_if_possible): Pass false to NESTED_P convert_like argument. * constexpr.cc (cxx_eval_constant_expression): Handle EXCESS_PRECISION_EXPR. (potential_constant_expression_1): Likewise. * pt.cc (tsubst_copy, tsubst_copy_and_build): Likewise. * cp-tree.h (cp_ep_convert_and_check): Declare. * cp-gimplify.cc (cp_fold): Handle EXCESS_PRECISION_EXPR. * typeck.cc (convert_arguments): For magic 1 remove EXCESS_PRECISION_EXPR. (cp_build_binary_op): Add excess precision support. (cp_build_unary_op): Likewise. (cp_build_compound_expr): Likewise. (build_static_cast_1): Remove EXCESS_PRECISION_EXPR. gcc/testsuite/ * gcc.target/i386/excess-precision-1.c: For C++ wrap abort and exit declarations into extern "C" block. * gcc.target/i386/excess-precision-2.c: Likewise. * gcc.target/i386/excess-precision-3.c: Likewise. Remove check_float_nonproto and check_double_nonproto tests for C++. * gcc.target/i386/excess-precision-7.c: For C++ wrap abort and exit declarations into extern "C" block. * gcc.target/i386/excess-precision-9.c: Likewise. * g++.target/i386/excess-precision-1.C: New test. * g++.target/i386/excess-precision-2.C: New test. * g++.target/i386/excess-precision-3.C: New test. * g++.target/i386/excess-precision-4.C: New test. * g++.target/i386/excess-precision-5.C: New test. * g++.target/i386/excess-precision-6.C: New test. * g++.target/i386/excess-precision-7.C: New test. * g++.target/i386/excess-precision-8.C: New test. * g++.target/i386/excess-precision-9.C: New test. * c-c++-common/dfp/convert-bfp-10.c: Add -fexcess-precision=fast as dg-additional-options. * c-c++-common/dfp/compare-eq-const.c: Likewise. * g++.dg/cpp1z/constexpr-96862.C: Likewise. * g++.dg/cpp1z/decomp12.C (main): Use 2.25 instead of 2.3 to avoid excess precision differences. * g++.dg/other/thunk1.C: Add -fexcess-precision=fast as dg-additional-options. * g++.dg/vect/pr64410.cc: Likewise. * g++.dg/cpp1y/pr68180.C: Likewise. * g++.dg/cpp0x/variadic-tuple.C: Likewise. * g++.dg/cpp0x/nsdmi-union1.C: Use 4.25 instead of 4.2 to avoid excess precision differences. * g++.old-deja/g++.brendan/copy9.C: Add -fexcess-precision=fast as dg-additional-options. * g++.old-deja/g++.brendan/overload7.C: Likewise. --- gcc/c-family/c-opts.cc.jj 2022-10-11 10:00:07.108129689 +0200 +++ gcc/c-family/c-opts.cc 2022-10-11 10:06:55.784412531 +0200 @@ -812,17 +812,9 @@ c_common_post_options (const char **pfil C_COMMON_OVERRIDE_OPTIONS; #endif - /* Excess precision other than "fast" requires front-end - support. */ - if (c_dialect_cxx ()) - { - if (flag_excess_precision == EXCESS_PRECISION_STANDARD) - sorry ("%<-fexcess-precision=standard%> for C++"); - flag_excess_precision = EXCESS_PRECISION_FAST; - } - else if (flag_excess_precision == EXCESS_PRECISION_DEFAULT) + if (flag_excess_precision == EXCESS_PRECISION_DEFAULT) flag_excess_precision = (flag_iso ? EXCESS_PRECISION_STANDARD - : EXCESS_PRECISION_FAST); + : EXCESS_PRECISION_FAST); /* ISO C restricts floating-point expression contraction to within source-language expressions (-ffp-contract=on, currently an alias --- gcc/c-family/c-lex.cc.jj 2022-10-11 09:59:39.300518701 +0200 +++ gcc/c-family/c-lex.cc 2022-10-11 10:06:55.784412531 +0200 @@ -1008,10 +1008,7 @@ interpret_float (const cpp_token *token, else type = double_type_node; - if (c_dialect_cxx ()) - const_type = NULL_TREE; - else - const_type = excess_precision_type (type); + const_type = excess_precision_type (type); if (!const_type) const_type = type; --- gcc/cp/parser.cc.jj 2022-10-10 11:57:40.158723041 +0200 +++ gcc/cp/parser.cc 2022-10-11 11:56:50.815463848 +0200 @@ -5583,7 +5583,9 @@ cp_parser_primary_expression (cp_parser /* Floating-point literals are only allowed in an integral constant expression if they are cast to an integral or enumeration type. */ - if (TREE_CODE (token->u.value) == REAL_CST + if ((TREE_CODE (token->u.value) == REAL_CST + || (TREE_CODE (token->u.value) == EXCESS_PRECISION_EXPR + && TREE_CODE (TREE_OPERAND (token->u.value, 0)) == REAL_CST)) && parser->integral_constant_expression_p && pedantic) { --- gcc/cp/cvt.cc.jj 2022-10-11 09:59:39.633514043 +0200 +++ gcc/cp/cvt.cc 2022-10-11 10:06:55.785412518 +0200 @@ -684,6 +684,33 @@ 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-11 09:59:39.424516967 +0200 +++ gcc/cp/call.cc 2022-10-11 10:06:55.787412490 +0200 @@ -5374,6 +5374,7 @@ build_conditional_expr (const op_locatio tree arg3_type; tree result = NULL_TREE; tree result_type = NULL_TREE; + tree semantic_result_type = NULL_TREE; bool is_glvalue = true; struct z_candidate *candidates = 0; struct z_candidate *cand; @@ -5407,6 +5408,9 @@ build_conditional_expr (const op_locatio expression, since it needs to be materialized for the conversion to bool, so treat it as an xvalue in arg2. */ arg2 = move (TARGET_EXPR_SLOT (arg1)); + else if (TREE_CODE (arg1) == EXCESS_PRECISION_EXPR) + arg2 = arg1 = build1 (EXCESS_PRECISION_EXPR, TREE_TYPE (arg1), + cp_save_expr (TREE_OPERAND (arg1, 0))); else arg2 = arg1 = cp_save_expr (arg1); } @@ -5565,6 +5569,46 @@ build_conditional_expr (const op_locatio if (error_operand_p (arg1)) return error_mark_node; + arg2_type = unlowered_expr_type (arg2); + arg3_type = unlowered_expr_type (arg3); + + if ((TREE_CODE (arg2) == EXCESS_PRECISION_EXPR + || TREE_CODE (arg3) == EXCESS_PRECISION_EXPR) + && (TREE_CODE (arg2_type) == INTEGER_TYPE + || TREE_CODE (arg2_type) == REAL_TYPE + || TREE_CODE (arg2_type) == COMPLEX_TYPE) + && (TREE_CODE (arg3_type) == INTEGER_TYPE + || TREE_CODE (arg3_type) == REAL_TYPE + || TREE_CODE (arg3_type) == COMPLEX_TYPE)) + { + semantic_result_type + = type_after_usual_arithmetic_conversions (arg2_type, arg3_type); + if (semantic_result_type == error_mark_node + && TREE_CODE (arg2_type) == REAL_TYPE + && TREE_CODE (arg3_type) == REAL_TYPE + && (extended_float_type_p (arg2_type) + || extended_float_type_p (arg3_type)) + && cp_compare_floating_point_conversion_ranks (arg2_type, + arg3_type) == 3) + { + if (complain & tf_error) + error_at (loc, "operands to % of types %qT and %qT " + "have unordered conversion rank", + arg2_type, arg3_type); + return error_mark_node; + } + if (TREE_CODE (arg2) == EXCESS_PRECISION_EXPR) + { + arg2 = TREE_OPERAND (arg2, 0); + arg2_type = TREE_TYPE (arg2); + } + if (TREE_CODE (arg3) == EXCESS_PRECISION_EXPR) + { + arg3 = TREE_OPERAND (arg3, 0); + arg3_type = TREE_TYPE (arg3); + } + } + /* [expr.cond] If either the second or the third operand has type (possibly @@ -5572,8 +5616,6 @@ build_conditional_expr (const op_locatio array-to-pointer (_conv.array_), and function-to-pointer (_conv.func_) standard conversions are performed on the second and third operands. */ - arg2_type = unlowered_expr_type (arg2); - arg3_type = unlowered_expr_type (arg3); if (VOID_TYPE_P (arg2_type) || VOID_TYPE_P (arg3_type)) { /* 'void' won't help in resolving an overloaded expression on the @@ -5937,6 +5979,10 @@ 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); } @@ -6024,9 +6070,15 @@ build_conditional_expr (const op_locatio /* If this expression is an rvalue, but might be mistaken for an lvalue, we must add a NON_LVALUE_EXPR. */ result = rvalue (result); + if (semantic_result_type) + result = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, + result); } else - result = force_paren_expr (result); + { + result = force_paren_expr (result); + gcc_assert (semantic_result_type == NULL_TREE); + } return result; } @@ -7890,7 +7942,7 @@ maybe_warn_array_conv (location_t loc, c } /* We call this recursively in convert_like_internal. */ -static tree convert_like (conversion *, tree, tree, int, bool, bool, +static tree convert_like (conversion *, tree, tree, int, bool, bool, bool, tsubst_flags_t); /* Perform the conversions in CONVS on the expression EXPR. FN and @@ -7906,7 +7958,7 @@ static tree convert_like (conversion *, static tree convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, bool issue_conversion_warnings, bool c_cast_p, - tsubst_flags_t complain) + bool nested_p, tsubst_flags_t complain) { tree totype = convs->type; diagnostic_t diag_kind; @@ -7983,7 +8035,8 @@ convert_like_internal (conversion *convs print_z_candidate (loc, N_("candidate is:"), t->cand); expr = convert_like (t, expr, fn, argnum, /*issue_conversion_warnings=*/false, - /*c_cast_p=*/false, complain); + /*c_cast_p=*/false, /*nested_p=*/true, + complain); if (convs->kind == ck_ref_bind) expr = convert_to_reference (totype, expr, CONV_IMPLICIT, LOOKUP_NORMAL, NULL_TREE, @@ -7998,13 +8051,15 @@ convert_like_internal (conversion *convs { expr = convert_like (t, expr, fn, argnum, /*issue_conversion_warnings=*/false, - /*c_cast_p=*/false, complain); + /*c_cast_p=*/false, /*nested_p=*/true, + complain); break; } else if (t->kind == ck_ambig) return convert_like (t, expr, fn, argnum, /*issue_conversion_warnings=*/false, - /*c_cast_p=*/false, complain); + /*c_cast_p=*/false, /*nested_p=*/true, + complain); else if (t->kind == ck_identity) break; } @@ -8124,6 +8179,8 @@ convert_like_internal (conversion *convs if (type_unknown_p (expr)) expr = instantiate_type (totype, expr, complain); + if (!nested_p && TREE_CODE (expr) == EXCESS_PRECISION_EXPR) + expr = cp_convert (totype, TREE_OPERAND (expr, 0), complain); if (expr == null_node && INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (totype)) /* If __null has been converted to an integer type, we do not want to @@ -8163,7 +8220,8 @@ convert_like_internal (conversion *convs FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), ix, val) { tree sub = convert_like (convs->u.list[ix], val, fn, - argnum, false, false, complain); + argnum, false, false, + /*nested_p=*/true, complain); if (sub == error_mark_node) return sub; if (!BRACE_ENCLOSED_INITIALIZER_P (val) @@ -8231,7 +8289,7 @@ convert_like_internal (conversion *convs expr = convert_like (next_conversion (convs), expr, fn, argnum, convs->kind == ck_ref_bind ? issue_conversion_warnings : false, - c_cast_p, complain & ~tf_no_cleanup); + c_cast_p, /*nested_p=*/true, complain & ~tf_no_cleanup); if (expr == error_mark_node) return error_mark_node; @@ -8493,7 +8551,15 @@ convert_like_internal (conversion *convs return error_mark_node; warning_sentinel w (warn_zero_as_null_pointer_constant); - if (issue_conversion_warnings) + 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 = cp_convert_and_check (totype, expr, complain); else expr = cp_convert (totype, expr, complain); @@ -8527,7 +8593,7 @@ conv_unsafe_in_template_p (tree to, tree static tree convert_like (conversion *convs, tree expr, tree fn, int argnum, - bool issue_conversion_warnings, bool c_cast_p, + bool issue_conversion_warnings, bool c_cast_p, bool nested_p, tsubst_flags_t complain) { /* Creating &TARGET_EXPR<> in a template breaks when substituting, @@ -8550,7 +8616,8 @@ convert_like (conversion *convs, tree ex error_mark_node. */ } expr = convert_like_internal (convs, expr, fn, argnum, - issue_conversion_warnings, c_cast_p, complain); + issue_conversion_warnings, c_cast_p, + nested_p, complain); if (expr == error_mark_node) return error_mark_node; return conv_expr ? conv_expr : expr; @@ -8563,7 +8630,7 @@ convert_like (conversion *convs, tree ex { return convert_like (convs, expr, NULL_TREE, 0, /*issue_conversion_warnings=*/true, - /*c_cast_p=*/false, complain); + /*c_cast_p=*/false, /*nested_p=*/false, complain); } /* Convenience wrapper for convert_like. */ @@ -8574,7 +8641,7 @@ convert_like_with_context (conversion *c { return convert_like (convs, expr, fn, argnum, /*issue_conversion_warnings=*/true, - /*c_cast_p=*/false, complain); + /*c_cast_p=*/false, /*nested_p=*/false, complain); } /* ARG is being passed to a varargs function. Perform any conversions @@ -8605,6 +8672,8 @@ convert_arg_to_ellipsis (tree arg, tsubs "implicit conversion from %qH to %qI when passing " "argument to function", arg_type, double_type_node); + if (TREE_CODE (arg) == EXCESS_PRECISION_EXPR) + arg = TREE_OPERAND (arg, 0); arg = mark_rvalue_use (arg); arg = convert_to_real_nofold (double_type_node, arg); } @@ -8911,9 +8980,9 @@ convert_for_arg_passing (tree type, tree /* Returns non-zero iff FN is a function with magic varargs, i.e. ones for which just decay_conversion or no conversions at all should be done. This is true for some builtins which don't act like normal functions. - Return 2 if no conversions at all should be done, 1 if just - decay_conversion. Return 3 for special treatment of the 3rd argument - for __builtin_*_overflow_p. */ + Return 2 if just decay_conversion and removal of excess precision should + be done, 1 if just decay_conversion. Return 3 for special treatment of + the 3rd argument for __builtin_*_overflow_p. */ int magic_varargs_p (tree fn) @@ -8932,7 +9001,15 @@ magic_varargs_p (tree fn) case BUILT_IN_MUL_OVERFLOW_P: return 3; - default:; + case BUILT_IN_ISFINITE: + case BUILT_IN_ISINF: + case BUILT_IN_ISINF_SIGN: + case BUILT_IN_ISNAN: + case BUILT_IN_ISNORMAL: + case BUILT_IN_FPCLASSIFY: + return 2; + + default: return lookup_attribute ("type generic", TYPE_ATTRIBUTES (TREE_TYPE (fn))) != 0; } @@ -9764,7 +9841,7 @@ build_over_call (struct z_candidate *can for (; arg_index < vec_safe_length (args); ++arg_index) { tree a = (*args)[arg_index]; - if ((magic == 3 && arg_index == 2) || magic == 2) + if (magic == 3 && arg_index == 2) { /* Do no conversions for certain magic varargs. */ a = mark_type_use (a); @@ -9772,8 +9849,12 @@ build_over_call (struct z_candidate *can return error_mark_node; } else if (magic != 0) - /* For other magic varargs only do decay_conversion. */ - a = decay_conversion (a, complain); + { + if (magic == 1 && TREE_CODE (a) == EXCESS_PRECISION_EXPR) + a = TREE_OPERAND (a, 0); + /* For other magic varargs only do decay_conversion. */ + a = decay_conversion (a, complain); + } else if (DECL_CONSTRUCTOR_P (fn) && same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (fn), TREE_TYPE (a))) @@ -13051,7 +13132,7 @@ perform_direct_initialization_if_possibl else expr = convert_like (conv, expr, NULL_TREE, 0, /*issue_conversion_warnings=*/false, - c_cast_p, complain); + c_cast_p, /*nested_p=*/false, complain); /* Free all the conversions we allocated. */ obstack_free (&conversion_obstack, p); --- gcc/cp/constexpr.cc.jj 2022-10-11 09:59:39.481516169 +0200 +++ gcc/cp/constexpr.cc 2022-10-11 10:06:55.788412476 +0200 @@ -7618,6 +7618,19 @@ cxx_eval_constant_expression (const cons } break; + case EXCESS_PRECISION_EXPR: + { + tree oldop = TREE_OPERAND (t, 0); + + tree op = cxx_eval_constant_expression (ctx, oldop, + lval, + non_constant_p, overflow_p); + if (*non_constant_p) + return t; + r = fold_convert (TREE_TYPE (t), op); + break; + } + case EMPTY_CLASS_EXPR: /* Handle EMPTY_CLASS_EXPR produced by build_call_a by lowering it to an appropriate CONSTRUCTOR. */ @@ -8918,6 +8931,9 @@ potential_constant_expression_1 (tree t, sub-object of such an object; */ return RECUR (TREE_OPERAND (t, 0), rval); + case EXCESS_PRECISION_EXPR: + return RECUR (TREE_OPERAND (t, 0), rval); + case VAR_DECL: if (DECL_HAS_VALUE_EXPR_P (t)) { --- gcc/cp/pt.cc.jj 2022-10-11 09:59:39.698513133 +0200 +++ gcc/cp/pt.cc 2022-10-11 10:06:55.792412420 +0200 @@ -17401,6 +17401,15 @@ tsubst_copy (tree t, tree args, tsubst_f return r; } + case EXCESS_PRECISION_EXPR: + { + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); + if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR) + return op0; + return build1_loc (EXPR_LOCATION (t), code, type, op0); + } + case COMPONENT_REF: { tree object; @@ -20429,6 +20438,16 @@ tsubst_copy_and_build (tree t, templated_operator_saved_lookups (t), complain|decltype_flag)); + case EXCESS_PRECISION_EXPR: + { + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + tree op0 = RECUR (TREE_OPERAND (t, 0)); + if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR) + RETURN (op0); + RETURN (build1_loc (input_location, EXCESS_PRECISION_EXPR, + type, op0)); + } + case FIX_TRUNC_EXPR: /* convert_like should have created an IMPLICIT_CONV_EXPR. */ gcc_unreachable (); --- gcc/cp/cp-tree.h.jj 2022-10-11 09:59:39.512515736 +0200 +++ gcc/cp/cp-tree.h 2022-10-11 10:06:55.793412406 +0200 @@ -6766,6 +6766,8 @@ 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/cp-gimplify.cc.jj 2022-10-11 09:59:39.482516155 +0200 +++ gcc/cp/cp-gimplify.cc 2022-10-11 10:06:55.794412392 +0200 @@ -2522,6 +2522,11 @@ cp_fold (tree x) break; + case EXCESS_PRECISION_EXPR: + op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops); + x = fold_convert_loc (EXPR_LOCATION (x), TREE_TYPE (x), op0); + break; + case INDIRECT_REF: /* We don't need the decltype(auto) obfuscation anymore. */ if (REF_PARENTHESIZED_P (x)) --- gcc/cp/typeck.cc.jj 2022-10-11 09:59:39.738512574 +0200 +++ gcc/cp/typeck.cc 2022-10-11 10:24:31.875679017 +0200 @@ -4603,11 +4603,16 @@ convert_arguments (tree typelist, vec +#ifdef __cplusplus +extern "C" { +#endif extern void abort (void); extern void exit (int); +#ifdef __cplusplus +} +#endif volatile float f1 = 1.0f; volatile float f2 = 0x1.0p-30f; --- gcc/testsuite/gcc.target/i386/excess-precision-2.c.jj 2022-10-11 09:59:39.877510630 +0200 +++ gcc/testsuite/gcc.target/i386/excess-precision-2.c 2022-10-11 10:06:55.796412364 +0200 @@ -4,8 +4,14 @@ #include +#ifdef __cplusplus +extern "C" { +#endif extern void abort (void); extern void exit (int); +#ifdef __cplusplus +} +#endif volatile long double ldadd1 = 1.0l + 0x1.0p-30l; volatile long double ld11f = 1.1f; --- gcc/testsuite/gcc.target/i386/excess-precision-3.c.jj 2022-10-11 09:59:39.894510392 +0200 +++ gcc/testsuite/gcc.target/i386/excess-precision-3.c 2022-10-11 10:06:55.796412364 +0200 @@ -6,8 +6,14 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif extern void abort (void); extern void exit (int); +#ifdef __cplusplus +} +#endif volatile float f1 = 1.0f; volatile float f2 = 0x1.0p-30f; @@ -100,6 +106,7 @@ check_double (double d) abort (); } +#ifndef __cplusplus static inline void check_float_nonproto (f) float f; @@ -115,6 +122,7 @@ check_double_nonproto (d) if (d != dadd2) abort (); } +#endif static void check_double_va (int i, ...) @@ -132,9 +140,11 @@ test_call (void) check_float (f1 + f2); check_double (d1 + d2 + d3); check_double (f1 + f2 + f3); +#ifndef __cplusplus check_float_nonproto (f1 + f2); check_double_nonproto (d1 + d2 + d3); check_double_nonproto (f1 + f2 + f3); +#endif check_double_va (0, d1 + d2 + d3); check_double_va (0, f1 + f2 + f3); } --- gcc/testsuite/gcc.target/i386/excess-precision-7.c.jj 2022-10-11 09:59:39.917510070 +0200 +++ gcc/testsuite/gcc.target/i386/excess-precision-7.c 2022-10-11 10:06:55.796412364 +0200 @@ -4,8 +4,14 @@ /* { dg-do run } */ /* { dg-options "-std=c99 -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-9.c.jj 2022-10-11 09:59:39.947509650 +0200 +++ gcc/testsuite/gcc.target/i386/excess-precision-9.c 2022-10-11 10:06:55.796412364 +0200 @@ -3,8 +3,14 @@ /* { dg-do run } */ /* { dg-options "-std=c99 -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-1.C.jj 2022-10-11 10:06:55.796412364 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-1.C 2022-10-11 10:06:55.796412364 +0200 @@ -0,0 +1,6 @@ +// Excess precision tests. Test that excess precision is carried +// through various operations. +// { dg-do run } +// { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" } + +#include "../../gcc.target/i386/excess-precision-1.c" --- gcc/testsuite/g++.target/i386/excess-precision-2.C.jj 2022-10-11 10:06:55.796412364 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-2.C 2022-10-11 10:06:55.796412364 +0200 @@ -0,0 +1,5 @@ +// Excess precision tests. Test excess precision of constants. +// { dg-do run } +// { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" } + +#include "../../gcc.target/i386/excess-precision-2.c" --- gcc/testsuite/g++.target/i386/excess-precision-3.C.jj 2022-10-11 10:06:55.796412364 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-3.C 2022-10-11 10:06:55.796412364 +0200 @@ -0,0 +1,6 @@ +// Excess precision tests. Test excess precision is removed when +// necessary. +// { dg-do run } +// { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" } + +#include "../../gcc.target/i386/excess-precision-3.c" --- gcc/testsuite/g++.target/i386/excess-precision-4.C.jj 2022-10-11 10:06:55.796412364 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-4.C 2022-10-11 10:06:55.796412364 +0200 @@ -0,0 +1,7 @@ +// Excess precision tests. Test diagnostics for excess precision of +// constants. +// { dg-do compile } +// { dg-options "-mfpmath=387 -fexcess-precision=standard" } + +float f = 0.0f * 1e50f; // { dg-warning "floating constant exceeds range of 'float'" } +double d = 0.0 * 1e400; // { dg-warning "floating constant exceeds range of 'double'" } --- gcc/testsuite/g++.target/i386/excess-precision-5.C.jj 2022-10-11 10:06:55.797412351 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-5.C 2022-10-11 10:06:55.797412351 +0200 @@ -0,0 +1,32 @@ +// Excess precision tests. Verify excess precision doesn't affect +// actual types. +// { dg-do compile { target c++11 } } +// { dg-options "-mfpmath=387 -fexcess-precision=standard" } + +namespace std { + template struct integral_constant { + static constexpr T value = v; + }; + typedef integral_constant false_type; + typedef integral_constant true_type; + template + struct is_same : std::false_type {}; + template + struct is_same : std::true_type {}; +} + +float f; +double d; + +void +test_types (void) +{ +#define CHECK_FLOAT(E) static_assert (std::is_same ::value, "") +#define CHECK_DOUBLE(E) static_assert (std::is_same ::value, "") + CHECK_FLOAT (f + f); + CHECK_DOUBLE (d + d); + CHECK_FLOAT (f * f / f); + CHECK_DOUBLE (d * d / d); + CHECK_FLOAT (f ? f - f : f); + CHECK_DOUBLE (d ? d - d : d); +} --- gcc/testsuite/g++.target/i386/excess-precision-6.C.jj 2022-10-11 10:06:55.797412351 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-6.C 2022-10-11 10:06:55.797412351 +0200 @@ -0,0 +1,19 @@ +// Excess precision tests. Make sure sqrt is not inlined for float or +// double. +// { dg-do compile } +// { dg-options "-mfpmath=387 -O2 -fno-math-errno -fexcess-precision=standard" } + +float f; +double d; + +float fr; +double dr; + +void +test_builtins (void) +{ + fr = __builtin_sqrtf (f); + dr = __builtin_sqrt (d); +} + +// { dg-final { scan-assembler-not "fsqrt" } } --- gcc/testsuite/g++.target/i386/excess-precision-7.C.jj 2022-10-11 10:06:55.797412351 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-7.C 2022-10-11 10:06:55.797412351 +0200 @@ -0,0 +1,7 @@ +// 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-11 10:06:55.797412351 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-8.C 2022-10-11 10:06:55.797412351 +0200 @@ -0,0 +1,105 @@ +// Excess precision tests. Test excess precision is removed when +// necessary. +// { dg-do run } +// { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" } + +#include +#include + +extern "C" void abort (); + +volatile float f1 = 1.0f; +volatile float f2 = 0x1.0p-30f; +volatile float f3 = 0x1.0p-60f; +volatile double d1 = 1.0; +volatile double d2 = 0x1.0p-30; +volatile double d3 = 0x1.0p-60; +volatile double d3d = 0x1.0p-52; +volatile float fadd1 = 1.0f + 0x1.0p-30f; +volatile double dadd2 = 1.0 + 0x1.0p-30 + 0x1.0p-60; +volatile double dh = 0x1.0p-24; +volatile float fha = 1.0f + 0x1.0p-23f; + +static inline void +check_float (float f) +{ + if (f != fadd1) + abort (); +} + +static inline void +check_float (double) +{ + abort (); +} + +static inline void +check_float (long double) +{ + abort (); +} + +static inline void +check_double (double d) +{ + if (d != dadd2) + abort (); +} + +static inline void +check_double (long double) +{ + abort (); +} + +static inline void +check_float2 (float f) +{ + if (f != fha) + abort (); +} + +struct S { + S () {} + S (float f) { if (f != fadd1) abort (); } +}; + +struct T { + T () {} + T (double d) { if (d != dadd2) abort (); } +}; + +static inline void +check_float3 (S) +{ +} + +static inline void +check_double2 (T) +{ +} + +void +test_call () +{ + check_float (f1 + f2); + check_double (f1 + f2); + check_double (d1 + d2 + d3); + /* Verify rounding direct to float without double rounding. */ + if (sizeof (long double) > sizeof (double)) + check_float2 (d1 + dh + d3); + else + check_float2 (d1 + dh + d3d); + check_float3 (f1 + f2); + check_double2 (f1 + f2); + check_double2 (d1 + d2 + d3); + S s1 = static_cast (f1 + f2); + T t2 = static_cast (f1 + f2); + T t3 = static_cast (d1 + d2 + d3); +} + +int +main () +{ + test_call (); +} --- gcc/testsuite/g++.target/i386/excess-precision-9.C.jj 2022-10-11 10:06:55.797412351 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-9.C 2022-10-11 10:06:55.797412351 +0200 @@ -0,0 +1,6 @@ +// 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/c-c++-common/dfp/convert-bfp-10.c.jj 2020-01-12 11:54:37.003404507 +0100 +++ gcc/testsuite/c-c++-common/dfp/convert-bfp-10.c 2022-10-11 11:20:40.511702027 +0200 @@ -1,4 +1,5 @@ /* This test assumes IEEE float and double. */ +/* { dg-additional-options "-fexcess-precision=fast" } */ #include "convert.h" --- gcc/testsuite/c-c++-common/dfp/compare-eq-const.c.jj 2020-01-12 11:54:37.003404507 +0100 +++ gcc/testsuite/c-c++-common/dfp/compare-eq-const.c 2022-10-11 11:18:31.432502023 +0200 @@ -1,5 +1,6 @@ /* C99 6.5.9 Equality operators. Compare decimal float constants against each other. */ +/* { dg-additional-options "-fexcess-precision=fast" } */ #include "dfp-dbg.h" --- gcc/testsuite/g++.dg/cpp1z/constexpr-96862.C.jj 2020-09-03 20:11:34.160825160 +0200 +++ gcc/testsuite/g++.dg/cpp1z/constexpr-96862.C 2022-10-11 11:51:31.563910365 +0200 @@ -1,6 +1,6 @@ // PR c++/96862 // { dg-do compile { target c++17 } } -// { dg-additional-options "-frounding-math" } +// { dg-additional-options "-frounding-math -fexcess-precision=fast" } constexpr double a = 0x1.0p+100 + 0x1.0p-100; const double b = 0x1.0p+100 + 0x1.0p-100; --- gcc/testsuite/g++.dg/cpp1z/decomp12.C.jj 2020-01-12 11:54:37.128402621 +0100 +++ gcc/testsuite/g++.dg/cpp1z/decomp12.C 2022-10-11 11:30:05.737825169 +0200 @@ -7,13 +7,13 @@ template struct sam template struct same_type {}; int main() { - std::tuple tuple = { 1, 'a', 2.3, true }; + std::tuple tuple = { 1, 'a', 2.25, true }; auto[i, c, d, b] = tuple; same_type::type, decltype(i)>{}; same_type{}; same_type{}; same_type{}; same_type{}; - if (i != 1 || c != 'a' || d != 2.3 || b != true) + if (i != 1 || c != 'a' || d != 2.25 || b != true) __builtin_abort (); } --- gcc/testsuite/g++.dg/other/thunk1.C.jj 2020-01-12 11:54:37.218401263 +0100 +++ gcc/testsuite/g++.dg/other/thunk1.C 2022-10-11 11:30:37.350384645 +0200 @@ -1,5 +1,6 @@ // PR c++/12007 Multiple inheritance float pass by value fails // { dg-do run } +// { dg-additional-options "-fexcess-precision=fast" } extern "C" void abort (void); --- gcc/testsuite/g++.dg/vect/pr64410.cc.jj 2020-01-12 11:54:37.279400343 +0100 +++ gcc/testsuite/g++.dg/vect/pr64410.cc 2022-10-11 11:31:54.970302984 +0200 @@ -1,5 +1,6 @@ // { dg-do compile } // { dg-require-effective-target vect_double } +// { dg-additional-options "-fexcess-precision=fast" } #include #include --- gcc/testsuite/g++.dg/cpp1y/pr68180.C.jj 2020-01-12 11:54:37.121402727 +0100 +++ gcc/testsuite/g++.dg/cpp1y/pr68180.C 2022-10-11 11:50:42.324596315 +0200 @@ -1,6 +1,6 @@ // PR c++/68180 // { dg-do compile { target c++14 } } -// { dg-additional-options "-Wno-psabi" } +// { dg-additional-options "-Wno-psabi -fexcess-precision=fast" } typedef float __attribute__( ( vector_size( 16 ) ) ) float32x4_t; constexpr float32x4_t fill(float x) { --- gcc/testsuite/g++.dg/cpp0x/variadic-tuple.C.jj 2022-05-20 11:45:17.801744787 +0200 +++ gcc/testsuite/g++.dg/cpp0x/variadic-tuple.C 2022-10-11 11:28:34.282099648 +0200 @@ -1,4 +1,5 @@ // { dg-do run { target c++11 } } +// { dg-additional-options "-fexcess-precision=fast" } // An implementation of TR1's using variadic teplates // Contributed by Douglas Gregor --- gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C.jj 2020-01-12 11:54:37.087403240 +0100 +++ gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C 2022-10-11 11:27:50.009716597 +0200 @@ -18,8 +18,8 @@ int main() { Test t; B b; - B b2(4.2); + B b2(4.25); - if (t.a != 4 || b.i != 42 || b2.d != 4.2) + if (t.a != 4 || b.i != 42 || b2.d != 4.25) __builtin_abort(); } --- gcc/testsuite/g++.old-deja/g++.brendan/copy9.C.jj 2020-01-11 16:31:54.872295939 +0100 +++ gcc/testsuite/g++.old-deja/g++.brendan/copy9.C 2022-10-11 11:10:40.589067853 +0200 @@ -1,4 +1,5 @@ // { dg-do run } +// { dg-additional-options "-fexcess-precision=fast" } // GROUPS passed copy-ctors #include --- gcc/testsuite/g++.old-deja/g++.brendan/overload7.C.jj 2020-01-11 16:31:54.877295864 +0100 +++ gcc/testsuite/g++.old-deja/g++.brendan/overload7.C 2022-10-11 11:11:45.238166331 +0200 @@ -1,4 +1,5 @@ // { dg-do run } +// { dg-additional-options "-fexcess-precision=fast" } // GROUPS passed overloading extern "C" int printf (const char *, ...); Jakub