Skip to content
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

forbid mutable references in all constant contexts except for const-fns #72934

Merged
merged 4 commits into from
Jun 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc_error_codes/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ E0760: include_str!("./error_codes/E0760.md"),
E0761: include_str!("./error_codes/E0761.md"),
E0762: include_str!("./error_codes/E0762.md"),
E0763: include_str!("./error_codes/E0763.md"),
E0764: include_str!("./error_codes/E0764.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
Expand Down
39 changes: 39 additions & 0 deletions src/librustc_error_codes/error_codes/E0764.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Mutable references (`&mut`) can only be used in constant functions, not statics
or constants. This limitation exists to prevent the creation of constants that
have a mutable reference in their final value. If you had a constant of `&mut
i32` type, you could modify the value through that reference, making the
constant essentially mutable. While there could be a more fine-grained scheme
in the future that allows mutable references if they are not "leaked" to the
final value, a more conservative approach was chosen for now. `const fn` do not
have this problem, as the borrow checker will prevent the `const fn` from
returning new mutable references.

Erroneous code example:

```compile_fail,E0764
#![feature(const_fn)]
#![feature(const_mut_refs)]

fn main() {
const OH_NO: &'static mut usize = &mut 1; // error!
}
```

Remember: you cannot use a function call inside a constant or static. However,
you can totally use it in constant functions:

```
#![feature(const_fn)]
#![feature(const_mut_refs)]

const fn foo(x: usize) -> usize {
let mut y = 1;
let z = &mut y;
*z += x;
y
}

fn main() {
const FOO: usize = foo(10); // ok!
}
```
34 changes: 23 additions & 11 deletions src/librustc_mir/transform/check_consts/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,22 +205,34 @@ impl NonConstOp for CellBorrow {
#[derive(Debug)]
pub struct MutBorrow;
impl NonConstOp for MutBorrow {
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
// Forbid everywhere except in const fn
ccx.const_kind() == hir::ConstContext::ConstFn
&& ccx.tcx.features().enabled(Self::feature_gate().unwrap())
}

fn feature_gate() -> Option<Symbol> {
Some(sym::const_mut_refs)
}

fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
let mut err = feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
span,
&format!(
"references in {}s may only refer \
to immutable values",
ccx.const_kind()
),
);
err.span_label(span, format!("{}s require immutable values", ccx.const_kind()));
let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
span,
&format!("mutable references are not allowed in {}s", ccx.const_kind()),
)
} else {
struct_span_err!(
ccx.tcx.sess,
span,
E0764,
"mutable references are not allowed in {}s",
ccx.const_kind(),
)
};
err.span_label(span, "`&mut` is only allowed in `const fn`".to_string());
if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"References in statics and constants may only refer \
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-52443.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fn main() {
[(); { for _ in 0usize.. {}; 0}];
//~^ ERROR `for` is not allowed in a `const`
//~| ERROR calls in constants are limited to constant functions
//~| ERROR references in constants may only refer to immutable values
//~| ERROR mutable references are not allowed in constants
//~| ERROR calls in constants are limited to constant functions
//~| ERROR evaluation of constant value failed
}
2 changes: 1 addition & 1 deletion src/test/ui/check-static-immutable-mut-slices.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Checks that immutable static items can't have mutable slices

static TEST: &'static mut [isize] = &mut [];
//~^ ERROR references in statics may only refer to immutable values
//~^ ERROR mutable references are not allowed in statics

pub fn main() { }
9 changes: 3 additions & 6 deletions src/test/ui/check-static-immutable-mut-slices.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
error[E0658]: references in statics may only refer to immutable values
error[E0764]: mutable references are not allowed in statics
--> $DIR/check-static-immutable-mut-slices.rs:3:37
|
LL | static TEST: &'static mut [isize] = &mut [];
| ^^^^^^^ statics require immutable values
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
| ^^^^^^^ `&mut` is only allowed in `const fn`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
For more information about this error, try `rustc --explain E0764`.
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-eval/issue-65394.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

const _: Vec<i32> = {
let mut x = Vec::<i32>::new(); //~ ERROR destructors cannot be evaluated at compile-time
let r = &mut x; //~ ERROR references in constants may only refer to immutable values
let r = &mut x; //~ ERROR mutable references are not allowed in constants
let y = x;
y
};
Expand Down
9 changes: 3 additions & 6 deletions src/test/ui/consts/const-eval/issue-65394.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
error[E0658]: references in constants may only refer to immutable values
error[E0764]: mutable references are not allowed in constants
--> $DIR/issue-65394.rs:8:13
|
LL | let r = &mut x;
| ^^^^^^ constants require immutable values
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
| ^^^^^^ `&mut` is only allowed in `const fn`

error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/issue-65394.rs:7:9
Expand All @@ -15,5 +12,5 @@ LL | let mut x = Vec::<i32>::new();

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0493, E0658.
Some errors have detailed explanations: E0493, E0764.
For more information about an error, try `rustc --explain E0493`.
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-multi-ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

const _: i32 = {
let mut a = 5;
let p = &mut a; //~ ERROR references in constants may only refer to immutable values
let p = &mut a; //~ ERROR mutable references are not allowed in constants

let reborrow = {p};
let pp = &reborrow;
Expand Down
9 changes: 3 additions & 6 deletions src/test/ui/consts/const-multi-ref.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
error[E0658]: references in constants may only refer to immutable values
error[E0764]: mutable references are not allowed in constants
--> $DIR/const-multi-ref.rs:6:13
|
LL | let p = &mut a;
| ^^^^^^ constants require immutable values
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
| ^^^^^^ `&mut` is only allowed in `const fn`

error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
--> $DIR/const-multi-ref.rs:16:13
Expand All @@ -15,5 +12,5 @@ LL | let p = &a;

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0492, E0658.
Some errors have detailed explanations: E0492, E0764.
For more information about an error, try `rustc --explain E0492`.
4 changes: 2 additions & 2 deletions src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// check-pass

#![feature(const_mut_refs)]
#![feature(const_fn)]
#![feature(raw_ref_op)]
Expand All @@ -24,7 +22,9 @@ const fn baz(foo: &mut Foo)-> *mut usize {

const _: () = {
foo().bar();
//~^ ERROR mutable references are not allowed in constants
baz(&mut foo());
//~^ ERROR mutable references are not allowed in constants
};

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error[E0764]: mutable references are not allowed in constants
--> $DIR/const_mut_address_of.rs:24:5
|
LL | foo().bar();
| ^^^^^ `&mut` is only allowed in `const fn`

error[E0764]: mutable references are not allowed in constants
--> $DIR/const_mut_address_of.rs:26:9
|
LL | baz(&mut foo());
| ^^^^^^^^^^ `&mut` is only allowed in `const fn`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0764`.
5 changes: 3 additions & 2 deletions src/test/ui/consts/const-mut-refs/const_mut_refs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// run-pass

#![feature(const_mut_refs)]

struct Foo {
Expand Down Expand Up @@ -31,6 +29,9 @@ const fn bazz(foo: &mut Foo) -> usize {

fn main() {
let _: [(); foo().bar()] = [(); 1];
//~^ ERROR mutable references are not allowed in constants
let _: [(); baz(&mut foo())] = [(); 2];
//~^ ERROR mutable references are not allowed in constants
let _: [(); bazz(&mut foo())] = [(); 3];
//~^ ERROR mutable references are not allowed in constants
}
21 changes: 21 additions & 0 deletions src/test/ui/consts/const-mut-refs/const_mut_refs.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0764]: mutable references are not allowed in constants
--> $DIR/const_mut_refs.rs:31:17
|
LL | let _: [(); foo().bar()] = [(); 1];
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
| ^^^^^ `&mut` is only allowed in `const fn`

error[E0764]: mutable references are not allowed in constants
--> $DIR/const_mut_refs.rs:33:21
|
LL | let _: [(); baz(&mut foo())] = [(); 2];
| ^^^^^^^^^^ `&mut` is only allowed in `const fn`

error[E0764]: mutable references are not allowed in constants
--> $DIR/const_mut_refs.rs:35:22
|
LL | let _: [(); bazz(&mut foo())] = [(); 3];
| ^^^^^^^^^^ `&mut` is only allowed in `const fn`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0764`.
4 changes: 2 additions & 2 deletions src/test/ui/consts/const_let_assign3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ impl S {

const FOO: S = {
let mut s = S { state: 42 };
s.foo(3); //~ ERROR references in constants may only refer to immutable values
s.foo(3); //~ ERROR mutable references are not allowed in constants
s
};

type Array = [u32; {
let mut x = 2;
let y = &mut x;
//~^ ERROR references in constants may only refer to immutable values
//~^ ERROR mutable references are not allowed in constants
*y = 42;
//~^ ERROR constant contains unimplemented expression type
*y
Expand Down
16 changes: 5 additions & 11 deletions src/test/ui/consts/const_let_assign3.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,17 @@ LL | self.state = x;
|
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

error[E0658]: references in constants may only refer to immutable values
error[E0764]: mutable references are not allowed in constants
--> $DIR/const_let_assign3.rs:16:5
|
LL | s.foo(3);
| ^ constants require immutable values
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
| ^ `&mut` is only allowed in `const fn`

error[E0658]: references in constants may only refer to immutable values
error[E0764]: mutable references are not allowed in constants
--> $DIR/const_let_assign3.rs:22:13
|
LL | let y = &mut x;
| ^^^^^^ constants require immutable values
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
| ^^^^^^ `&mut` is only allowed in `const fn`

error[E0019]: constant contains unimplemented expression type
--> $DIR/const_let_assign3.rs:24:5
Expand All @@ -34,5 +28,5 @@ LL | *y = 42;

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0019, E0658.
Some errors have detailed explanations: E0019, E0764.
For more information about an error, try `rustc --explain E0019`.
11 changes: 9 additions & 2 deletions src/test/ui/consts/projection_qualif.mut_refs.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
error[E0764]: mutable references are not allowed in constants
--> $DIR/projection_qualif.rs:10:27
|
LL | let b: *mut u32 = &mut a;
| ^^^^^^ `&mut` is only allowed in `const fn`

error[E0658]: dereferencing raw pointers in constants is unstable
--> $DIR/projection_qualif.rs:11:18
|
Expand All @@ -7,6 +13,7 @@ LL | unsafe { *b = 5; }
= note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
= help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable

error: aborting due to previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.
Some errors have detailed explanations: E0658, E0764.
For more information about an error, try `rustc --explain E0658`.
2 changes: 1 addition & 1 deletion src/test/ui/consts/projection_qualif.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::cell::Cell;
const FOO: &u32 = {
let mut a = 42;
{
let b: *mut u32 = &mut a; //[stock]~ ERROR may only refer to immutable values
let b: *mut u32 = &mut a; //~ ERROR mutable references are not allowed in constants
unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants
//[stock]~^ contains unimplemented expression
}
Expand Down
9 changes: 3 additions & 6 deletions src/test/ui/consts/projection_qualif.stock.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
error[E0658]: references in constants may only refer to immutable values
error[E0764]: mutable references are not allowed in constants
--> $DIR/projection_qualif.rs:10:27
|
LL | let b: *mut u32 = &mut a;
| ^^^^^^ constants require immutable values
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
| ^^^^^^ `&mut` is only allowed in `const fn`

error[E0658]: dereferencing raw pointers in constants is unstable
--> $DIR/projection_qualif.rs:11:18
Expand All @@ -26,5 +23,5 @@ LL | unsafe { *b = 5; }

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0019, E0658.
Some errors have detailed explanations: E0019, E0658, E0764.
For more information about an error, try `rustc --explain E0019`.
9 changes: 4 additions & 5 deletions src/test/ui/consts/read_from_static_mut_ref.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// run-pass
// We are keeping this test in case we decide to allow mutable references in statics again
#![feature(const_mut_refs)]
#![allow(const_err)]

static OH_YES: &mut i32 = &mut 42;

static OH_NO: &mut i32 = &mut 42;
//~^ ERROR mutable references are not allowed in statics
fn main() {
// Make sure `OH_YES` can be read.
assert_eq!(*OH_YES, 42);
assert_eq!(*OH_NO, 42);
}
9 changes: 9 additions & 0 deletions src/test/ui/consts/read_from_static_mut_ref.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
error[E0764]: mutable references are not allowed in statics
--> $DIR/read_from_static_mut_ref.rs:5:26
|
LL | static OH_NO: &mut i32 = &mut 42;
| ^^^^^^^ `&mut` is only allowed in `const fn`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0764`.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
error[E0080]: could not evaluate static initializer
--> $DIR/static_mut_containing_mut_ref2.rs:7:45
error[E0764]: mutable references are not allowed in statics
--> $DIR/static_mut_containing_mut_ref2.rs:7:46
|
LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0080`.
For more information about this error, try `rustc --explain E0764`.
Loading