c++function-pointerslanguage-lawyerone-definition-rulecomdat-folding

Do distinct functions have distinct addresses?


Consider these two functions:

void foo() {}
void bar() {}

is it guaranteed that &foo != &bar?

Similarly,

template<class T> void foo() { }

is it guaranteed that &foo<int> != &foo<double>?


There are two linkers I know of that fold function definitions together.

MSVC aggressively COMDAT folds functions, so two functions with the same implementation can be turned into one function. As a side effect, the two functions share the same address. I was under the impression that this was illegal, but I cannot find where in the standard it is made illegal.

The Gold linker also folds functions, with both a safe and all setting. safe means that if a function address is taken, it is not folded, while all folds even if the address is taken. So gold's fold safe behaves as-if functions have distinct addresses.

While folding might be unexpected, and there is code that relies on distinct (identical implementation) functions having different addresses (so it can be dangerous to fold), is it actually illegal under the current C++ standard? (C++14 at this point) (Naturally as-if safe folding is legal)


Solution

  • 5.10 Equality operators [expr.eq]

    1 The == (equal to) and the != (not equal to) operators group left-to-right. The operands shall have arithmetic, enumeration, pointer, or pointer to member type, or type std::nullptr_t. The operators == and != both yield true or false, i.e., a result of type bool. In each case below, the operands shall have the same type after the specified conversions have been applied.
    2 If at least one of the operands is a pointer, pointer conversions (4.10) and qualification conversions (4.4) are performed on both operands to bring them to their composite pointer type (Clause 5). Comparing pointers is defined as follows: Two pointers compare equal if they are both null, both point to the same function, or both represent the same address (3.9.2), otherwise they compare unequal.

    Let's take the last bit-for-bit:

    1. Two null pointers compare equal.
      Good for your sanity.
    2. Two pointers to the same function compare equal.
      Anything else would be extremely surprising.
      It also means that only one out-of-line version of any inline-function may ever have its address taken, unless you want to make function-pointer comparisons prohibitively complicated and expensive.
    3. Both represent the same address.
      Now that one is what it's all about. Dropping this and reducing if and only if to a simple if would leave it to interpretation, but that's a clear mandate to make any two functions identical, as long as it does not otherwise change observable behavior of a conformant program.