C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Guarantees over addresses from function pointers created from lambda

From: Tiago Freire <tmiguelf_at_[hidden]>
Date: Wed, 30 Apr 2025 05:30:27 +0000
I feel that function addresses at compile time are kind of broken. They can’t be reasoned the same way as regular values.

If:
constexpr auto fun = &foo;
is allowed and
static_assert(&f != &g);
is allowed and
uintptr_t fun_number = std::bit_cast<uintptr_t>(fun)
is allowed
then why not
constexpr uintptr_t fun_number = std::bit_cast<uintptr_t>(fun)
?
That is weird.
Because functions at compile time can’t have addresses, they have “pseudo-adresses”, it’s all just smoke and mirrors, utterly meaningless.
I would not be bothered by
static_assert( &f != &g); //ok
assert( &f != &g); //trouble town
but that is my opinion.



From: Std-Proposals <std-proposals-bounces_at_[hidden]> On Behalf Of Arthur O'Dwyer via Std-Proposals
Sent: Wednesday, April 30, 2025 1:58 AM
To: Brian Bi <bbi5291_at_[hidden]>
Cc: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>; std-proposals_at_[hidden]
Subject: Re: [std-proposals] Guarantees over addresses from function pointers created from lambda

On Mon, Apr 28, 2025 at 1:02 PM Brian Bi <bbi5291_at_[hidden]<mailto:bbi5291_at_[hidden]>> wrote:
On Mon, Apr 28, 2025 at 12:56 PM Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]<mailto:arthur.j.odwyer_at_[hidden]>> wrote:
On Sun, Apr 27, 2025 at 1:22 PM Brian Bi via Std-Proposals <std-proposals_at_[hidden]<mailto:std-proposals_at_[hidden]>> wrote:

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.

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.
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]<https://cplusplus.github.io/CWG/issues/2753.html>, 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

Received on 2025-04-30 05:30:30