-
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
Tracking issue for RFC #1909: Unsized Rvalues (unsized_locals, unsized_fn_params) #48055
Comments
@aturon: Are you referring to |
@Aaron1011 that was copied straight from the RFC. But yes, I presume that's what it's referring to. |
Why would unsized temporaries ever be necessary? The only way it would make sense to pass them as arguments would be by fat pointer, and I cannot think of a situation that would require the memory to be copied/moved. They cannot be assigned or returned from functions under the RFC. Unsized local variables could also be treated as pointers. In other words, is there any reason why unsized temporary elision shouldn't be always guaranteed? |
Is there any progress on this issue? enum RepeatSyntax { Dyn, None }
syntax::ast::ExprKind::Repeat(P<Expr>, P<Expr>, RepeatSyntax)
enum RepeatExprCount {
Const(BodyId),
Dyn(P<Expr>),
}
hir::Expr_::ExprRepeat(P<Expr>, RepeatExprCount) But for the MIR part, I have no idea how to construct a correct MIR. Should I update the structure of Thanks in advance if someone would like to write a simple mentoring instruction. |
I'm trying to remove the |
An alternative that would solve both of the unresolved questions would be explicit If I remember correctly, the main reason for this RFC was to get cc @arielb1 (RFC author) @qnighy (currently implementing this RFC in #51131) @eddyb (knows a lot about this stuff) |
@mikeyhew There's not really much of a problem with making by-value |
I guess I can see why people think it's more ergonomic: in order to opt into it, you just have to add If we're going to go ahead with this implicit syntax, then there are a few details that would be good to nail down:
|
@eddyb have you seen @alercah's RFC for DerefMove? rust-lang/rfcs#2439 |
Implement Unsized Rvalues This PR is the first step to implement RFC1909: unsized rvalues (#48055). ## Implemented - `Sized` is removed for arguments and local bindings. (under `#![feature(unsized_locals)]`) - Unsized locations are allowed in MIR - Unsized places and operands are correctly translated at codegen ## Not implemented in this PR - Additional `Sized` checks: - tuple struct constructor (accidentally compiles now) - closure arguments at closure generation (accidentally compiles now) - upvars (ICEs now) - Generating vtable for `fn method(self)` (ICEs now) - VLAs: `[e; n]` where `n` isn't const - Reduce unnecessary allocations ## Current status - [x] Fix `__rust_probestack` (rust-lang/compiler-builtins#244) - [x] Get the fix merged - [x] `#![feature(unsized_locals)]` - [x] Give it a tracking issue number - [x] Lift sized checks in typeck and MIR-borrowck - [ ] <del>Forbid `A(unsized-expr)`</del> will be another PR - [x] Minimum working codegen - [x] Add more examples and fill in unimplemented codegen paths - [ ] <del>Loosen object-safety rules (will be another PR)</del> - [ ] <del>Implement `Box<FnOnce>` (will be another PR)</del> - [ ] <del>Reduce temporaries (will be another PR)</del>
As a next step, I'll be working on trait object safety. |
@alexreg I would definitely appreciate your help, if I end up writing an RFC for The idea I have so far is to treat unsized rvalues as a sort of sugar for |
@mikeyhew That sounds like a reasonable approach to me. Has anyone specified the supposed semantics of |
Not sure if this is the right place to document this, but I found a way to make a subset of unsized returns (technically, all of them, given a
// Rust definitions
trait CloneAs<T: ?Sized> {
fn clone_as(&self) -> T;
}
impl<T: Trait + Clone> CloneAs<dyn Trait> for T {
fn clone_as(&self) -> dyn Trait { self.clone() }
}
trait Trait: CloneAs<dyn Trait> {} // Call ABI signature for `<dyn Trait as CloneAs<dyn Trait>>::clone_as`
fn(
// opaque pointer passed to `ret` as the first argument
ret_opaque: *(),
// called to return the unsized value
ret: fn(
// `ret_opaque` from above
opaque: *(),
// the `dyn Trait` return value's components
ptr: *(), vtable: *(),
) -> (),
// `self: &dyn Trait`'s components
self_ptr: *(), self_vtable: *(),
) -> ()
y = call f(x); // returns an unsized value
z = call g(y); // takes the unsized value and returns a sized one // by compiling it into:
f(&mut z, |z, y| { *z = call g(y); }, x)
cc @rust-lang/compiler |
I don't think it's been formally specified. Informally,
Don't think that bikeshed has been painted yet. I guess |
=== stdout === === stderr === warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes --> /home/runner/work/glacier/glacier/ices/67981.rs:1:12 | 1 | #![feature(unsized_locals)] | ^^^^^^^^^^^^^^ | = note: `#[warn(incomplete_features)]` on by default = note: see issue #48055 <rust-lang/rust#48055> for more information error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> /home/runner/work/glacier/glacier/ices/67981.rs:4:24 | 4 | let f: fn([u8]) = |_| {}; | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | 4 | let f: fn([u8]) = |&_| {}; | ^ error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0277`. ==============
=== stdout === === stderr === warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes --> /home/runner/work/glacier/glacier/ices/68538.rs:1:12 | 1 | #![feature(unsized_locals)] | ^^^^^^^^^^^^^^ | = note: `#[warn(incomplete_features)]` on by default = note: see issue #48055 <rust-lang/rust#48055> for more information error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> /home/runner/work/glacier/glacier/ices/68538.rs:4:27 | 4 | pub fn take_unsized_slice(s: [u8]) { | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | 4 | pub fn take_unsized_slice(&s: [u8]) { | ^ error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0277`. ==============
=== stdout === === stderr === warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes --> /home/runner/work/glacier/glacier/ices/68543.rs:1:12 | 1 | #![feature(unsized_locals)] | ^^^^^^^^^^^^^^ | = note: `#[warn(incomplete_features)]` on by default = note: see issue #48055 <rust-lang/rust#48055> for more information error[E0277]: the size for values of type `(dyn Future<Output = T> + Unpin + 'static)` cannot be known at compilation time --> /home/runner/work/glacier/glacier/ices/68543.rs:6:17 | 6 | async fn bug<T>(mut f: dyn Future<Output = T> + Unpin) -> T { | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Future<Output = T> + Unpin + 'static)` = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | 6 | async fn bug<T>(&mut f: dyn Future<Output = T> + Unpin) -> T { | ^ error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0277`. ==============
Will there be any way to do an unsized coercion on an unsized local without using dynamic memory allocation? The RFC didn't seem clear on this point. At the moment, as far as I can tell the only way is to go through fn run_fn_dyn<'a>(f: dyn FnOnce() -> u32 + 'a) -> u32 {
f() + 1
} and want to run it on a known size fn run_fn<'a, F: FnOnce() -> u32 + 'a>(f: F) -> u32 {
// With optimizations enabled the dynamic allocation seems to be removed.
let f = {
// Declare b in local scope so that it gets dropped before run_fn_dyn is called. Otherwise
// the compiler isn't smart enough to figure out that the memory allocation is unnecessary
// and remove it.
let b = Box::new(f) as Box<dyn FnOnce() -> u32 + 'a>;
*b
};
run_fn_dyn(f)
} |
I'm not sure how exactly how such (https://stackoverflow.com/questions/70463366/the-data-structure-that-is-the-result-of-stack-based-flattening-of-nested-homoge) data structure for some known dimensionality (=level of nesting) should interact with allocation on the heap. It seems that my data structure must keep track of its lengths in terms of gcd(sizeof(T), sizeof(usize)) and allow conversion to length in bytes. EDIT: even better than that, it can track the count of lengths len_count and count of elements elem_count. Then the byte-length of the data structure will be the integer linear combination len_count * sizeof(usize) + elem_count * sizeof(T). |
@rustbot label F-unsized_fn_params |
=== stdout === === stderr === warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes --> /home/runner/work/glacier/glacier/ices/61335.rs:2:12 | 2 | #![feature(unsized_locals)] | ^^^^^^^^^^^^^^ | = note: see issue #48055 <rust-lang/rust#48055> for more information = note: `#[warn(incomplete_features)]` on by default warning: the feature `async_await` has been stable since 1.39.0 and no longer requires an attribute to enable --> /home/runner/work/glacier/glacier/ices/61335.rs:1:12 | 1 | #![feature(async_await)] | ^^^^^^^^^^^ | = note: `#[warn(stable_features)]` on by default error[E0277]: the size for values of type `dyn std::fmt::Display` cannot be known at compilation time --> /home/runner/work/glacier/glacier/ices/61335.rs:7:9 | 7 | let _x = *x; | ^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `dyn std::fmt::Display` = note: all values live across `await` must have a statically known size error: aborting due to previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0277`. ==============
=== stdout === === stderr === warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes --> /home/runner/work/glacier/glacier/ices/68543.rs:1:31 | 1 | #![feature(unsized_fn_params, unsized_locals)] | ^^^^^^^^^^^^^^ | = note: see issue #48055 <rust-lang/rust#48055> for more information = note: `#[warn(incomplete_features)]` on by default error[E0277]: the size for values of type `(dyn Future<Output = T> + Unpin + 'static)` cannot be known at compilation time --> /home/runner/work/glacier/glacier/ices/68543.rs:6:17 | 6 | async fn bug<T>(mut f: dyn Future<Output = T> + Unpin) -> T { | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Future<Output = T> + Unpin + 'static)` = note: all values captured by value by a closure must have a statically known size error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0277`. ==============
=== stdout === === stderr === warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes --> /home/runner/work/glacier/glacier/ices/88212.rs:1:12 | 1 | #![feature(unsized_locals)] | ^^^^^^^^^^^^^^ | = note: see issue #48055 <rust-lang/rust#48055> for more information = note: `#[warn(incomplete_features)]` on by default error[E0277]: the size for values of type `dyn Example` cannot be known at compilation time --> /home/runner/work/glacier/glacier/ices/88212.rs:16:18 | 15 | (move || { // ERROR | -- this closure captures all values by move 16 | let _y = x; | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `dyn Example` = note: all values captured by value by a closure must have a statically known size error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0277`. ==============
We should probably reject unsized arguments for non-Rust ABIs... it makes little sense to do this with an |
With #111374, unsized locals are no longer blatantly unsound. However, they still lack an actual operational semantics in MIR -- and the way they are represented in MIR doesn't lend itself to a sensible semantics; they need a from-scratch re-design I think. We are getting more and more MIR optimizations and without a semantics, the interactions of unsized locals with those optimizations are basically unpredictable. The issue with their MIR form is that and assignment
However, when If they were suggested for addition to rustc today, we'd not accept a PR adding them to MIR without giving them semantics. Unsized locals are the only part of MIR that doesn't even have a proposed semantics that could be implemented in Miri. (We used to have a hack, but I removed it because it was hideous and affected the entire interpreter.) I'm not comfortable having even an unstable feature be in such a bad state, with no sign of improvement for many years. So I still feel that unsized locals should be either re-implemented in a well-designed way, or removed -- the current status is very unsatisfying and prone to bugs. Unstable features are what we use to experiment, and sometimes the result of an experiment is that whatever we do doesn't work and we need to try something else. (Unsized argument do not have that issue: function arguments get marked as "live" when the stack frame is pushed, and at that moment we know the values for all the arguments. Allocating the local and initializing it are done together as part of argument passing. That means we can use the size information we get from the value that the caller chose to allocate the right amount of memory in the callee.) |
This is a tracking issue for the RFC "Unsized Rvalues " (rust-lang/rfcs#1909).
Steps:
Blocking bugs for
unsized_fn_params
:extern
types) #115709 (bad interaction with extern_type: we either need to be okay with post-mono checks or need a trait for "dynamically sized" types)Related bugs:
Box<dyn FnOnce>
doesn't respect self alignmentUnresolved questions:
extern type
arguments withunsized_fn_params
, but that does not make much sense and leads to ICEs: unsized_fn_params should not accept types that don't have a dynamically fixed size (such asextern
types) #115709The text was updated successfully, but these errors were encountered: