c++exception

Can a noexcept C++ function be passed as pointer-to-function to an argument for a function with C linkage?


Imagine the following situation where I have a noexcept C++ free function that is passed as function pointer to another function with C linkage:

extern "C" {
   void some_fun(void(*)());
}

void my_fun() noexcept { /* do stuff */; }

int main()
{
   some_fun(my_fun);
}

Is that correct and/or allowed? What happens in this case? What are the semantics here considering that since C++17 noexcept belongs to the type of a function?

In addition, and to my surprise, this even compiles (with both gcc and clang):

extern "C" {
   void some_fun(void(*)() noexcept);
}

void my_fun() noexcept { /* do stuff */; }

int main()
{
   some_fun(my_fun);
}

Does it even make sense that a function pointer in the signature of a C function allows the qualifier noexcept in it?


Solution

  • Is that correct and/or allowed? What happens in this case? What are the semantics here considering that since C++17 noexcept belongs to the type of a function?

    It is correct and allowed. What happens is that there is an implicit conversion sequence from void(*)() noexcept to void(*)() (but not the other way around). This conversion will convert the function pointer to the expected type without noexcept. The function can be called through the pointer without noexcept without any restrictions.

    In addition, and to my surprise, this even compiles (with both gcc and clang):

    There is no requirement that types used in a function declaration with "C" linkage must be C types. From the point of view of C++ there is no difference to normal behavior, except that the name of the function ignores namespaces and can't be overloaded (i.e. from the typical implementation point-of-view name mangling is disable).

    However, what such a declaration means for actual interop with C code, is implementation-defined. Of course you wouldn't be able to declare or define the function with the same signature in C. If you changed the signature for the C part of the program, you should really be sure about the specific way in which your compiler compiles the code to make sure that there is well-defined behavior.


    As the other answer by @Artyer points out, according to the standard, the language linkage of a function is part of its type and the function parameter in the function declared with "C" linkage inherits this language linkage. my_fun is not a function with "C" linkage and therefore can't be passed as a pointer to a function with "C" linkage. I suppose this is intended to allow different calling conventions between C and C++. In all cases I am aware of compilers ignore this part of the standard and consider the language linkage not part of the type.