Date: Sun, 27 Apr 2025 10:07:33 +0200
On 26/04/2025 9:53 pm, Jens Maurer via Std-Discussion wrote:
>
>
> On 26/04/2025 19.43, Jennifier Burnett via Std-Discussion wrote:
>> Quoting [expr.eq]p2:
>>
>>> 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
>>
>> Specifically we're interested in "Two pointers compare equal if ... both point to the same function".
>>
>> Given
>>
>> ```
>> void foo(){}
>> void bar(){}
>> ```
>>
>> The only way in which `&foo == &bar` could be true is if you say that both foo and bar are the same function. Since they have different names, that to me would would exclude them from being the same function.
>
> Right, but as was already said on this thread, optimizers
> violate that provision quite often.
>
> Could you demonstrate why &foo and &bar not being the same wold
> matter to start with? They have the same behavior.
>
> Jens
Granted, I started the thread with function pointers created through
lambdas, not functions, and the discussion drifted a bit.
Assuming that it is fine to merge them, wouldn't it be better to the
standard to reflect that?
It seems that currently the standard say one thing, but in practice code
relying on it is not portable or considered as fragile, which seems to
be the worst possible outcome.
As to examples, doesn't the one I made qualify?
If
void foo(){}
void bar(){}
have &foo == &bar, I expect it would make sense that
void foo2(){1+1;}
void bar2(){}
have the same address two, because both functions are functionally
equivalent, and after optimizations they cannot be distinguished anymore.
And that leads to my use-case (leaving launder out and using c-style
cast for legibility)
struct pod{int i;}
void foo2(void* dest, const void* source){ *(int*)(dest) =
*(int*)(source); }
void bar2(void* dest, const void* source){ *(pod*)(dest) =
*(pod*)(source); }
can both be optimized to (assuming that sizeof(int) == sizeof(pod),
which is true on most compilers)
void foo2(void* dest, const void* source){ memcpy(dest, source,
sizeof(int); }
void bar2(void* dest, const void* source){ memcpy(dest, source,
sizeof(int); }
Thus foo2 and bar2 are different function (with different bodies), but
after optimizations are the same (which is what the linker cares about).
Right now I'm realizing that maybe(?)
>
>
> On 26/04/2025 19.43, Jennifier Burnett via Std-Discussion wrote:
>> Quoting [expr.eq]p2:
>>
>>> 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
>>
>> Specifically we're interested in "Two pointers compare equal if ... both point to the same function".
>>
>> Given
>>
>> ```
>> void foo(){}
>> void bar(){}
>> ```
>>
>> The only way in which `&foo == &bar` could be true is if you say that both foo and bar are the same function. Since they have different names, that to me would would exclude them from being the same function.
>
> Right, but as was already said on this thread, optimizers
> violate that provision quite often.
>
> Could you demonstrate why &foo and &bar not being the same wold
> matter to start with? They have the same behavior.
>
> Jens
Granted, I started the thread with function pointers created through
lambdas, not functions, and the discussion drifted a bit.
Assuming that it is fine to merge them, wouldn't it be better to the
standard to reflect that?
It seems that currently the standard say one thing, but in practice code
relying on it is not portable or considered as fragile, which seems to
be the worst possible outcome.
As to examples, doesn't the one I made qualify?
If
void foo(){}
void bar(){}
have &foo == &bar, I expect it would make sense that
void foo2(){1+1;}
void bar2(){}
have the same address two, because both functions are functionally
equivalent, and after optimizations they cannot be distinguished anymore.
And that leads to my use-case (leaving launder out and using c-style
cast for legibility)
struct pod{int i;}
void foo2(void* dest, const void* source){ *(int*)(dest) =
*(int*)(source); }
void bar2(void* dest, const void* source){ *(pod*)(dest) =
*(pod*)(source); }
can both be optimized to (assuming that sizeof(int) == sizeof(pod),
which is true on most compilers)
void foo2(void* dest, const void* source){ memcpy(dest, source,
sizeof(int); }
void bar2(void* dest, const void* source){ memcpy(dest, source,
sizeof(int); }
Thus foo2 and bar2 are different function (with different bodies), but
after optimizations are the same (which is what the linker cares about).
Right now I'm realizing that maybe(?)
---- nontrivial_storage& operator=(const nontrivial_storage& other) { if (&other != this) { if(other.f.assign_copy != this->f.assign_copy){ f.destroy(this->buffer); other.f.copy(this->buffer, other->buffer); }else{ this->f.assign_copy(this->buffer, other.buffer); } this->f = other.f; } return *this; } ---- is not broken as I thought if foo2 and bar2 compare equals, because where such optimization happens the rules for implicit lifetimes would kick in. But what Nate wrote about sentinel values still holds, thus if the standard changes and allows different function to have the same address (to allow current practice) it would be nice if there was a way to opt-out from this behavior.
Received on 2025-04-27 08:07:43