]> git.proxmox.com Git - rustc.git/blame - src/doc/unstable-book/src/language-features/unsized-locals.md
Merge tag 'debian/1.52.1+dfsg1-1_exp2' into proxmox/buster
[rustc.git] / src / doc / unstable-book / src / language-features / unsized-locals.md
CommitLineData
b7449926
XL
1# `unsized_locals`
2
3The tracking issue for this feature is: [#48055]
4
5[#48055]: https://github.com/rust-lang/rust/issues/48055
6
7------------------------
8
9This implements [RFC1909]. When turned on, you can have unsized arguments and locals:
10
0731742a 11[RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-unsized-rvalues.md
b7449926
XL
12
13```rust
29967ef6
XL
14#![allow(incomplete_features)]
15#![feature(unsized_locals, unsized_fn_params)]
b7449926
XL
16
17use std::any::Any;
18
19fn main() {
20 let x: Box<dyn Any> = Box::new(42);
21 let x: dyn Any = *x;
22 // ^ unsized local variable
23 // ^^ unsized temporary
24 foo(x);
25}
26
27fn foo(_: dyn Any) {}
28// ^^^^^^ unsized argument
29```
30
31The RFC still forbids the following unsized expressions:
32
6a06907d 33```rust,compile_fail
b7449926
XL
34#![feature(unsized_locals)]
35
36use std::any::Any;
37
38struct MyStruct<T: ?Sized> {
39 content: T,
40}
41
42struct MyTupleStruct<T: ?Sized>(T);
43
44fn answer() -> Box<dyn Any> {
45 Box::new(42)
46}
47
48fn main() {
49 // You CANNOT have unsized statics.
50 static X: dyn Any = *answer(); // ERROR
51 const Y: dyn Any = *answer(); // ERROR
52
53 // You CANNOT have struct initialized unsized.
54 MyStruct { content: *answer() }; // ERROR
55 MyTupleStruct(*answer()); // ERROR
56 (42, *answer()); // ERROR
57
58 // You CANNOT have unsized return types.
59 fn my_function() -> dyn Any { *answer() } // ERROR
60
61 // You CAN have unsized local variables...
62 let mut x: dyn Any = *answer(); // OK
63 // ...but you CANNOT reassign to them.
64 x = *answer(); // ERROR
65
66 // You CANNOT even initialize them separately.
67 let y: dyn Any; // OK
68 y = *answer(); // ERROR
69
70 // Not mentioned in the RFC, but by-move captured variables are also Sized.
71 let x: dyn Any = *answer();
72 (move || { // ERROR
73 let y = x;
74 })();
75
76 // You CAN create a closure with unsized arguments,
77 // but you CANNOT call it.
78 // This is an implementation detail and may be changed in the future.
79 let f = |x: dyn Any| {};
80 f(*answer()); // ERROR
81}
82```
83
b7449926
XL
84## By-value trait objects
85
86With this feature, you can have by-value `self` arguments without `Self: Sized` bounds.
87
88```rust
29967ef6 89#![feature(unsized_fn_params)]
b7449926
XL
90
91trait Foo {
92 fn foo(self) {}
93}
94
95impl<T: ?Sized> Foo for T {}
96
97fn main() {
98 let slice: Box<[i32]> = Box::new([1, 2, 3]);
99 <[i32] as Foo>::foo(*slice);
100}
101```
102
a1dfa0c6 103And `Foo` will also be object-safe.
b7449926 104
a1dfa0c6 105```rust
29967ef6 106#![feature(unsized_fn_params)]
b7449926
XL
107
108trait Foo {
109 fn foo(self) {}
110}
111
112impl<T: ?Sized> Foo for T {}
113
114fn main () {
115 let slice: Box<dyn Foo> = Box::new([1, 2, 3]);
116 // doesn't compile yet
117 <dyn Foo as Foo>::foo(*slice);
118}
119```
120
dc9dc135 121One of the objectives of this feature is to allow `Box<dyn FnOnce>`.
b7449926
XL
122
123## Variable length arrays
124
125The RFC also describes an extension to the array literal syntax: `[e; dyn n]`. In the syntax, `n` isn't necessarily a constant expression. The array is dynamically allocated on the stack and has the type of `[T]`, instead of `[T; n]`.
126
6a06907d 127```rust,ignore (not-yet-implemented)
b7449926
XL
128#![feature(unsized_locals)]
129
130fn mergesort<T: Ord>(a: &mut [T]) {
131 let mut tmp = [T; dyn a.len()];
132 // ...
133}
134
135fn main() {
136 let mut a = [3, 1, 5, 6];
137 mergesort(&mut a);
138 assert_eq!(a, [1, 3, 5, 6]);
139}
140```
141
142VLAs are not implemented yet. The syntax isn't final, either. We may need an alternative syntax for Rust 2015 because, in Rust 2015, expressions like `[e; dyn(1)]` would be ambiguous. One possible alternative proposed in the RFC is `[e; n]`: if `n` captures one or more local variables, then it is considered as `[e; dyn n]`.
143
144## Advisory on stack usage
145
146It's advised not to casually use the `#![feature(unsized_locals)]` feature. Typical use-cases are:
147
148- When you need a by-value trait objects.
149- When you really need a fast allocation of small temporary arrays.
150
151Another pitfall is repetitive allocation and temporaries. Currently the compiler simply extends the stack frame every time it encounters an unsized assignment. So for example, the code
152
153```rust
154#![feature(unsized_locals)]
155
156fn main() {
157 let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
158 let _x = {{{{{{{{{{*x}}}}}}}}}};
159}
160```
161
162and the code
163
164```rust
165#![feature(unsized_locals)]
166
167fn main() {
168 for _ in 0..10 {
169 let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
170 let _x = *x;
171 }
172}
173```
174
175will unnecessarily extend the stack frame.