Home > database >  Is it allowed to create a `typedef` for a function with attributes?
Is it allowed to create a `typedef` for a function with attributes?

Time:08-04

I have several functions with identical prototypes declared as noreturn. I want to declare a pointer to these functions in a header shared between C and C .

typedef __attribute__ ((noreturn)) void (*apply_transition_effects_t)(object_t *, data_t *);

I am using GCC's syntax here, but the question applies equally to [[attribute]] or _Noreturn syntax found in standard C and C.

Is such declaration allowed by the languages' standards? If yes, does it make any difference to specify this attribute in a type declaration? What about other functions' attributes, can/should they be specified in a type declaration?

CodePudding user response:

Answer applying to C (C 20):

__attribute__ is completely a compiler-specific feature that is not covered in any way by the standard. The standard does not say where it may or may not appear. From its point of view this is simply an identifier which is reserved in all contexts and therefore using it in the program causes undefined behavior (meaning that the standard technically does not impose any requirement on the compiler as to how it handles the program).

The C equivalent [[...]], where ... is a stand-in for any attribute specification, is allowed in a typedef declaration, but not in the position you are using __attribute__. In

typedef void (*apply_transition_effects_t)(object_t *, data_t *);

it can appear before and after any two tokens except between typedef and void and between ( and *. Depending on where the attribute is placed it will appertain to a different entity in the declaration.

You are trying to apply the attribute to either the declared type name, in which case it should be placed in either of the following positions:

[[...]] typedef void (*apply_transition_effects_t [[...]])(object_t *, data_t *);

or you are trying to apply it to the function pointer type, in which case it should be placed

typedef void (* [[...]] apply_transition_effects_t)(object_t *, data_t *);

or you are trying to apply the attribute to the function type to which the pointer-to-function type refers, in which case it should be placed

typedef void (*apply_transition_effects_t)(object_t *, data_t *) [[...]];

For the specific attribute you are trying to use here the standard-equivalent would be [[noreturn]]. However [[noreturn]] is only allowed to apply to functions. (see [dcl.attr.noreturn]/3) Therefore it can't be used in any of the positions mentioned above (or anywhere else in the declaration). Doing so anyway makes the program ill-formed. (see [dcl.attr]/5)

[[noreturn]] is not part of the function type in C and so cannot be preserved through function pointers. That decision was consciously made, see CWG issue 836 closed as not-a-defect.

The error you get in your answer is not actually an error, just a warning which you asked the compiler to turn into an error with -Werror.

A function marked [[noreturn]] has undefined behavior if it returns anyway and it is suggested that implementations warn if the function might return (see [dcl.attr.noreturn]/3), but a program is not ill-formed just because you call a function or function pointer which is not known to be noreturn at the end of a noreturn function. It is a quality-of-implementation issue under which conditions the compiler issues a warning for such situations.

Of course if the noreturn attribute was part of the function type, it would make the analysis required for determining whether a noreturn function actually returns easier and that seems to be how GCC's __attribute__((noreturn)) works.

CodePudding user response:

It turned out that it is not only possible to specify noreturn in a typedef, but it is also required to have it if I want to call a noreturn function pointer from other functions marked as noreturn on their own.

Otherwise the compiler cannot reliably determine whether the outermost functions can return or not:

/path/to/file.cc:123:1: error: "noreturn" function does return [-Werror]

I.e.,

typedef __attribute__ ((noreturn)) void (*apply_transition_effects_t)(object_t *, data_t *);

__attribute__ ((noreturn)) void common_exception(object_t *, data_t *) {
   // call exit(), or throw exception, or do longjmp() etc.
   ...
}


... somewhere later ...

apply_transition_effects_t fn = common_exception;

... later, in another compilation unit ...

__attribute__ ((noreturn)) void specific_exception() {
   ...
   fn(obj, data); // here the compiler wants to know if fn() returns or not.
}


  • Related