-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Some promotion cleanup #76411
Some promotion cleanup #76411
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
80d0e22
to
3ef54f1
Compare
// We can only promote interior borrows of promotable temps (non-temps | ||
// don't get promoted anyway). | ||
// We only actually promote the projection base, so only that is further validated. | ||
// Make sure it does not need dropping! |
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 think this is correct, based on the fact that we can promote this:
const ALL_THE_NUMS: [u32; 1] = [
1
];
#[inline(never)]
fn array(i: usize) -> &'static u32 {
return &ALL_THE_NUMS[i];
}
But maybe we are even more clever, and promote those projections that we can, stopping at Index
?
3ef54f1
to
2eacc12
Compare
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 don't think we should be doing non-trivial refactors of this code without crater runs. I think this PR should just be the two crater-tested changes coupled with the removal of the const_kind
check for things that are forbidden in a const-context anyways and promotion of &mut []
. We just don't have good enough test coverage here, although I appreciate that you're trying to rectify that.
// Only allow statics (not consts) to refer to other statics. | ||
// FIXME(eddyb) does this matter at all for promotion? | ||
let is_static = matches!(self.const_kind, Some(hir::ConstContext::Static(_))); | ||
if !is_static { | ||
return Err(Unpromotable); | ||
} | ||
|
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.
Why do we want to promote &STATIC
? The resulting reference is already 'static
, no? Is this doing something else that I'm not seeing? I would have expected us to go the other way and make statics ineligible for promotion in all contexts for now.
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.
This enables let _val: &'static [&'static u32] = &[&FOO2];
in a fn
.
I would have expected us to go the other way and make statics ineligible for promotion in all contexts for now.
I'm all in for restricting promotion but I doubt this one can be taken back -- and then it seems strange to not promote this in fn
.
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 think this should remain the same for now. Promoting &STATIC
will cause us to generate more useless promoted MIR bodies for little benefit.
I doubt this one can be taken back.
Perhaps, but I would like some time to consider before committing to this in all contexts. &STATIC
already works everywhere. static OTHER: &[&u32] = &[&STATIC];
should work without promotion due to the "top-level scope" rule, so promotion is only helpful in very narrow circumstances.
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.
Promoting &STATIC will cause us to generate more useless promoted MIR bodies for little benefit.
That's an argument against most promotion though...
My point is, there is absolutely no reason to do this promotion only in statics. That just makes no sense. And also I was hoping to make this a PR that doesn't require its own crater run with associated 2-3 weeks of waiting.
If there is a performance problem here due to too many MIR bodies, shouldn't we also fix it inside static
then?
static OTHER: &[&u32] = &[&STATIC]; should work without promotion due to the "top-level scope" rule, so promotion is only helpful in very narrow circumstances.
But TupleStruct(&[&STATIC])
won't work without this. That might be narrow but not more narrow than many other cases here.
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, I guess we can do baby steps for now. I'm just not very patient now that I finally see an endgame for this long-standing problem.^^
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'm happy to discuss this change as part of its own PR. If I were consistent I suppose I would have demanded that the &mut []
change be split out as well, but I'm less concerned about that one since promotion actually does lifetime extension and it fits better into my (pipe) dream of requiring that all promotable expressions be valid patterns.
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.
&mut []
is also widely used, there is no taking it back, so it seems just odd to reject it in const fn
/const
/static
.
fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { | ||
match *rvalue { | ||
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.const_kind.is_none() => { | ||
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.maybe_runtime() => { |
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.
Pointer to int casts are not allowed in any const context. We should never promote these.
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 can remove it, but in the review comment you said you preferred not changing behavior without a crater run so I am not sure now what you'd prefer me to do.
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.
To me, this change is trivial, while the validate_ref
refactor is not.
return Err(Unpromotable); | ||
} | ||
_ => {} | ||
} | ||
} | ||
|
||
Rvalue::BinaryOp(op, ref lhs, _) if self.const_kind.is_none() => { | ||
Rvalue::BinaryOp(op, ref lhs, _) if self.maybe_runtime() => { |
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.
Pointer comparison/offset is not stable in any const context. We should never promote these.
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 was also surprised to see no mention of floating point arithmetic, so we currently promote e.g. &(42.0 * 55.1)
. This is actually okay, because the IEEE spec mandates the precision for simple arithmetic operations, so there shouldn't be a difference between the run-time and compile-time result. I wonder if this was a conscious choice way way back, or just a happy accident.
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.
It probably was an accident.^^
@@ -701,32 +674,7 @@ impl<'tcx> Validator<'_, 'tcx> { | |||
} |
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.
place
gets mutated here, so your refactor has changed the logic in ways that's difficult to predict.
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.
Place gets rebound here, yeah... I thought that was fine but on the second time reading this I agree I don't understand this code well enough. It removes a top-level *
but only if the thing right below it is a reference... but that changes its type?!?
I'll move the validate_ref
change to a separate PR once #75585 lands.
☔ The latest upstream changes (presumably #75585) made this pull request unmergeable. Please resolve the merge conflicts. Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:
|
eed2710
to
d604246
Compare
r? @ecstatic-morse if you have the time, if not reassign to me |
d604246
to
782bcb6
Compare
if self.const_kind.is_none() { | ||
if self.maybe_runtime() { |
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 didn't realize this in my first round of comments, but this means that we currently promote union field accesses in constants and statics but not fn
, which is somewhat weird. Union field accesses are currently unstable in const fn
, so this doesn't change anything for stable users, but if the goal is to normalize promotion across all const contexts, we need to figure out what to do here eventually.
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.
Yes, I mentioned this in rust-lang/const-eval#53.
We cannot accept them in fn
as union field access are a fallible operation -- they can cause UB. So either we keep them const/static-only, or we never promote them. In my follow-up PR that needs crater anyway, I intend to reject promoting them to see what the fallout of that would be.
r=me I think FCPs are 7 days long, so the one on #75502 has concluded even though the bot didn't leave a comment. Is this correct? This is a better abstraction than the one in #75502, so there's no need to wait for that one to filter through the queue unless we're worried about bisection. @RalfJung, do you wanna wait or squash this and add the title of #75502 to the PR summary? |
FCPs are 10 days long, so it should finish today or tomorrow. It seems confusing to not let the FCP's PR land (confusing to someone browsing through the history in the future to see what was done why). So I'd just let #75502 land. |
140f586
to
bc52c8c
Compare
☔ The latest upstream changes (presumably #76912) made this pull request unmergeable. Please resolve the merge conflicts. Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:
|
in particular allow a few more promotions for consistency when they were already allowed in other contexts
bc52c8c
to
9216eb8
Compare
@bors r=ecstatic-morse |
📌 Commit 9216eb8 has been approved by |
…tatic-morse Some promotion cleanup Based on top of both rust-lang#75502 and rust-lang#75585, this does some cleanup of the promotion code. The last 2 commits are new. * Remove the remaining cases where `const fn` is treated different from `fn`. This means no longer promoting ptr-to-int casts, raw ptr operations, and union field accesses in `const fn` -- or anywhere, for that matter. These are all unstable in const-context so this should not break any stable code. Fixes rust-lang#75586. * ~~Promote references to statics even outside statics (i.e., in functions) for consistency.~~ * Promote `&mut []` everywhere, not just in non-`const` functions, for consistency. * Explain why we do not promote deref's of statics outside statics. ~~(This is the only remaining direct user of `const_kind`.)~~ This can only land once the other two PRs land; I am mostly putting this up already because I couldn't wait ;) and to get some feedback from @rust-lang/wg-const-eval .
…tatic-morse Some promotion cleanup Based on top of both rust-lang#75502 and rust-lang#75585, this does some cleanup of the promotion code. The last 2 commits are new. * Remove the remaining cases where `const fn` is treated different from `fn`. This means no longer promoting ptr-to-int casts, raw ptr operations, and union field accesses in `const fn` -- or anywhere, for that matter. These are all unstable in const-context so this should not break any stable code. Fixes rust-lang#75586. * ~~Promote references to statics even outside statics (i.e., in functions) for consistency.~~ * Promote `&mut []` everywhere, not just in non-`const` functions, for consistency. * Explain why we do not promote deref's of statics outside statics. ~~(This is the only remaining direct user of `const_kind`.)~~ This can only land once the other two PRs land; I am mostly putting this up already because I couldn't wait ;) and to get some feedback from @rust-lang/wg-const-eval .
…tatic-morse Some promotion cleanup Based on top of both rust-lang#75502 and rust-lang#75585, this does some cleanup of the promotion code. The last 2 commits are new. * Remove the remaining cases where `const fn` is treated different from `fn`. This means no longer promoting ptr-to-int casts, raw ptr operations, and union field accesses in `const fn` -- or anywhere, for that matter. These are all unstable in const-context so this should not break any stable code. Fixes rust-lang#75586. * ~~Promote references to statics even outside statics (i.e., in functions) for consistency.~~ * Promote `&mut []` everywhere, not just in non-`const` functions, for consistency. * Explain why we do not promote deref's of statics outside statics. ~~(This is the only remaining direct user of `const_kind`.)~~ This can only land once the other two PRs land; I am mostly putting this up already because I couldn't wait ;) and to get some feedback from @rust-lang/wg-const-eval .
…tatic-morse Some promotion cleanup Based on top of both rust-lang#75502 and rust-lang#75585, this does some cleanup of the promotion code. The last 2 commits are new. * Remove the remaining cases where `const fn` is treated different from `fn`. This means no longer promoting ptr-to-int casts, raw ptr operations, and union field accesses in `const fn` -- or anywhere, for that matter. These are all unstable in const-context so this should not break any stable code. Fixes rust-lang#75586. * ~~Promote references to statics even outside statics (i.e., in functions) for consistency.~~ * Promote `&mut []` everywhere, not just in non-`const` functions, for consistency. * Explain why we do not promote deref's of statics outside statics. ~~(This is the only remaining direct user of `const_kind`.)~~ This can only land once the other two PRs land; I am mostly putting this up already because I couldn't wait ;) and to get some feedback from @rust-lang/wg-const-eval .
☀️ Test successful - checks-actions, checks-azure |
Based on top of both #75502 and #75585, this does some cleanup of the promotion code. The last 2 commits are new.
const fn
is treated different fromfn
. This means no longer promoting ptr-to-int casts, raw ptr operations, and union field accesses inconst fn
-- or anywhere, for that matter. These are all unstable in const-context so this should not break any stable code. Fixes Treatconst fn
likefn
for promotion. #75586.Promote references to statics even outside statics (i.e., in functions) for consistency.&mut []
everywhere, not just in non-const
functions, for consistency.(This is the only remaining direct user ofconst_kind
.)This can only land once the other two PRs land; I am mostly putting this up already because I couldn't wait ;) and to get some feedback from @rust-lang/wg-const-eval .