On Tue, Apr 29, 2025 at 7:58 PM Arthur O'Dwyer <arthur.j.odwyer@gmail.com> wrote:
On Mon, Apr 28, 2025 at 1:02 PM Brian Bi <bbi5291@gmail.com> wrote:
On Mon, Apr 28, 2025 at 12:56 PM Arthur O'Dwyer <arthur.j.odwyer@gmail.com> wrote:
On Sun, Apr 27, 2025 at 1:22 PM Brian Bi via Std-Proposals <std-proposals@lists.isocpp.org> wrote:

A function is not an object, it is a function.
There's no reason to reason about functions as if they were objects.
 
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):
    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.

Hm, I'm very unsympathetic to the argument that "people might be relying on function addresses to be distinct and we don't want to break them." I'd like to break them if we could.

In my view, features that make programs harder to reason about, but may have a minor impact on performance, should be opt-in. Allowing functions to be declared `[[no_unique_address]]` makes sense to me (or perhaps we should pick a different attribute token, since that one has a lot of baggage).
 
But I think we still run into a physical roadblock here:
    int f(); int g();
    static_assert(f != g);  // definitely unequal at compile time, right?
    int main() { return (f == g); }  // but we want to permit them to be equal at run-time?!
The only way to avoid this inconsistency, IMHO, is to treat function addresses as potentially non-unique [entities], i.e., forbid mangling them into symbol names and forbid comparing them at compile-time. Which I think is too onerous. But I'd love to see that proposal anyway — maybe there would be appetite for it!
Such a proposal would definitely want to explore/discuss the status quo for inherited functions and especially inherited virtuals (thunks), where comparing their addresses is already pretty weird at the codegen level.

–Arthur


--
Brian Bi