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 90C843858C56 for ; Thu, 13 Oct 2022 19:28:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 90C843858C56 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=1665689287; h=from:from: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: in-reply-to:in-reply-to:references:references; bh=OFCqiN6lhDVkLmlh4A1SZOGc7d0Y65KvGtRwRzbisV8=; b=ANMyLcoQXGk0P2fW29pZ/dOoLPWJVSDadjYZ7+1TtJxK4B93GQ7HrxNGDsezG1cN3P/zMg FX42vCQFElicRgzyqFJMSETeHhsQVNrSiZm+uSIt0O8ggLrpQMrSyVgH6tdeXihfIlPSEi wlg5t1TJ+rXChePoVzr298GHvbj73ic= Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-58-RRIVdCBoOZ2oEiojr8zibw-1; Thu, 13 Oct 2022 15:28:06 -0400 X-MC-Unique: RRIVdCBoOZ2oEiojr8zibw-1 Received: by mail-qt1-f199.google.com with SMTP id k9-20020ac85fc9000000b00399e6517f9fso2247326qta.18 for ; Thu, 13 Oct 2022 12:28:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=OFCqiN6lhDVkLmlh4A1SZOGc7d0Y65KvGtRwRzbisV8=; b=rzKLyfs4fW3mGLAw3o68JCtXSgR+yBSmoyJTkx13KsMgMxPhIUVii3NIOoI7hE1pfz nTDIQ20Xidz3hwEPNy4aLTKdRiYM5Eo7jYJWaH1cSx4x8pPuvdA44bGmGLzOm5n0pPDm b2QJH2aZza3ziTvRjk69OzYmS0N2ZXO4O1ix9/L6Rle5yg9GL7dJh6pGew6tF8nVVwId 5EeX5Zhmoiv0a7KdCy02leobOgjnCiA0wBZ3wPnbAKsaKXsuip8eVG8OIvZG6v/M2pdk fIq8KImqgrLZiuP/e2vYtGdxltVJ2J4sb5+VClwOLQfOS0+dgHqC++tizdB1RkHHrkK/ CTeQ== X-Gm-Message-State: ACrzQf3kyDrejUmbFNhOIFwi0NtWf1r3enq/UOcqUvdxjikEzwa/kbGh rdRcMoxGhpAx686Xczm8EeJ+ssDsK5msQ7t/rS74vSgaEXIdWHTGRuvY81oJupKokAJUCvJfGMb BGyAtXF3AdSnk63XkOg== X-Received: by 2002:a05:622a:1212:b0:39c:bece:df15 with SMTP id y18-20020a05622a121200b0039cbecedf15mr1290974qtx.124.1665689284478; Thu, 13 Oct 2022 12:28:04 -0700 (PDT) X-Google-Smtp-Source: AMsMyM6rw2ReDlMonMCEM/+1OI4CDCBvd6POCKgQHTqMmGtqtiAo5/w3LhdoAu/1UtWmPQAdkz1YLg== X-Received: by 2002:a05:622a:1212:b0:39c:bece:df15 with SMTP id y18-20020a05622a121200b0039cbecedf15mr1290921qtx.124.1665689283513; Thu, 13 Oct 2022 12:28:03 -0700 (PDT) Received: from [192.168.1.101] (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id z2-20020ac87102000000b0039cbe823f3csm544237qto.10.2022.10.13.12.28.02 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 13 Oct 2022 12:28:02 -0700 (PDT) Message-ID: Date: Thu, 13 Oct 2022 15:28:02 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.3.2 Subject: Re: [PATCH] c++, v2: Implement excess precision support for C++ [PR107097, PR323] To: Jakub Jelinek Cc: "Joseph S. Myers" , gcc-patches@gcc.gnu.org References: From: Jason Merrill In-Reply-To: X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-7.3 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,KAM_SHORT,NICE_REPLY_A,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: On 10/13/22 12:40, Jakub Jelinek wrote: > 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. > > --- 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; I notice you're assuming this will have the right type, which seems likely, but I wonder about either checking_asserting that or setting its type to the one we just tsubsted? OK with or without that change, along with the followup patch. > + 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 } > else > { > - if (fndecl && magic_varargs_p (fndecl)) > - /* Don't do ellipsis conversion for __built_in_constant_p > - as this will result in spurious errors for non-trivial > - types. */ > - val = require_complete_type (val, complain); > + int magic = fndecl ? magic_varargs_p (fndecl) : 0; > + if (magic) > + { > + /* Don't truncate excess precision to the semantic type. */ > + if (magic == 1 && TREE_CODE (val) == EXCESS_PRECISION_EXPR) > + val = TREE_OPERAND (val, 0); > + /* Don't do ellipsis conversion for __built_in_constant_p > + as this will result in spurious errors for non-trivial > + types. */ > + val = require_complete_type (val, complain); > + } > else > val = convert_arg_to_ellipsis (val, complain); > > @@ -5057,7 +5065,7 @@ cp_build_binary_op (const op_location_t > { > tree op0, op1; > enum tree_code code0, code1; > - tree type0, type1; > + tree type0, type1, orig_type0, orig_type1; > const char *invalid_op_diag; > > /* Expression code to give to the expression when it is built. > @@ -5069,6 +5077,10 @@ cp_build_binary_op (const op_location_t > In the simplest cases this is the common type of the arguments. */ > tree result_type = NULL_TREE; > > + /* When the computation is in excess precision, the type of the > + final EXCESS_PRECISION_EXPR. */ > + tree semantic_result_type = NULL; > + > /* Nonzero means operands have already been type-converted > in whatever way is necessary. > Zero means they need to be converted to RESULT_TYPE. */ > @@ -5116,6 +5128,10 @@ cp_build_binary_op (const op_location_t > /* Tree holding instrumentation expression. */ > tree instrument_expr = NULL_TREE; > > + /* True means this is an arithmetic operation that may need excess > + precision. */ > + bool may_need_excess_precision; > + > /* Apply default conversions. */ > op0 = resolve_nondeduced_context (orig_op0, complain); > op1 = resolve_nondeduced_context (orig_op1, complain); > @@ -5167,8 +5183,8 @@ cp_build_binary_op (const op_location_t > } > } > > - type0 = TREE_TYPE (op0); > - type1 = TREE_TYPE (op1); > + orig_type0 = type0 = TREE_TYPE (op0); > + orig_type1 = type1 = TREE_TYPE (op1); > > /* The expression codes of the data types of the arguments tell us > whether the arguments are integers, floating, pointers, etc. */ > @@ -5201,6 +5217,47 @@ cp_build_binary_op (const op_location_t > return error_mark_node; > } > > + switch (code) > + { > + case PLUS_EXPR: > + case MINUS_EXPR: > + case MULT_EXPR: > + case TRUNC_DIV_EXPR: > + case CEIL_DIV_EXPR: > + case FLOOR_DIV_EXPR: > + case ROUND_DIV_EXPR: > + case EXACT_DIV_EXPR: > + may_need_excess_precision = true; > + break; > + default: > + may_need_excess_precision = false; > + break; > + } > + if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR) > + { > + op0 = TREE_OPERAND (op0, 0); > + type0 = TREE_TYPE (op0); > + } > + else if (may_need_excess_precision > + && (code0 == REAL_TYPE || code0 == COMPLEX_TYPE)) > + if (tree eptype = excess_precision_type (type0)) > + { > + type0 = eptype; > + op0 = convert (eptype, op0); > + } > + if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR) > + { > + op1 = TREE_OPERAND (op1, 0); > + type1 = TREE_TYPE (op1); > + } > + else if (may_need_excess_precision > + && (code1 == REAL_TYPE || code1 == COMPLEX_TYPE)) > + if (tree eptype = excess_precision_type (type1)) > + { > + type1 = eptype; > + op1 = convert (eptype, op1); > + } > + > /* Issue warnings about peculiar, but valid, uses of NULL. */ > if ((null_node_p (orig_op0) || null_node_p (orig_op1)) > /* It's reasonable to use pointer values as operands of && > @@ -5240,7 +5297,7 @@ cp_build_binary_op (const op_location_t > op0 = convert (TREE_TYPE (type1), op0); > op0 = save_expr (op0); > op0 = build_vector_from_val (type1, op0); > - type0 = TREE_TYPE (op0); > + orig_type0 = type0 = TREE_TYPE (op0); > code0 = TREE_CODE (type0); > converted = 1; > break; > @@ -5250,7 +5307,7 @@ cp_build_binary_op (const op_location_t > op1 = convert (TREE_TYPE (type0), op1); > op1 = save_expr (op1); > op1 = build_vector_from_val (type0, op1); > - type1 = TREE_TYPE (op1); > + orig_type1 = type1 = TREE_TYPE (op1); > code1 = TREE_CODE (type1); > converted = 1; > break; > @@ -6067,12 +6124,20 @@ cp_build_binary_op (const op_location_t > && (shorten || common || short_compare)) > { > result_type = cp_common_type (type0, type1); > - if (result_type == error_mark_node > - && code0 == REAL_TYPE > - && code1 == REAL_TYPE > - && (extended_float_type_p (type0) || extended_float_type_p (type1)) > - && cp_compare_floating_point_conversion_ranks (type0, type1) == 3) > + if (result_type == error_mark_node) > { > + tree t1 = type0; > + tree t2 = type1; > + 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) > { > rich_location richloc (line_table, location); > @@ -6091,6 +6156,33 @@ cp_build_binary_op (const op_location_t > TREE_TYPE (orig_op1)); > } > } > + if (may_need_excess_precision > + && (orig_type0 != type0 || orig_type1 != type1)) > + { > + gcc_assert (common); > + semantic_result_type = cp_common_type (orig_type0, orig_type1); > + if (semantic_result_type == error_mark_node) > + { > + tree t1 = orig_type0; > + tree t2 = orig_type1; > + 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) > + { > + rich_location richloc (line_table, location); > + binary_op_error (&richloc, code, type0, type1); > + } > + return error_mark_node; > + } > + } > > if (code == SPACESHIP_EXPR) > { > @@ -6181,6 +6273,8 @@ cp_build_binary_op (const op_location_t > build_type ? build_type : result_type, > NULL_TREE, op1); > TREE_OPERAND (tmp, 0) = op0; > + if (semantic_result_type) > + tmp = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, tmp); > return tmp; > } > > @@ -6268,6 +6362,9 @@ cp_build_binary_op (const op_location_t > } > } > result = build2 (COMPLEX_EXPR, result_type, real, imag); > + if (semantic_result_type) > + result = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, > + result); > return result; > } > > @@ -6363,9 +6460,11 @@ cp_build_binary_op (const op_location_t > { > warning_sentinel w (warn_sign_conversion, short_compare); > if (!same_type_p (TREE_TYPE (op0), result_type)) > - op0 = cp_convert_and_check (result_type, op0, complain); > + op0 = cp_ep_convert_and_check (result_type, op0, > + semantic_result_type, complain); > if (!same_type_p (TREE_TYPE (op1), result_type)) > - op1 = cp_convert_and_check (result_type, op1, complain); > + op1 = cp_ep_convert_and_check (result_type, op1, > + semantic_result_type, complain); > > if (op0 == error_mark_node || op1 == error_mark_node) > return error_mark_node; > @@ -6435,6 +6534,9 @@ cp_build_binary_op (const op_location_t > if (resultcode == SPACESHIP_EXPR && !processing_template_decl) > result = get_target_expr (result, complain); > > + if (semantic_result_type) > + result = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, result); > + > if (!c_inhibit_evaluation_warnings) > { > if (!processing_template_decl) > @@ -7161,6 +7263,7 @@ cp_build_unary_op (enum tree_code code, > tree arg = xarg; > location_t location = cp_expr_loc_or_input_loc (arg); > tree argtype = 0; > + tree eptype = NULL_TREE; > const char *errstring = NULL; > tree val; > const char *invalid_op_diag; > @@ -7181,6 +7284,12 @@ cp_build_unary_op (enum tree_code code, > return error_mark_node; > } > > + if (TREE_CODE (arg) == EXCESS_PRECISION_EXPR) > + { > + eptype = TREE_TYPE (arg); > + arg = TREE_OPERAND (arg, 0); > + } > + > switch (code) > { > case UNARY_PLUS_EXPR: > @@ -7276,8 +7385,11 @@ cp_build_unary_op (enum tree_code code, > > case REALPART_EXPR: > case IMAGPART_EXPR: > - arg = build_real_imag_expr (input_location, code, arg); > - return arg; > + val = build_real_imag_expr (input_location, code, arg); > + if (eptype && TREE_CODE (eptype) == COMPLEX_EXPR) > + val = build1_loc (input_location, EXCESS_PRECISION_EXPR, > + TREE_TYPE (eptype), val); > + return val; > > case PREINCREMENT_EXPR: > case POSTINCREMENT_EXPR: > @@ -7288,7 +7400,7 @@ cp_build_unary_op (enum tree_code code, > > val = unary_complex_lvalue (code, arg); > if (val != 0) > - return val; > + goto return_build_unary_op; > > arg = mark_lvalue_use (arg); > > @@ -7304,8 +7416,8 @@ cp_build_unary_op (enum tree_code code, > real = cp_build_unary_op (code, real, true, complain); > if (real == error_mark_node || imag == error_mark_node) > return error_mark_node; > - return build2 (COMPLEX_EXPR, TREE_TYPE (arg), > - real, imag); > + val = build2 (COMPLEX_EXPR, TREE_TYPE (arg), real, imag); > + goto return_build_unary_op; > } > > /* Report invalid types. */ > @@ -7468,7 +7580,7 @@ cp_build_unary_op (enum tree_code code, > val = build2 (code, TREE_TYPE (arg), arg, inc); > > TREE_SIDE_EFFECTS (val) = 1; > - return val; > + goto return_build_unary_op; > } > > case ADDR_EXPR: > @@ -7484,7 +7596,11 @@ cp_build_unary_op (enum tree_code code, > { > if (argtype == 0) > argtype = TREE_TYPE (arg); > - return build1 (code, argtype, arg); > + val = build1 (code, argtype, arg); > + return_build_unary_op: > + if (eptype) > + val = build1 (EXCESS_PRECISION_EXPR, eptype, val); > + return val; > } > > if (complain & tf_error) > @@ -7875,6 +7991,15 @@ cp_build_compound_expr (tree lhs, tree r > if (lhs == error_mark_node || rhs == error_mark_node) > return error_mark_node; > > + if (TREE_CODE (lhs) == EXCESS_PRECISION_EXPR) > + lhs = TREE_OPERAND (lhs, 0); > + tree eptype = NULL_TREE; > + if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) > + { > + eptype = TREE_TYPE (rhs); > + rhs = TREE_OPERAND (rhs, 0); > + } > + > if (TREE_CODE (rhs) == TARGET_EXPR) > { > /* If the rhs is a TARGET_EXPR, then build the compound > @@ -7885,6 +8010,8 @@ cp_build_compound_expr (tree lhs, tree r > init = build2 (COMPOUND_EXPR, TREE_TYPE (init), lhs, init); > TREE_OPERAND (rhs, 1) = init; > > + if (eptype) > + rhs = build1 (EXCESS_PRECISION_EXPR, eptype, rhs); > return rhs; > } > > @@ -7896,7 +8023,10 @@ cp_build_compound_expr (tree lhs, tree r > return error_mark_node; > } > > - return build2 (COMPOUND_EXPR, TREE_TYPE (rhs), lhs, rhs); > + tree ret = build2 (COMPOUND_EXPR, TREE_TYPE (rhs), lhs, rhs); > + if (eptype) > + ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret); > + return ret; > } > > /* Issue a diagnostic message if casting from SRC_TYPE to DEST_TYPE > @@ -8180,7 +8310,11 @@ build_static_cast_1 (location_t loc, tre > > Any expression can be explicitly converted to type cv void. */ > if (VOID_TYPE_P (type)) > - return convert_to_void (expr, ICV_CAST, complain); > + { > + if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR) > + expr = TREE_OPERAND (expr, 0); > + return convert_to_void (expr, ICV_CAST, complain); > + } > > /* [class.abstract] > An abstract class shall not be used ... as the type of an explicit > @@ -8259,6 +8393,8 @@ build_static_cast_1 (location_t loc, tre > { > if (processing_template_decl) > return expr; > + if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR) > + expr = TREE_OPERAND (expr, 0); > return ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL, complain); > } > > --- gcc/testsuite/gcc.target/i386/excess-precision-1.c.jj 2022-10-11 14:49:42.367213104 +0200 > +++ gcc/testsuite/gcc.target/i386/excess-precision-1.c 2022-10-13 09:35:28.016241320 +0200 > @@ -5,8 +5,14 @@ > > #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; > --- 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 *, ...); > > > > Jakub >