Skip to content

Commit

Permalink
Rollup merge of #72934 - christianpoveda:mut-borrows-in-consts, r=oli…
Browse files Browse the repository at this point in the history
…-obk

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

PR to address #71212

cc: @ecstatic-morse
  • Loading branch information
Manishearth authored Jun 20, 2020
2 parents c0a25be + 96031e2 commit dac512e
Show file tree
Hide file tree
Showing 32 changed files with 193 additions and 141 deletions.
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];
| ^^^^^ `&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

0 comments on commit dac512e

Please sign in to comment.