Date: Mon, 28 Apr 2025 13:02:40 -0400
On Mon, Apr 28, 2025 at 12:56 PM Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
wrote:
> On Sun, Apr 27, 2025 at 1:22 PM Brian Bi via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> On Sun, Apr 27, 2025 at 12:42 PM Tiago Freire via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> > Why do you want different things to pretend they're the same thing?
>>> If you want the language to be changed, you need to offer a reason why it
>>> would be good, not simply "why not".
>>>
>>> My proposition was that because it could produce smaller binaries (and
>>> allow for better code optimization) is itself reason enough to make the
>>> change.
>>> And I'm trying to challenge this idea that "functions have different
>>> names and therefore should have different addresses, just because".
>>> Same logic applies as to why zero size objects shouldn't have at least
>>> 1byte. no_unique_address should be the default and not the opt-in exception
>>> IMO.
>>> [...]
>>> A function is not an object, it is a function.
>>> There's no reason to reason about functions as if they were objects.
>>>
>>
>
>> In
>> https://github.com/bloomberg/bde/blob/main/groups/bsl/bsltf/bsltf_templatetestfacility.h#L1285
>> we use the fact that different functions have different addresses to
>> produce 128 unique values of type `TemplateTestFacility::MethodPtr` (which
>> is a typedef to a pointer to member function), which are then used to test
>> e.g. containers that must work with various kinds of element types.
>>
>
> That's not *quite* right [although see below]. You don't rely on the fact
> that different functions have different addresses; you rely on the fact
> that functions with different *behavior* must *necessarily* have
> different addresses.
> You use (here
> <https://github.com/bloomberg/bde/blob/main/groups/bsl/bsltf/bsltf_templatetestfacility.h#L1089-L1093>
> ):
> template <int IDENTIFIER>
> int TemplateTestFacility_StubClass::method() {
> return IDENTIFIER;
> }
> static_assert(&method<1> != &method<2>);
>
Ah, right. But I think the only reason we have to give them different
behaviour is that MSVC does the standard-noncompliant merging by default.
There are probably codebases somewhere that support only Unix, and use
empty bodies, and we shouldn't break those users.
>
> I assume Tiago doesn't propose to break *that*. He would simply
> standardize the somewhat-existing practice that we could reasonably put
> *identical* functions at identical addresses. (E.g. I know Green Hills'
> linker has done this for >20 years. But I don't know how Green Hills solves
> the problem below: whether it turns off the optimization if the address is
> ever taken, or just lets the behavior be unpredictable at runtime, or what.)
>
> template <int IDENTIFIER>
> int TemplateTestFacility_StubClass::method() {
> return 0;
> }
> assert_possibly_true(&method<1> == &method<2>);
>
> Although notice that this is tricky for two reasons. One, the optimizer
> may cause functions that "look" different to actually have the same
> behavior after optimization. A classic example is:
>
> template<class T> int distance(T *a, T *b) { return b - a; }
> static_assert(&distance<int> != &distance<short>); // must have
> different codegen, since sizeof(int) != sizeof(short)
> assert_possibly_true(&distance<int> == &distance<float>); // can have
> identical codegen, since sizeof(int) == sizeof(float)
>
> Two, letting the value of (fptr1 == fptr2) be unspecified at compile time
> means that expressions formerly compile-time-constant are no longer
> compile-time-constant. For example, today this is legal C++:
> int f();
> int g();
> constexpr bool b = (f == g);
> static_assert(b == false);
> Making it legal for (f == g) at runtime [that is, "after link-time"] would
> make the compiler unable to compile this program. We'd have to bite the
> bullet and add programs like this to Annex C — "used to be valid C++, but
> no longer." This is totally achievable — after all, this is the very reason
> why we have an Annex C — but it certainly puts an item in the "Cons" column
> of our "Pros and Cons" table.
>
> In fact, I guess this brings me full circle back to Brian Bi's point.
> Consider:
> int f();
> int g();
> template<auto*> struct A {};
> A<&f> a;
> A<&g> b;
> static_assert(!__is_same(decltype(a), decltype(b)));
>
> If `&f == &g`, then this breaks down: Surely `A<value>` must be the same
> type whenever `value` is the same value! And if `&f` and `&g` have the same
> value, then `A<&f>` and `A<&g>` must be the same type. But we won't know
> whether they're the same type until link-time. So... we can't know at
> compile-time whether these two types are the same or different? That's...
> not something we can physically represent in C++.
> So, to make this idea work at all, we would have to retroactively make it
> invalid to use *the address of a function* as a template argument — in
> the same way it's currently invalid to use the address of a string literal.
> But that would almost certainly break someone's code. (Not Brian's
> example, AFAICT, since he never uses the unique function address as a
> template argument. But surely it'll break *someone's* code.)
>
> HTH,
> Arthur
>
wrote:
> On Sun, Apr 27, 2025 at 1:22 PM Brian Bi via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> On Sun, Apr 27, 2025 at 12:42 PM Tiago Freire via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> > Why do you want different things to pretend they're the same thing?
>>> If you want the language to be changed, you need to offer a reason why it
>>> would be good, not simply "why not".
>>>
>>> My proposition was that because it could produce smaller binaries (and
>>> allow for better code optimization) is itself reason enough to make the
>>> change.
>>> And I'm trying to challenge this idea that "functions have different
>>> names and therefore should have different addresses, just because".
>>> Same logic applies as to why zero size objects shouldn't have at least
>>> 1byte. no_unique_address should be the default and not the opt-in exception
>>> IMO.
>>> [...]
>>> A function is not an object, it is a function.
>>> There's no reason to reason about functions as if they were objects.
>>>
>>
>
>> In
>> https://github.com/bloomberg/bde/blob/main/groups/bsl/bsltf/bsltf_templatetestfacility.h#L1285
>> we use the fact that different functions have different addresses to
>> produce 128 unique values of type `TemplateTestFacility::MethodPtr` (which
>> is a typedef to a pointer to member function), which are then used to test
>> e.g. containers that must work with various kinds of element types.
>>
>
> That's not *quite* right [although see below]. You don't rely on the fact
> that different functions have different addresses; you rely on the fact
> that functions with different *behavior* must *necessarily* have
> different addresses.
> You use (here
> <https://github.com/bloomberg/bde/blob/main/groups/bsl/bsltf/bsltf_templatetestfacility.h#L1089-L1093>
> ):
> template <int IDENTIFIER>
> int TemplateTestFacility_StubClass::method() {
> return IDENTIFIER;
> }
> static_assert(&method<1> != &method<2>);
>
Ah, right. But I think the only reason we have to give them different
behaviour is that MSVC does the standard-noncompliant merging by default.
There are probably codebases somewhere that support only Unix, and use
empty bodies, and we shouldn't break those users.
>
> I assume Tiago doesn't propose to break *that*. He would simply
> standardize the somewhat-existing practice that we could reasonably put
> *identical* functions at identical addresses. (E.g. I know Green Hills'
> linker has done this for >20 years. But I don't know how Green Hills solves
> the problem below: whether it turns off the optimization if the address is
> ever taken, or just lets the behavior be unpredictable at runtime, or what.)
>
> template <int IDENTIFIER>
> int TemplateTestFacility_StubClass::method() {
> return 0;
> }
> assert_possibly_true(&method<1> == &method<2>);
>
> Although notice that this is tricky for two reasons. One, the optimizer
> may cause functions that "look" different to actually have the same
> behavior after optimization. A classic example is:
>
> template<class T> int distance(T *a, T *b) { return b - a; }
> static_assert(&distance<int> != &distance<short>); // must have
> different codegen, since sizeof(int) != sizeof(short)
> assert_possibly_true(&distance<int> == &distance<float>); // can have
> identical codegen, since sizeof(int) == sizeof(float)
>
> Two, letting the value of (fptr1 == fptr2) be unspecified at compile time
> means that expressions formerly compile-time-constant are no longer
> compile-time-constant. For example, today this is legal C++:
> int f();
> int g();
> constexpr bool b = (f == g);
> static_assert(b == false);
> Making it legal for (f == g) at runtime [that is, "after link-time"] would
> make the compiler unable to compile this program. We'd have to bite the
> bullet and add programs like this to Annex C — "used to be valid C++, but
> no longer." This is totally achievable — after all, this is the very reason
> why we have an Annex C — but it certainly puts an item in the "Cons" column
> of our "Pros and Cons" table.
>
> In fact, I guess this brings me full circle back to Brian Bi's point.
> Consider:
> int f();
> int g();
> template<auto*> struct A {};
> A<&f> a;
> A<&g> b;
> static_assert(!__is_same(decltype(a), decltype(b)));
>
> If `&f == &g`, then this breaks down: Surely `A<value>` must be the same
> type whenever `value` is the same value! And if `&f` and `&g` have the same
> value, then `A<&f>` and `A<&g>` must be the same type. But we won't know
> whether they're the same type until link-time. So... we can't know at
> compile-time whether these two types are the same or different? That's...
> not something we can physically represent in C++.
> So, to make this idea work at all, we would have to retroactively make it
> invalid to use *the address of a function* as a template argument — in
> the same way it's currently invalid to use the address of a string literal.
> But that would almost certainly break someone's code. (Not Brian's
> example, AFAICT, since he never uses the unique function address as a
> template argument. But surely it'll break *someone's* code.)
>
> HTH,
> Arthur
>
-- *Brian Bi*
Received on 2025-04-28 17:02:53