]> git.lizzy.rs Git - rust.git/blob - src/doc/unstable-book/src/language-features/unsized-locals.md
Rollup merge of #106904 - khuey:preserve_debuginfo_for_rlibs, r=davidtwco
[rust.git] / src / doc / unstable-book / src / language-features / unsized-locals.md
1 # `unsized_locals`
2
3 The tracking issue for this feature is: [#48055]
4
5 [#48055]: https://github.com/rust-lang/rust/issues/48055
6
7 ------------------------
8
9 This implements [RFC1909]. When turned on, you can have unsized arguments and locals:
10
11 [RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-unsized-rvalues.md
12
13 ```rust
14 #![allow(incomplete_features)]
15 #![feature(unsized_locals, unsized_fn_params)]
16
17 use std::any::Any;
18
19 fn 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
27 fn foo(_: dyn Any) {}
28 //     ^^^^^^ unsized argument
29 ```
30
31 The RFC still forbids the following unsized expressions:
32
33 ```rust,compile_fail
34 #![feature(unsized_locals)]
35
36 use std::any::Any;
37
38 struct MyStruct<T: ?Sized> {
39     content: T,
40 }
41
42 struct MyTupleStruct<T: ?Sized>(T);
43
44 fn answer() -> Box<dyn Any> {
45     Box::new(42)
46 }
47
48 fn 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
84 ## By-value trait objects
85
86 With this feature, you can have by-value `self` arguments without `Self: Sized` bounds.
87
88 ```rust
89 #![feature(unsized_fn_params)]
90
91 trait Foo {
92     fn foo(self) {}
93 }
94
95 impl<T: ?Sized> Foo for T {}
96
97 fn main() {
98     let slice: Box<[i32]> = Box::new([1, 2, 3]);
99     <[i32] as Foo>::foo(*slice);
100 }
101 ```
102
103 And `Foo` will also be object-safe.
104
105 ```rust
106 #![feature(unsized_fn_params)]
107
108 trait Foo {
109     fn foo(self) {}
110 }
111
112 impl<T: ?Sized> Foo for T {}
113
114 fn 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
121 One of the objectives of this feature is to allow `Box<dyn FnOnce>`.
122
123 ## Variable length arrays
124
125 The 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
127 ```rust,ignore (not-yet-implemented)
128 #![feature(unsized_locals)]
129
130 fn mergesort<T: Ord>(a: &mut [T]) {
131     let mut tmp = [T; dyn a.len()];
132     // ...
133 }
134
135 fn main() {
136     let mut a = [3, 1, 5, 6];
137     mergesort(&mut a);
138     assert_eq!(a, [1, 3, 5, 6]);
139 }
140 ```
141
142 VLAs 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
146 It'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
151 Another 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
156 fn main() {
157     let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
158     let _x = {{{{{{{{{{*x}}}}}}}}}};
159 }
160 ```
161
162 and the code
163
164 ```rust
165 #![feature(unsized_locals)]
166
167 fn 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
175 will unnecessarily extend the stack frame.