From patchwork Thu Oct 13 16:40:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 2091 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:4ac7:0:0:0:0:0 with SMTP id y7csp373033wrs; Thu, 13 Oct 2022 09:41:51 -0700 (PDT) X-Google-Smtp-Source: AMsMyM5OuLoP4ibUBz+YfqO1MyjlrKJLtb5erhb1g68DqLlCpHEnGBdcXpgnl4US1qYDU5JDxBgJ X-Received: by 2002:a17:907:1ca2:b0:78d:ec49:9c2f with SMTP id nb34-20020a1709071ca200b0078dec499c2fmr459061ejc.308.1665679311361; Thu, 13 Oct 2022 09:41:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1665679311; cv=none; d=google.com; s=arc-20160816; b=H9mMK9FJvmcg1jNRqwjcnS7ukwQe8ndkJGSIQHAZXVNZRNePk9bjzAacs4PAvuhANH puq47PEu8gpWRxV7RZkC4VWgCsKYMsnH7Od+elrhahcl8toT4Hym60HoQ9DH2O7HoHcD tW7OjzVdPZw6WkILApYms+7coyPMgENAhQrokFr8+WERwp8bRN7d2EbDYxFyqYdCFRK6 5WnwfU85AmUZHXRVxhgUb+8tFZsoHjBC0rhBRRUyA0CB/AUan+oUyVl8e/riX7lIQH6b 8ijJuBcF1uLXzevYedSt+kHtvLxbbP7L7W3t9okALOsmQ8Tn0FvOXUrdyNY0r6KzBwqW cTlQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:reply-to:from:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence :content-disposition:in-reply-to:mime-version:references:message-id :subject:to:date:dmarc-filter:delivered-to:dkim-signature :dkim-filter; bh=Sc+0icPLURXVNZ3GZmz2k6Xe4LO78QjmXy2GQq/XjDc=; b=h0i4JFDTy6B9/XV8PBxjaX42ALhjSXGByrMtFa8G6h0Ohu6cxVqhY94CJA3AEcmCzP PeS6tEp7wdmRSaLXFZrf+4e67+ozgqIKQ04d0Ifedrg9QWW6dJXDOzItYggkZdY/Ep+C WkhLjWF/WgDPxb45se0AM9lizbdJecRPIfdLJhNi7uiiYimGMptqKc9XRwJZR8ah6DBH rYNMDUQUiCma01XEp+b/9rQNFgLZQnSP33BMs/UQI5BRnISBW8tWVdk1c6vKN/5p2mi9 ly8KJ1K5xJtfga6q1ETPYjrHO/bDqEj3UEG+u0mXDMbtjYXI+DI8q2acMZp9OJHmZBVE VgRg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=nMn9+ctV; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id sa19-20020a1709076d1300b0078dcdbe650fsi133842ejc.443.2022.10.13.09.41.51 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Oct 2022 09:41:51 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=nMn9+ctV; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2802B3857C4B for ; Thu, 13 Oct 2022 16:41:50 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2802B3857C4B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1665679310; bh=Sc+0icPLURXVNZ3GZmz2k6Xe4LO78QjmXy2GQq/XjDc=; h=Date:To:Subject:References:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=nMn9+ctVkXk+IgT9rRRJ3fsCCEzmV7apx3g2/9x1yh2JcCgJJlaVxs9JVKArQQ8pL uG3GWnoZac0METyeRaDBX1S/amRwTebUzYMJ25Okgz3wVDnZ9Qr3PzW3hkTshabXNn 39J91cCBIG4e1b+Nm9icH4xkgkglplnYuZ0CmIok= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id D208C3858C55 for ; Thu, 13 Oct 2022 16:40:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D208C3858C55 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-331-2FrsaqnyO_OsRApj9oUw0g-1; Thu, 13 Oct 2022 12:40:44 -0400 X-MC-Unique: 2FrsaqnyO_OsRApj9oUw0g-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 6A747811E67; Thu, 13 Oct 2022 16:40:41 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.192.55]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 8F4F71415102; Thu, 13 Oct 2022 16:40:40 +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 29DGeamq654996 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Thu, 13 Oct 2022 18:40:37 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 29DGeaPa654995; Thu, 13 Oct 2022 18:40:36 +0200 Date: Thu, 13 Oct 2022 18:40:35 +0200 To: Jason Merrill Subject: [PATCH] c++, v2: Implement excess precision support for C++ [PR107097, PR323] Message-ID: References: MIME-Version: 1.0 In-Reply-To: X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline 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 X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jakub Jelinek via Gcc-patches From: Jakub Jelinek Reply-To: Jakub Jelinek Cc: gcc-patches@gcc.gnu.org, "Joseph S. Myers" Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1746591349322189745?= X-GMAIL-MSGID: =?utf-8?q?1746591349322189745?= On Wed, Oct 12, 2022 at 02:08:20PM -0400, Jason Merrill wrote: > > 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. > > https://eel.is/c++draft/expr#pre-6 seems identical to C99 (apart from a > stray "the"?); presumably nobody has proposed to copy the N1531 > clarifications. But since those are clarifications, I'd prefer to use our > C11+ semantics to avoid divergence between the default modes of the C and > C++ front ends. Ok, so that it is more readable and say if we decide to make e.g. C++98 behave like C99 and only C++11 and later like C11, I'm sending this as a 2 patch series, this patch is just an updated version of the previous patch (your review comments, Marek's mail and missed changes to doc/invoke.texi) and another mail will be upgrade of this to the C11 behavior. > > + 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)) > > What if semantic_result_type is error_mark_node and the other conditions > don't hold? That seems impossible, so maybe the other conditions should > move into a gcc_checking_assert? (And likewise for result_type below) Changed in all places to an assert, though previously I missed that cp_common_type on complex type(s) could have similar problem. > > @@ -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); > > It was confusing me that this mentions 1, and the magic_varargs_p comment > above mentions 2: Let's add a comment That is because removing excess precision means keeping EXCESS_PRECISION_EXPR around and preserving excess precision means removing of EXCESS_PRECISION_EXPR. > > /* Don't truncate excess precision to the semantic type. */ > > to clarify. Ok. Here is an updated patch, bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2022-10-13 Jakub Jelinek PR middle-end/323 PR c++/107097 gcc/ * doc/invoke.texi (-fexcess-precision=standard): Mention that the option now also works in C++. gcc/c-family/ * c-common.def (EXCESS_PRECISION_EXPR): Remove comment part about the tree being specific to C/ObjC. * 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. When type_after_usual_arithmetic_conversions returns error_mark_node, use gcc_checking_assert that it is because of uncomparable floating point ranks instead of checking all those conditions and make it work also with complex types. (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 (cp_common_type): For COMPLEX_TYPEs, return error_mark_node if recursive call returned it. (convert_arguments): For magic 1 remove EXCESS_PRECISION_EXPR. (cp_build_binary_op): Add excess precision support. When cp_common_type returns error_mark_node, use gcc_checking_assert that it is because of uncomparable floating point ranks instead of checking all those conditions and make it work also with complex types. (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-9.C: New test. * g++.target/i386/excess-precision-11.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/vect/pr89653.cc: 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. Jakub --- gcc/doc/invoke.texi.jj 2022-10-12 22:06:36.029279569 +0200 +++ gcc/doc/invoke.texi 2022-10-13 16:49:19.313221247 +0200 @@ -13785,18 +13785,18 @@ default, @option{-fexcess-precision=fast operations may be carried out in a wider precision than the types specified in the source if that would result in faster code, and it is unpredictable when rounding to the types specified in the source code takes place. -When compiling C, if @option{-fexcess-precision=standard} is specified then -excess precision follows the rules specified in ISO C99; in particular, +When compiling C or C++, if @option{-fexcess-precision=standard} is specified +then excess precision follows the rules specified in ISO C99 or C++; in particular, both casts and assignments cause values to be rounded to their semantic types (whereas @option{-ffloat-store} only affects -assignments). This option is enabled by default for C if a strict -conformance option such as @option{-std=c99} is used. +assignments). This option is enabled by default for C or C++ if a strict +conformance option such as @option{-std=c99} or @option{-std=c++17} is used. @option{-ffast-math} enables @option{-fexcess-precision=fast} by default regardless of whether a strict conformance option is used. @opindex mfpmath @option{-fexcess-precision=standard} is not implemented for languages -other than C. On the x86, it has no effect if @option{-mfpmath=sse} +other than C or C++. On the x86, it has no effect if @option{-mfpmath=sse} or @option{-mfpmath=sse+387} is specified; in the former case, IEEE semantics apply without excess precision, and in the latter, rounding is unpredictable. --- gcc/c-family/c-common.def.jj 2022-01-11 22:31:40.595769716 +0100 +++ gcc/c-family/c-common.def 2022-10-13 16:44:13.408422330 +0200 @@ -38,10 +38,9 @@ along with GCC; see the file COPYING3. not. */ DEFTREECODE (C_MAYBE_CONST_EXPR, "c_maybe_const_expr", tcc_expression, 2) -/* An EXCESS_PRECISION_EXPR, currently only used for C and Objective - C, represents an expression evaluated in greater range or precision - than its type. The type of the EXCESS_PRECISION_EXPR is the - semantic type while the operand represents what is actually being +/* An EXCESS_PRECISION_EXPR represents an expression evaluated in greater + range or precision than its type. The type of the EXCESS_PRECISION_EXPR + is the semantic type while the operand represents what is actually being evaluated. */ DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1) --- gcc/c-family/c-opts.cc.jj 2022-10-11 14:49:41.396226397 +0200 +++ gcc/c-family/c-opts.cc 2022-10-13 09:35:27.829243895 +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 14:49:41.328227329 +0200 +++ gcc/c-family/c-lex.cc 2022-10-13 09:35:27.900242917 +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-13 08:40:37.991533161 +0200 +++ gcc/cp/parser.cc 2022-10-13 09:35:27.912242752 +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 14:49:41.705222167 +0200 +++ gcc/cp/cvt.cc 2022-10-13 09:35:27.956242146 +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-13 08:41:04.735165185 +0200 +++ gcc/cp/call.cc 2022-10-13 16:01:37.241523281 +0200 @@ -5359,6 +5359,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; @@ -5392,6 +5393,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); } @@ -5550,6 +5554,52 @@ 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 t1 = arg2_type; + tree t2 = arg3_type; + 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", + 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 @@ -5557,8 +5607,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 @@ -5850,14 +5898,20 @@ build_conditional_expr (const op_locatio /* In this case, there is always a common type. */ result_type = type_after_usual_arithmetic_conversions (arg2_type, arg3_type); - if (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 (result_type == error_mark_node) { + tree t1 = arg2_type; + tree t2 = arg3_type; + 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", @@ -5922,6 +5976,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); } @@ -6009,9 +6067,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; } @@ -7875,7 +7939,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 @@ -7891,7 +7955,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; @@ -7968,7 +8032,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, @@ -7983,13 +8048,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; } @@ -8109,6 +8176,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 @@ -8148,7 +8217,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) @@ -8216,7 +8286,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; @@ -8475,7 +8545,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); @@ -8509,7 +8587,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, @@ -8532,7 +8610,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; @@ -8545,7 +8624,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. */ @@ -8556,7 +8635,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 @@ -8587,6 +8666,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); } @@ -8893,9 +8974,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) @@ -8914,7 +8995,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; } @@ -9717,7 +9806,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); @@ -9725,8 +9814,13 @@ 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); + { + /* Don't truncate excess precision to the semantic type. */ + 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))) @@ -13004,7 +13098,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-12 17:51:00.909944772 +0200 +++ gcc/cp/constexpr.cc 2022-10-13 09:35:27.989241691 +0200 @@ -7598,6 +7598,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. */ @@ -8898,6 +8911,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-13 08:40:38.010532899 +0200 +++ gcc/cp/pt.cc 2022-10-13 09:46:41.112966988 +0200 @@ -17412,6 +17412,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; @@ -20440,6 +20449,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 (EXPR_LOCATION (t), 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-13 08:41:04.737165157 +0200 +++ gcc/cp/cp-tree.h 2022-10-13 09:35:27.999241554 +0200 @@ -6793,6 +6793,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-13 08:40:37.954533670 +0200 +++ gcc/cp/cp-gimplify.cc 2022-10-13 09:35:28.000241540 +0200 @@ -2515,6 +2515,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-13 08:41:04.780164565 +0200 +++ gcc/cp/typeck.cc 2022-10-13 18:36:08.223309058 +0200 @@ -439,6 +439,8 @@ cp_common_type (tree t1, tree t2) tree subtype = type_after_usual_arithmetic_conversions (subtype1, subtype2); + if (subtype == error_mark_node) + return subtype; if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype) return build_type_attribute_variant (t1, attributes); else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype) @@ -4603,11 +4605,17 @@ 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 14:49:42.439212118 +0200 +++ gcc/testsuite/gcc.target/i386/excess-precision-2.c 2022-10-13 09:35:28.037241031 +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 14:49:42.456211885 +0200 +++ gcc/testsuite/gcc.target/i386/excess-precision-3.c 2022-10-13 09:35:28.054240796 +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 14:49:42.456211885 +0200 +++ gcc/testsuite/gcc.target/i386/excess-precision-7.c 2022-10-13 09:35:28.070240576 +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 14:49:42.542210707 +0200 +++ gcc/testsuite/gcc.target/i386/excess-precision-9.c 2022-10-13 09:35:28.078240466 +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-13 09:35:28.078240466 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-1.C 2022-10-13 09:35:28.078240466 +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-13 09:35:28.079240452 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-2.C 2022-10-13 09:35:28.079240452 +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-13 09:35:28.079240452 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-3.C 2022-10-13 09:35:28.079240452 +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-13 09:35:28.079240452 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-4.C 2022-10-13 09:35:28.079240452 +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-13 09:35:28.079240452 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-5.C 2022-10-13 09:35:28.079240452 +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-13 09:35:28.080240438 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-6.C 2022-10-13 09:35:28.080240438 +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-13 09:35:28.080240438 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-7.C 2022-10-13 09:35:28.080240438 +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-9.C.jj 2022-10-13 09:35:28.080240438 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-9.C 2022-10-13 09:35:28.080240438 +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/g++.target/i386/excess-precision-11.C.jj 2022-10-13 09:35:28.080240438 +0200 +++ gcc/testsuite/g++.target/i386/excess-precision-11.C 2022-10-13 09:35:28.080240438 +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/c-c++-common/dfp/convert-bfp-10.c.jj 2022-10-11 14:49:42.046217498 +0200 +++ gcc/testsuite/c-c++-common/dfp/convert-bfp-10.c 2022-10-13 09:35:28.092240273 +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 2022-10-11 14:49:42.024217800 +0200 +++ gcc/testsuite/c-c++-common/dfp/compare-eq-const.c 2022-10-13 09:35:28.104240108 +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 2022-10-11 14:49:42.188215554 +0200 +++ gcc/testsuite/g++.dg/cpp1z/constexpr-96862.C 2022-10-13 09:35:28.112239998 +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 2022-10-11 14:49:42.193215485 +0200 +++ gcc/testsuite/g++.dg/cpp1z/decomp12.C 2022-10-13 09:35:28.113239984 +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 2022-10-11 14:49:42.224215061 +0200 +++ gcc/testsuite/g++.dg/other/thunk1.C 2022-10-13 09:35:28.120239887 +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 2022-10-11 14:49:42.264214513 +0200 +++ gcc/testsuite/g++.dg/vect/pr64410.cc 2022-10-13 09:35:28.121239874 +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/vect/pr89653.cc.jj 2020-01-12 11:54:37.280400328 +0100 +++ gcc/testsuite/g++.dg/vect/pr89653.cc 2022-10-13 10:01:35.564649879 +0200 @@ -1,5 +1,6 @@ // { dg-do compile } // { dg-require-effective-target vect_double } +// { dg-additional-options "-fexcess-precision=fast" } #include --- gcc/testsuite/g++.dg/cpp1y/pr68180.C.jj 2022-10-11 14:49:42.168215827 +0200 +++ gcc/testsuite/g++.dg/cpp1y/pr68180.C 2022-10-13 09:35:28.121239874 +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-10-11 14:49:42.135216279 +0200 +++ gcc/testsuite/g++.dg/cpp0x/variadic-tuple.C 2022-10-13 09:35:28.130239750 +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 2022-10-11 14:49:42.104216704 +0200 +++ gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C 2022-10-13 09:35:28.140239612 +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 2022-10-11 14:49:42.304213966 +0200 +++ gcc/testsuite/g++.old-deja/g++.brendan/copy9.C 2022-10-13 09:35:28.152239447 +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 2022-10-11 14:49:42.327213651 +0200 +++ gcc/testsuite/g++.old-deja/g++.brendan/overload7.C 2022-10-13 09:35:28.152239447 +0200 @@ -1,4 +1,5 @@ // { dg-do run } +// { dg-additional-options "-fexcess-precision=fast" } // GROUPS passed overloading extern "C" int printf (const char *, ...);