Compare https://rust.godbolt.org/z/osMY8777W and https://rust.godbolt.org/z/azGjbbzc8. I'm not sure why the inlining doesn't happen in the case when we do use the Debug implementation though.
Moreover, how would you deal with downstream usage by dependents? Should I be able to make my dependency's type implement Debug (which is at least in spirit a violation of the orphan rule, and would make the bookkeeping/extra logic described above explode for any non-trivial dependency tree)?
People already find the Rust compiler too slow. If there's budget for adding more expensive checks, I don't think I'd want it to be spent on something like this.
I really doubt lazily code genning the Debug trait makes things worse or is super expensive to track. The main tension is more how this interplays with LTO (which I'm guessing would be unable to do this) and designing a generic language feature here for macros.
A rough sketch of the idea would be that you can annotate functions with #[lazy] and the Rust compiler knows to save off the function body for later and only keep the function definition around (no codegen). Then if it does need to codegen because it gets invoked from a non-#[lazy] function, the function is treated as inlineable and #[cold] so that if it's not inlined it's put in a cold region of the binary. It's non-trivial because you somehow need to put the codegen back into the original crate's object file which is probably tricky.
I don't understand the concern regarding the orphan rule or "downstream usage by dependents" - that's not relevant here and no language semantics change.
I don't understand how you don't think it's relevant or a semantic change. If I don't put Debug on my type, and I export it in a library, you don't have Debug today. Under what you're proposing, you'd be able to implement Debug on it by using the Debug implementation on it. If you don't allow that in your system, then it becomes impossible to ever Debug types from dependencies (unless the library authors just manually invoke the Debug implementation on their types I guess, but at that point you're back to the same thing we already have, just with a more annoying way of doing it)
When you're compiling a library, anything that's exported is a possible entrypoint for the purpose of dead code elimination. When compiling a binary, the only entrypoint is the `main` function. Apart from that, the dead code elimination algorithm is basically the same.