-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Remove support for dynamic allocas #142911
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
Conversation
rustbot has assigned @petrochenkov. Use |
Some changes occurred in compiler/rustc_codegen_gcc Some changes occurred in compiler/rustc_codegen_ssa |
The removal part LGTM, the type checker part I don't know. |
/// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place). | ||
/// `*p` is the wide pointer that references the actual unsized place. | ||
/// Every time it is initialized, we have to reallocate the place | ||
/// and update the wide pointer. That's the reason why it is indirect. | ||
/// | ||
/// Rust has no alloca and thus no ability to move the unsized place. |
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.
Could this be made a direct place in the future? If so maybe add a FIXME?
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 know anything about codegen, so I don't know about that. There are quite a few occasions of UnsizedPlace(_) => bug!()
though, so it does look like something that could be refactored.
//! `#![feature(unsized_fn_params)]` lets you use unsized function parameters. In particular this | ||
//! is load bearing for `Box<dyn FnOnce()>: FnOnce()`. To do that, borrowck relaxes the requirement | ||
//! that certain places must be `Sized`. That means when `unsized_fn_params` is enabled, we must | ||
//! explicitly check for the sizedness of various expressions to not ICE at codegen. Note that it is | ||
//! specifically the blocks and scopes that are problematic; `udrop::<[u8]>(*foo());` is just fine. | ||
//! Also see tests/ui/unsized_locals/unsized-exprs-rpass.rs |
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 a bit skeptical about this.
I don't think the fact that there's a block or a "scope" (not sure what actually is mean by this) is problematic. Instead, I think in order to get arguments that don't require alloca's, they must be unsized place expressions. Does that make sense, and might that seem more consistent with the desugaring?
My understanding is that when we convert the unsized arg back to a pointer for the fn ABI, we just take a ref of the place if it's a place expression, rather than having to alloca storage for the value if it's a temporary.
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.
Specifically, nothing strikes me as particularly unique about block expressions. They're, AFAICT, just temporaries that evaluate to their final expression. They obviously have some special behavior with promotion, but that shouldn't have any impact 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.
For example, the difference between udrop(*foo());
and udrop({ *foo() })
is that the arg in the latter example is not a place.
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 not sure about the wording either. I appreciate the help.
Instead, I think in order to get arguments that don't require alloca's, they must be unsized place expressions. Does that make sense, and might that seem more consistent with the desugaring?
That is a much nicer and principled way to couch it. What is the best way to implement that? I don't see any obvious "is this a place" functionality in borrowck. or am I better off staying in typeck and just checking for all ExprKinds that I know are (not) place expressions like not a Deref/Index/Field etc expression?
Specifically, nothing strikes me as particularly unique about block expressions. They're, AFAICT, just temporaries that evaluate to their final expression. They obviously have some special behavior with promotion, but that shouldn't have any impact here.
Using them as the final operand of a block expression causes a move, and you don't have to bind them to anything to do that which is why it doesn't trigger existing Sized checks like assigning to a variable would do. That and the loop break example are the only way to do it as far as I can tell.
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.
What is the best way to implement that?
Well, two things I'd change here:
- Use
is_place_expr
. Look through typeck for other uses of this function to use it correctly. This is the most consistent way to check that something is a place in HIR typeck. - Move this check into argument checking, since this AFAICT only matters for unsized args.
Does the case where this is a bare expression actually matter? Like, the { *foo(); }
case? In that case, I'd still really rather keep this out of the general check_expr_kind
function, and instead check the types of unsized statement-expressions. In that case, this may be duplicated in two places -- argument checking, and the StmtKind::Semi
branch of check_stmt
.
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.
That and the loop break example are the only way to do it as far as I can tell.
Match expressions too?
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 yeah, match foo() { x => *x }
is an dynamic alloca as well. (can't unsize in the scrutinee, that's an error)
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.
Does the case where this is a bare expression actually matter?
Yeah, you will overflow the stack with a program like this (with any of the "block like" expressions discussed so far)
#![feature(unsized_fn_params)]
use std::hint::black_box;
fn udrop(t: [u8]) {
black_box(&t);
}
fn foo() -> Box<[u8]> {
Box::new([0; 1000])
}
fn main() {
for _ in 0..100000 {
udrop({ *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.
Hm, it's not just about call arguments. If you have
pub fn foo() -> Box<[u8]> {
Box::new([0;1000])
}
fn main() {
{ *foo() };
}
then that doesn't compile. But if you enable unsized_fn_params
, it starts compiling. I think that should always be an error. At least it doesn't end up alloca'ing, I guess.
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.
That's why I said:
I'd still really rather keep this out of the general
check_expr_kind
function, and instead check the types of unsized statement-expressions. In that case, this may be duplicated in two places -- argument checking, and theStmtKind::Semi
branch ofcheck_stmt
.
If you implemented that, then the expression { *foo() };
should fail.
I've implemented the checks. Maybe the error messages could use some work, but I'm not too fussed about it given they should only pop up if you incorrectly use an internal feature... @rustbot ready |
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.
Thanks. I do have one nit that I was going to let slide but it's pretty pervasive through the PR so I'd really prefer if it was fixed up really quick.
Right now you mention "because we can't move them" as the justification for why we require non-place (i.e. temp) expressions to be sized, in comments and in the ObligationCauseCode
message -- that's not totally accurate, since in the callee of an unsized arg, the arg will be moved from (like, that's why we consume the Box
in <Box<dyn FnOnce> as FnOnce>
).
I'd really prefer if we say "because we can't store them in MIR locals as temporaries" or something, since it's more precise. Could you fix that, and also perhaps link to this PR somewhere, or add additional justification that this check is specifically because we've removed support for dynamic alloca's and/or unsized locals?
Thanks. r=me after.
@bors delegate+ |
✌️ @mejrs, you can now approve this pull request! If @compiler-errors told you to " |
f9f886c
to
f972fbf
Compare
This comment has been minimized.
This comment has been minimized.
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.
"alloca" is technically also an idea in LLVM that is used with statically-known arguments and creates the expected known-sized stack storage, so we should be clear what we're interacting with here.
/// Every time it is initialized, we have to reallocate the place | ||
/// and update the wide pointer. That's the reason why it is indirect. | ||
/// | ||
/// Rust has no alloca anymore, so we cannot reallocate from the place. |
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.
/// Rust has no alloca anymore, so we cannot reallocate from the place. | |
/// MIR only supports unsized args, not dynamically-sized locals, so | |
/// new unsized temps don't exist and we must reuse the referred-to place. |
This comment has been minimized.
This comment has been minimized.
@bors r=compiler-errors |
Remove support for dynamic allocas Followup to rust-lang#141811
Rollup of 9 pull requests Successful merges: - #141996 (Fix `proc_macro::Ident`'s handling of `$crate`) - #142911 (Remove support for dynamic allocas) - #142950 (mbe: Rework diagnostics for metavariable expressions) - #143270 (tests/codegen/enum/enum-match.rs: accept negative range attribute) - #143298 (`tests/ui`: A New Order [23/N]) - #143398 (tidy: add support for `--extra-checks=auto:` feature) - #143632 (fix: correct parameter names in LLVMRustBuildMinNum and LLVMRustBuildMaxNum FFI declarations) - #143644 (Add triagebot stdarch mention ping) - #143651 (Win: Use exceptions with empty data for SEH panic exception copies instead of a new panic) r? `@ghost` `@rustbot` modify labels: rollup
Possible failure at #143715 (comment) since nothing else touched codegen @bors r- |
Remove support for dynamic allocas Followup to #141811 try-job: i686-gnu-nopt-2
💥 Test timed out |
Trying to get a concrete answer... |
Remove support for dynamic allocas Followup to #141811 try-job: i686-gnu-nopt-2
seems fine. @bors r=compiler-errors rollup=never |
☀️ Test successful - checks-actions |
What is this?This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.Comparing cdac44e (parent) -> 855e0fe (this PR) Test differencesShow 7 test diffsStage 1
Stage 2
Additionally, 5 doctest diffs were found. These are ignored, as they are noisy. Job group index
Test dashboardRun cargo run --manifest-path src/ci/citool/Cargo.toml -- \
test-dashboard 855e0fe46e68d94e9f6147531b75ac2d488c548e --output-dir test-dashboard And then open Job duration changes
How to interpret the job duration changes?Job durations can vary a lot, based on the actual runner instance |
Finished benchmarking commit (855e0fe): comparison URL. Overall result: ✅ improvements - no action needed@rustbot label: -perf-regression Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (secondary -3.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary -0.4%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 464.73s -> 464.604s (-0.03%) |
Followup to #141811