]> git.proxmox.com Git - rustc.git/blame - src/doc/unstable-book/src/language-features/unsized-locals.md
New upstream version 1.48.0+dfsg1
[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
14#![feature(unsized_locals)]
15
16use std::any::Any;
17
18fn main() {
19 let x: Box<dyn Any> = Box::new(42);
20 let x: dyn Any = *x;
21 // ^ unsized local variable
22 // ^^ unsized temporary
23 foo(x);
24}
25
26fn foo(_: dyn Any) {}
27// ^^^^^^ unsized argument
28```
29
30The RFC still forbids the following unsized expressions:
31
32```rust,ignore
33#![feature(unsized_locals)]
34
35use std::any::Any;
36
37struct MyStruct<T: ?Sized> {
38 content: T,
39}
40
41struct MyTupleStruct<T: ?Sized>(T);
42
43fn answer() -> Box<dyn Any> {
44 Box::new(42)
45}
46
47fn main() {
48 // You CANNOT have unsized statics.
49 static X: dyn Any = *answer(); // ERROR
50 const Y: dyn Any = *answer(); // ERROR
51
52 // You CANNOT have struct initialized unsized.
53 MyStruct { content: *answer() }; // ERROR
54 MyTupleStruct(*answer()); // ERROR
55 (42, *answer()); // ERROR
56
57 // You CANNOT have unsized return types.
58 fn my_function() -> dyn Any { *answer() } // ERROR
59
60 // You CAN have unsized local variables...
61 let mut x: dyn Any = *answer(); // OK
62 // ...but you CANNOT reassign to them.
63 x = *answer(); // ERROR
64
65 // You CANNOT even initialize them separately.
66 let y: dyn Any; // OK
67 y = *answer(); // ERROR
68
69 // Not mentioned in the RFC, but by-move captured variables are also Sized.
70 let x: dyn Any = *answer();
71 (move || { // ERROR
72 let y = x;
73 })();
74
75 // You CAN create a closure with unsized arguments,
76 // but you CANNOT call it.
77 // This is an implementation detail and may be changed in the future.
78 let f = |x: dyn Any| {};
79 f(*answer()); // ERROR
80}
81```
82
b7449926
XL
83## By-value trait objects
84
85With this feature, you can have by-value `self` arguments without `Self: Sized` bounds.
86
87```rust
88#![feature(unsized_locals)]
89
90trait Foo {
91 fn foo(self) {}
92}
93
94impl<T: ?Sized> Foo for T {}
95
96fn main() {
97 let slice: Box<[i32]> = Box::new([1, 2, 3]);
98 <[i32] as Foo>::foo(*slice);
99}
100```
101
a1dfa0c6 102And `Foo` will also be object-safe.
b7449926 103
a1dfa0c6 104```rust
b7449926
XL
105#![feature(unsized_locals)]
106
107trait Foo {
108 fn foo(self) {}
109}
110
111impl<T: ?Sized> Foo for T {}
112
113fn main () {
114 let slice: Box<dyn Foo> = Box::new([1, 2, 3]);
115 // doesn't compile yet
116 <dyn Foo as Foo>::foo(*slice);
117}
118```
119
dc9dc135 120One of the objectives of this feature is to allow `Box<dyn FnOnce>`.
b7449926
XL
121
122## Variable length arrays
123
124The 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]`.
125
126```rust,ignore
127#![feature(unsized_locals)]
128
129fn mergesort<T: Ord>(a: &mut [T]) {
130 let mut tmp = [T; dyn a.len()];
131 // ...
132}
133
134fn main() {
135 let mut a = [3, 1, 5, 6];
136 mergesort(&mut a);
137 assert_eq!(a, [1, 3, 5, 6]);
138}
139```
140
141VLAs 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]`.
142
143## Advisory on stack usage
144
145It's advised not to casually use the `#![feature(unsized_locals)]` feature. Typical use-cases are:
146
147- When you need a by-value trait objects.
148- When you really need a fast allocation of small temporary arrays.
149
150Another 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
151
152```rust
153#![feature(unsized_locals)]
154
155fn main() {
156 let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
157 let _x = {{{{{{{{{{*x}}}}}}}}}};
158}
159```
160
161and the code
162
163```rust
164#![feature(unsized_locals)]
165
166fn main() {
167 for _ in 0..10 {
168 let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
169 let _x = *x;
170 }
171}
172```
173
174will unnecessarily extend the stack frame.