-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Allow assignments in const contexts #56070
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
bc543d7
59eff14
7d5b5ff
f98235e
6bcb0d6
f70abe8
7d96f2c
3e081c7
37fcd5c
301ce8b
3c290a5
42a3f73
e05b61c
22aebd5
6db8c6c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -243,13 +243,30 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { | |
return; | ||
} | ||
|
||
if self.tcx.features().const_let { | ||
let mut dest = dest; | ||
let index = loop { | ||
match dest { | ||
Place::Local(index) => break *index, | ||
Place::Projection(proj) => dest = &proj.base, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Continuing with
Projections would include
Maybe we should just whitelist field projections for now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem is something like this: const FOO: &(Cell<usize>, bool) = &{
let mut foo = (Cell::new(0), false);
foo.1 = true; // resets `qualif(foo)` to `qualif(true)`
foo
}; I suspect that will actually compile with this PR, although I'd like a confirmation. We could add this as a testcase, but you might be able to come up with something simpler/more general. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This indeed compiles successfully with this PR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My suggestion is field (or projections in general) assignment should combine qualifications (i.e. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I now reuse the existing projection checks for reading values. These checks replace the qualification with |
||
Place::Promoted(..) => bug!("promoteds don't exist yet during promotion"), | ||
Place::Static(..) => { | ||
// Catch more errors in the destination. | ||
self.visit_place( | ||
dest, | ||
PlaceContext::MutatingUse(MutatingUseContext::Store), | ||
location | ||
); | ||
oli-obk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return; | ||
} | ||
} | ||
}; | ||
debug!("store to var {:?}", index); | ||
self.local_qualif[index] = Some(self.qualif); | ||
return; | ||
} | ||
|
||
match *dest { | ||
Place::Local(index) if (self.mir.local_kind(index) == LocalKind::Var || | ||
self.mir.local_kind(index) == LocalKind::Arg) && | ||
self.tcx.sess.features_untracked().const_let => { | ||
debug!("store to var {:?}", index); | ||
self.local_qualif[index] = Some(self.qualif); | ||
} | ||
Place::Local(index) if self.mir.local_kind(index) == LocalKind::Temp || | ||
self.mir.local_kind(index) == LocalKind::ReturnPointer => { | ||
debug!("store to {:?} (temp or return pointer)", index); | ||
|
@@ -478,6 +495,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { | |
|
||
// Only allow statics (not consts) to refer to other statics. | ||
if self.mode == Mode::Static || self.mode == Mode::StaticMut { | ||
if context.is_mutating_use() { | ||
// this is not strictly necessary as miri will also bail out | ||
// For interior mutability we can't really catch this statically as that | ||
// goes through raw pointers and intermediate temporaries, so miri has | ||
// to catch this anyway | ||
self.tcx.sess.span_err( | ||
self.span, | ||
"cannot mutate statics in the initializer of another static", | ||
); | ||
} | ||
return; | ||
} | ||
self.add(Qualif::NOT_CONST); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// 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. | ||
|
||
// New test for #53818: modifying static memory at compile-time is not allowed. | ||
// The test should never compile successfully | ||
|
||
#![feature(const_raw_ptr_deref)] | ||
#![feature(const_let)] | ||
|
||
use std::cell::UnsafeCell; | ||
|
||
struct Foo(UnsafeCell<u32>); | ||
|
||
unsafe impl Send for Foo {} | ||
unsafe impl Sync for Foo {} | ||
|
||
static FOO: Foo = Foo(UnsafeCell::new(42)); | ||
|
||
static BAR: () = unsafe { | ||
*FOO.0.get() = 5; //~ ERROR could not evaluate static initializer | ||
}; | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
error[E0080]: could not evaluate static initializer | ||
--> $DIR/assign-to-static-within-other-static-2.rs:27:5 | ||
| | ||
LL | *FOO.0.get() = 5; //~ ERROR could not evaluate static initializer | ||
| ^^^^^^^^^^^^^^^^ tried to modify a static's initial value from another static's initializer | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0080`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// 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. | ||
|
||
// New test for #53818: modifying static memory at compile-time is not allowed. | ||
// The test should never compile successfully | ||
|
||
#![feature(const_raw_ptr_deref)] | ||
#![feature(const_let)] | ||
|
||
use std::cell::UnsafeCell; | ||
|
||
static mut FOO: u32 = 42; | ||
static BOO: () = unsafe { | ||
FOO = 5; //~ ERROR cannot mutate statics in the initializer of another static | ||
}; | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
error: cannot mutate statics in the initializer of another static | ||
--> $DIR/assign-to-static-within-other-static.rs:21:5 | ||
| | ||
LL | FOO = 5; //~ ERROR cannot mutate statics in the initializer of another static | ||
| ^^^^^^^ | ||
|
||
error: aborting due to previous error | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,9 @@ | ||
error[E0658]: statements in statics are unstable (see issue #48821) | ||
--> $DIR/mod-static-with-const-fn.rs:29:5 | ||
| | ||
LL | *FOO.0.get() = 5; | ||
| ^^^^^^^^^^^^^^^^ | ||
| | ||
= help: add #![feature(const_let)] to the crate attributes to enable | ||
|
||
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants | ||
--> $DIR/mod-static-with-const-fn.rs:34:5 | ||
--> $DIR/mod-static-with-const-fn.rs:31:5 | ||
| | ||
LL | foo(); | ||
| ^^^^^ | ||
|
||
error: aborting due to 2 previous errors | ||
error: aborting due to previous error | ||
|
||
Some errors occurred: E0015, E0658. | ||
For more information about an error, try `rustc --explain E0015`. | ||
For more information about this error, try `rustc --explain E0015`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// compile-pass | ||
|
||
#![feature(const_let)] | ||
|
||
struct S(i32); | ||
|
||
const A: () = { | ||
let mut s = S(0); | ||
s.0 = 1; | ||
}; | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// compile-pass | ||
|
||
#![feature(const_let)] | ||
#![feature(const_fn)] | ||
|
||
pub struct AA { | ||
pub data: [u8; 10], | ||
} | ||
|
||
impl AA { | ||
pub const fn new() -> Self { | ||
let mut res: AA = AA { data: [0; 10] }; | ||
res.data[0] = 5; | ||
res | ||
} | ||
} | ||
|
||
static mut BB: AA = AA::new(); | ||
|
||
fn main() { | ||
let ptr = unsafe { &mut BB }; | ||
for a in ptr.data.iter() { | ||
println!("{}", a); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#![feature(const_let)] | ||
#![feature(const_fn)] | ||
|
||
struct S { | ||
state: u32, | ||
} | ||
|
||
impl S { | ||
const fn foo(&mut self, x: u32) { | ||
self.state = x; | ||
} | ||
} | ||
|
||
const FOO: S = { | ||
let mut s = S { state: 42 }; | ||
s.foo(3); //~ ERROR references in constants may only refer to immutable values | ||
s | ||
}; | ||
|
||
fn main() { | ||
assert_eq!(FOO.state, 3); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
error[E0017]: references in constants may only refer to immutable values | ||
--> $DIR/const_let_assign3.rs:16:5 | ||
| | ||
LL | s.foo(3); //~ ERROR references in constants may only refer to immutable values | ||
| ^ constants require immutable values | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0017`. |
Uh oh!
There was an error while loading. Please reload this page.