Document: N1396
Date: 2009/09/25
References: WG14
reference documents: N1362, N1382, DR 290, N1353
Authors:
Subject: Wide
function return values
Here’s the relevant text from N1362:
6.8.6.4 [3]
If a return
statement with an expression is executed, the value of the expression is
returned to the caller as the value of the function call expression. If the
expression has a type different from the return type of the function in which
it appears, the value is converted as if by assignment to an object having the
return type of the function.142)
142) The
return statement is not an assignment. The overlap restriction of subclause
6.5.16.1 does not apply to the case of function return. The representation of
floating-point values may have wider range or precision [deleted by N1382: and
is determined by FLT_EVAL_METHOD]. A cast may be used to remove this extra
range and precision.
Problems:
I believe C99’s not requiring
function returns to be narrowed to the type of the function was an oversight. A
primary goal of Annex F and the standard evaluation methods was to require
fully determined results from floating-point computation using IEC 60559 (IEEE
754-1985) basic formats and operations. The license for widened function
returns undermines this goal. To my knowledge, the goal is otherwise met if
__STDC_IEC_559__ is defined and FLT_EVAL_METHOD is 0 or 1.
Also, there are other problems with
the current specification. Conversion as if by assignment to the type of the
function is required if the return expression has a different type than the
function, but not if the return expression has a wider value only because of wide
evaluation. This allows seemingly inconsistent and confusing behavior. Consider
float f(float x) { return x * 0.1f;
}
float g(float x) { return x * 0.1; }
Function f is allowed to return a
value wider than float, but function g (which uses the wider constant) is not.
Although the current text does not
require narrowing return expressions of the same type as the function, it does
not clearly state what is allowed. Is it allowed to narrow the result? Is it
allowed to narrow the result sometimes but not always? Is it allowed to
partially narrow the result (e.g., if the ABI returns floats in double format
but a float function has a float return expression evaluated to wider than
double)? An aggressive implementation could argue “yes” to all these, though
the resulting behavior would complicate debugging and error analysis.
Footnote 142 says a cast may be used
to remove extra range and precision from the return expression. This means a
predictable program must have casts on all floating-point function calls
(except where the function directly feeds an operator like assignment that
implies the conversion). With type-generic math (tgmath), the programmer has to
reason through the tgmath resolution rules to determine which casts to apply.
These are significant obstacles to writing predictable code.
Recommendation:
Require
return expressions to be converted as if by assignment to the type of the
function.
5.2.4.2.2
[9]: change “Except for assignment and cast” to “Except for assignment, cast,
and
return”.
6.8.6.4
[3]: change the second sentence to “If the expression is evaluated to a format
different
from the return type of the function in which it appears …”
Footnote
142: remove the last two sentences.
Alternate Recommendation:
Require
return expressions to be converted as if by assignment to the type of the
function, but only in Annex F. This is a compromise that addresses the problems
for Annex F implementations while not impacting non-Annex F implementations
that exercise the license for wide returns.
Insert
the following new subclause after F.5 (and increment subsequent subclause
numbers):
F.6
The return statement
If
the return expression is evaluated in a floating-point format different from
the return type, then the expression is converted to the return type of the
function and the resulting value is returned to the caller.