-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
What are the guarantees around which constants (and callees) in a function get monomorphized? #122301
Comments
Cc @rust-lang/wg-const-eval Ultimately this is a t-lang question though so might need a t-lang design meeting or some such thing. |
In fact you don't need closures, this builds as well: struct S<T>(T);
impl<T> S<T> {
const C: () = panic!();
}
const fn bar<T>() { S::<T>::C }
struct Invoke<T, const N: usize>(T);
impl<T, const N: usize> Invoke<T, N> {
const FUN: () = if N != 0 {
bar::<T>() // not called for N == 0, and hence not monomorphized
} else {
()
};
}
fn main() {
let _val = Invoke::<(), 0>::FUN;
} |
Your example doesn't quite seem to have the right shape for that use-case; could you flesh out the example a bit more to make this more clear? |
Added it to the top post. |
Makes sense, thanks! Note that without generic_const_exprs such a |
if this ought to be broken it should at least happen intentionally
if this ought to be broken it should at least happen intentionally
…fJung add test for rust-lang#122301 to cover behavior that's on stable If this ought to be broken it should at least happen intentionally See rust-lang#122301
…fJung add test for rust-lang#122301 to cover behavior that's on stable If this ought to be broken it should at least happen intentionally See rust-lang#122301
…iaskrgr Rollup of 6 pull requests Successful merges: - rust-lang#120640 (Mark UEFI std support as WIP) - rust-lang#121862 (Add release notes for 1.77.0) - rust-lang#122572 (add test for rust-lang#122301 to cover behavior that's on stable) - rust-lang#122578 (Only invoke `decorate` if the diag can eventually be emitted) - rust-lang#122615 (Mention Zalathar for coverage changes) - rust-lang#122636 (some minor code simplifications) r? `@ghost` `@rustbot` modify labels: rollup
Rollup merge of rust-lang#122572 - the8472:test-const-deadness, r=RalfJung add test for rust-lang#122301 to cover behavior that's on stable If this ought to be broken it should at least happen intentionally See rust-lang#122301
…l, r=<try> select Vec::from_iter impls in a const block to optimize compile times This relies on the trick from rust-lang#122301 Split out from rust-lang#120682
…l, r=Amanieu select Vec::from_iter impls in a const block to optimize compile times Ignoring whitespace diffs should make this easier to review. This relies on the trick from rust-lang#122301 Split out from rust-lang#120682
Nominated to get clarification from T-lang on whether this pattern - and the inline const block variant - can be relied on. I have already found this useful for compilation performance (#122785) and it could also provide a (partial?) solution to rust-lang/rfcs#3582 until more ergonomic and more powerful language features are available. Edit: And a followup question if we can rely on this, can we also expect this to be forward-compatible with pattern types on const generics or const generic exprs? |
Note that we are currently also exploring various ways to evaluate more constants, which requires some amount of monomorphization in dead code. This is done to combat the problem of optimization-level-dependent build failures:
|
This one shouldn't be optimization-dependent though, so I hope there's no conflict between them. |
It's not opt-dependent, but it's also unclear how we want to resolve the opt-dependent issue. Some proposals involve also walking all items "mentioned" in a const. That would be in direct conflict with your goal here I think. To be clear I think that's a weakness of those proposals. But if that turns out to be the only viable strategy then we'll have to decide what we want more: using |
One crucial part of this construction is that everything involved is generic. If somewhere in the two "branches" you end up calling a monomorphic function, then that may have its constants evaluated even if it is in the "dead" branch -- or it may not, it depends on which functions are deemed cross-crate-inlinable. That's basically what #122814 is about. |
I would really like to have a (Just speaking for me, not for Lang as a whole.) |
Yeah it would be nice to have that. Currently I don't see how to implement it though. |
That's rust-lang/rfcs#3582. This issue here is about whether we want to stably guarantee something about the current syntax that can stand-in for the desired feature, if somewhat crudely. I think what we'd need is that in a That said, even if we had |
#119214 can only affect monomorphic functions. I don't think we can provide any guarantees that a monomorphic function won't be codegen'd and thus have its consts evaluated. Even if there is a But... I think if we disregard monomorphic functions, then I think it is true that in a Well, and there's #122828. But that can only happen when the function in question is called from somewhere that we compute optimized_mir on. And in your example @the8472 I assume So... yeah I think your pattern is safe. But there's so many moving parts here it's really hard to say. That said, guaranteeing that your pattern is safe is exactly as hard as guaranteeing that an |
So concretely, I think that if a function is
(both of which should be true for your pattern) That said, there is this thing called polymorphization, and I have absolutely no idea how it works. If a function gets polymorphized, does it behave basically like a monomorphic function despite being generic? In that case you'd have to further make sure that your function does not get polymorphized. I don't even know which functions we can polymorphize. There does not seem to be a tracking issue for polymorphization, and it does seem to be nightly-only. |
I think it's fine to ignore polymorphization in the decision here. It should not change what gets monomorphized but instead only merges different monomorphic instances in one polymorphic one. It's the same as the linker/llvm deduplicating equivalent functions, which is something we already have to support |
Currently this compiles in stable.
This is a useful property¹ but if the panic path were not completely excluded this could lead to monomorphization-time errors which are undesirable since they only show up in
cargo build
and not incargo check
. But not as undesirable as #107503 where the errors are optimization-dependent.Still, @RalfJung indicated that the current behavior might not be intentional so I'm filing this issue for clarification.
(Also see rust-lang/rfcs#3582 for more discussion of the same question.)
¹actual use could look like this:
The text was updated successfully, but these errors were encountered: