Auto merge of #51110 - alexreg:new-static-eval-rules, r=eddyb
Loosened rules involving statics mentioning other statics
Before this PR, trying to mention a static in any way other than taking a reference to it caused a compile-time error. So, while
```rust
static A: u32 = 42;
static B: &u32 = &A;
```
compiles successfully,
```rust
static A: u32 = 42;
static B: u32 = A; // error
```
and
```rust
static A: u32 = 42;
static B: u32 = *&A; // error
```
are not possible to express in Rust. On the other hand, introducing an intermediate `const fn` can presently allow one to do just that:
```rust
static A: u32 = 42;
static B: u32 = foo(&A); // success!
const fn foo(a: &u32) -> u32 {
*a
}
```
Preventing `const fn` from allowing to work around the ban on reading from statics would cripple `const fn` almost into uselessness.
Additionally, the limitation for reading from statics comes from the old const evaluator(s) and is not shared by `miri`.
This PR loosens the rules around use of statics to allow statics to evaluate other statics by value, allowing all of the above examples to compile and run successfully.
Reads from extern (foreign) statics are however still disallowed by miri, because there is no compile-time value to be read.
```rust
extern static A: u32;
static B: u32 = A; // error
```
This opens up a new avenue of potential issues, as a static can now not just refer to other statics or read from other statics, but even contain references that point into itself.
While it might seem like this could cause subtle bugs like allowing a static to be initialized by its own value, this is inherently impossible in miri.
Reading from a static causes the `const_eval` query for that static to be invoked. Calling the `const_eval` query for a static while already inside the `const_eval` query of said static will cause cycle errors.
It is not possible to accidentally create a bug in miri that would enable initializing a static with itself, because the memory of the static *does not exist* while being initialized.
The memory is not uninitialized, it is not there. Thus any change that would accidentally allow reading from a not yet initialized static would cause ICEs.
Tests have been modified according to the new rules, and new tests have been added for writing to `static mut`s within definitions of statics (which needs to fail), and incremental compilation with complex/interlinking static definitions.
Note that incremental compilation did not need to be adjusted, because all of this was already possible before with workarounds (like intermediate `const fn`s) and the encoding/decoding already supports all the possible cases.
r? @eddyb
This commit is contained in:
commit
c697a56d01
25 changed files with 127 additions and 236 deletions
|
|
@ -29,7 +29,6 @@ static Y: u32 = 0;
|
|||
const fn get_Y() -> u32 {
|
||||
Y
|
||||
//~^ ERROR E0013
|
||||
//~| ERROR cannot refer to statics by value
|
||||
}
|
||||
|
||||
const fn get_Y_addr() -> &'static u32 {
|
||||
|
|
@ -49,5 +48,4 @@ const fn get() -> u32 {
|
|||
//~| ERROR let bindings in constant functions are unstable
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@
|
|||
extern {
|
||||
pub static symbol: ();
|
||||
}
|
||||
static CRASH: () = symbol; //~ cannot refer to other statics by value
|
||||
static CRASH: () = symbol;
|
||||
//~^ ERROR could not evaluate static initializer
|
||||
//~| tried to read from foreign (extern) static
|
||||
//~^^^ ERROR could not evaluate static initializer
|
||||
//~| tried to read from foreign (extern) static
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ mod Y {
|
|||
|
||||
static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
|
||||
//~^ ERROR `*const usize` cannot be shared between threads safely [E0277]
|
||||
//~| ERROR cannot refer to other statics by value, use the address-of operator or a constant instead
|
||||
//~| ERROR E0015
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -22,14 +22,13 @@ static T4: &'static usize = &S;
|
|||
|
||||
const T5: usize = C;
|
||||
const T6: usize = S; //~ ERROR: constants cannot refer to statics
|
||||
//~^ cannot refer to statics
|
||||
static T7: usize = C;
|
||||
static T8: usize = S; //~ ERROR: cannot refer to other statics by value
|
||||
static T8: usize = S;
|
||||
|
||||
const T9: Struct = Struct { a: C };
|
||||
const T10: Struct = Struct { a: S }; //~ ERROR: cannot refer to statics by value
|
||||
const T10: Struct = Struct { a: S };
|
||||
//~^ ERROR: constants cannot refer to statics
|
||||
static T11: Struct = Struct { a: C };
|
||||
static T12: Struct = Struct { a: S }; //~ ERROR: cannot refer to other statics by value
|
||||
static T12: Struct = Struct { a: S };
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ extern {
|
|||
}
|
||||
|
||||
pub static BAZ: u32 = *&error_message_count;
|
||||
//~^ ERROR cannot refer to other statics by value
|
||||
//~^ ERROR could not evaluate static initializer
|
||||
//~| tried to read from foreign (extern) static
|
||||
//~^^^ ERROR could not evaluate static initializer
|
||||
//~| tried to read from foreign (extern) static
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
|
@ -8,12 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct Foo {
|
||||
a: u32
|
||||
}
|
||||
pub static FOO: u32 = FOO;
|
||||
//~^ ERROR cycle detected when const-evaluating `FOO`
|
||||
|
||||
static S : Foo = Foo { a : 0 };
|
||||
static A : &'static u32 = &S.a; //~ ERROR E0494
|
||||
|
||||
fn main() {
|
||||
}
|
||||
fn main() {}
|
||||
|
|
@ -15,14 +15,12 @@ static A: u32 = 1;
|
|||
|
||||
static B: u32 = A;
|
||||
//~^ ERROR thread-local statics cannot be accessed at compile-time
|
||||
//~| ERROR cannot refer to other statics by value
|
||||
|
||||
static C: &u32 = &A;
|
||||
//~^ ERROR thread-local statics cannot be accessed at compile-time
|
||||
|
||||
const D: u32 = A;
|
||||
//~^ ERROR thread-local statics cannot be accessed at compile-time
|
||||
//~| ERROR cannot refer to statics by value
|
||||
|
||||
const E: &u32 = &A;
|
||||
//~^ ERROR thread-local statics cannot be accessed at compile-time
|
||||
|
|
@ -30,7 +28,6 @@ const E: &u32 = &A;
|
|||
const fn f() -> u32 {
|
||||
A
|
||||
//~^ ERROR thread-local statics cannot be accessed at compile-time
|
||||
//~| ERROR cannot refer to statics by value
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
22
src/test/compile-fail/write-to-static-mut-in-static.rs
Normal file
22
src/test/compile-fail/write-to-static-mut-in-static.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
#![feature(const_let)]
|
||||
|
||||
pub static mut A: u32 = 0;
|
||||
pub static mut B: () = unsafe { A = 1; };
|
||||
//~^ ERROR statements in statics are unstable
|
||||
|
||||
pub static mut C: u32 = unsafe { C = 1; 0 };
|
||||
//~^ ERROR statements in statics are unstable
|
||||
|
||||
pub static D: u32 = D;
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
// revisions:rpass1 rpass2
|
||||
|
||||
#[cfg(rpass1)]
|
||||
pub static A: u8 = 42;
|
||||
#[cfg(rpass2)]
|
||||
pub static A: u8 = 43;
|
||||
|
||||
static B: &u8 = &C.1;
|
||||
static C: (&&u8, u8) = (&B, A);
|
||||
|
||||
fn main() {
|
||||
assert_eq!(*B, A);
|
||||
assert_eq!(**C.0, A);
|
||||
assert_eq!(C.1, A);
|
||||
}
|
||||
|
|
@ -11,9 +11,6 @@
|
|||
#![allow(dead_code, warnings)]
|
||||
|
||||
static mut x: isize = 3;
|
||||
static mut y: isize = unsafe {
|
||||
x
|
||||
//~^ ERROR cannot refer to other statics by value, use the address-of operator or a constant instea
|
||||
};
|
||||
static mut y: isize = unsafe { x };
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -9,17 +9,19 @@
|
|||
// except according to those terms.
|
||||
|
||||
struct S { a: usize }
|
||||
static A: S = S { a: 3 };
|
||||
|
||||
static A: S = S { a: 3 };
|
||||
static B: &'static usize = &A.a;
|
||||
//~^ ERROR: cannot refer to the interior of another static
|
||||
static C: &'static usize = &(A.a);
|
||||
//~^ ERROR: cannot refer to the interior of another static
|
||||
|
||||
static D: [usize; 1] = [1];
|
||||
static E: usize = D[0];
|
||||
//~^ ERROR: cannot refer to the interior of another static
|
||||
//~^^ ERROR: cannot refer to other statics by value
|
||||
static F: &'static usize = &D[0];
|
||||
//~^ ERROR: cannot refer to the interior of another static
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
assert_eq!(*B, A.a);
|
||||
assert_eq!(*B, A.a);
|
||||
|
||||
assert_eq!(E, D[0]);
|
||||
assert_eq!(*F, D[0]);
|
||||
}
|
||||
|
|
@ -16,6 +16,5 @@ struct A {
|
|||
|
||||
static B: &'static A = &A { a: &() };
|
||||
static C: &'static A = &B;
|
||||
//~^ ERROR cannot refer to other statics by value
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -10,6 +10,5 @@
|
|||
|
||||
static x: &'static usize = &1;
|
||||
static y: usize = *x;
|
||||
//~^ ERROR cannot refer to other statics by value,
|
||||
// use the address-of operator or a constant instead
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
|
@ -8,11 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
static A: u32 = 0;
|
||||
static B: u32 = A;
|
||||
//~^ ERROR E0394
|
||||
static A: usize = 42;
|
||||
static B: usize = A;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(B, 42);
|
||||
}
|
||||
|
|
@ -15,13 +15,7 @@ extern crate pub_static_array as array;
|
|||
use array::ARRAY;
|
||||
|
||||
static X: &'static u8 = &ARRAY[0];
|
||||
//~^ ERROR: cannot refer to the interior of another static, use a constant
|
||||
|
||||
static Y: &'static u8 = &(&ARRAY)[0];
|
||||
//~^ ERROR: cannot refer to the interior of another static, use a constant
|
||||
|
||||
static Z: u8 = (&ARRAY)[0];
|
||||
//~^ ERROR: cannot refer to the interior of another static, use a constant
|
||||
//~^^ ERROR: cannot refer to other statics by value
|
||||
|
||||
pub fn main() {}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
error[E0394]: cannot refer to other statics by value, use the address-of operator or a constant instead
|
||||
--> $DIR/E0394.rs:14:17
|
||||
|
|
||||
LL | static B: u32 = A;
|
||||
| ^ referring to another static by value
|
||||
|
|
||||
= note: use the address-of operator or a constant instead
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0394`.
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
error[E0494]: cannot refer to the interior of another static, use a constant instead
|
||||
--> $DIR/E0494.rs:16:27
|
||||
|
|
||||
LL | static A : &'static u32 = &S.a; //~ ERROR E0494
|
||||
| ^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0494`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue