]>
Commit | Line | Data |
---|---|---|
a7813a04 XL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | #![allow(non_snake_case)] | |
12 | ||
13 | register_long_diagnostics! { | |
14 | ||
15 | E0010: r##" | |
16 | The value of statics and constants must be known at compile time, and they live | |
17 | for the entire lifetime of a program. Creating a boxed value allocates memory on | |
18 | the heap at runtime, and therefore cannot be done at compile time. Erroneous | |
19 | code example: | |
20 | ||
21 | ```compile_fail | |
22 | #![feature(box_syntax)] | |
23 | ||
24 | const CON : Box<i32> = box 0; | |
25 | ``` | |
26 | "##, | |
27 | ||
28 | E0013: r##" | |
29 | Static and const variables can refer to other const variables. But a const | |
30 | variable cannot refer to a static variable. For example, `Y` cannot refer to | |
31 | `X` here: | |
32 | ||
33 | ```compile_fail | |
34 | static X: i32 = 42; | |
35 | const Y: i32 = X; | |
36 | ``` | |
37 | ||
38 | To fix this, the value can be extracted as a const and then used: | |
39 | ||
40 | ``` | |
41 | const A: i32 = 42; | |
42 | static X: i32 = A; | |
43 | const Y: i32 = A; | |
44 | ``` | |
45 | "##, | |
46 | ||
47 | // FIXME(#24111) Change the language here when const fn stabilizes | |
48 | E0015: r##" | |
49 | The only functions that can be called in static or constant expressions are | |
50 | `const` functions, and struct/enum constructors. `const` functions are only | |
51 | available on a nightly compiler. Rust currently does not support more general | |
52 | compile-time function execution. | |
53 | ||
54 | ``` | |
55 | const FOO: Option<u8> = Some(1); // enum constructor | |
56 | struct Bar {x: u8} | |
57 | const BAR: Bar = Bar {x: 1}; // struct constructor | |
58 | ``` | |
59 | ||
60 | See [RFC 911] for more details on the design of `const fn`s. | |
61 | ||
62 | [RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md | |
63 | "##, | |
64 | ||
65 | E0016: r##" | |
66 | Blocks in constants may only contain items (such as constant, function | |
67 | definition, etc...) and a tail expression. Erroneous code example: | |
68 | ||
69 | ```compile_fail | |
70 | const FOO: i32 = { let x = 0; x }; // 'x' isn't an item! | |
71 | ``` | |
72 | ||
73 | To avoid it, you have to replace the non-item object: | |
74 | ||
75 | ``` | |
76 | const FOO: i32 = { const X : i32 = 0; X }; | |
77 | ``` | |
78 | "##, | |
79 | ||
80 | E0017: r##" | |
81 | References in statics and constants may only refer to immutable values. | |
82 | Erroneous code example: | |
83 | ||
84 | ```compile_fail | |
85 | static X: i32 = 1; | |
86 | const C: i32 = 2; | |
87 | ||
88 | // these three are not allowed: | |
89 | const CR: &'static mut i32 = &mut C; | |
90 | static STATIC_REF: &'static mut i32 = &mut X; | |
91 | static CONST_REF: &'static mut i32 = &mut C; | |
92 | ``` | |
93 | ||
94 | Statics are shared everywhere, and if they refer to mutable data one might | |
95 | violate memory safety since holding multiple mutable references to shared data | |
96 | is not allowed. | |
97 | ||
98 | If you really want global mutable state, try using `static mut` or a global | |
99 | `UnsafeCell`. | |
100 | "##, | |
101 | ||
102 | E0018: r##" | |
103 | ||
104 | The value of static and constant integers must be known at compile time. You | |
105 | can't cast a pointer to an integer because the address of a pointer can | |
106 | vary. | |
107 | ||
108 | For example, if you write: | |
109 | ||
110 | ```compile_fail | |
111 | static MY_STATIC: u32 = 42; | |
112 | static MY_STATIC_ADDR: usize = &MY_STATIC as *const _ as usize; | |
113 | static WHAT: usize = (MY_STATIC_ADDR^17) + MY_STATIC_ADDR; | |
114 | ``` | |
115 | ||
116 | Then `MY_STATIC_ADDR` would contain the address of `MY_STATIC`. However, | |
117 | the address can change when the program is linked, as well as change | |
118 | between different executions due to ASLR, and many linkers would | |
119 | not be able to calculate the value of `WHAT`. | |
120 | ||
121 | On the other hand, static and constant pointers can point either to | |
122 | a known numeric address or to the address of a symbol. | |
123 | ||
124 | ``` | |
125 | static MY_STATIC_ADDR: &'static u32 = &MY_STATIC; | |
126 | // ... and also | |
127 | static MY_STATIC_ADDR2: *const u32 = &MY_STATIC; | |
128 | ||
129 | const CONST_ADDR: *const u8 = 0x5f3759df as *const u8; | |
130 | ``` | |
131 | ||
132 | This does not pose a problem by itself because they can't be | |
133 | accessed directly. | |
134 | "##, | |
135 | ||
136 | E0019: r##" | |
137 | A function call isn't allowed in the const's initialization expression | |
138 | because the expression's value must be known at compile-time. Erroneous code | |
139 | example: | |
140 | ||
141 | ```compile_fail | |
142 | enum Test { | |
143 | V1 | |
144 | } | |
145 | ||
146 | impl Test { | |
147 | fn test(&self) -> i32 { | |
148 | 12 | |
149 | } | |
150 | } | |
151 | ||
152 | fn main() { | |
153 | const FOO: Test = Test::V1; | |
154 | ||
155 | const A: i32 = FOO.test(); // You can't call Test::func() here ! | |
156 | } | |
157 | ``` | |
158 | ||
159 | Remember: you can't use a function call inside a const's initialization | |
160 | expression! However, you can totally use it anywhere else: | |
161 | ||
162 | ``` | |
163 | fn main() { | |
164 | const FOO: Test = Test::V1; | |
165 | ||
166 | FOO.func(); // here is good | |
167 | let x = FOO.func(); // or even here! | |
168 | } | |
169 | ``` | |
170 | "##, | |
171 | ||
172 | E0022: r##" | |
173 | Constant functions are not allowed to mutate anything. Thus, binding to an | |
174 | argument with a mutable pattern is not allowed. For example, | |
175 | ||
176 | ```compile_fail | |
177 | const fn foo(mut x: u8) { | |
178 | // do stuff | |
179 | } | |
180 | ``` | |
181 | ||
182 | Is incorrect because the function body may not mutate `x`. | |
183 | ||
184 | Remove any mutable bindings from the argument list to fix this error. In case | |
185 | you need to mutate the argument, try lazily initializing a global variable | |
186 | instead of using a `const fn`, or refactoring the code to a functional style to | |
187 | avoid mutation if possible. | |
188 | "##, | |
189 | ||
190 | E0394: r##" | |
5bcae85e | 191 | A static was referred to by value by another static. |
a7813a04 | 192 | |
5bcae85e | 193 | Erroneous code examples: |
a7813a04 | 194 | |
5bcae85e SL |
195 | ```compile_fail,E0394 |
196 | static A: u32 = 0; | |
197 | static B: u32 = A; // error: cannot refer to other statics by value, use the | |
198 | // address-of operator or a constant instead | |
199 | ``` | |
200 | ||
201 | A static cannot be referred by value. To fix this issue, either use a | |
202 | constant: | |
203 | ||
204 | ``` | |
205 | const A: u32 = 0; // `A` is now a constant | |
206 | static B: u32 = A; // ok! | |
207 | ``` | |
208 | ||
209 | Or refer to `A` by reference: | |
210 | ||
211 | ``` | |
212 | static A: u32 = 0; | |
213 | static B: &'static u32 = &A; // ok! | |
214 | ``` | |
a7813a04 XL |
215 | "##, |
216 | ||
217 | ||
218 | E0395: r##" | |
219 | The value assigned to a constant scalar must be known at compile time, | |
220 | which is not the case when comparing raw pointers. | |
221 | ||
222 | Erroneous code example: | |
223 | ||
224 | ```compile_fail | |
225 | static FOO: i32 = 42; | |
226 | static BAR: i32 = 42; | |
227 | ||
228 | static BAZ: bool = { (&FOO as *const i32) == (&BAR as *const i32) }; | |
229 | // error: raw pointers cannot be compared in statics! | |
230 | ``` | |
231 | ||
232 | The address assigned by the linker to `FOO` and `BAR` may or may not | |
233 | be identical, so the value of `BAZ` can't be determined. | |
234 | ||
235 | If you want to do the comparison, please do it at run-time. | |
236 | ||
237 | For example: | |
238 | ||
239 | ``` | |
240 | static FOO: i32 = 42; | |
241 | static BAR: i32 = 42; | |
242 | ||
243 | let baz: bool = { (&FOO as *const i32) == (&BAR as *const i32) }; | |
244 | // baz isn't a constant expression so it's ok | |
245 | ``` | |
246 | "##, | |
247 | ||
248 | E0396: r##" | |
249 | The value behind a raw pointer can't be determined at compile-time | |
250 | (or even link-time), which means it can't be used in a constant | |
251 | expression. Erroneous code example: | |
252 | ||
253 | ```compile_fail | |
254 | const REG_ADDR: *const u8 = 0x5f3759df as *const u8; | |
255 | ||
256 | const VALUE: u8 = unsafe { *REG_ADDR }; | |
257 | // error: raw pointers cannot be dereferenced in constants | |
258 | ``` | |
259 | ||
260 | A possible fix is to dereference your pointer at some point in run-time. | |
261 | ||
262 | For example: | |
263 | ||
264 | ``` | |
265 | const REG_ADDR: *const u8 = 0x5f3759df as *const u8; | |
266 | ||
267 | let reg_value = unsafe { *REG_ADDR }; | |
268 | ``` | |
269 | "##, | |
270 | ||
271 | E0492: r##" | |
272 | A borrow of a constant containing interior mutability was attempted. Erroneous | |
273 | code example: | |
274 | ||
275 | ```compile_fail | |
276 | use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; | |
277 | ||
278 | const A: AtomicUsize = ATOMIC_USIZE_INIT; | |
279 | static B: &'static AtomicUsize = &A; | |
280 | // error: cannot borrow a constant which contains interior mutability, create a | |
281 | // static instead | |
282 | ``` | |
283 | ||
284 | A `const` represents a constant value that should never change. If one takes | |
285 | a `&` reference to the constant, then one is taking a pointer to some memory | |
286 | location containing the value. Normally this is perfectly fine: most values | |
287 | can't be changed via a shared `&` pointer, but interior mutability would allow | |
288 | it. That is, a constant value could be mutated. On the other hand, a `static` is | |
289 | explicitly a single memory location, which can be mutated at will. | |
290 | ||
291 | So, in order to solve this error, either use statics which are `Sync`: | |
292 | ||
293 | ``` | |
294 | use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; | |
295 | ||
296 | static A: AtomicUsize = ATOMIC_USIZE_INIT; | |
297 | static B: &'static AtomicUsize = &A; // ok! | |
298 | ``` | |
299 | ||
300 | You can also have this error while using a cell type: | |
301 | ||
302 | ```compile_fail | |
303 | #![feature(const_fn)] | |
304 | ||
305 | use std::cell::Cell; | |
306 | ||
307 | const A: Cell<usize> = Cell::new(1); | |
308 | const B: &'static Cell<usize> = &A; | |
309 | // error: cannot borrow a constant which contains interior mutability, create | |
310 | // a static instead | |
311 | ||
312 | // or: | |
313 | struct C { a: Cell<usize> } | |
314 | ||
315 | const D: C = C { a: Cell::new(1) }; | |
316 | const E: &'static Cell<usize> = &D.a; // error | |
317 | ||
318 | // or: | |
319 | const F: &'static C = &D; // error | |
320 | ``` | |
321 | ||
322 | This is because cell types do operations that are not thread-safe. Due to this, | |
323 | they don't implement Sync and thus can't be placed in statics. In this | |
324 | case, `StaticMutex` would work just fine, but it isn't stable yet: | |
325 | https://doc.rust-lang.org/nightly/std/sync/struct.StaticMutex.html | |
326 | ||
327 | However, if you still wish to use these types, you can achieve this by an unsafe | |
328 | wrapper: | |
329 | ||
330 | ``` | |
331 | #![feature(const_fn)] | |
332 | ||
333 | use std::cell::Cell; | |
334 | use std::marker::Sync; | |
335 | ||
336 | struct NotThreadSafe<T> { | |
337 | value: Cell<T>, | |
338 | } | |
339 | ||
340 | unsafe impl<T> Sync for NotThreadSafe<T> {} | |
341 | ||
342 | static A: NotThreadSafe<usize> = NotThreadSafe { value : Cell::new(1) }; | |
343 | static B: &'static NotThreadSafe<usize> = &A; // ok! | |
344 | ``` | |
345 | ||
346 | Remember this solution is unsafe! You will have to ensure that accesses to the | |
347 | cell are synchronized. | |
348 | "##, | |
349 | ||
350 | E0493: r##" | |
351 | A type with a destructor was assigned to an invalid type of variable. Erroneous | |
352 | code example: | |
353 | ||
354 | ```compile_fail | |
355 | struct Foo { | |
356 | a: u32 | |
357 | } | |
358 | ||
359 | impl Drop for Foo { | |
360 | fn drop(&mut self) {} | |
361 | } | |
362 | ||
363 | const F : Foo = Foo { a : 0 }; | |
364 | // error: constants are not allowed to have destructors | |
365 | static S : Foo = Foo { a : 0 }; | |
366 | // error: destructors in statics are an unstable feature | |
367 | ``` | |
368 | ||
369 | To solve this issue, please use a type which does allow the usage of type with | |
370 | destructors. | |
371 | "##, | |
372 | ||
373 | E0494: r##" | |
374 | A reference of an interior static was assigned to another const/static. | |
375 | Erroneous code example: | |
376 | ||
377 | ```compile_fail | |
378 | struct Foo { | |
379 | a: u32 | |
380 | } | |
381 | ||
382 | static S : Foo = Foo { a : 0 }; | |
383 | static A : &'static u32 = &S.a; | |
384 | // error: cannot refer to the interior of another static, use a | |
385 | // constant instead | |
386 | ``` | |
387 | ||
388 | The "base" variable has to be a const if you want another static/const variable | |
389 | to refer to one of its fields. Example: | |
390 | ||
391 | ``` | |
392 | struct Foo { | |
393 | a: u32 | |
394 | } | |
395 | ||
396 | const S : Foo = Foo { a : 0 }; | |
397 | static A : &'static u32 = &S.a; // ok! | |
398 | ``` | |
399 | "##, | |
400 | ||
401 | } | |
402 | ||
403 | register_diagnostics! { | |
404 | E0526, // shuffle indices are not constant | |
405 | } |