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)
Let's take the last bit-for-bit:
Good for your sanity.
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.Now that one is what it's all about. Dropping this and reducing
if and only if
to a simpleif
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.Yes. From the standard (§5.10/1): "Two pointers of the same type compare equal if and only if they are both null, both point to the same function, or both represent the same address"
Once they have been instantiated,
foo<int>
andfoo<double>
are two different functions, so the above applies to them as well.It looks like defect report 1400: Function pointer equality deals with this issue and seems to me to say that it is okay to do this optimization but as comments indicate, there is disagreement. It says (emphasis mine):
and the response was:
The question is asking about two issues:
Based on comments I see two interpretations of the response:
This optimization is ok, the standard gives the implementation this freedom under the as-if rule. The as-if rule is covered in section
1.9
and means the implementation only has to emulate the observable behavior with respect to the requirements of the standard.This is still my interpretation of the response.The issue is at hand is completely ignored and the statement merely says no adjustment to the standard is required because clearly the as-if rules covers this but the interpretation is left as an exercise to the reader. Although I acknowledge due to the terseness of the response I can not dismiss this view, it ends up being a totally unhelpful response. It also seems inconsistent with the responses in the other
NAD
issues which as far as I can tell point out issue if they exist.What the draft standard says
Since we know we are dealing with the as-if rule, we can start there and note that section
1.8
says:and note
4
says:but a note from that section says:
although it is not normative, the requirements for an object laid out in paragraph
1
do not make sense in the context of a function and so it is consistent with this note. So we are explicitly restricted from aliasing objects with some exceptions but not such restriction applies to functions.Next we have section
5.10
Equality operators which says (emphasis mine):which tells us two pointers are equal if they are:
The or both represent the same address seems to give enough latitude to allow a compiler to alias two different functions and does not require pointers to different functions to compare unequal.
Observations
Keith Thompson has made some great observations that I feel are worth adding to the answer since they get to core issues involved, he says:
which I agree with and if we could shows that there is a requirement for the pointers to be unequal that would indeed violate the as-if rule but so far we can not show that.
and:
As I noted in my comment the C standard requires these macros to generate distinct values, from
7.14
in C11:So although this case is covered perhaps there are other cases that would make this optimization dangerous.
Update
Jan Hubička a
gcc
developer wrote a blog post Link time and inter-procedural optimization improvements in GCC 5, code folding was one of many topics he covered.I asked him to comment on whether folding identical functions to the same address was conforming behavior or not and he says it is not conforming behavior and indeed such an optimization would break
gcc
itself:In hindsight, after months more of reading defect reports and thinking about optimization issues, I am biased towards a more conservative reading of the committee's response. Taking the address of a function is observable behavior and therefore folding identical functions would violate the as-if rule.
So the problematic part is clearly the phrase or both represent the same address (3.9.2).
IMO this part is clearly there to define the semantics for object pointer types. And only for object pointer types.
The phrase references section 3.9.2, which means we should look there. 3.9.2 talks (among others) about the addresses that object pointers represent. It does not talk about the addresses that function pointers represent. Which, IMO, leaves just two possible interpretations:
1) The phrase simply does not apply to function pointers. Which leaves just the two null pointers and two pointers to the same function comparing equal, which is what probably most of us expected.
2) The phrase does apply. Since it's referring to 3.9.2, which says nothing about the addresses that function pointers represent, we may make any two function pointers compare equal. Which is very unexpected and of course renders comparing function pointers utterly useless.
So, while technically an argument could be made that (2) is a valid interpretation, IMO it's not a meaningful interpretation and thus should be disregarded. And since not everyone seems to agree on this, I also think that a clarification in the standard is needed.