2025-02-16
integration into IS ISO/IEC 9899:202y
document number | date | comment |
---|---|---|
n3424 | 202412 | Original proposal |
n3456 | 202501 | - emphasize that the special functions are excluded because their control flow is considered to be exceptional |
- briefly discuss other cases where the gcc and C23 features disagree | ||
n3494 | 202502 | - unspecified occurence of effects |
- add a footnote to show the unspecified occurence |
CC BY, see https://creativecommons.org/licenses/by/4.0
The current wording in 6.7.13.8.1 has lead to misunderstandings about
the status of function calls with respect to the [[reproducible]]
and [[unsequenced]]
attributes for the case that such an attributed function does not
return. It seems that the corresponding gcc attributes __attribute__((pure))
and __attribute__((const))
assumed that such calls always return, without clearly documenting that
expectation, nor by documenting its reach.
Clearly, such an expectation makes sense, since otherwise a side effect could be inhibited by a call that does not return. Thus several optimizations that are the goal of these attributes would not be valid.
Currently this misunderstanding has the effect that gcc distinguishes the C23 attributes and their gcc predecessors even for the case where no pointer parameters or pointer return values are involved. The goal of this paper is to revert this unfortunate incident and establish the C23 attributes as having identical semantics as the gcc attributes for this case.
During the discussion on this paper it also became clear, that the
gcc and C23 attributes deviate on pointer parameters and return values,
namely on the fact if and when pointer targets are modifiable. Where C23
follows the model for restrict
that is
already present in the standard, the gcc attributes
const
-qualifiedconst
-qualified
target of a returned pointer of a function with __attribute__((const))
is immutable.If WG14 would have been aware of that assumed semantic when specifying the C23 attributes the result might have been different; unfortunately it now seems too late to make any semantic changes that would bring those features closer together with respect to pointers. In any case, it is not the goal of this paper here to deal with these questions.
The most important cases for non returning functions are already
covered by the current wording. In particular, calling functions that
implicitly change program state by closing streams (exit
and quick_exit
), by changing callback state
(exit
, quick_exit
and thread_exit
) are already prohibited. The aim
of this paper is to clarify this situation and to apply this rule more
widely, namely to prohibit termination of the execution whenever a side
effect may reasonably be expected during program termination.
Nevertheless, several cases of non-returning functions are not yet covered:
longjmp
.abort
, _Exit
).assert
invocation triggers.All these cases concern situations that are usually not taken into
account by optimizers. In particular, the resulting status of the
execution is specifically determined by wording for these features. Thus
not allowing the use of these features could change the behavior of a
function call from defined (whatever is defined for abort
, for example) to undefined. We don’t
think that the introduction of undefined behavior in that way is
reasonable.
New text is underlined green, removed text is
stroke-out red.
Add at the end of 6.7.13.8.1, p4, that talks about the effects that are considered for the attributes:
Similarly, a function call expression E that does not return to its caller is considered to have a visible effect on the execution state. This notwithstandingresult in exceptional control flow and are therefore not considered for the effects they produce, here. If a call to a function with the
- an invocation of
longjmp
that bypasses E,- an invocation of
abort
or_Exit
,FNT1)- an invocation of
assert
,FNT2) and- the generation of a signal, interrupt or trap that terminates the execution,
[[reproducible]]
or[[unsequenced]]
attribute would, in the absence of the attribute, result in one of the events above, then it is unspecified whether and when the event occurs.FNT3)
FNT1) In particular, each of the functionsexit
,quick_exit
andthrd_exit
have visible side effects because they close streams and modify the corresponding state that holds the activeatexit
handlers,at_quick_exit
handlers ortss_t
destructors, respectively.
FNT2) Here, in case the asserted expression evaluates to
false, even the diagnostic output that the assert
macro produces is not considered as
an effect.
FNT3) In particular, if calls to attributed functions, in
compliance with the spefications in this clause, are moved or even
completely omitted by the translator, the produced side effects may be
different or may appear in a different order than in the absence of the
attribute. For example an assertion that triggers from the function
without the attribute may produce output in a different order than for
the function with the attribute, or the output and final call to abort
may not happen at all.
Add <assert.h>
,
<setjmp.h>
and <stdlib.h>
to the Forward references.
Thanks to Paul Eggert, Bruno Haible, Jan Hubicka and Joseph Myers for discussion and feedback.