Bug 87390 - [x86 32bit only] GCC does not honor FLT_EVAL_METHOD on implicit conversion of integer to floating point
Summary: [x86 32bit only] GCC does not honor FLT_EVAL_METHOD on implicit conversion of...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 9.0
: P3 normal
Target Milestone: 9.0
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2018-09-22 09:47 UTC by Vincent Lefèvre
Modified: 2022-10-14 07:34 UTC (History)
1 user (show)

See Also:
Host:
Target: i?86-*-*
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vincent Lefèvre 2018-09-22 09:47:40 UTC
On 32-bit x86, i.e. with FLT_EVAL_METHOD = 2, the following program

#include <stdio.h>
#include <float.h>

int main (void)
{
  unsigned long long i = 1ULL << 63;
  double d;

  d = i;

  printf ("FLT_EVAL_METHOD = %d\n", (int) FLT_EVAL_METHOD);
  printf ("%d\n", d + 1.0 == (float) d + (float) 1.0);
  printf ("%d\n", d == (float) d + (float) 1.0);
  printf ("%d\n", d == i + 1);

  return 0;
}

gives:

cventin:~> gcc-snapshot -std=c99 tst.c -o tst -m32
cventin:~> ./tst
FLT_EVAL_METHOD = 2
1
0
1

instead of 0 for the last line. Indeed, according to ISO C99 5.2.4.2.2:

  Except for assignment and cast (which remove all extra range and precision),
  the values of operations with floating operands and values subject to the
  usual arithmetic conversions and of floating constants are evaluated to a
  format whose range and precision may be greater than required by the type.
  The use of evaluation formats is characterized by the implementation-defined
  value of FLT_EVAL_METHOD:
[...]
  2  evaluate all operations and constants to the range and precision of the
     long double type.

(slightly changed in C11: "[...] the values yielded by operators with [...]").

For the first two tests, (float) d + (float) 1.0 has type float and has been evaluated with the type long double, and for the == test, this expression is converted to the semantic type double (because the left-hand side has type double), but the evaluation type is long double, thus the results 1 and 0 respectively.

For the third test, i + 1 has type unsigned long long, and for the == test, similarly, this expression should be converted to the semantic type double, but the evaluation type should be long double, thus the result should be 0, like in the second test, not 1.
Comment 1 Andrew Pinski 2018-09-22 11:05:39 UTC
Not much people care about 32bit x86 any more ...
Comment 2 Eric Gallager 2018-09-23 18:31:27 UTC
This bug originally came from this discussion on gcc-help: https://gcc.gnu.org/ml/gcc-help/2018-09/msg00072.html

(In reply to Andrew Pinski from comment #1)
> Not much people care about 32bit x86 any more ...

I still do.
Comment 3 jsm-csl@polyomino.org.uk 2018-09-25 21:55:53 UTC
I believe this is correct for C99 (see the discussions in bug 82071): my 
reading of C99 is that conversions of integers to floating point, both 
explicit and implicit, produce results that can be represented in the 
semantic type.  However, in C11 implicit conversions of integers to 
floating point can have excess precision, and as GCC produces the same 
results with -std=c11 there is still a bug there (a case I missed when 
fixing bug 82071: excess precision needs adding for comparisons of 
floating-point and integer types in this case).
Comment 4 Vincent Lefèvre 2018-09-26 12:10:16 UTC
(In reply to joseph@codesourcery.com from comment #3)
> I believe this is correct for C99 (see the discussions in bug 82071): [...]

Bug 82071 has no discussions. The main reference is N1531, which one can find at: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1531.pdf

but this is actually a clarification of potentially ambiguous text in C99. C99 6.3.1.8p2 says: "The values of floating operands and of the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby." Thus, in the example, even though one has an implicit conversion of unsigned long long to double, the result may be represented in greater precision, and this is where FLT_EVAL_METHOD is taken into account.

Note that there is an error in N1531, which says "6.3.1.8 (Usual arithmetic conversions) refers to conversions of operands of a floating type to another floating type." This is wrong! 6.3.1.8 also covers integer types; it actually uses the term "real type", and C99 defines it as "The integer and real floating types are collectively called real types." i.e. this includes integer types. There must have been a confusion by the authors of N1531.

Then, the issue is whether 6.3.1.8 covers semantic types or evaluation types when considering the values. Considering the semantic types would defeat the purpose of the possibility to have an intermediate greater precision. Indeed, consider a, b and c of type double, and the floating-point expression

  (a + b) + c

The result of a + b has semantic type double, like c. Using 6.3.1.8p1 "Otherwise, if the corresponding real type of either operand is double, the other operand is converted, without change of type domain, to a type whose corresponding real type is double.", the result of a + b would have to be converted to double, thus removing the extra precision and range.

In short, either you should always do the conversion of the value to the semantic type for each implicit conversion (though this is clearly not the intent), or you should do the conversion to the evaluation type. But be consistent.
Comment 5 jsm-csl@polyomino.org.uk 2018-09-26 16:39:45 UTC
It's 6.3.1.4 for conversions between real floating and integer types that, 
in C99 but not C11, I think requires the resulting value to be 
representable in the resulting real floating type.
Comment 6 Vincent Lefèvre 2018-09-26 18:45:29 UTC
(In reply to joseph@codesourcery.com from comment #5)
> It's 6.3.1.4 for conversions between real floating and integer types that, 
> in C99 but not C11, I think requires the resulting value to be 
> representable in the resulting real floating type.

No, it just requires the value to be in the range of values that can be represented (which is always the case in practice, even though the C standard does not forbid very long integers). Anyway, this is unrelated to the use of extra precision and range.

Note that:
* 6.3.1.4 is about the behavior of conversion between real floating and integer, for given types.
* 6.3.1.5 is about the behavior of conversion between real floating types, for given types.
* 6.3.1.8 is about the selection of the arithmetic types (implicit conversions).

Neither 6.3.1.4, nor 6.3.1.5 deals with semantic vs evaluation type (6.3.1.5 mentions "greater precision and range than required by its semantic type", but *only* for the other direction, in an *explicit* conversion). It is 6.3.1.8 that deals with the rules about extra precision and range.

BTW, note 52 of 6.3.1.8 says "The cast and assignment operators are still required to perform their specified conversions as described in 6.3.1.4 and 6.3.1.5." i.e. mentioning both 6.3.1.4 and 6.3.1.5, thus confirming that implicit conversions of integer to real floating is also covered by the extra precision and range (otherwise referencing 6.3.1.4 would be pointless). That is, if d has type double,

  d + (1ULL << 63)

and

  d + (double) (1ULL << 63)

are handled differently.
Comment 7 jsm-csl@polyomino.org.uk 2018-09-26 19:43:18 UTC
On Wed, 26 Sep 2018, vincent-gcc at vinc17 dot net wrote:

> > It's 6.3.1.4 for conversions between real floating and integer types that, 
> > in C99 but not C11, I think requires the resulting value to be 
> > representable in the resulting real floating type.
> 
> No, it just requires the value to be in the range of values that can be
> represented (which is always the case in practice, even though the C standard
> does not forbid very long integers). Anyway, this is unrelated to the use of
> extra precision and range.

It's the "If the value being converted is in the range of values that can 
be represented but cannot be represented exactly" bit I'm concerned with, 
in the absence of anything there in C99 (as opposed to in C11) to allow 
for a wider evaluation format to be used for that purpose - together with 
the cast operand being integer, not floating-point (see the notes on 
ambiguous issues in 
<https://gcc.gnu.org/ml/gcc-patches/2008-11/msg00105.html>).

> * 6.3.1.5 is about the behavior of conversion between real floating types, for
> given types.

(As clarified in C99 TC3 for DR#318.)
Comment 8 Vincent Lefèvre 2018-09-26 20:34:57 UTC
(In reply to joseph@codesourcery.com from comment #7)
> It's the "If the value being converted is in the range of values that can 
> be represented but cannot be represented exactly" bit I'm concerned with,

Note that 6.3.1.5 has the same thing for floating type to floating type.
Comment 9 jsm-csl@polyomino.org.uk 2018-09-26 20:42:10 UTC
On Wed, 26 Sep 2018, vincent-gcc at vinc17 dot net wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87390
> 
> --- Comment #8 from Vincent Lefèvre <vincent-gcc at vinc17 dot net> ---
> (In reply to joseph@codesourcery.com from comment #7)
> > It's the "If the value being converted is in the range of values that can 
> > be represented but cannot be represented exactly" bit I'm concerned with,
> 
> Note that 6.3.1.5 has the same thing for floating type to floating type.

6.3.1.5 in C99 has a clear division between promotions (no change to 
value) and demotions + explicit conversions (remove excess precision).  
(DR#318 / TC3 dealt with the case where explicit conversion from float to 
double acts like a demotion because the float was represented in long 
double format.)
Comment 10 Joseph S. Myers 2018-09-26 21:14:49 UTC
Author: jsm28
Date: Wed Sep 26 21:14:16 2018
New Revision: 264656

URL: https://gcc.gnu.org/viewcvs?rev=264656&root=gcc&view=rev
Log:
Support excess precision for integer / floating-point comparisons (PR c/87390).

In C11, implicit conversions from integer to floating-point types
produce results with the range and precision of the corresponding
evaluation format rather than only those of the type implicitly
converted to.  This patch implements that case of C11 excess precision
semantics in the case of a comparison between integer and
floating-point types, previously missed when implementing other cases
of excess precision for such implicit conversions.  As with other such
fixes, this patch conservatively follows the reading of C99 where
conversions from integer to floating-point do not produce results with
excess precision and so the change is made for C11 mode only.

Bootstrapped with no regressions on x86_64-pc-linux-gnu.

gcc/c:
	PR c/87390
	* c-typeck.c (build_binary_op): Use excess precision for
	comparisons of integers and floating-point for C11 and later.

gcc/testsuite:
	PR c/87390
	* gcc.target/i386/excess-precision-9.c,
	gcc.target/i386/excess-precision-10.c: New tests.

Added:
    trunk/gcc/testsuite/gcc.target/i386/excess-precision-10.c
    trunk/gcc/testsuite/gcc.target/i386/excess-precision-9.c
Modified:
    trunk/gcc/c/ChangeLog
    trunk/gcc/c/c-typeck.c
    trunk/gcc/testsuite/ChangeLog
Comment 11 Joseph S. Myers 2018-09-26 21:17:08 UTC
Fixed for GCC 9 to behave as you expect with -std=c11 (and deliberately not for -std=c99, keeping existing behavior in that case).
Comment 12 Vincent Lefèvre 2018-09-26 21:18:10 UTC
(In reply to joseph@codesourcery.com from comment #9)
> 6.3.1.5 in C99 has a clear division between promotions (no change to 
> value) and demotions + explicit conversions (remove excess precision).  

But there are no differences with 6.3.1.4 (when converting to a floating type): in both cases, either the value can be represented exactly, in which case it is unchanged, or it cannot, in which case it is rounded. When doing a conversion to some given type, the C standard does not care of the origin type of the value.

In any case, this is orthogonal to the rules given by 6.3.1.8 (which cover extra precision and range).
Comment 13 jsm-csl@polyomino.org.uk 2018-09-26 21:25:48 UTC
On Wed, 26 Sep 2018, vincent-gcc at vinc17 dot net wrote:

> But there are no differences with 6.3.1.4 (when converting to a floating type):
> in both cases, either the value can be represented exactly, in which case it is
> unchanged, or it cannot, in which case it is rounded. When doing a conversion
> to some given type, the C standard does not care of the origin type of the
> value.

In 6.3.1.5 in C99, that distinction is only applied in the case of 
demotions and explicit conversions (second paragraph); it does not apply 
in the first paragraph (implicit promotions).  I.e., the 6.3.1.4 handling 
of conversions from integer to floating-point is analogous to the 6.3.1.5 
second paragraph handling of demotions and explicit conversions from 
floating-point to floating-point (not to the first paragraph handling of 
implicit promotions).
Comment 14 Vincent Lefèvre 2018-09-26 21:35:09 UTC
(In reply to joseph@codesourcery.com from comment #13)
> On Wed, 26 Sep 2018, vincent-gcc at vinc17 dot net wrote:
> 
> > But there are no differences with 6.3.1.4 (when converting to a floating type):
> > in both cases, either the value can be represented exactly, in which case it is
> > unchanged, or it cannot, in which case it is rounded. When doing a conversion
> > to some given type, the C standard does not care of the origin type of the
> > value.
> 
> In 6.3.1.5 in C99, that distinction is only applied in the case of

which distinction?

> demotions and explicit conversions (second paragraph); it does not apply 
> in the first paragraph (implicit promotions).  I.e., the 6.3.1.4 handling 
> of conversions from integer to floating-point is analogous to the 6.3.1.5 
> second paragraph handling of demotions and explicit conversions from 
> floating-point to floating-point (not to the first paragraph handling of 
> implicit promotions).

Analogous? Where does the C standard say that?
Comment 15 Vincent Lefèvre 2018-09-26 21:41:50 UTC
Note also that 6.3.1.5p2 occurs in case of explicit conversions or function calls, not in typical floating-point expressions, in which types can be promoted, but never demoted. So, I don't see really what you mean.
Comment 16 jsm-csl@polyomino.org.uk 2018-09-26 21:46:47 UTC
On Wed, 26 Sep 2018, vincent-gcc at vinc17 dot net wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87390
> 
> --- Comment #14 from Vincent Lefèvre <vincent-gcc at vinc17 dot net> ---
> (In reply to joseph@codesourcery.com from comment #13)
> > On Wed, 26 Sep 2018, vincent-gcc at vinc17 dot net wrote:
> > 
> > > But there are no differences with 6.3.1.4 (when converting to a floating type):
> > > in both cases, either the value can be represented exactly, in which case it is
> > > unchanged, or it cannot, in which case it is rounded. When doing a conversion
> > > to some given type, the C standard does not care of the origin type of the
> > > value.
> > 
> > In 6.3.1.5 in C99, that distinction is only applied in the case of
> 
> which distinction?

The one you made above, between values that can be represented in the 
target type, and those that cannot and are thus rounded.

> > demotions and explicit conversions (second paragraph); it does not apply 
> > in the first paragraph (implicit promotions).  I.e., the 6.3.1.4 handling 
> > of conversions from integer to floating-point is analogous to the 6.3.1.5 
> > second paragraph handling of demotions and explicit conversions from 
> > floating-point to floating-point (not to the first paragraph handling of 
> > implicit promotions).
> 
> Analogous? Where does the C standard say that?

It doesn't say so directly.  Rather, if you apply your comparison 
(comment#12) of 6.3.1.4 and 6.3.1.5 ("in both cases, either the value can 
be represented exactly, in which case it is unchanged, or it cannot, in 
which case it is rounded"), I think it has to be one of 6.3.1.4 with 
6.3.1.5 paragraph 2, and in 6.3.1.5 paragraph 2 there is no excess 
precision in the result of the conversion.

I see no reason here, if someone has explicitly chosen an old standard 
mode (-std=c99), to deviate from the interpretations of ambiguities used 
since excess precision support was first added, given that the changes in 
C11 did not results from the Defect Report process but from a separate 
paper outside of that process.
Comment 17 Vincent Lefèvre 2018-09-26 22:17:55 UTC
(In reply to joseph@codesourcery.com from comment #16)
> On Wed, 26 Sep 2018, vincent-gcc at vinc17 dot net wrote:
> > which distinction?
> 
> The one you made above, between values that can be represented in the 
> target type, and those that cannot and are thus rounded.

Then this distinction is also applied in the first paragraph: that's why there is a parenthesis "(if the source value is represented in the precision and range of its type)", meaning that the value can also change (and the full description is in the second paragraph). The way it is specified is a bit ugly, but I assume that this comes from the modification for TC3, and they didn't want to rewrite everything at this point.

Note also that...

> > > demotions and explicit conversions (second paragraph); it does not apply 
> > > in the first paragraph (implicit promotions).

This is wrong. The first paragraph does not concern only implicit promotions. If you cast a float expression to double, this is an explicit conversion, and there are still 2 cases: If the value is exactly representable, it is unchanged; if the value is not exactly representable, it is rounded (that part is actually described in the second paragraph, as I've just said above).

> > Analogous? Where does the C standard say that?
> 
> It doesn't say so directly.  Rather, if you apply your comparison 
> (comment#12) of 6.3.1.4 and 6.3.1.5 ("in both cases, either the value can 
> be represented exactly, in which case it is unchanged, or it cannot, in 
> which case it is rounded"), I think it has to be one of 6.3.1.4 with 
> 6.3.1.5 paragraph 2, and in 6.3.1.5 paragraph 2 there is no excess 
> precision in the result of the conversion.

6.3.1.5p2 is only about explicit conversions and function calls (otherwise, types are not demoted magically). But in my example, d == i + 1, no demotion is involved.

> I see no reason here, if someone has explicitly chosen an old standard 
> mode (-std=c99), to deviate from the interpretations of ambiguities used 
> since excess precision support was first added, given that the changes in 
> C11 did not results from the Defect Report process but from a separate 
> paper outside of that process.

I think that C11 just clarified. There hasn't been a defect report against C99, AFAIK. If you think that 6.3.1.5 implies a conversion to the semantic type, then this should not be done just for values of integer source, but also for those of floating-point source. But as I've said, this somewhat defeats the purpose of extra precision and range.
Comment 18 Vincent Lefèvre 2018-09-26 22:26:50 UTC
Anyway, I recall that the behavior related to extra precision and range is described by 6.3.1.8. Thus I really don't see why 6.3.1.4 and 6.3.1.5 would come into play here (except in case of explicit conversion).
Comment 19 jsm-csl@polyomino.org.uk 2018-09-26 22:30:30 UTC
On Wed, 26 Sep 2018, vincent-gcc at vinc17 dot net wrote:

> 6.3.1.5p2 is only about explicit conversions and function calls (otherwise,
> types are not demoted magically). But in my example, d == i + 1, no demotion is
> involved.

Assignments and function return can also demote types.  As explained in my 
message adding the feature in the first place, I chose to treat all of 
(assignment, initialization, cast, function call, function return, 
increment and decrement as variants of assignment) the same (removing 
excess precision in all cases), as a practical ABI matter when function 
calls and return are involved (and including when the calls is to an 
unprototyped or variadic function).

> I think that C11 just clarified. There hasn't been a defect report against C99,

Whereas I consider this an actual semantic change in C11, with no 
allowance in C99 for any kind of conversion from integer to floating-point 
to have a result with excess precision and such an allowance explicitly 
added in C11.
Comment 20 jsm-csl@polyomino.org.uk 2018-09-26 22:38:42 UTC
I think the statement in 6.3.1.8 is only observing a consequence of 
specifications elsewhere, and stating that this excess range and precision 
does not affect semantic types; it does not, by itself, result in any 
expression having excess range and precision for a given value of 
FLT_EVAL_METHOD, because it's the specification elsewhere that has those 
results.
Comment 21 Vincent Lefèvre 2018-09-26 23:02:12 UTC
(In reply to joseph@codesourcery.com from comment #20)
> I think the statement in 6.3.1.8 is only observing a consequence of 
> specifications elsewhere,

No, 6.3.1.8 gives a specification about the choices of the types for the operations. It is not an informative part of the standard. And in it, there is nothing that differentiates integer sources from floating-point sources. This is just an operand converted to (here) a floating-point type. Note: at this point, the precision and range are unspecified, and that's why 6.3.1.4 and 6.3.1.5 do not come into play and are currently unrelated. It is only when considering 5.2.4.2.2p8 (about FLT_EVAL_METHOD) that a specification can be given using 6.3.1.4 and 6.3.1.5: with FLT_EVAL_METHOD = 2, "evaluate all operations and constants to the range and precision of the long double type", so that 6.3.1.4 and 6.3.1.5 are applied with long double as the target type for conversions.

> and stating that this excess range and precision 
> does not affect semantic types;

Note that the reason this is described like that may be that the expression needs to have a type, which cannot necessarily be expressed by the range and precision (think of FLT_EVAL_METHOD = -1, for instance).

> it does not, by itself, result in any 
> expression having excess range and precision for a given value of 
> FLT_EVAL_METHOD, because it's the specification elsewhere that has those 
> results.

5.2.4.2.2p8 (about FLT_EVAL_METHOD) just gives *additional* information about the range and precision when FLT_EVAL_METHOD is not -1.
Comment 22 jsm-csl@polyomino.org.uk 2018-09-26 23:17:04 UTC
6.3.1.8 specifies *types*.  It only gives some partial information about 
*evaluation formats*, which is essentially a consequence of information 
elsewhere (it states the possibility of wider evaluation formats, while 
never requiring them to be used, and states that when they are used they 
don't affect the types).  I think 5.2.4.2.2 has the main specification of 
when wider evaluation formats are used.  I think the combined effect of 
5.2.4.2.2 and 6.3.1.5 is that the particular form of implicit conversion 
involved in the usual arithmetic conversions does not *remove* excess 
range and precision from an operand to an operator that applies the usual 
arithmetic conversions, but that this does not result in excess precision 
being *introduced* by such an implicit conversion when the argument was of 
integer type, in the absence of any explicit wording providing for such 
conversions to result in a value with excess precision.

There are places where it is unspecified even in C11 whether an implicit 
conversion does or does not result in a value with excess range and 
precision.  For example, for function return in the absence of Annex F 
(when Annex F is implemented, function return is required to remove excess 
range and precision).
Comment 23 Vincent Lefèvre 2018-09-26 23:46:19 UTC
(In reply to joseph@codesourcery.com from comment #22)
> 6.3.1.8 specifies *types*.  It only gives some partial information about 
> *evaluation formats*, which is essentially a consequence of information 
> elsewhere (it states the possibility of wider evaluation formats, while 
> never requiring them to be used, and states that when they are used they 
> don't affect the types).

No, this does not reflect the historical practice. Information in 6.3.1.8 predates information you can find elsewhere. You can see a C89 draft here:

https://port70.net/~nsz/c/c89/c89-draft.html

3.2.1.5 Usual arithmetic conversions[*]

(which was the old 6.3.1.8) already has: "The values of operands and of the results of expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby." but information you can now find in 5.2.4.2.2 is not present (in particular, FLT_EVAL_METHOD does not exist).

[*] https://port70.net/~nsz/c/c89/c89-draft.html#3.2.1.5 

> I think 5.2.4.2.2 has the main specification of 
> when wider evaluation formats are used.

It completes information from 6.3.1.8. But if FLT_EVAL_METHOD = -1, this is just like old C89 behavior and its clause 3.2.1.5 (corresponding to 6.3.1.8 in C99).

> I think the combined effect of 
> 5.2.4.2.2 and 6.3.1.5 is that the particular form of implicit conversion 
> involved in the usual arithmetic conversions does not *remove* excess 
> range and precision from an operand to an operator that applies the usual 
> arithmetic conversions, but that this does not result in excess precision 
> being *introduced* by such an implicit conversion when the argument was of 
> integer type, in the absence of any explicit wording providing for such 
> conversions to result in a value with excess precision.

5.2.4.2.2p8 does not have specific rules for integer types. It says "[...] values subject to the usual arithmetic conversions [...] are evaluated to a format whose range and precision may be greater than required by the type." This is quite clear: values subject to the usual arithmetic conversions can either be floating-point values or integer values, as described in "6.3.1.8 Usual arithmetic conversions". And for FLT_EVAL_METHOD = 2, the format in question is long double.
Comment 24 Joseph S. Myers 2018-09-27 00:11:06 UTC
You note that "values subject to the usual arithmetic conversions can either be floating-point values or integer values".  Only in the floating-point case is excess range and precision applicable to them; there is no such concept for values with integer types (values *resulting* from the usual arithmetic conversions are a separate matter, where the rules for implicit conversions must apply to determine when there is excess range and precision).  (I don't think 5.2.4.2.2 is that well phrased, but I don't think in C99 it requires excess precision for the results of such conversions from floating-point to integer.)

The interpretation of C99 rules for excess precision used in GCC has been explained at length from 2008 onwards.  In case of doubt about whether some change reflects a defect, or about whether the resolution of a DR against one standard should be considered also to apply to a previous version, we deliberately keep compatibility with the existing interpretation for previous standard versions and only apply the change to newer ones, on the basis that users of -std= options for old standards should get stability and there is no way to get a DR resolution for what something "should" mean in an old standard version (even for features within the current standard but obsolescent, such as unprototyped functions, in practice you have to come up with your own reasonable interpretations and stick to them because WG14 doesn't want to clarify how things should work there).
Comment 25 Vincent Lefèvre 2018-09-27 00:54:41 UTC
(In reply to Joseph S. Myers from comment #24)
> You note that "values subject to the usual arithmetic conversions can either
> be floating-point values or integer values".  Only in the floating-point
> case is excess range and precision applicable to them; there is no such
> concept for values with integer types (values *resulting* from the usual
> arithmetic conversions are a separate matter, where the rules for implicit
> conversions must apply to determine when there is excess range and
> precision).  (I don't think 5.2.4.2.2 is that well phrased, but I don't
> think in C99 it requires excess precision for the results of such
> conversions from floating-point to integer.)

Yes, 5.2.4.2.2 is not well-written, but I think that it is something that is only on top of other clauses. For instance, 6.3.1.8p2 is more explicit: "The values of floating operands [...]", and 6.3.1.8 itself is applied only in the context of each particular operation that are based on these usual arithmetic conversions, as said at the beginning of 6.3: "The list in 6.3.1.8 summarizes the conversions performed by most ordinary operators; it is supplemented as required by the discussion of each operator in 6.5."

For instance, in my example, I was using "==", and "6.5.9 Equality operators" says: "If both of the operands have arithmetic type, the usual arithmetic conversions are performed. [...]", i.e. it refers to 6.3.1.8. And for an operation with floating-point operands (which was the case for "==" in my example), additional information is given by 5.2.4.2.2.

> The interpretation of C99 rules for excess precision used in GCC has been
> explained at length from 2008 onwards.

Could you cite where this bug is documented in GCC?

Even if this was an old, incorrect interpretation in GCC, saying that the bug is fixed is misleading.
Comment 26 jsm-csl@polyomino.org.uk 2018-09-27 15:34:39 UTC
On Thu, 27 Sep 2018, vincent-gcc at vinc17 dot net wrote:

> > The interpretation of C99 rules for excess precision used in GCC has been
> > explained at length from 2008 onwards.
> 
> Could you cite where this bug is documented in GCC?

The general explanation of the choices made in the cases where C99 was 
less than optimally clear is in 
<https://gcc.gnu.org/ml/gcc-patches/2008-11/msg00105.html>, the original 
addition of support for -fexcess-precision=standard.

The part of this issue that I consider a bug (i.e. the case of C11 and 
later modes, the default being -std=gnu17, so if someone just uses 
-fexcess-precision=standard in the default mode they'll get the C11 
semantics) is fixed for GCC 9.
Comment 27 Vincent Lefèvre 2018-09-27 16:27:37 UTC
(In reply to joseph@codesourcery.com from comment #26)
> The general explanation of the choices made in the cases where C99 was 
> less than optimally clear is in 
> <https://gcc.gnu.org/ml/gcc-patches/2008-11/msg00105.html>, the original 
> addition of support for -fexcess-precision=standard.

This is not visible by the end user. The decision made for -std=c99 should really be documented in the GCC manual (in Section 4.6 Floating Point), in particular as this is the only exception and yields different results for similar code (e.g. the last two cases in my example). This is made worse by the fact that -Wfloat-conversion does not warn (bug 87447).
Comment 28 Joseph S. Myers 2018-09-28 15:46:31 UTC
Author: jsm28
Date: Fri Sep 28 15:45:51 2018
New Revision: 264696

URL: https://gcc.gnu.org/viewcvs?rev=264696&root=gcc&view=rev
Log:
Fix gcc.dg/torture/fp-int-convert.h for excess precision after PR c/87390.

As reported in
<https://gcc.gnu.org/ml/gcc-patches/2018-09/msg01684.html>, some
fp-int-convert tests fail after my fix for PR c/87390, in Arm /
AArch64 configurations where _Float16 uses excess precision by
default.  The issue is comparisons of the results of a conversion by
assignment (compile-time or run-time) from integer to floating-point
with the original integer value; previously this would compare against
an implicit compile-time conversion to the target type, but now, for
C11 and later, it compares against an implicit compile-time conversion
to a possibly wider evaluation format.  This is fixed by adding casts
to the test so that the comparison is with a value converted
explicitly to the target type at compile time, without any use of a
wider evaluation format.

	PR c/87390
	* gcc.dg/torture/fp-int-convert.h (TEST_I_F_VAL): Convert integer
	values explicitly to target type for comparison.

Modified:
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/gcc.dg/torture/fp-int-convert.h
Comment 29 GCC Commits 2022-10-14 07:34:40 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:16ec267063c8ce60769888d4097bcd158410adc8

commit r13-3291-g16ec267063c8ce60769888d4097bcd158410adc8
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Fri Oct 14 09:33:23 2022 +0200

    c++: Excess precision for ? int : float or int == float [PR107097, PR82071, PR87390]
    
    The following incremental patch implements the C11 behavior (for all C++
    versions) for
    cond ? int : float
    cond ? float : int
    int cmp float
    float cmp int
    where int is any integral type, float any floating point type with
    excess precision and cmp ==, !=, >, <, >=, <= and <=>.
    
    2022-10-14  Jakub Jelinek  <jakub@redhat.com>
    
            PR c/82071
            PR c/87390
            PR c++/107097
    gcc/cp/
            * cp-tree.h (cp_ep_convert_and_check): Remove.
            * cvt.cc (cp_ep_convert_and_check): Remove.
            * call.cc (build_conditional_expr): Use excess precision for ?: with
            one arm floating and another integral.  Don't convert first to
            semantic result type from integral types.
            (convert_like_internal): Don't call cp_ep_convert_and_check, instead
            just strip EXCESS_PRECISION_EXPR before calling cp_convert_and_check
            or cp_convert.
            * typeck.cc (cp_build_binary_op): Set may_need_excess_precision
            for comparisons or SPACESHIP_EXPR with at least one operand integral.
            Don't compute semantic_result_type if build_type is non-NULL.  Call
            cp_convert_and_check instead of cp_ep_convert_and_check.
    gcc/testsuite/
            * gcc.target/i386/excess-precision-8.c: For C++ wrap abort and
            exit declarations into extern "C" block.
            * gcc.target/i386/excess-precision-10.c: Likewise.
            * g++.target/i386/excess-precision-7.C: Remove.
            * g++.target/i386/excess-precision-8.C: New test.
            * g++.target/i386/excess-precision-9.C: Remove.
            * g++.target/i386/excess-precision-10.C: New test.
            * g++.target/i386/excess-precision-12.C: New test.