-
Notifications
You must be signed in to change notification settings - Fork 17
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
update promotion docs #54
Conversation
promotion.md
Outdated
* `#[rustc_args_required_const]` arguments | ||
* lifetime extension in the bodies of `const` and `static` items and array lengths | ||
|
||
Everything else is an implicit promotion context, including `const fn` bodies and non-`Copy` array initializers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const fn
bodies are also explicit promotion contexts:
const fn foo() -> i32 {
42
}
const fn bar() -> &'static i32 {
&foo()
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But... that's bad? They can be evaluated at runtime! And they need codegen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure, but you can't do anything bad as the expression must already be const evaluable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can do tons of bad things, like divide by 0 or panic. This breaks everything, it means we cannot make const-eval failures hard errors. Just imagine doing codegen for
const fn evil() { /* do something nasty */ }
const fn bar() {
if false { &evil() }
}
We have to evaluate the promoted for codegen, but if evaluation fails we cannot cause a hard error as that would mean we broke the build for no good reason.
Since control flow has just gotten stable in const, can we quickly fix this hole and make const fn
implicit promotion contexts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since control flow has just gotten stable in const, can we quickly fix this hole and make
const fn
implicit promotion contexts?
turning it into implicit promotion contexts is a breaking change that is entirely independent of control flow
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh no. I wish I would have realized this while doing the initial refactoring of const-checking. That logic is here BTW. I can do a crater run to see how many people depend on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wish I had read the code more careful to be able to provide such input more timely. No point lamenting over spilled beans, though I wonder if there is something we can do with our process to help with such things, without drowning in paperwork. The MCP mechanism could have helped, assuming that such details of the desired analysis would be spelled out in the MCP. It's much easier for me to provide such feedback based on a high-level but precise design document, than based on the code.
That logic is here BTW
This looks like const fn
are not an explicit promotion context, but get some kind of special treatment that is half-way between explicit and implicit contexts? Are there other such "hybrid" cases?
I can do a crater run to see how many people depend on this.
Yes that would be great.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: this has worked for every stable release after 1.35.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have collected my current thoughts on this in a hackmd. Please feel free to expand that with missing information!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opened an issue at rust-lang/rust#75586, so we have a dedicated place to track this problem. I will adjust the text here to reality.
When looking at the code, I found something else this document didn't mention yet: promotion of inline assembly arguments. In the future, when landing such things, could you please open an issue to adjust the docs, or (even better) a PR? Is there anything else that I missed? |
Here are some more strange things I found -- differences in promotion behavior not captured by the implicit/explicit split, and not documented here:
So to conclude, we have an entire suite of differences that has nothing to do with explicit vs implicit, and that was never mentioned in any discussion or documented anywhere 😨 . This mess has dimensions I was not aware of, and I was paying close attention on this topic for years now, just without ever reading the actual code and relying on docs instead. The docs say Is there any chance we can ditch |
I just hope this is not representative of the qualttiy of our design documents for other things like const qualification or pattern matching. If I have to read all that code to verify that the documents make sense, then what is the point of having such documents? (Well I actually read a bunch of const qualification code here and there and generally the latest version of that was quite easy to follow. I don't look at min_const_fn qualification though.^^) I'm somewhat frustrated, TBH. I realize everyone is doing their best in the amount of time that they have. But also, given the amount of time I have, I just cannot read all that code -- if we cannot make this work based on design documents, I don't see how we can make it work at all. And I fear some of this will be really hard to sort out as it has been stable forever. |
this is a very recent change fixing a regression where a static wasn't able to promote its use of another static.
we carried this over from the original promotion impl which was also the const checker. We should look into just removing that check.
Some of that mess is actually us trying to contain preexisting messes. We can defintely try to cut down on the variants of |
That doesn't answer the question though -- if promoteds are evaluated like consts, won't this stuff be put into immutable memory? Or is there some other special handling elsewhere to make it mutable?
rust-lang/rust#74945, I guess.
Sure. But that doesn't explain why it is not described in documents like this one. The first step to cleaning up a mess is to properly understand the mess, and to me that means describing it in a higher level than code. The point of this document here was not to describe the ideal scenario, but to describe reality. |
I also just realized that our sanity check for explicit promotion, namely "if it fails to promote, it fails to compile", does not make sense for lifetime extension in I see this as yet another argument that the old scheme of not doing lifetime extension via promotion, but simply by just dropping the local, actually made a lot of sense. The only thing that doesn't make sense is that this would be decided by a "promotion" analysis -- the concerns are very different, e.g. interior mutability would not be a problem I think. |
I hope we're putting it in mutable memory in the interner, if not, we have an unsoundness and can fix it by just not promoting it anymore
Yes, and we're doing that, we're just not allowing statics in constants, so we don't ever test this code path. |
If I read the code correctly, we are not promoting EDIT: yeah, this fails to compile: fn foo() -> &'static (i32, i32) {
static FOO: i32 = 13;
&(42, FOO)
} |
The generated LLVM IR says it is indeed mutable only when using pub static RO_TEST: &[i32] = { let x = &[1,2,3,4]; x };
pub static mut MUT_TEST: &mut [i32] = { let x = &mut [0xFFFF]; x }; generates
I just don't understand why, given this line. |
That surprised me, too, but I found the reason quickly: https://github.com/rust-lang/rust/blob/7189ca604ad5d9dfff7d0aeef6a42c89d73cbac7/src/librustc_mir/const_eval/eval_queries.rs#L61 |
Not sure how that explains anything, isn't The query docs say /// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item.
query static_mutability(def_id: DefId) -> Option<hir::Mutability> {
desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) }
} |
Yes, but for promoteds we just check their owner and not whether they are promoted unless it's not a static So promoteds in statics are interned as statics |
Could you point me to that code? |
Btw, not using promotion for lifetime extension of |
Btw, after I raised my frustration earlier I should also say that the |
I only found this code and it seems to require something with a |
The original thing I linked is what decides the interning mode: https://github.com/rust-lang/rust/blob/43bec40138bab10c08ac916bff2f2f81b2b70669/src/librustc_mir/const_eval/eval_queries.rs#L60-L70 So I'm not sure what else to link. This is the code that decides, and the match is only happening on the |
That is the part which I missed, thanks. |
I updated the docs now to hopefully reflect reality. Could someone check that? |
promotion.md
Outdated
compiles. Why that? The reason is that the reference obtains the lifetime of | ||
the "enclosing scope", similar to how `let x = &mut x;` creates a reference | ||
whose lifetime lasts for the enclosing scope. This is decided during MIR | ||
building already, and does not involve lifetime extension. | ||
|
||
This is also sometimes called "outermost scope" rule. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eddyb calls it "outermost scope" rule. I am not sure why. I will try to find out.
…n-const-fn, r=RalfJung Use implicit (not explicit) rules for promotability by default in `const fn` For crater run. See rust-lang/const-eval#54 (comment). cc rust-lang#75586
I updated these docs to reflect the current situation after the recent PRs that cleaned things up a bit. |
The promotion documentation was partially outdated (like saying that in const initializers, we wouldn't actually promote) and partially confusing (like the
Vec::new
example). I hope this helps.Cc @rust-lang/wg-const-eval