388 lines
9.7 KiB
Rust
388 lines
9.7 KiB
Rust
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
|
// file at the top-level directory of this distribution and at
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
// option. This file may not be copied, modified, or distributed
|
|
// except according to those terms.
|
|
|
|
#![allow(non_snake_case)]
|
|
|
|
register_long_diagnostics! {
|
|
|
|
E0010: r##"
|
|
The value of statics and constants must be known at compile time, and they live
|
|
for the entire lifetime of a program. Creating a boxed value allocates memory on
|
|
the heap at runtime, and therefore cannot be done at compile time. Erroneous
|
|
code example:
|
|
|
|
```compile_fail
|
|
#![feature(box_syntax)]
|
|
|
|
const CON : Box<i32> = box 0;
|
|
```
|
|
"##,
|
|
|
|
E0013: r##"
|
|
Static and const variables can refer to other const variables. But a const
|
|
variable cannot refer to a static variable. For example, `Y` cannot refer to
|
|
`X` here:
|
|
|
|
```compile_fail
|
|
static X: i32 = 42;
|
|
const Y: i32 = X;
|
|
```
|
|
|
|
To fix this, the value can be extracted as a const and then used:
|
|
|
|
```
|
|
const A: i32 = 42;
|
|
static X: i32 = A;
|
|
const Y: i32 = A;
|
|
```
|
|
"##,
|
|
|
|
// FIXME(#24111) Change the language here when const fn stabilizes
|
|
E0015: r##"
|
|
The only functions that can be called in static or constant expressions are
|
|
`const` functions, and struct/enum constructors. `const` functions are only
|
|
available on a nightly compiler. Rust currently does not support more general
|
|
compile-time function execution.
|
|
|
|
```
|
|
const FOO: Option<u8> = Some(1); // enum constructor
|
|
struct Bar {x: u8}
|
|
const BAR: Bar = Bar {x: 1}; // struct constructor
|
|
```
|
|
|
|
See [RFC 911] for more details on the design of `const fn`s.
|
|
|
|
[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
|
|
"##,
|
|
|
|
E0016: r##"
|
|
Blocks in constants may only contain items (such as constant, function
|
|
definition, etc...) and a tail expression. Erroneous code example:
|
|
|
|
```compile_fail
|
|
const FOO: i32 = { let x = 0; x }; // 'x' isn't an item!
|
|
```
|
|
|
|
To avoid it, you have to replace the non-item object:
|
|
|
|
```
|
|
const FOO: i32 = { const X : i32 = 0; X };
|
|
```
|
|
"##,
|
|
|
|
E0017: r##"
|
|
References in statics and constants may only refer to immutable values.
|
|
Erroneous code example:
|
|
|
|
```compile_fail
|
|
static X: i32 = 1;
|
|
const C: i32 = 2;
|
|
|
|
// these three are not allowed:
|
|
const CR: &'static mut i32 = &mut C;
|
|
static STATIC_REF: &'static mut i32 = &mut X;
|
|
static CONST_REF: &'static mut i32 = &mut C;
|
|
```
|
|
|
|
Statics are shared everywhere, and if they refer to mutable data one might
|
|
violate memory safety since holding multiple mutable references to shared data
|
|
is not allowed.
|
|
|
|
If you really want global mutable state, try using `static mut` or a global
|
|
`UnsafeCell`.
|
|
"##,
|
|
|
|
E0018: r##"
|
|
|
|
The value of static and constant integers must be known at compile time. You
|
|
can't cast a pointer to an integer because the address of a pointer can
|
|
vary.
|
|
|
|
For example, if you write:
|
|
|
|
```compile_fail
|
|
static MY_STATIC: u32 = 42;
|
|
static MY_STATIC_ADDR: usize = &MY_STATIC as *const _ as usize;
|
|
static WHAT: usize = (MY_STATIC_ADDR^17) + MY_STATIC_ADDR;
|
|
```
|
|
|
|
Then `MY_STATIC_ADDR` would contain the address of `MY_STATIC`. However,
|
|
the address can change when the program is linked, as well as change
|
|
between different executions due to ASLR, and many linkers would
|
|
not be able to calculate the value of `WHAT`.
|
|
|
|
On the other hand, static and constant pointers can point either to
|
|
a known numeric address or to the address of a symbol.
|
|
|
|
```
|
|
static MY_STATIC_ADDR: &'static u32 = &MY_STATIC;
|
|
// ... and also
|
|
static MY_STATIC_ADDR2: *const u32 = &MY_STATIC;
|
|
|
|
const CONST_ADDR: *const u8 = 0x5f3759df as *const u8;
|
|
```
|
|
|
|
This does not pose a problem by itself because they can't be
|
|
accessed directly.
|
|
"##,
|
|
|
|
E0019: r##"
|
|
A function call isn't allowed in the const's initialization expression
|
|
because the expression's value must be known at compile-time. Erroneous code
|
|
example:
|
|
|
|
```compile_fail
|
|
enum Test {
|
|
V1
|
|
}
|
|
|
|
impl Test {
|
|
fn test(&self) -> i32 {
|
|
12
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
const FOO: Test = Test::V1;
|
|
|
|
const A: i32 = FOO.test(); // You can't call Test::func() here !
|
|
}
|
|
```
|
|
|
|
Remember: you can't use a function call inside a const's initialization
|
|
expression! However, you can totally use it anywhere else:
|
|
|
|
```
|
|
fn main() {
|
|
const FOO: Test = Test::V1;
|
|
|
|
FOO.func(); // here is good
|
|
let x = FOO.func(); // or even here!
|
|
}
|
|
```
|
|
"##,
|
|
|
|
E0022: r##"
|
|
Constant functions are not allowed to mutate anything. Thus, binding to an
|
|
argument with a mutable pattern is not allowed. For example,
|
|
|
|
```compile_fail
|
|
const fn foo(mut x: u8) {
|
|
// do stuff
|
|
}
|
|
```
|
|
|
|
Is incorrect because the function body may not mutate `x`.
|
|
|
|
Remove any mutable bindings from the argument list to fix this error. In case
|
|
you need to mutate the argument, try lazily initializing a global variable
|
|
instead of using a `const fn`, or refactoring the code to a functional style to
|
|
avoid mutation if possible.
|
|
"##,
|
|
|
|
E0394: r##"
|
|
From [RFC 246]:
|
|
|
|
> It is invalid for a static to reference another static by value. It is
|
|
> required that all references be borrowed.
|
|
|
|
[RFC 246]: https://github.com/rust-lang/rfcs/pull/246
|
|
"##,
|
|
|
|
|
|
E0395: r##"
|
|
The value assigned to a constant scalar must be known at compile time,
|
|
which is not the case when comparing raw pointers.
|
|
|
|
Erroneous code example:
|
|
|
|
```compile_fail
|
|
static FOO: i32 = 42;
|
|
static BAR: i32 = 42;
|
|
|
|
static BAZ: bool = { (&FOO as *const i32) == (&BAR as *const i32) };
|
|
// error: raw pointers cannot be compared in statics!
|
|
```
|
|
|
|
The address assigned by the linker to `FOO` and `BAR` may or may not
|
|
be identical, so the value of `BAZ` can't be determined.
|
|
|
|
If you want to do the comparison, please do it at run-time.
|
|
|
|
For example:
|
|
|
|
```
|
|
static FOO: i32 = 42;
|
|
static BAR: i32 = 42;
|
|
|
|
let baz: bool = { (&FOO as *const i32) == (&BAR as *const i32) };
|
|
// baz isn't a constant expression so it's ok
|
|
```
|
|
"##,
|
|
|
|
E0396: r##"
|
|
The value behind a raw pointer can't be determined at compile-time
|
|
(or even link-time), which means it can't be used in a constant
|
|
expression. Erroneous code example:
|
|
|
|
```compile_fail
|
|
const REG_ADDR: *const u8 = 0x5f3759df as *const u8;
|
|
|
|
const VALUE: u8 = unsafe { *REG_ADDR };
|
|
// error: raw pointers cannot be dereferenced in constants
|
|
```
|
|
|
|
A possible fix is to dereference your pointer at some point in run-time.
|
|
|
|
For example:
|
|
|
|
```
|
|
const REG_ADDR: *const u8 = 0x5f3759df as *const u8;
|
|
|
|
let reg_value = unsafe { *REG_ADDR };
|
|
```
|
|
"##,
|
|
|
|
E0492: r##"
|
|
A borrow of a constant containing interior mutability was attempted. Erroneous
|
|
code example:
|
|
|
|
```compile_fail
|
|
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
|
|
|
|
const A: AtomicUsize = ATOMIC_USIZE_INIT;
|
|
static B: &'static AtomicUsize = &A;
|
|
// error: cannot borrow a constant which contains interior mutability, create a
|
|
// static instead
|
|
```
|
|
|
|
A `const` represents a constant value that should never change. If one takes
|
|
a `&` reference to the constant, then one is taking a pointer to some memory
|
|
location containing the value. Normally this is perfectly fine: most values
|
|
can't be changed via a shared `&` pointer, but interior mutability would allow
|
|
it. That is, a constant value could be mutated. On the other hand, a `static` is
|
|
explicitly a single memory location, which can be mutated at will.
|
|
|
|
So, in order to solve this error, either use statics which are `Sync`:
|
|
|
|
```
|
|
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
|
|
|
|
static A: AtomicUsize = ATOMIC_USIZE_INIT;
|
|
static B: &'static AtomicUsize = &A; // ok!
|
|
```
|
|
|
|
You can also have this error while using a cell type:
|
|
|
|
```compile_fail
|
|
#![feature(const_fn)]
|
|
|
|
use std::cell::Cell;
|
|
|
|
const A: Cell<usize> = Cell::new(1);
|
|
const B: &'static Cell<usize> = &A;
|
|
// error: cannot borrow a constant which contains interior mutability, create
|
|
// a static instead
|
|
|
|
// or:
|
|
struct C { a: Cell<usize> }
|
|
|
|
const D: C = C { a: Cell::new(1) };
|
|
const E: &'static Cell<usize> = &D.a; // error
|
|
|
|
// or:
|
|
const F: &'static C = &D; // error
|
|
```
|
|
|
|
This is because cell types do operations that are not thread-safe. Due to this,
|
|
they don't implement Sync and thus can't be placed in statics. In this
|
|
case, `StaticMutex` would work just fine, but it isn't stable yet:
|
|
https://doc.rust-lang.org/nightly/std/sync/struct.StaticMutex.html
|
|
|
|
However, if you still wish to use these types, you can achieve this by an unsafe
|
|
wrapper:
|
|
|
|
```
|
|
#![feature(const_fn)]
|
|
|
|
use std::cell::Cell;
|
|
use std::marker::Sync;
|
|
|
|
struct NotThreadSafe<T> {
|
|
value: Cell<T>,
|
|
}
|
|
|
|
unsafe impl<T> Sync for NotThreadSafe<T> {}
|
|
|
|
static A: NotThreadSafe<usize> = NotThreadSafe { value : Cell::new(1) };
|
|
static B: &'static NotThreadSafe<usize> = &A; // ok!
|
|
```
|
|
|
|
Remember this solution is unsafe! You will have to ensure that accesses to the
|
|
cell are synchronized.
|
|
"##,
|
|
|
|
E0493: r##"
|
|
A type with a destructor was assigned to an invalid type of variable. Erroneous
|
|
code example:
|
|
|
|
```compile_fail
|
|
struct Foo {
|
|
a: u32
|
|
}
|
|
|
|
impl Drop for Foo {
|
|
fn drop(&mut self) {}
|
|
}
|
|
|
|
const F : Foo = Foo { a : 0 };
|
|
// error: constants are not allowed to have destructors
|
|
static S : Foo = Foo { a : 0 };
|
|
// error: destructors in statics are an unstable feature
|
|
```
|
|
|
|
To solve this issue, please use a type which does allow the usage of type with
|
|
destructors.
|
|
"##,
|
|
|
|
E0494: r##"
|
|
A reference of an interior static was assigned to another const/static.
|
|
Erroneous code example:
|
|
|
|
```compile_fail
|
|
struct Foo {
|
|
a: u32
|
|
}
|
|
|
|
static S : Foo = Foo { a : 0 };
|
|
static A : &'static u32 = &S.a;
|
|
// error: cannot refer to the interior of another static, use a
|
|
// constant instead
|
|
```
|
|
|
|
The "base" variable has to be a const if you want another static/const variable
|
|
to refer to one of its fields. Example:
|
|
|
|
```
|
|
struct Foo {
|
|
a: u32
|
|
}
|
|
|
|
const S : Foo = Foo { a : 0 };
|
|
static A : &'static u32 = &S.a; // ok!
|
|
```
|
|
"##,
|
|
|
|
}
|
|
|
|
register_diagnostics! {
|
|
E0526, // shuffle indices are not constant
|
|
}
|