Change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --This code panics when compiled with with cross-crate inlining being turned on: ok panics ok ( to panic) It is clearly caused by because: it is ok on but panics on it requires , and not (feature to be enabled) Ways to fix this minimal example: make - probably this is not a root cause fix set Originally I found this problem in (embedded framework using async). They are using such a comparison to ensure that passed was created by the Embassy executor. In Embassy it is possible to fix it by either: making or making (bug still here): <details<summaryPrecise versions (just skip, too much extra info)</summary<p</p</details<details<summaryBacktrace</summary<p</p</details<details<summaryExample more like in Embassy</summary<p</p</details
This may be related to but here are some points on this case: it also panics with for makes no sense?
This probably isn't a bug, but deserves some extra docs and maybe a lint.
Agree, it's not a bug, but it really does look like one without a lint when it breaks in release.. With such a description of what happens we can I guess construct a valid fix to original code: In this code we are using global variable so any access to address happens from single place and we can actually compare such a pointers. ( variables are guaranteed to have a single fixed location in memory as stated , and ) On the other hand, making isn't really a valid fix since it is about inlining and doesn't ensure/guarantee that the function will exists only once in the memory
As for a possible place to document such a thing I see section of the book and I guess page of the reference
Briefly looking at LLVM IR (, look inside ) this is what seems to be happening: is inlined from the lib to the bin crate is also inlined from the lib to the bin crate does NOT get inlined (because it does not follow the "no function calls" heuristic) copies of now: one in the bin crate for , another in the lib crate for pointers =boom This seems reasonable, albeit a bit surprising
One way to stop this surprising behavior might be to not inline functions that take address of other functions? Might be too strict though, forfeiting inlining just because somebody might want to compare function pointers doesn't seem reasonable
Another way to stop this behavior is to not inline functions when their addresses are taken and only inline in case of a call. It is more complicated I guess but seems more sensible. There is no point in inlining a function that is referenced by address (because it needs to be separate) or duplicating it (it will be the same)
I'm commenting here because I want to be helpful. I'm afraid that the way this issue leaves off without the comment I'm writing makes it sound like the compiler might be changed in order to preserve the previous behavior. I am glad to see that you promptly updated embassy in I do not expect anyone to implement the suggestions you both made; I'll admit I am not the most experienced compiler contributor but they both sound difficult/impossible for rustc-specific reasons. One problem is that "cross-crate-inlining" is not actual inlining, it is a change to the code generation strategy for a function. A function which is cross-crate-inlinable gets the behavior of ; we generate code for it lazily, and in every codegen unit that references it, and with weak linkage so that duplicates are permitted. So the address of a cross-crate-inlinable function can become unstable even if the inlining optimization never fires on it. The other problem is that cross-crate-inlinability is determined early in compilation, because it needs to inform whether other functions and static get internal or external linkage. A function which is cross-crate-inlinable exposes any static or function that it references. Since this whole process happens early, in rustc it happens before monomorphization. Disabling cross-crate-inlining for functions that reference other functions wouldn't just shut it off for all functions with a call, it would also turn it off for any function that takes the address of a generic which we can't prove is not a function.
That's completely fair, I don't know that much about rustc, so my suggestions were more like guesses how I thought this could potentially be implemented. Thanks for taking time to point out why is this infeasible, it's definitely helpful For the problem at hand though, I guess this just means that we shouldn't rely on function address, which has been true already. Just that there's now more optimizations that can lead to problems.
Do we have an issue tracking "function pointer comparison is non-deterministic", with the goal of having better docs and lints? Basically the fn ptr equivalent of , ,
Would you consider this to be fixed by That adds a note on the type docs indicating that comparing function pointers is unreliable. This is hard to find, but I'm also not sure what would be a better place.
Maybe also add a similar note to ? Otherwise, seems good to me
Oh you mean, because it has ptr fields? Hm yeah fair, I do wonder why that type implements to begin with...
Yeah, this is how the issue has started: embassy from a waker to check if belongs to its own executor. AFAIU, what it does now is still not guaranteed to work, but replacing by stopped the duplicated vtables from appearing in different compilation units.

Discussion:
/// * [`UnwindSafe`] /// * [`RefUnwindSafe`] /// <ins> /// Note that while this type implements `PartialEq`, comparing function pointers is unreliable: /// pointers to the same function can compare inequal (because functions are duplicated in multiple /// codegen units), and pointers to *different* functions can compare equal (since identical /// functions can be deduplicated within a codegen unit). /// </ins> /// [`Hash`]: hash::Hash /// [`Pointer`]: fmt::Pointer /// [`UnwindSafe`]: panic::UnwindSafe

/// /// It is possible to name this struct with a type parameter that is not a `dyn` trait object /// (for example `DynMetadata<u64>`) but not to obtain a meaningful value of that struct. <ins> /// /// Note that while this type implements `PartialEq`, comparing vtable pointers is unreliable: /// pointers to vtables of the same type for the same trait can compare inequal (because vtables are /// duplicated in multiple codegen units), and pointers to vtables of *different* types/traits can /// compare equal (since identical vtables can be deduplicated within a codegen unit). </ins> #[lang = "dyn_metadata"] pub struct DynMetadata<Dyn: ?Sized> { vtable_ptr: &'static VTable,

/// [`RawWaker`] implementation. Calling one of the contained functions using /// any other `data` pointer will cause undefined behavior. /// <ins> /// Note that while this type implements `PartialEq`, comparing function pointers, and hence /// comparing structs like this that contain function pointers, is unreliable: pointers to the same /// function can compare inequal (because functions are duplicated in multiple codegen units), and /// pointers to *different* functions can compare equal (since identical functions can be /// deduplicated within a codegen unit). /// </ins> /// # Thread safety /// If the [`RawWaker`] will be used to construct a [`Waker`] then /// these functions must all be thread-safe (even though [`RawWaker`] is