Clarify status of non-returning functions with respect to function attributes

Jens Gustedt, INRIA and ICube, France

2024-12-21

target

integration into IS ISO/IEC 9899:202y

document history

document number date comment
n3424 202412 Original proposal

license

CC BY, see https://creativecommons.org/licenses/by/4.0

1 Motivation

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 C attributes and their gnu predecessors even for the cases where function prototypes otherwise agree. The goal of this paper is to revert this unfortunate incident and establish the C attributes as a superposition of the gnu attributes.

2 Approach

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:

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.

3 Suggested changes to the wording.

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 not withstanding are not considered for the effects they produce.
FNT1) Note that in particular the functions exit, quick_exit and thrd_exit have visible side effects because they close streams and modify the states of atexit handlers, at_quick_exit handlers and tss_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.

Modify p7:

A store operation to an object X that is sequenced during a function call such that both synchronize is said to be observable if X is not local to the call, if the lifetime of X ends after the call, if the stored value is different from the value observed by the call, if any, and if it is the last value written before the termination of the call. An evaluation of a function callFNT0) is effectless if any store operation with side effect that is sequenced during the call is the modification of an object X that synchronizes with the call; if additionally the operation is observable, there shall be a unique pointer parameter P of the function such that any access to X shall be to an lvalue that is based on P. A function pointer value f is effectless if any evaluation of a function call that calls f is effectless. A function definition is effectless if the derived function pointer value is effectless.

Add <assert.h>, <setjmp.h> and <stdlib.h> to the Forward references.

Aknowledgements

Thanks to Jan Hubicka and Joseph Myers for discussion and feedback.