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 2FFD13858D38 for ; Wed, 12 Oct 2022 18:08:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2FFD13858D38 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=1665598105; 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=+VodEme3mWV5936v0hx6ghKllwScclFQrq1aH2FysgY=; b=OG+kH25lF8T3v1oP45uJp8XI3YPABxBBTAqRluU5Hte9hf91evfgFUA5XzXFzBzUKrYLUf 2CyBFTUb2i+VHU0AEEFbfCEzp19HCsol7T7ihcNwv5xsQH2z8VHg/JDbPCUKswI7Sk/p/o 0QMaTQnGwpH2HNFiJobQYSQ2tYFyYM0= Received: from mail-qk1-f199.google.com (mail-qk1-f199.google.com [209.85.222.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-60-YCI1qc8KMH62PEdgnTx7Qw-1; Wed, 12 Oct 2022 14:08:24 -0400 X-MC-Unique: YCI1qc8KMH62PEdgnTx7Qw-1 Received: by mail-qk1-f199.google.com with SMTP id x22-20020a05620a259600b006b552a69231so14869833qko.18 for ; Wed, 12 Oct 2022 11:08:24 -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=+VodEme3mWV5936v0hx6ghKllwScclFQrq1aH2FysgY=; b=c/XaHzHs+VlxeFlRawdUb53lZWw0uPMcySD2Bw9givYxRD7hkFmfc2wdzMuzd4nSJy jHP2gdnW/VziqJZaHafduZFCw3CvFEOdLIEpiew6D3vf3NdcxyUIuYjfvbKV7Fcw+KQb 9wzVeO2QQS5usqeTe7ZxE670v/onm5XFsKysjarqGyJbXYX848/0ZwXEAyrXDaJsIwiC geoNgdhp4q8qQMhjkzGp/bk7pWHIUT348eqweB0DP+gc8y/g5auJ2i+BqZmemkN6+FWg pMb/+NVpIa85NZPew4D8rKr+f4wDdBm51KiUlc/Kzqktqd/1xi+8aEn+fFbr88Yvqe6a rFqg== X-Gm-Message-State: ACrzQf2MY2ZPeLp8A996MMOLMwWWWyKIj4hFVPdeD05PBjIdJffvOI3m S2m2bI348taR2wZlfzYM9d+pQEx9BZsw0+qNt3BtuNb7Dh8rvpx1G6EBvXuyNQZ9nXls6oFyC7Y JDilj56mi/HTuAcdCnw== X-Received: by 2002:a05:620a:12ec:b0:6ee:9e71:190 with SMTP id f12-20020a05620a12ec00b006ee9e710190mr2443816qkl.527.1665598103543; Wed, 12 Oct 2022 11:08:23 -0700 (PDT) X-Google-Smtp-Source: AMsMyM6d92E/EZ9V5dvoXbZeeoXFHuvYal/QKAcP7y/vhTQ1Iu1WvzUhAa3r1UBBT6ftCeAKgWKvVw== X-Received: by 2002:a05:620a:12ec:b0:6ee:9e71:190 with SMTP id f12-20020a05620a12ec00b006ee9e710190mr2443751qkl.527.1665598102649; Wed, 12 Oct 2022 11:08:22 -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 t12-20020a05622a180c00b0039953dcc480sm8517938qtc.88.2022.10.12.11.08.21 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 12 Oct 2022 11:08:21 -0700 (PDT) Message-ID: Date: Wed, 12 Oct 2022 14:08:20 -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++: Implement excess precision support for C++ [PR107097, PR323] To: Jakub Jelinek , "Joseph S. Myers" Cc: 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: 8bit X-Spam-Status: No, score=-6.9 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/11/22 09:33, Jakub Jelinek wrote: > Hi! > > The following patch implements excess precision support for C++. Great! > Like for C, it uses EXCESS_PRECISION_EXPR tree to say that its operand > is evaluated in excess precision and what the semantic type of the > expression is. > In most places I've followed what the C FE does in similar spots, so > e.g. for binary ops if one or both operands are already > EXCESS_PRECISION_EXPR, strip those away or for operations that might need > excess precision (+, -, *, /) check if the operands should use excess > precision and convert to that type and at the end wrap into > EXCESS_PRECISION_EXPR with the common semantic type. > In general I've tried to follow the C99 handling, C11+ relies on the > C standard saying that in case of integral conversions excess precision > can be used (see PR87390 for more details), but I don't see anything similar > on the C++ standard side. 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. > There are some cases which needed to be handled differently, the C FE can > just strip EXCESS_PRECISION_EXPR (replace it with its operand) when handling > explicit cast, but that IMHO isn't right for C++ - the discovery what exact > conversion should be used (e.g. if user conversion or standard or their > sequence) should be decided based on the semantic type (i.e. type of > EXCESS_PRECISION_EXPR), and that decision continues in convert_like* where > we pick the right user conversion, again, if say some class has ctor > from double and long double and we are on ia32 with standard excess > precision promoting float/double to long double, then we should pick the > ctor from double. Or when some other class has ctor from just double, > and EXCESS_PRECISION_EXPR semantic type is float, we should choose the > user ctor from double, but actually just convert the long double excess > precision to double and not to float first. That sounds right. > We need to make sure > even identity conversion converts from excess precision to the semantic one > though, but if identity is chained with other conversions, we don't want > the identity next_conversion to drop to semantic precision only to widen > afterwards. > > The existing testcases tweaks were for cases on i686-linux where excess > precision breaks those tests, e.g. if we have > double d = 4.2; > if (d == 4.2) > then it does the expected thing only with -fexcess-precision=fast, > because with -fexcess-precision=standard it is actually > double d = 4.2; > if ((long double) d == 4.2L) > where 4.2L is different from 4.2. I've added -fexcess-precision=fast > to some tests and changed other tests to use constants that are exactly > representable and don't suffer from these excess precision issues. > > There is one exception, pr68180.C looks like a bug in the patch which is > also present in the C FE (so I'd like to get it resolved incrementally > in both). Reduced testcase: > typedef float __attribute__((vector_size (16))) float32x4_t; > float32x4_t foo(float32x4_t x, float y) { return x + y; } > with -m32 -std=c11 -Wno-psabi or -m32 -std=c++17 -Wno-psabi > it is rejected with: > pr68180.c:2:52: error: conversion of scalar ‘long double’ to vector ‘float32x4_t’ {aka ‘__vector(4) float’} involves truncation > but without excess precision (say just -std=c11 -Wno-psabi or -std=c++17 -Wno-psabi) > it is accepted. Perhaps we should pass down the semantic type to > scalar_to_vector and use the semantic type rather than excess precision type > in the diagnostics. Makes sense. > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2022-10-11 Jakub Jelinek > > PR middle-end/323 > PR c++/107097 > gcc/c-family/ > * c-opts.cc (c_common_post_options): Handle flag_excess_precision > in C++ the same as in C. > * c-lex.cc (interpret_float): Set const_type to excess_precision () > even for C++. > gcc/cp/ > * parser.cc (cp_parser_primary_expression): Handle > EXCESS_PRECISION_EXPR with REAL_CST operand the same as REAL_CST. > * cvt.cc (cp_ep_convert_and_check): New function. > * call.cc (build_conditional_expr): Add excess precision support. > (convert_like_internal): Likewise. Add NESTED_P argument, pass true > to recursive calls to convert_like. > (convert_like): Add NESTED_P argument, pass it through to > convert_like_internal. For other overload pass false to it. > (convert_like_with_context): Pass false to NESTED_P. > (convert_arg_to_ellipsis): Add excess precision support. > (magic_varargs_p): For __builtin_is{finite,inf,inf_sign,nan,normal} > and __builtin_fpclassify return 2 instead of 1, document what it > means. > (build_over_call): Don't handle former magic 2 which is no longer > used, instead for magic 1 remove EXCESS_PRECISION_EXPR. > (perform_direct_initialization_if_possible): Pass false to NESTED_P > convert_like argument. > * constexpr.cc (cxx_eval_constant_expression): Handle > EXCESS_PRECISION_EXPR. > (potential_constant_expression_1): Likewise. > * pt.cc (tsubst_copy, tsubst_copy_and_build): Likewise. > * cp-tree.h (cp_ep_convert_and_check): Declare. > * cp-gimplify.cc (cp_fold): Handle EXCESS_PRECISION_EXPR. > * typeck.cc (convert_arguments): For magic 1 remove > EXCESS_PRECISION_EXPR. > (cp_build_binary_op): Add excess precision support. > (cp_build_unary_op): Likewise. > (cp_build_compound_expr): Likewise. > (build_static_cast_1): Remove EXCESS_PRECISION_EXPR. > gcc/testsuite/ > * gcc.target/i386/excess-precision-1.c: For C++ wrap abort and > exit declarations into extern "C" block. > * gcc.target/i386/excess-precision-2.c: Likewise. > * gcc.target/i386/excess-precision-3.c: Likewise. Remove > check_float_nonproto and check_double_nonproto tests for C++. > * gcc.target/i386/excess-precision-7.c: For C++ wrap abort and > exit declarations into extern "C" block. > * gcc.target/i386/excess-precision-9.c: Likewise. > * g++.target/i386/excess-precision-1.C: New test. > * g++.target/i386/excess-precision-2.C: New test. > * g++.target/i386/excess-precision-3.C: New test. > * g++.target/i386/excess-precision-4.C: New test. > * g++.target/i386/excess-precision-5.C: New test. > * g++.target/i386/excess-precision-6.C: New test. > * g++.target/i386/excess-precision-7.C: New test. > * g++.target/i386/excess-precision-8.C: New test. > * g++.target/i386/excess-precision-9.C: New test. > * c-c++-common/dfp/convert-bfp-10.c: Add -fexcess-precision=fast > as dg-additional-options. > * c-c++-common/dfp/compare-eq-const.c: Likewise. > * g++.dg/cpp1z/constexpr-96862.C: Likewise. > * g++.dg/cpp1z/decomp12.C (main): Use 2.25 instead of 2.3 to > avoid excess precision differences. > * g++.dg/other/thunk1.C: Add -fexcess-precision=fast > as dg-additional-options. > * g++.dg/vect/pr64410.cc: Likewise. > * g++.dg/cpp1y/pr68180.C: Likewise. > * g++.dg/cpp0x/variadic-tuple.C: Likewise. > * g++.dg/cpp0x/nsdmi-union1.C: Use 4.25 instead of 4.2 to > avoid excess precision differences. > * g++.old-deja/g++.brendan/copy9.C: Add -fexcess-precision=fast > as dg-additional-options. > * g++.old-deja/g++.brendan/overload7.C: Likewise. > > --- gcc/c-family/c-opts.cc.jj 2022-10-11 10:00:07.108129689 +0200 > +++ gcc/c-family/c-opts.cc 2022-10-11 10:06:55.784412531 +0200 > @@ -812,17 +812,9 @@ c_common_post_options (const char **pfil > C_COMMON_OVERRIDE_OPTIONS; > #endif > > - /* Excess precision other than "fast" requires front-end > - support. */ > - if (c_dialect_cxx ()) > - { > - if (flag_excess_precision == EXCESS_PRECISION_STANDARD) > - sorry ("%<-fexcess-precision=standard%> for C++"); > - flag_excess_precision = EXCESS_PRECISION_FAST; > - } > - else if (flag_excess_precision == EXCESS_PRECISION_DEFAULT) > + if (flag_excess_precision == EXCESS_PRECISION_DEFAULT) > flag_excess_precision = (flag_iso ? EXCESS_PRECISION_STANDARD > - : EXCESS_PRECISION_FAST); > + : EXCESS_PRECISION_FAST); > > /* ISO C restricts floating-point expression contraction to within > source-language expressions (-ffp-contract=on, currently an alias > --- gcc/c-family/c-lex.cc.jj 2022-10-11 09:59:39.300518701 +0200 > +++ gcc/c-family/c-lex.cc 2022-10-11 10:06:55.784412531 +0200 > @@ -1008,10 +1008,7 @@ interpret_float (const cpp_token *token, > else > type = double_type_node; > > - if (c_dialect_cxx ()) > - const_type = NULL_TREE; > - else > - const_type = excess_precision_type (type); > + const_type = excess_precision_type (type); > if (!const_type) > const_type = type; > > --- gcc/cp/parser.cc.jj 2022-10-10 11:57:40.158723041 +0200 > +++ gcc/cp/parser.cc 2022-10-11 11:56:50.815463848 +0200 > @@ -5583,7 +5583,9 @@ cp_parser_primary_expression (cp_parser > /* Floating-point literals are only allowed in an integral > constant expression if they are cast to an integral or > enumeration type. */ > - if (TREE_CODE (token->u.value) == REAL_CST > + if ((TREE_CODE (token->u.value) == REAL_CST > + || (TREE_CODE (token->u.value) == EXCESS_PRECISION_EXPR > + && TREE_CODE (TREE_OPERAND (token->u.value, 0)) == REAL_CST)) > && parser->integral_constant_expression_p > && pedantic) > { > --- gcc/cp/cvt.cc.jj 2022-10-11 09:59:39.633514043 +0200 > +++ gcc/cp/cvt.cc 2022-10-11 10:06:55.785412518 +0200 > @@ -684,6 +684,33 @@ cp_convert_and_check (tree type, tree ex > return result; > } > > +/* Similarly, but deal with excess precision. SEMANTIC_TYPE is the type this > + conversion would use without excess precision. If SEMANTIC_TYPE is NULL, > + this function is equivalent to cp_convert_and_check. This function is > + a wrapper that handles conversions that may be different than the usual > + ones because of excess precision. */ > + > +tree > +cp_ep_convert_and_check (tree type, tree expr, tree semantic_type, > + tsubst_flags_t complain) > +{ > + if (TREE_TYPE (expr) == type) > + return expr; > + if (expr == error_mark_node) > + return expr; > + if (!semantic_type) > + return cp_convert_and_check (type, expr, complain); > + > + if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE > + && TREE_TYPE (expr) != semantic_type) > + /* For integers, we need to check the real conversion, not > + the conversion to the excess precision type. */ > + expr = cp_convert_and_check (semantic_type, expr, complain); > + /* Result type is the excess precision type, which should be > + large enough, so do not check. */ > + return cp_convert (type, expr, complain); > +} > + > /* Conversion... > > FLAGS indicates how we should behave. */ > --- gcc/cp/call.cc.jj 2022-10-11 09:59:39.424516967 +0200 > +++ gcc/cp/call.cc 2022-10-11 10:06:55.787412490 +0200 > @@ -5374,6 +5374,7 @@ build_conditional_expr (const op_locatio > tree arg3_type; > tree result = NULL_TREE; > tree result_type = NULL_TREE; > + tree semantic_result_type = NULL_TREE; > bool is_glvalue = true; > struct z_candidate *candidates = 0; > struct z_candidate *cand; > @@ -5407,6 +5408,9 @@ build_conditional_expr (const op_locatio > expression, since it needs to be materialized for the > conversion to bool, so treat it as an xvalue in arg2. */ > arg2 = move (TARGET_EXPR_SLOT (arg1)); > + else if (TREE_CODE (arg1) == EXCESS_PRECISION_EXPR) > + arg2 = arg1 = build1 (EXCESS_PRECISION_EXPR, TREE_TYPE (arg1), > + cp_save_expr (TREE_OPERAND (arg1, 0))); > else > arg2 = arg1 = cp_save_expr (arg1); > } > @@ -5565,6 +5569,46 @@ build_conditional_expr (const op_locatio > if (error_operand_p (arg1)) > return error_mark_node; > > + arg2_type = unlowered_expr_type (arg2); > + arg3_type = unlowered_expr_type (arg3); > + > + if ((TREE_CODE (arg2) == EXCESS_PRECISION_EXPR > + || TREE_CODE (arg3) == EXCESS_PRECISION_EXPR) > + && (TREE_CODE (arg2_type) == INTEGER_TYPE > + || TREE_CODE (arg2_type) == REAL_TYPE > + || TREE_CODE (arg2_type) == COMPLEX_TYPE) > + && (TREE_CODE (arg3_type) == INTEGER_TYPE > + || TREE_CODE (arg3_type) == REAL_TYPE > + || TREE_CODE (arg3_type) == COMPLEX_TYPE)) > + { > + semantic_result_type > + = type_after_usual_arithmetic_conversions (arg2_type, arg3_type); > + if (semantic_result_type == error_mark_node > + && TREE_CODE (arg2_type) == REAL_TYPE > + && TREE_CODE (arg3_type) == REAL_TYPE > + && (extended_float_type_p (arg2_type) > + || extended_float_type_p (arg3_type)) 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) > + && cp_compare_floating_point_conversion_ranks (arg2_type, > + arg3_type) == 3) > + { > + if (complain & tf_error) > + error_at (loc, "operands to % of types %qT and %qT " > + "have unordered conversion rank", > + arg2_type, arg3_type); > + return error_mark_node; > + } > + if (TREE_CODE (arg2) == EXCESS_PRECISION_EXPR) > + { > + arg2 = TREE_OPERAND (arg2, 0); > + arg2_type = TREE_TYPE (arg2); > + } > + if (TREE_CODE (arg3) == EXCESS_PRECISION_EXPR) > + { > + arg3 = TREE_OPERAND (arg3, 0); > + arg3_type = TREE_TYPE (arg3); > + } > + } > + > /* [expr.cond] > > If either the second or the third operand has type (possibly > @@ -5572,8 +5616,6 @@ build_conditional_expr (const op_locatio > array-to-pointer (_conv.array_), and function-to-pointer > (_conv.func_) standard conversions are performed on the second > and third operands. */ > - arg2_type = unlowered_expr_type (arg2); > - arg3_type = unlowered_expr_type (arg3); > if (VOID_TYPE_P (arg2_type) || VOID_TYPE_P (arg3_type)) > { > /* 'void' won't help in resolving an overloaded expression on the > @@ -5937,6 +5979,10 @@ build_conditional_expr (const op_locatio > } > } > > + if (semantic_result_type && INTEGRAL_TYPE_P (arg2_type)) > + arg2 = perform_implicit_conversion (semantic_result_type, arg2, complain); > + else if (semantic_result_type && INTEGRAL_TYPE_P (arg3_type)) > + arg3 = perform_implicit_conversion (semantic_result_type, arg3, complain); > arg2 = perform_implicit_conversion (result_type, arg2, complain); > arg3 = perform_implicit_conversion (result_type, arg3, complain); > } > @@ -6024,9 +6070,15 @@ build_conditional_expr (const op_locatio > /* If this expression is an rvalue, but might be mistaken for an > lvalue, we must add a NON_LVALUE_EXPR. */ > result = rvalue (result); > + if (semantic_result_type) > + result = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, > + result); > } > else > - result = force_paren_expr (result); > + { > + result = force_paren_expr (result); > + gcc_assert (semantic_result_type == NULL_TREE); > + } > > return result; > } > @@ -7890,7 +7942,7 @@ maybe_warn_array_conv (location_t loc, c > } > > /* We call this recursively in convert_like_internal. */ > -static tree convert_like (conversion *, tree, tree, int, bool, bool, > +static tree convert_like (conversion *, tree, tree, int, bool, bool, bool, > tsubst_flags_t); > > /* Perform the conversions in CONVS on the expression EXPR. FN and > @@ -7906,7 +7958,7 @@ static tree convert_like (conversion *, > static tree > convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, > bool issue_conversion_warnings, bool c_cast_p, > - tsubst_flags_t complain) > + bool nested_p, tsubst_flags_t complain) > { > tree totype = convs->type; > diagnostic_t diag_kind; > @@ -7983,7 +8035,8 @@ convert_like_internal (conversion *convs > print_z_candidate (loc, N_("candidate is:"), t->cand); > expr = convert_like (t, expr, fn, argnum, > /*issue_conversion_warnings=*/false, > - /*c_cast_p=*/false, complain); > + /*c_cast_p=*/false, /*nested_p=*/true, > + complain); > if (convs->kind == ck_ref_bind) > expr = convert_to_reference (totype, expr, CONV_IMPLICIT, > LOOKUP_NORMAL, NULL_TREE, > @@ -7998,13 +8051,15 @@ convert_like_internal (conversion *convs > { > expr = convert_like (t, expr, fn, argnum, > /*issue_conversion_warnings=*/false, > - /*c_cast_p=*/false, complain); > + /*c_cast_p=*/false, /*nested_p=*/true, > + complain); > break; > } > else if (t->kind == ck_ambig) > return convert_like (t, expr, fn, argnum, > /*issue_conversion_warnings=*/false, > - /*c_cast_p=*/false, complain); > + /*c_cast_p=*/false, /*nested_p=*/true, > + complain); > else if (t->kind == ck_identity) > break; > } > @@ -8124,6 +8179,8 @@ convert_like_internal (conversion *convs > > if (type_unknown_p (expr)) > expr = instantiate_type (totype, expr, complain); > + if (!nested_p && TREE_CODE (expr) == EXCESS_PRECISION_EXPR) > + expr = cp_convert (totype, TREE_OPERAND (expr, 0), complain); > if (expr == null_node > && INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (totype)) > /* If __null has been converted to an integer type, we do not want to > @@ -8163,7 +8220,8 @@ convert_like_internal (conversion *convs > FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), ix, val) > { > tree sub = convert_like (convs->u.list[ix], val, fn, > - argnum, false, false, complain); > + argnum, false, false, > + /*nested_p=*/true, complain); > if (sub == error_mark_node) > return sub; > if (!BRACE_ENCLOSED_INITIALIZER_P (val) > @@ -8231,7 +8289,7 @@ convert_like_internal (conversion *convs > expr = convert_like (next_conversion (convs), expr, fn, argnum, > convs->kind == ck_ref_bind > ? issue_conversion_warnings : false, > - c_cast_p, complain & ~tf_no_cleanup); > + c_cast_p, /*nested_p=*/true, complain & ~tf_no_cleanup); > if (expr == error_mark_node) > return error_mark_node; > > @@ -8493,7 +8551,15 @@ convert_like_internal (conversion *convs > return error_mark_node; > > warning_sentinel w (warn_zero_as_null_pointer_constant); > - if (issue_conversion_warnings) > + if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR) > + { > + if (issue_conversion_warnings) > + expr = cp_ep_convert_and_check (totype, TREE_OPERAND (expr, 0), > + TREE_TYPE (expr), complain); > + else > + expr = cp_convert (totype, TREE_OPERAND (expr, 0), complain); > + } > + else if (issue_conversion_warnings) > expr = cp_convert_and_check (totype, expr, complain); > else > expr = cp_convert (totype, expr, complain); > @@ -8527,7 +8593,7 @@ conv_unsafe_in_template_p (tree to, tree > > static tree > convert_like (conversion *convs, tree expr, tree fn, int argnum, > - bool issue_conversion_warnings, bool c_cast_p, > + bool issue_conversion_warnings, bool c_cast_p, bool nested_p, > tsubst_flags_t complain) > { > /* Creating &TARGET_EXPR<> in a template breaks when substituting, > @@ -8550,7 +8616,8 @@ convert_like (conversion *convs, tree ex > error_mark_node. */ > } > expr = convert_like_internal (convs, expr, fn, argnum, > - issue_conversion_warnings, c_cast_p, complain); > + issue_conversion_warnings, c_cast_p, > + nested_p, complain); > if (expr == error_mark_node) > return error_mark_node; > return conv_expr ? conv_expr : expr; > @@ -8563,7 +8630,7 @@ convert_like (conversion *convs, tree ex > { > return convert_like (convs, expr, NULL_TREE, 0, > /*issue_conversion_warnings=*/true, > - /*c_cast_p=*/false, complain); > + /*c_cast_p=*/false, /*nested_p=*/false, complain); > } > > /* Convenience wrapper for convert_like. */ > @@ -8574,7 +8641,7 @@ convert_like_with_context (conversion *c > { > return convert_like (convs, expr, fn, argnum, > /*issue_conversion_warnings=*/true, > - /*c_cast_p=*/false, complain); > + /*c_cast_p=*/false, /*nested_p=*/false, complain); > } > > /* ARG is being passed to a varargs function. Perform any conversions > @@ -8605,6 +8672,8 @@ convert_arg_to_ellipsis (tree arg, tsubs > "implicit conversion from %qH to %qI when passing " > "argument to function", > arg_type, double_type_node); > + if (TREE_CODE (arg) == EXCESS_PRECISION_EXPR) > + arg = TREE_OPERAND (arg, 0); > arg = mark_rvalue_use (arg); > arg = convert_to_real_nofold (double_type_node, arg); > } > @@ -8911,9 +8980,9 @@ convert_for_arg_passing (tree type, tree > /* Returns non-zero iff FN is a function with magic varargs, i.e. ones for > which just decay_conversion or no conversions at all should be done. > This is true for some builtins which don't act like normal functions. > - Return 2 if no conversions at all should be done, 1 if just > - decay_conversion. Return 3 for special treatment of the 3rd argument > - for __builtin_*_overflow_p. */ > + Return 2 if just decay_conversion and removal of excess precision should > + be done, 1 if just decay_conversion. Return 3 for special treatment of > + the 3rd argument for __builtin_*_overflow_p. */ > > int > magic_varargs_p (tree fn) > @@ -8932,7 +9001,15 @@ magic_varargs_p (tree fn) > case BUILT_IN_MUL_OVERFLOW_P: > return 3; > > - default:; > + case BUILT_IN_ISFINITE: > + case BUILT_IN_ISINF: > + case BUILT_IN_ISINF_SIGN: > + case BUILT_IN_ISNAN: > + case BUILT_IN_ISNORMAL: > + case BUILT_IN_FPCLASSIFY: > + return 2; > + > + default: > return lookup_attribute ("type generic", > TYPE_ATTRIBUTES (TREE_TYPE (fn))) != 0; > } > @@ -9764,7 +9841,7 @@ build_over_call (struct z_candidate *can > for (; arg_index < vec_safe_length (args); ++arg_index) > { > tree a = (*args)[arg_index]; > - if ((magic == 3 && arg_index == 2) || magic == 2) > + if (magic == 3 && arg_index == 2) > { > /* Do no conversions for certain magic varargs. */ > a = mark_type_use (a); > @@ -9772,8 +9849,12 @@ build_over_call (struct z_candidate *can > return error_mark_node; > } > else if (magic != 0) > - /* For other magic varargs only do decay_conversion. */ > - a = decay_conversion (a, complain); > + { > + if (magic == 1 && TREE_CODE (a) == EXCESS_PRECISION_EXPR) > + a = TREE_OPERAND (a, 0); It was confusing me that this mentions 1, and the magic_varargs_p comment above mentions 2: Let's add a comment /* Don't truncate excess precision to the semantic type. */ to clarify. > + /* For other magic varargs only do decay_conversion. */ > + a = decay_conversion (a, complain); > + } > else if (DECL_CONSTRUCTOR_P (fn) > && same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (fn), > TREE_TYPE (a))) > @@ -13051,7 +13132,7 @@ perform_direct_initialization_if_possibl > else > expr = convert_like (conv, expr, NULL_TREE, 0, > /*issue_conversion_warnings=*/false, > - c_cast_p, complain); > + c_cast_p, /*nested_p=*/false, complain); > > /* Free all the conversions we allocated. */ > obstack_free (&conversion_obstack, p); > --- gcc/cp/constexpr.cc.jj 2022-10-11 09:59:39.481516169 +0200 > +++ gcc/cp/constexpr.cc 2022-10-11 10:06:55.788412476 +0200 > @@ -7618,6 +7618,19 @@ cxx_eval_constant_expression (const cons > } > break; > > + case EXCESS_PRECISION_EXPR: > + { > + tree oldop = TREE_OPERAND (t, 0); > + > + tree op = cxx_eval_constant_expression (ctx, oldop, > + lval, > + non_constant_p, overflow_p); > + if (*non_constant_p) > + return t; > + r = fold_convert (TREE_TYPE (t), op); > + break; > + } > + > case EMPTY_CLASS_EXPR: > /* Handle EMPTY_CLASS_EXPR produced by build_call_a by lowering > it to an appropriate CONSTRUCTOR. */ > @@ -8918,6 +8931,9 @@ potential_constant_expression_1 (tree t, > sub-object of such an object; */ > return RECUR (TREE_OPERAND (t, 0), rval); > > + case EXCESS_PRECISION_EXPR: > + return RECUR (TREE_OPERAND (t, 0), rval); > + > case VAR_DECL: > if (DECL_HAS_VALUE_EXPR_P (t)) > { > --- gcc/cp/pt.cc.jj 2022-10-11 09:59:39.698513133 +0200 > +++ gcc/cp/pt.cc 2022-10-11 10:06:55.792412420 +0200 > @@ -17401,6 +17401,15 @@ tsubst_copy (tree t, tree args, tsubst_f > return r; > } > > + case EXCESS_PRECISION_EXPR: > + { > + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); > + tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); > + if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR) > + return op0; > + return build1_loc (EXPR_LOCATION (t), code, type, op0); > + } > + > case COMPONENT_REF: > { > tree object; > @@ -20429,6 +20438,16 @@ tsubst_copy_and_build (tree t, > templated_operator_saved_lookups (t), > complain|decltype_flag)); > > + case EXCESS_PRECISION_EXPR: > + { > + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); > + tree op0 = RECUR (TREE_OPERAND (t, 0)); > + if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR) > + RETURN (op0); > + RETURN (build1_loc (input_location, EXCESS_PRECISION_EXPR, Why not EXPR_LOCATION (t)? > + type, op0)); > + } > + > case FIX_TRUNC_EXPR: > /* convert_like should have created an IMPLICIT_CONV_EXPR. */ > gcc_unreachable (); > --- gcc/cp/cp-tree.h.jj 2022-10-11 09:59:39.512515736 +0200 > +++ gcc/cp/cp-tree.h 2022-10-11 10:06:55.793412406 +0200 > @@ -6766,6 +6766,8 @@ extern tree ocp_convert (tree, tree, > tsubst_flags_t); > extern tree cp_convert (tree, tree, tsubst_flags_t); > extern tree cp_convert_and_check (tree, tree, tsubst_flags_t); > +extern tree cp_ep_convert_and_check (tree, tree, tree, > + tsubst_flags_t); > extern tree cp_fold_convert (tree, tree); > extern tree cp_get_callee (tree); > extern tree cp_get_callee_fndecl (tree); > --- gcc/cp/cp-gimplify.cc.jj 2022-10-11 09:59:39.482516155 +0200 > +++ gcc/cp/cp-gimplify.cc 2022-10-11 10:06:55.794412392 +0200 > @@ -2522,6 +2522,11 @@ cp_fold (tree x) > > break; > > + case EXCESS_PRECISION_EXPR: > + op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops); > + x = fold_convert_loc (EXPR_LOCATION (x), TREE_TYPE (x), op0); > + break; > + > case INDIRECT_REF: > /* We don't need the decltype(auto) obfuscation anymore. */ > if (REF_PARENTHESIZED_P (x)) > --- gcc/cp/typeck.cc.jj 2022-10-11 09:59:39.738512574 +0200 > +++ gcc/cp/typeck.cc 2022-10-11 10:24:31.875679017 +0200 > @@ -4603,11 +4603,16 @@ convert_arguments (tree typelist, vec } > 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) > + { > + if (magic == 1 && TREE_CODE (val) == EXCESS_PRECISION_EXPR) > + val = TREE_OPERAND (val, 0); Same magic == 1 issue here. > + /* 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 +5062,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 +5074,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 +5125,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 +5180,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 +5214,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 +5294,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 +5304,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; > @@ -6091,6 +6145,27 @@ 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 > + && code0 == REAL_TYPE > + && code1 == REAL_TYPE > + && (extended_float_type_p (orig_type0) > + || extended_float_type_p (orig_type1)) > + && cp_compare_floating_point_conversion_ranks (orig_type0, > + orig_type1) == 3) > + { > + if (complain & tf_error) > + { > + rich_location richloc (line_table, location); > + binary_op_error (&richloc, code, type0, type1); > + } > + return error_mark_node; > + } Same error_mark_node issue here. > + } > > if (code == SPACESHIP_EXPR) > { > @@ -6181,6 +6256,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 +6345,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 +6443,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 +6517,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 +7246,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 +7267,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 +7368,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 +7383,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 +7399,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 +7563,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 +7579,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 +7974,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 +7993,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 +8006,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 +8293,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 +8376,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 09:59:39.861510854 +0200 > +++ gcc/testsuite/gcc.target/i386/excess-precision-1.c 2022-10-11 10:06:55.795412378 +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 09:59:39.877510630 +0200 > +++ gcc/testsuite/gcc.target/i386/excess-precision-2.c 2022-10-11 10:06:55.796412364 +0200 > @@ -4,8 +4,14 @@ > > #include > > +#ifdef __cplusplus > +extern "C" { > +#endif > extern void abort (void); > extern void exit (int); > +#ifdef __cplusplus > +} > +#endif > > volatile long double ldadd1 = 1.0l + 0x1.0p-30l; > volatile long double ld11f = 1.1f; > --- gcc/testsuite/gcc.target/i386/excess-precision-3.c.jj 2022-10-11 09:59:39.894510392 +0200 > +++ gcc/testsuite/gcc.target/i386/excess-precision-3.c 2022-10-11 10:06:55.796412364 +0200 > @@ -6,8 +6,14 @@ > #include > #include > > +#ifdef __cplusplus > +extern "C" { > +#endif > extern void abort (void); > extern void exit (int); > +#ifdef __cplusplus > +} > +#endif > > volatile float f1 = 1.0f; > volatile float f2 = 0x1.0p-30f; > @@ -100,6 +106,7 @@ check_double (double d) > abort (); > } > > +#ifndef __cplusplus > static inline void > check_float_nonproto (f) > float f; > @@ -115,6 +122,7 @@ check_double_nonproto (d) > if (d != dadd2) > abort (); > } > +#endif > > static void > check_double_va (int i, ...) > @@ -132,9 +140,11 @@ test_call (void) > check_float (f1 + f2); > check_double (d1 + d2 + d3); > check_double (f1 + f2 + f3); > +#ifndef __cplusplus > check_float_nonproto (f1 + f2); > check_double_nonproto (d1 + d2 + d3); > check_double_nonproto (f1 + f2 + f3); > +#endif > check_double_va (0, d1 + d2 + d3); > check_double_va (0, f1 + f2 + f3); > } > --- gcc/testsuite/gcc.target/i386/excess-precision-7.c.jj 2022-10-11 09:59:39.917510070 +0200 > +++ gcc/testsuite/gcc.target/i386/excess-precision-7.c 2022-10-11 10:06:55.796412364 +0200 > @@ -4,8 +4,14 @@ > /* { dg-do run } */ > /* { dg-options "-std=c99 -mfpmath=387 -fexcess-precision=standard" } */ > > +#ifdef __cplusplus > +extern "C" { > +#endif > extern void abort (void); > extern void exit (int); > +#ifdef __cplusplus > +} > +#endif > > int > main (void) > --- gcc/testsuite/gcc.target/i386/excess-precision-9.c.jj 2022-10-11 09:59:39.947509650 +0200 > +++ gcc/testsuite/gcc.target/i386/excess-precision-9.c 2022-10-11 10:06:55.796412364 +0200 > @@ -3,8 +3,14 @@ > /* { dg-do run } */ > /* { dg-options "-std=c99 -mfpmath=387 -fexcess-precision=standard" } */ > > +#ifdef __cplusplus > +extern "C" { > +#endif > extern void abort (void); > extern void exit (int); > +#ifdef __cplusplus > +} > +#endif > > int > main (void) > --- gcc/testsuite/g++.target/i386/excess-precision-1.C.jj 2022-10-11 10:06:55.796412364 +0200 > +++ gcc/testsuite/g++.target/i386/excess-precision-1.C 2022-10-11 10:06:55.796412364 +0200 > @@ -0,0 +1,6 @@ > +// Excess precision tests. Test that excess precision is carried > +// through various operations. > +// { dg-do run } > +// { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" } > + > +#include "../../gcc.target/i386/excess-precision-1.c" > --- gcc/testsuite/g++.target/i386/excess-precision-2.C.jj 2022-10-11 10:06:55.796412364 +0200 > +++ gcc/testsuite/g++.target/i386/excess-precision-2.C 2022-10-11 10:06:55.796412364 +0200 > @@ -0,0 +1,5 @@ > +// Excess precision tests. Test excess precision of constants. > +// { dg-do run } > +// { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" } > + > +#include "../../gcc.target/i386/excess-precision-2.c" > --- gcc/testsuite/g++.target/i386/excess-precision-3.C.jj 2022-10-11 10:06:55.796412364 +0200 > +++ gcc/testsuite/g++.target/i386/excess-precision-3.C 2022-10-11 10:06:55.796412364 +0200 > @@ -0,0 +1,6 @@ > +// Excess precision tests. Test excess precision is removed when > +// necessary. > +// { dg-do run } > +// { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" } > + > +#include "../../gcc.target/i386/excess-precision-3.c" > --- gcc/testsuite/g++.target/i386/excess-precision-4.C.jj 2022-10-11 10:06:55.796412364 +0200 > +++ gcc/testsuite/g++.target/i386/excess-precision-4.C 2022-10-11 10:06:55.796412364 +0200 > @@ -0,0 +1,7 @@ > +// Excess precision tests. Test diagnostics for excess precision of > +// constants. > +// { dg-do compile } > +// { dg-options "-mfpmath=387 -fexcess-precision=standard" } > + > +float f = 0.0f * 1e50f; // { dg-warning "floating constant exceeds range of 'float'" } > +double d = 0.0 * 1e400; // { dg-warning "floating constant exceeds range of 'double'" } > --- gcc/testsuite/g++.target/i386/excess-precision-5.C.jj 2022-10-11 10:06:55.797412351 +0200 > +++ gcc/testsuite/g++.target/i386/excess-precision-5.C 2022-10-11 10:06:55.797412351 +0200 > @@ -0,0 +1,32 @@ > +// Excess precision tests. Verify excess precision doesn't affect > +// actual types. > +// { dg-do compile { target c++11 } } > +// { dg-options "-mfpmath=387 -fexcess-precision=standard" } > + > +namespace std { > + template struct integral_constant { > + static constexpr T value = v; > + }; > + typedef integral_constant false_type; > + typedef integral_constant true_type; > + template > + struct is_same : std::false_type {}; > + template > + struct is_same : std::true_type {}; > +} > + > +float f; > +double d; > + > +void > +test_types (void) > +{ > +#define CHECK_FLOAT(E) static_assert (std::is_same ::value, "") > +#define CHECK_DOUBLE(E) static_assert (std::is_same ::value, "") > + CHECK_FLOAT (f + f); > + CHECK_DOUBLE (d + d); > + CHECK_FLOAT (f * f / f); > + CHECK_DOUBLE (d * d / d); > + CHECK_FLOAT (f ? f - f : f); > + CHECK_DOUBLE (d ? d - d : d); > +} > --- gcc/testsuite/g++.target/i386/excess-precision-6.C.jj 2022-10-11 10:06:55.797412351 +0200 > +++ gcc/testsuite/g++.target/i386/excess-precision-6.C 2022-10-11 10:06:55.797412351 +0200 > @@ -0,0 +1,19 @@ > +// Excess precision tests. Make sure sqrt is not inlined for float or > +// double. > +// { dg-do compile } > +// { dg-options "-mfpmath=387 -O2 -fno-math-errno -fexcess-precision=standard" } > + > +float f; > +double d; > + > +float fr; > +double dr; > + > +void > +test_builtins (void) > +{ > + fr = __builtin_sqrtf (f); > + dr = __builtin_sqrt (d); > +} > + > +// { dg-final { scan-assembler-not "fsqrt" } } > --- gcc/testsuite/g++.target/i386/excess-precision-7.C.jj 2022-10-11 10:06:55.797412351 +0200 > +++ gcc/testsuite/g++.target/i386/excess-precision-7.C 2022-10-11 10:06:55.797412351 +0200 > @@ -0,0 +1,7 @@ > +// Excess precision tests. Test C99 semantics for conversions from > +// integers to floating point: no excess precision for either explicit > +// or implicit conversions. > +// { dg-do run } > +// { dg-options "-mfpmath=387 -fexcess-precision=standard" } > + > +#include "../../gcc.target/i386/excess-precision-7.c" > --- gcc/testsuite/g++.target/i386/excess-precision-8.C.jj 2022-10-11 10:06:55.797412351 +0200 > +++ gcc/testsuite/g++.target/i386/excess-precision-8.C 2022-10-11 10:06:55.797412351 +0200 > @@ -0,0 +1,105 @@ > +// Excess precision tests. Test excess precision is removed when > +// necessary. > +// { dg-do run } > +// { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" } > + > +#include > +#include > + > +extern "C" void abort (); > + > +volatile float f1 = 1.0f; > +volatile float f2 = 0x1.0p-30f; > +volatile float f3 = 0x1.0p-60f; > +volatile double d1 = 1.0; > +volatile double d2 = 0x1.0p-30; > +volatile double d3 = 0x1.0p-60; > +volatile double d3d = 0x1.0p-52; > +volatile float fadd1 = 1.0f + 0x1.0p-30f; > +volatile double dadd2 = 1.0 + 0x1.0p-30 + 0x1.0p-60; > +volatile double dh = 0x1.0p-24; > +volatile float fha = 1.0f + 0x1.0p-23f; > + > +static inline void > +check_float (float f) > +{ > + if (f != fadd1) > + abort (); > +} > + > +static inline void > +check_float (double) > +{ > + abort (); > +} > + > +static inline void > +check_float (long double) > +{ > + abort (); > +} > + > +static inline void > +check_double (double d) > +{ > + if (d != dadd2) > + abort (); > +} > + > +static inline void > +check_double (long double) > +{ > + abort (); > +} > + > +static inline void > +check_float2 (float f) > +{ > + if (f != fha) > + abort (); > +} > + > +struct S { > + S () {} > + S (float f) { if (f != fadd1) abort (); } > +}; > + > +struct T { > + T () {} > + T (double d) { if (d != dadd2) abort (); } > +}; > + > +static inline void > +check_float3 (S) > +{ > +} > + > +static inline void > +check_double2 (T) > +{ > +} > + > +void > +test_call () > +{ > + check_float (f1 + f2); > + check_double (f1 + f2); > + check_double (d1 + d2 + d3); > + /* Verify rounding direct to float without double rounding. */ > + if (sizeof (long double) > sizeof (double)) > + check_float2 (d1 + dh + d3); > + else > + check_float2 (d1 + dh + d3d); > + check_float3 (f1 + f2); > + check_double2 (f1 + f2); > + check_double2 (d1 + d2 + d3); > + S s1 = static_cast (f1 + f2); > + T t2 = static_cast (f1 + f2); > + T t3 = static_cast (d1 + d2 + d3); > +} > + > +int > +main () > +{ > + test_call (); > +} > --- gcc/testsuite/g++.target/i386/excess-precision-9.C.jj 2022-10-11 10:06:55.797412351 +0200 > +++ gcc/testsuite/g++.target/i386/excess-precision-9.C 2022-10-11 10:06:55.797412351 +0200 > @@ -0,0 +1,6 @@ > +// Excess precision tests. Test implicit conversions in comparisons: > +// no excess precision in C++. > +// { dg-do run } > +// { dg-options "-mfpmath=387 -fexcess-precision=standard" } > + > +#include "../../gcc.target/i386/excess-precision-9.c" > --- gcc/testsuite/c-c++-common/dfp/convert-bfp-10.c.jj 2020-01-12 11:54:37.003404507 +0100 > +++ gcc/testsuite/c-c++-common/dfp/convert-bfp-10.c 2022-10-11 11:20:40.511702027 +0200 > @@ -1,4 +1,5 @@ > /* This test assumes IEEE float and double. */ > +/* { dg-additional-options "-fexcess-precision=fast" } */ > > #include "convert.h" > > --- gcc/testsuite/c-c++-common/dfp/compare-eq-const.c.jj 2020-01-12 11:54:37.003404507 +0100 > +++ gcc/testsuite/c-c++-common/dfp/compare-eq-const.c 2022-10-11 11:18:31.432502023 +0200 > @@ -1,5 +1,6 @@ > /* C99 6.5.9 Equality operators. > Compare decimal float constants against each other. */ > +/* { dg-additional-options "-fexcess-precision=fast" } */ > > #include "dfp-dbg.h" > > --- gcc/testsuite/g++.dg/cpp1z/constexpr-96862.C.jj 2020-09-03 20:11:34.160825160 +0200 > +++ gcc/testsuite/g++.dg/cpp1z/constexpr-96862.C 2022-10-11 11:51:31.563910365 +0200 > @@ -1,6 +1,6 @@ > // PR c++/96862 > // { dg-do compile { target c++17 } } > -// { dg-additional-options "-frounding-math" } > +// { dg-additional-options "-frounding-math -fexcess-precision=fast" } > > constexpr double a = 0x1.0p+100 + 0x1.0p-100; > const double b = 0x1.0p+100 + 0x1.0p-100; > --- gcc/testsuite/g++.dg/cpp1z/decomp12.C.jj 2020-01-12 11:54:37.128402621 +0100 > +++ gcc/testsuite/g++.dg/cpp1z/decomp12.C 2022-10-11 11:30:05.737825169 +0200 > @@ -7,13 +7,13 @@ template struct sam > template struct same_type {}; > > int main() { > - std::tuple tuple = { 1, 'a', 2.3, true }; > + std::tuple tuple = { 1, 'a', 2.25, true }; > auto[i, c, d, b] = tuple; > same_type::type, decltype(i)>{}; > same_type{}; > same_type{}; > same_type{}; > same_type{}; > - if (i != 1 || c != 'a' || d != 2.3 || b != true) > + if (i != 1 || c != 'a' || d != 2.25 || b != true) > __builtin_abort (); > } > --- gcc/testsuite/g++.dg/other/thunk1.C.jj 2020-01-12 11:54:37.218401263 +0100 > +++ gcc/testsuite/g++.dg/other/thunk1.C 2022-10-11 11:30:37.350384645 +0200 > @@ -1,5 +1,6 @@ > // PR c++/12007 Multiple inheritance float pass by value fails > // { dg-do run } > +// { dg-additional-options "-fexcess-precision=fast" } > > extern "C" void abort (void); > > --- gcc/testsuite/g++.dg/vect/pr64410.cc.jj 2020-01-12 11:54:37.279400343 +0100 > +++ gcc/testsuite/g++.dg/vect/pr64410.cc 2022-10-11 11:31:54.970302984 +0200 > @@ -1,5 +1,6 @@ > // { dg-do compile } > // { dg-require-effective-target vect_double } > +// { dg-additional-options "-fexcess-precision=fast" } > > #include > #include > --- gcc/testsuite/g++.dg/cpp1y/pr68180.C.jj 2020-01-12 11:54:37.121402727 +0100 > +++ gcc/testsuite/g++.dg/cpp1y/pr68180.C 2022-10-11 11:50:42.324596315 +0200 > @@ -1,6 +1,6 @@ > // PR c++/68180 > // { dg-do compile { target c++14 } } > -// { dg-additional-options "-Wno-psabi" } > +// { dg-additional-options "-Wno-psabi -fexcess-precision=fast" } > > typedef float __attribute__( ( vector_size( 16 ) ) ) float32x4_t; > constexpr float32x4_t fill(float x) { > --- gcc/testsuite/g++.dg/cpp0x/variadic-tuple.C.jj 2022-05-20 11:45:17.801744787 +0200 > +++ gcc/testsuite/g++.dg/cpp0x/variadic-tuple.C 2022-10-11 11:28:34.282099648 +0200 > @@ -1,4 +1,5 @@ > // { dg-do run { target c++11 } } > +// { dg-additional-options "-fexcess-precision=fast" } > // An implementation of TR1's using variadic teplates > // Contributed by Douglas Gregor > > --- gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C.jj 2020-01-12 11:54:37.087403240 +0100 > +++ gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C 2022-10-11 11:27:50.009716597 +0200 > @@ -18,8 +18,8 @@ int main() > { > Test t; > B b; > - B b2(4.2); > + B b2(4.25); > > - if (t.a != 4 || b.i != 42 || b2.d != 4.2) > + if (t.a != 4 || b.i != 42 || b2.d != 4.25) > __builtin_abort(); > } > --- gcc/testsuite/g++.old-deja/g++.brendan/copy9.C.jj 2020-01-11 16:31:54.872295939 +0100 > +++ gcc/testsuite/g++.old-deja/g++.brendan/copy9.C 2022-10-11 11:10:40.589067853 +0200 > @@ -1,4 +1,5 @@ > // { dg-do run } > +// { dg-additional-options "-fexcess-precision=fast" } > // GROUPS passed copy-ctors > #include > > --- gcc/testsuite/g++.old-deja/g++.brendan/overload7.C.jj 2020-01-11 16:31:54.877295864 +0100 > +++ gcc/testsuite/g++.old-deja/g++.brendan/overload7.C 2022-10-11 11:11:45.238166331 +0200 > @@ -1,4 +1,5 @@ > // { dg-do run } > +// { dg-additional-options "-fexcess-precision=fast" } > // GROUPS passed overloading > extern "C" int printf (const char *, ...); > > > Jakub >