Message ID | 005b01d7aedd$91545eb0$b3fd1c10$@nextmovesoftware.com |
---|---|
State | Changes Requested |
Headers |
Return-Path: <gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org> X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CDFB43858022 for <patchwork@sourceware.org>; Tue, 21 Sep 2021 11:41:25 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from server.nextmovesoftware.com (server.nextmovesoftware.com [162.254.253.69]) by sourceware.org (Postfix) with ESMTPS id 4B9253858C3A for <gcc-patches@gcc.gnu.org>; Tue, 21 Sep 2021 11:41:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4B9253858C3A Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=nextmovesoftware.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=nextmovesoftware.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=nextmovesoftware.com; s=default; h=Content-Type:MIME-Version:Message-ID: Date:Subject:To:From:Sender:Reply-To:Cc:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=+xhP7KLrklxKDuSN9zJnSLdhr/oSUv8W1IHQ+MrdZg4=; b=jI6xWHXsHb/ybrnU2KGHEy7wGo rPs4jQp47asnoL9bTBt6UeQJ4gK89QFNArHMEfxJQi8zV2wShscOTOcTpJjkQ1lUEVVjQ+tmSnA4r RzWH+1iofe+MmlK77t9uWdvP4YCYbhrL3/2ZC72tsO4Q6ReBvZR5Mo4A14/YbwXfARMPdGMKW9WYU jr3qLTGE/5J7sgTJUhLECWQj7eNXJuBNoTGSxKmM/D1vbQqS9JdanONiOB1u07QAqRm3XB9JRZIXf pco9zFsTa6tDOUzwadhMH6lDZ3RBPX7hmFnrULbZS2mt0pdCWMelzd+SbY3pg6iGwh9kGmZBG/RhP ejZVjJzA==; Received: from [185.62.158.67] (port=57627 helo=Dell) by server.nextmovesoftware.com with esmtpsa (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from <roger@nextmovesoftware.com>) id 1mSe95-0007Jx-Ix for gcc-patches@gcc.gnu.org; Tue, 21 Sep 2021 07:41:07 -0400 From: "Roger Sayle" <roger@nextmovesoftware.com> To: "'GCC Patches'" <gcc-patches@gcc.gnu.org> Subject: [RFC/PATCH] C++ constexpr vs. floating point exceptions. Date: Tue, 21 Sep 2021 12:41:06 +0100 Message-ID: <005b01d7aedd$91545eb0$b3fd1c10$@nextmovesoftware.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_005C_01D7AEE5.F318C6B0" X-Mailer: Microsoft Outlook 16.0 Thread-Index: Adeu3KuEslH2PuzMTAmOzF2gAiyhFg== Content-Language: en-gb X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.nextmovesoftware.com X-AntiAbuse: Original Domain - gcc.gnu.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - nextmovesoftware.com X-Get-Message-Sender-Via: server.nextmovesoftware.com: authenticated_id: roger@nextmovesoftware.com X-Authenticated-Sender: server.nextmovesoftware.com: roger@nextmovesoftware.com X-Source: X-Source-Args: X-Source-Dir: X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list <gcc-patches.gcc.gnu.org> List-Unsubscribe: <https://gcc.gnu.org/mailman/options/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe> List-Archive: <https://gcc.gnu.org/pipermail/gcc-patches/> List-Post: <mailto:gcc-patches@gcc.gnu.org> List-Help: <mailto:gcc-patches-request@gcc.gnu.org?subject=help> List-Subscribe: <https://gcc.gnu.org/mailman/listinfo/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe> Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" <gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org> |
Series |
[RFC/PATCH] C++ constexpr vs. floating point exceptions.
|
|
Commit Message
Roger Sayle
Sept. 21, 2021, 11:41 a.m. UTC
I was wondering if I may ask the C++ language experts for their opinion on whether (potential) floating point exceptions/traps can be ignored in constant expressions; this is related to PR c++/96862. I think my question boils down to whether (or not) the following is valid C++: constexpr float my_inf = 7.0 / 0.0; [This is currently an error with "-O2", but OK with "-O2 -ffast-math"!] There's a long history of g++'s semantics being accidentally tied to the middle-end's constant folding, such that the current status quo is that some middle-end bugs can't be fixed without breaking C++, and vice versa. I'm hoping that the patch below (following Jakub's lead with rounding math) might be a next step to improving things, provided that my understanding of the desired/correct behaviour of the C++ front-end is correct. This patch has been tested on x86_64-pc-linux-gnu with a "make bootstrap" and "make -k check" with no new failures after tweaking two checks in g++.dg/ubsan/pr63956.C. With this change the middle-end can become more strict about respecting flag_trapping_math without affecting C++'s behavior. Ideally, what the front-end considers valid should be independent of whether the user specified -fno-trapping-math (or -ffast-math) to the middle-end. Thoughts? Ok for mainline? 2021-09-21 Roger Sayle <roger@nextmovesoftware.com> gcc/cp/ChangeLog * constexpr.c (cxx_eval_outermost_const_expr): Temporarily disable the middle-end from honoring floating point exceptions/traps while folding "manifestly constant" expressions. gcc/testsuite/ChangeLog * g++.dg/ubsan/pr63956.C: Update to (always) allow floating point division in constexpr (if both operands are constexpr). Roger --
Comments
On Tue, 2021-09-21 at 12:41 +0100, Roger Sayle wrote: > > I was wondering if I may ask the C++ language experts for their > opinion > on whether (potential) floating point exceptions/traps can be ignored > in constant expressions; this is related to PR c++/96862. I think my > question boils down to whether (or not) the following is valid C++: > > constexpr float my_inf = 7.0 / 0.0; It's not. C++ disallows constexpr from invoking undefined behaviors in Clauses 4 through 19, while division by zero is an undefined behavior in Clause 8. > [This is currently an error with "-O2", but OK with "-O2 -ffast- > math"!] > There's a long history of g++'s semantics being accidentally tied to > the middle-end's constant folding, such that the current status quo > is that some middle-end bugs can't be fixed without breaking C++, > and vice versa. I'm hoping that the patch below (following Jakub's > lead with rounding math) might be a next step to improving things, > provided that my understanding of the desired/correct behaviour of > the C++ front-end is correct. > > This patch has been tested on x86_64-pc-linux-gnu with a "make > bootstrap" > and "make -k check" with no new failures after tweaking two checks in > g++.dg/ubsan/pr63956.C. > With this change the middle-end can become more > strict about respecting flag_trapping_math without affecting C++'s > behavior. Ideally, what the front-end considers valid should be > independent of whether the user specified -fno-trapping-math (or > -ffast-math) to the middle-end. I think we can allow a constexpr to contain floating div-by-zero with - fno-trapping-math, if we consider -fno-trapping-math make the behavior "no longer undefined" but I'm not sure. However -ffast-math also enables -ffinite-math-only, which makes div-by- zero absolutely undefined. So to me the expected behavior is: g++ t.cc -> Compile error g++ t.cc -ffast-math -> Compile error g++ t.cc -fno-trapping-math -> Ok g++ t.cc -fno-trapping-math -ffinite-math-only -> Compile Error > Thoughts? Ok for mainline? Based on the reasoning above I think it's not OK. But anyway I'm not a maintainer. > 2021-09-21 Roger Sayle <roger@nextmovesoftware.com> > > gcc/cp/ChangeLog > * constexpr.c (cxx_eval_outermost_const_expr): Temporarily > disable > the middle-end from honoring floating point exceptions/traps > while > folding "manifestly constant" expressions. > > gcc/testsuite/ChangeLog > * g++.dg/ubsan/pr63956.C: Update to (always) allow floating > point > division in constexpr (if both operands are constexpr). > > Roger > -- >
Can you double check? Integer division by zero is undefined, but isn't floating point division by zero defined by the appropriate IEEE standards? Roger -- -----Original Message----- From: Xi Ruoyao <xry111@mengyan1223.wang> Sent: 21 September 2021 14:07 To: Roger Sayle <roger@nextmovesoftware.com>; 'GCC Patches' <gcc-patches@gcc.gnu.org> Subject: Re: [RFC/PATCH] C++ constexpr vs. floating point exceptions. On Tue, 2021-09-21 at 12:41 +0100, Roger Sayle wrote: > > I was wondering if I may ask the C++ language experts for their > opinion on whether (potential) floating point exceptions/traps can be > ignored in constant expressions; this is related to PR c++/96862. I > think my question boils down to whether (or not) the following is > valid C++: > > constexpr float my_inf = 7.0 / 0.0; It's not. C++ disallows constexpr from invoking undefined behaviors in Clauses 4 through 19, while division by zero is an undefined behavior in Clause 8. > [This is currently an error with "-O2", but OK with "-O2 -ffast- > math"!] > There's a long history of g++'s semantics being accidentally tied to > the middle-end's constant folding, such that the current status quo is > that some middle-end bugs can't be fixed without breaking C++, and > vice versa. I'm hoping that the patch below (following Jakub's lead > with rounding math) might be a next step to improving things, provided > that my understanding of the desired/correct behaviour of the C++ > front-end is correct. > > This patch has been tested on x86_64-pc-linux-gnu with a "make > bootstrap" > and "make -k check" with no new failures after tweaking two checks in > g++.dg/ubsan/pr63956.C. > With this change the middle-end can become more strict about > respecting flag_trapping_math without affecting C++'s behavior. > Ideally, what the front-end considers valid should be independent of > whether the user specified -fno-trapping-math (or > -ffast-math) to the middle-end. I think we can allow a constexpr to contain floating div-by-zero with - fno-trapping-math, if we consider -fno-trapping-math make the behavior "no longer undefined" but I'm not sure. However -ffast-math also enables -ffinite-math-only, which makes div-by- zero absolutely undefined. So to me the expected behavior is: g++ t.cc -> Compile error g++ t.cc -ffast-math -> Compile error g++ t.cc -fno-trapping-math -> Ok g++ t.cc -fno-trapping-math -ffinite-math-only -> Compile Error > Thoughts? Ok for mainline? Based on the reasoning above I think it's not OK. But anyway I'm not a maintainer. > 2021-09-21 Roger Sayle <roger@nextmovesoftware.com> > > gcc/cp/ChangeLog > * constexpr.c (cxx_eval_outermost_const_expr): Temporarily > disable > the middle-end from honoring floating point exceptions/traps > while > folding "manifestly constant" expressions. > > gcc/testsuite/ChangeLog > * g++.dg/ubsan/pr63956.C: Update to (always) allow floating > point > division in constexpr (if both operands are constexpr). > > Roger > -- > -- Xi Ruoyao <xry111@mengyan1223.wang> School of Aerospace Science and Technology, Xidian University
On Tue, Sep 21, 2021 at 02:15:59PM +0100, Roger Sayle wrote: > Can you double check? Integer division by zero is undefined, but isn't floating point > division by zero defined by the appropriate IEEE standards? https://eel.is/c++draft/expr.mul#4 doesn't make the division by zero behavior conditional on integral types. C has similar wording. Jakub
On Tue, Sep 21, 2021 at 3:07 PM Xi Ruoyao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > On Tue, 2021-09-21 at 12:41 +0100, Roger Sayle wrote: > > > > I was wondering if I may ask the C++ language experts for their > > opinion > > on whether (potential) floating point exceptions/traps can be ignored > > in constant expressions; this is related to PR c++/96862. I think my > > question boils down to whether (or not) the following is valid C++: > > > > constexpr float my_inf = 7.0 / 0.0; > > It's not. C++ disallows constexpr from invoking undefined behaviors in > Clauses 4 through 19, while division by zero is an undefined behavior in > Clause 8. > > > [This is currently an error with "-O2", but OK with "-O2 -ffast- > > math"!] > > > There's a long history of g++'s semantics being accidentally tied to > > the middle-end's constant folding, such that the current status quo > > is that some middle-end bugs can't be fixed without breaking C++, > > and vice versa. I'm hoping that the patch below (following Jakub's > > lead with rounding math) might be a next step to improving things, > > provided that my understanding of the desired/correct behaviour of > > the C++ front-end is correct. > > > > This patch has been tested on x86_64-pc-linux-gnu with a "make > > bootstrap" > > and "make -k check" with no new failures after tweaking two checks in > > g++.dg/ubsan/pr63956.C. > > > With this change the middle-end can become more > > strict about respecting flag_trapping_math without affecting C++'s > > behavior. Ideally, what the front-end considers valid should be > > independent of whether the user specified -fno-trapping-math (or > > -ffast-math) to the middle-end. > > I think we can allow a constexpr to contain floating div-by-zero with - > fno-trapping-math, if we consider -fno-trapping-math make the behavior > "no longer undefined" but I'm not sure. Btw, -ftrapping-math also makes inexact operations possibly trapping so I'm not sure if any combination of -ftrapping-math and -ffinite-math-only can capture what C++ requires here. > However -ffast-math also enables -ffinite-math-only, which makes div-by- > zero absolutely undefined. So to me the expected behavior is: > > g++ t.cc -> Compile error > g++ t.cc -ffast-math -> Compile error > g++ t.cc -fno-trapping-math -> Ok > g++ t.cc -fno-trapping-math -ffinite-math-only -> Compile Error > > > Thoughts? Ok for mainline? > > Based on the reasoning above I think it's not OK. But anyway I'm not a > maintainer. > > > 2021-09-21 Roger Sayle <roger@nextmovesoftware.com> > > > > gcc/cp/ChangeLog > > * constexpr.c (cxx_eval_outermost_const_expr): Temporarily > > disable > > the middle-end from honoring floating point exceptions/traps > > while > > folding "manifestly constant" expressions. > > > > gcc/testsuite/ChangeLog > > * g++.dg/ubsan/pr63956.C: Update to (always) allow floating > > point > > division in constexpr (if both operands are constexpr). > > > > Roger > > -- > > > > -- > Xi Ruoyao <xry111@mengyan1223.wang> > School of Aerospace Science and Technology, Xidian University
On Tue, 2021-09-21 at 14:15 +0100, Roger Sayle wrote: > > Can you double check? Integer division by zero is undefined, but isn't > floating point > division by zero defined by the appropriate IEEE standards? It's an undefined behavior in C++ standard. Even if we assume C++ *was* IEEE-754 conforming (C++ standard is not saying "C++ is IEEE-754 conforming"!), it would be still not "something can be evaluated in compile time". IEEE 754 says the default behavior (it can be altered with some way, for example using feenableexcept() on systems with Glibc) of floating div-by-zero with both operands finite is "The divideByZero exception shall be signaled", and: "The operations of this standard, when exceptional, can as a side effect raise some of the following status flags: inexact, underflow, overflow, divideByZero, and invalid operation." And this is a side effect in real-life: those status flags are normally implemented as some bits in the floating point status register of the CPU and can be queried, for example ISO C defined fegetexceptflag() to do this. So it's a side effect anyway. You can't evaluate a side-effect during compilation. BTW the "correct" way to get a NaN in C++ seems: #include <limits> constexpr double my_nan = std::numeric_limits<double>::quiet_NaN(); If the C++ impl supports ISO/IEC 60559 (an alias of IEEE 754), it will produce a quiet NaN which can be used in constexpr (you can use signal_NaN() instead of quiet_NaN() if you want a signaling NaN). Otherwise the compilation will fail.
On Tue, 2021-09-21 at 21:38 +0800, Xi Ruoyao via Gcc-patches wrote: > BTW the "correct" way to get a NaN in C++ seems: > > #include <limits> > constexpr double my_nan = std::numeric_limits<double>::quiet_NaN(); Sorry, we were discussing inf, not NaN... Then constexpr double my_inf = std::numeric_limits<double>::infinity(); If the C++ impl supports ISO/IEC 60559 (an alias of IEEE 754), it will produce a positive infinity. Otherwise the compilation will fail.
Thanks. It's a minefield. I'm regretting using a division by zero example (as it unintentionally drags in the whole undefined behaviour thing). How about my recently added g++.dg/pr88173-1.C, is the following valid, i.e. const, if ordered comparisons against NaNs should raise an exception with (the default) -ftrapping-math? Or only with -fno-trapping-math? constexpr bool my_false1 = __builtin_nan("") < 1.0; constexpr bool my_false2 = __builtin_nans("") < 1.0; I think Richard Beiner was right; some trapping math is acceptable and other trapping math is unacceptable, with (currently) no distinction (in the middle-end) between the two. Perhaps the g++ front-end relies on/is abusing flag_trapping_math as a proxy to ensure that division by zero is undefined (is unfolded). Cheers, Roger -- -----Original Message----- From: Jakub Jelinek <jakub@redhat.com> Sent: 21 September 2021 14:22 To: Roger Sayle <roger@nextmovesoftware.com>; Jason Merrill <jason@redhat.com>; Jonathan Wakely <jwakely@redhat.com> Cc: 'Xi Ruoyao' <xry111@mengyan1223.wang>; 'GCC Patches' <gcc-patches@gcc.gnu.org> Subject: Re: [RFC/PATCH] C++ constexpr vs. floating point exceptions. On Tue, Sep 21, 2021 at 02:15:59PM +0100, Roger Sayle wrote: > Can you double check? Integer division by zero is undefined, but > isn't floating point division by zero defined by the appropriate IEEE standards? https://eel.is/c++draft/expr.mul#4 doesn't make the division by zero behavior conditional on integral types. C has similar wording. Jakub
On Tue, 21 Sep 2021, Jakub Jelinek via Gcc-patches wrote: > On Tue, Sep 21, 2021 at 02:15:59PM +0100, Roger Sayle wrote: > > Can you double check? Integer division by zero is undefined, but isn't floating point > > division by zero defined by the appropriate IEEE standards? > > https://eel.is/c++draft/expr.mul#4 doesn't make the division by zero > behavior conditional on integral types. > C has similar wording. The position for C is that Annex F semantics take precedence over all the ways in which floating-point arithmetic has undefined behavior in the main body of the standard. So floating-point overflow and division by zero are fully defined in the presence of Annex F support, while out-of-range conversions from floating point to integer types produce an unspecified value (not necessarily the same unspecified value for different executions of the conversion in the abstract machine - as discussed in bug 93806, GCC can get that wrong and act as if a single execution of such a conversion in the abstract machine produces more than one result). In C, as specified in Annex F, initializers for floating-point objects with static or thread storage duration are evaluated with exceptions discarded and the default rounding mode in effect; 7.0 / 0.0 is a fully valid initializer for such an object to initialize it to positive infinity. As I understand it, the question for this thread is whether C++ constexpr should have a similar rule to C static initializers (which ought to apply to 1.0 / 3.0, raising inexact, just as much as to 7.0 / 0.0).
On Tue, Sep 21, 2021 at 4:30 PM Joseph Myers <joseph@codesourcery.com> wrote: > On Tue, 21 Sep 2021, Jakub Jelinek via Gcc-patches wrote: > > > On Tue, Sep 21, 2021 at 02:15:59PM +0100, Roger Sayle wrote: > > > Can you double check? Integer division by zero is undefined, but > isn't floating point > > > division by zero defined by the appropriate IEEE standards? > > > > https://eel.is/c++draft/expr.mul#4 doesn't make the division by zero > > behavior conditional on integral types. > > C has similar wording. > > The position for C is that Annex F semantics take precedence over all the > ways in which floating-point arithmetic has undefined behavior in the main > body of the standard. So floating-point overflow and division by zero are > fully defined in the presence of Annex F support, while out-of-range > conversions from floating point to integer types produce an unspecified > value (not necessarily the same unspecified value for different executions > of the conversion in the abstract machine - as discussed in bug 93806, GCC > can get that wrong and act as if a single execution of such a conversion > in the abstract machine produces more than one result). > > In C, as specified in Annex F, initializers for floating-point objects > with static or thread storage duration are evaluated with exceptions > discarded and the default rounding mode in effect; 7.0 / 0.0 is a fully > valid initializer for such an object to initialize it to positive > infinity. As I understand it, the question for this thread is whether C++ > constexpr should have a similar rule to C static initializers (which ought > to apply to 1.0 / 3.0, raising inexact, just as much as to 7.0 / 0.0). > The C rules seem to be F.8.2 Translation During translation the IEC 60559 default modes are in effect: — The rounding direction mode is rounding to nearest. — The rounding precision mode (if supported) is set so that results are not shortened. — Trapping or stopping (if supported) is disabled on all floating-point exceptions. Recommended practice: The implementation should produce a diagnostic message for each translation-time floating-point exception, other than “inexact”; the implementation should then proceed with the translation of the program. I think following the same rules for C++ would be appropriate in a diagnosing context: warn and continue. In a template argument deduction (SFINAE) context, where errors become silent substitution failures, it's probably better to treat them as non-constant. Jason
On Tue, 21 Sep 2021, Jason Merrill via Gcc-patches wrote: > On Tue, Sep 21, 2021 at 4:30 PM Joseph Myers <joseph@codesourcery.com> > wrote: > >> On Tue, 21 Sep 2021, Jakub Jelinek via Gcc-patches wrote: >> >>> On Tue, Sep 21, 2021 at 02:15:59PM +0100, Roger Sayle wrote: >>>> Can you double check? Integer division by zero is undefined, but >> isn't floating point >>>> division by zero defined by the appropriate IEEE standards? >>> >>> https://eel.is/c++draft/expr.mul#4 doesn't make the division by zero >>> behavior conditional on integral types. >>> C has similar wording. >> >> The position for C is that Annex F semantics take precedence over all the >> ways in which floating-point arithmetic has undefined behavior in the main >> body of the standard. So floating-point overflow and division by zero are >> fully defined in the presence of Annex F support, while out-of-range >> conversions from floating point to integer types produce an unspecified >> value (not necessarily the same unspecified value for different executions >> of the conversion in the abstract machine - as discussed in bug 93806, GCC >> can get that wrong and act as if a single execution of such a conversion >> in the abstract machine produces more than one result). >> >> In C, as specified in Annex F, initializers for floating-point objects >> with static or thread storage duration are evaluated with exceptions >> discarded and the default rounding mode in effect; 7.0 / 0.0 is a fully >> valid initializer for such an object to initialize it to positive >> infinity. As I understand it, the question for this thread is whether C++ >> constexpr should have a similar rule to C static initializers (which ought >> to apply to 1.0 / 3.0, raising inexact, just as much as to 7.0 / 0.0). >> > > The C rules seem to be > > F.8.2 Translation > During translation the IEC 60559 default modes are in effect: > — The rounding direction mode is rounding to nearest. > — The rounding precision mode (if supported) is set so that results are > not shortened. > — Trapping or stopping (if supported) is disabled on all floating-point > exceptions. > Recommended practice: > The implementation should produce a diagnostic message for each > translation-time floating-point exception, other than “inexact”; the > implementation should then proceed with the translation of the program. > > I think following the same rules for C++ would be appropriate in a I agree that looking at the C standard is more interesting, C++ is very bad at specifying anything float related. > diagnosing context: warn and continue. In a template argument deduction > (SFINAE) context, where errors become silent substitution failures, it's > probably better to treat them as non-constant. I am trying to imagine a sfinae example affected by whether 1./0. is constant. Does that mean A<0.,__builtin_inf()> would fail to use the specialization in template<double a,double d>struct A{}; template<double a>struct A<a,1/a>{}; ? I don't like that, I believe it should use the specialization. With ieee754, 1./0. is perfectly well defined as +inf, the only question is whether it should also set a flag at runtime, which is not relevant in a manifestly consteval context (fetestexcept, etc are not constexpr, that should be enough to catch mistakes). If some user wants to forbid FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW or FE_UNDERFLOW in compile-time operations, that looks like it could be part of a separate compiler flag or pragma, like C's FENV_ROUND can affect the rounding mode in static initializers (of course C++ templates make pragmas less convenient).
On Tue, Sep 21, 2021 at 5:19 PM Jason Merrill <jason@redhat.com> wrote: > On Tue, Sep 21, 2021 at 4:30 PM Joseph Myers <joseph@codesourcery.com> > wrote: > >> On Tue, 21 Sep 2021, Jakub Jelinek via Gcc-patches wrote: >> >> > On Tue, Sep 21, 2021 at 02:15:59PM +0100, Roger Sayle wrote: >> > > Can you double check? Integer division by zero is undefined, but >> isn't floating point >> > > division by zero defined by the appropriate IEEE standards? >> > >> > https://eel.is/c++draft/expr.mul#4 doesn't make the division by zero >> > behavior conditional on integral types. >> > C has similar wording. >> >> The position for C is that Annex F semantics take precedence over all the >> ways in which floating-point arithmetic has undefined behavior in the >> main >> body of the standard. So floating-point overflow and division by zero >> are >> fully defined in the presence of Annex F support, while out-of-range >> conversions from floating point to integer types produce an unspecified >> value (not necessarily the same unspecified value for different >> executions >> of the conversion in the abstract machine - as discussed in bug 93806, >> GCC >> can get that wrong and act as if a single execution of such a conversion >> in the abstract machine produces more than one result). >> >> In C, as specified in Annex F, initializers for floating-point objects >> with static or thread storage duration are evaluated with exceptions >> discarded and the default rounding mode in effect; 7.0 / 0.0 is a fully >> valid initializer for such an object to initialize it to positive >> infinity. As I understand it, the question for this thread is whether >> C++ >> constexpr should have a similar rule to C static initializers (which >> ought >> to apply to 1.0 / 3.0, raising inexact, just as much as to 7.0 / 0.0). >> > > The C rules seem to be > > F.8.2 Translation > During translation the IEC 60559 default modes are in effect: > — The rounding direction mode is rounding to nearest. > — The rounding precision mode (if supported) is set so that results are > not shortened. > — Trapping or stopping (if supported) is disabled on all floating-point > exceptions. > Recommended practice: > The implementation should produce a diagnostic message for each > translation-time floating-point exception, other than “inexact”; the > implementation should then proceed with the translation of the program. > > I think following the same rules for C++ would be appropriate in a > diagnosing context: warn and continue. In a template argument deduction > (SFINAE) context, where errors become silent substitution failures, it's > probably better to treat them as non-constant. > I've now added -fconstexpr-fp-except to treat manifestly-constant-evaluated expressions the same as C static initializers for floating point arithmetic. This does not distinguish between diagnosing and SFINAE context as I was suggesting above, and indeed neither front end currently warns about compile-time exceptions as Annex F recommends. Jason
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 8a5dd06..ddea132 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -7276,6 +7276,13 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, /* Turn off -frounding-math for manifestly constant evaluation. */ warning_sentinel rm (flag_rounding_math, ctx.manifestly_const_eval); + /* For manifestly constant evaluation, trapping (floating point) + exceptions don't prevent evaluation at compile-time, so temporarily + turn off -fsignaling-nans, -ftrapping-math and -ftrapv. */ + warning_sentinel sn (flag_signaling_nans, ctx.manifestly_const_eval); + warning_sentinel tm (flag_trapping_math, ctx.manifestly_const_eval); + warning_sentinel tv (flag_trapv, ctx.manifestly_const_eval); + tree type = initialized_type (t); tree r = t; bool is_consteval = false; diff --git a/gcc/testsuite/g++.dg/ubsan/pr63956.C b/gcc/testsuite/g++.dg/ubsan/pr63956.C index 3a1596e..126ed1d 100644 --- a/gcc/testsuite/g++.dg/ubsan/pr63956.C +++ b/gcc/testsuite/g++.dg/ubsan/pr63956.C @@ -69,12 +69,12 @@ constexpr float fn4 (float a, float b) { if (b != 2.0) - a = a / b; // { dg-error "is not a constant expression" } + a = a / b; return a; } constexpr float l1 = fn4 (5.0, 3.0); -constexpr float l2 = fn4 (7.0, 0.0); // { dg-message "in .constexpr. expansion" } +constexpr float l2 = fn4 (7.0, 0.0); constexpr int fn5 (const int *a, int b)