Why does the C++ linker allow undefined functions?

c++, compilation, language-lawyer, linker, undefined-function

Solution

What's happening here is that the function pointer is implicitly converted to `bool`. This is specified by `[conv.bool]`:

A zero value, null pointer value, or null member pointer value is converted to `false`; any other value is converted to `true`

where "null pointer value" includes null function pointers. Since the function pointer obtained from decay of a function name cannot be null, this gives `true`. You can see this by including `<< std::boolalpha` in the output command.

The following does cause a link error in g++: `(int)x;`

Regarding whether this behaviour is permitted or not, C++14 `[basic.odr.ref]/3` says:

A function whose name appears as a potentially-evaluated expression is odr-used if it is the unique lookup result or the selected member of a set of overloaded functions [...]

which does cover this case, since `x` in the output expression is looked up to the declaration of `x` above and that is the unique result. Then in `/4` we have:

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.

so the program is ill-formed but no diagnostic is required, meaning that the program's behaviour is completely undefined.

Incidentally this clause implies that no link error is required for `x();` either, however from a quality-of-implementation angle; that would be silly. The course that `g++` has chosen here seems reasonable to me.

Problem

This C++ code, perhaps surprisingly, prints out `1`. ``` #include <iostream> std::string x(); int main() { std::cout << "x: " << x << std::endl; return 0; } ``` `x` is a function prototype, which seems to be viewed as a function pointer, and C++ Standard section 4.12 Boolean conversions says: 4.12 Boolean conversions [conv.bool] 1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true. For direct-initialization (8.5), a prvalue of type std::nullptr_t can be converted to a prvalue of type bool; the resulting value is false. However, `x` is never bound to a function. As I would expect, the C linker doesn't allow this. However in C++ this isn't a problem at all. Can anyone explain this behavior?

Original source