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

Add feature gate for mut refs in const fn #66606

Merged
merged 15 commits into from
Dec 7, 2019
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: 0 additions & 1 deletion src/librustc_error_codes/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ E0010: include_str!("./error_codes/E0010.md"),
E0013: include_str!("./error_codes/E0013.md"),
E0014: include_str!("./error_codes/E0014.md"),
E0015: include_str!("./error_codes/E0015.md"),
E0017: include_str!("./error_codes/E0017.md"),
E0019: include_str!("./error_codes/E0019.md"),
E0023: include_str!("./error_codes/E0023.md"),
E0025: include_str!("./error_codes/E0025.md"),
Expand Down
20 changes: 0 additions & 20 deletions src/librustc_error_codes/error_codes/E0017.md

This file was deleted.

3 changes: 3 additions & 0 deletions src/librustc_feature/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,9 @@ declare_features! (
/// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
(active, cfg_sanitize, "1.41.0", Some(39699), None),

/// Allows using `&mut` in constant functions.
(active, const_mut_refs, "1.41.0", Some(57349), None),

// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
Expand Down
64 changes: 39 additions & 25 deletions src/librustc_mir/transform/check_consts/ops.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Concrete error types for all operations which may be invalid in a certain const context.

use rustc::hir::def_id::DefId;
use rustc::mir::BorrowKind;
use rustc::session::config::nightly_options;
use rustc::ty::TyCtxt;
use syntax::feature_gate::feature_err;
Expand Down Expand Up @@ -181,38 +180,53 @@ impl NonConstOp for Loop {
}

#[derive(Debug)]
pub struct MutBorrow(pub BorrowKind);
pub struct CellBorrow;
impl NonConstOp for CellBorrow {
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
span_err!(item.tcx.sess, span, E0492,
"cannot borrow a constant which may contain \
interior mutability, create a static instead");
}
}

#[derive(Debug)]
pub struct MutBorrow;
impl NonConstOp for MutBorrow {
fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
Some(tcx.features().const_mut_refs)
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
}

fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
let kind = self.0;
if let BorrowKind::Mut { .. } = kind {
let mut err = struct_span_err!(item.tcx.sess, span, E0017,
"references in {}s may only refer \
to immutable values", item.const_kind());
err.span_label(span, format!("{}s require immutable values",
item.const_kind()));
if item.tcx.sess.teach(&err.get_code().unwrap()) {
err.note("References in statics and constants may only refer \
to immutable values.\n\n\
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.\n\n\
If you really want global mutable state, try using \
static mut or a global UnsafeCell.");
}
err.emit();
} else {
span_err!(item.tcx.sess, span, E0492,
"cannot borrow a constant which may contain \
interior mutability, create a static instead");
let mut err = feature_err(
&item.tcx.sess.parse_sess,
sym::const_mut_refs,
span,
&format!("references in {}s may only refer \
to immutable values", item.const_kind())
);
err.span_label(span, format!("{}s require immutable values",
item.const_kind()));
if item.tcx.sess.teach(&err.get_code().unwrap()) {
err.note("References in statics and constants may only refer \
to immutable values.\n\n\
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.\n\n\
If you really want global mutable state, try using \
static mut or a global UnsafeCell.");
}
err.emit();
}
}

#[derive(Debug)]
pub struct MutDeref;
impl NonConstOp for MutDeref {}
impl NonConstOp for MutDeref {
fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
Some(tcx.features().const_mut_refs)
}
}

#[derive(Debug)]
pub struct Panic;
Expand Down
13 changes: 10 additions & 3 deletions src/librustc_mir/transform/check_consts/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,11 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
};

if !is_allowed {
self.check_op(ops::MutBorrow(kind));
if let BorrowKind::Mut{ .. } = kind {
self.check_op(ops::MutBorrow);
} else {
self.check_op(ops::CellBorrow);
}
}
}

Expand All @@ -385,7 +389,11 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
);

if borrowed_place_has_mut_interior {
self.check_op(ops::MutBorrow(kind));
if let BorrowKind::Mut{ .. } = kind {
self.check_op(ops::MutBorrow);
} else {
self.check_op(ops::CellBorrow);
}
}
}

Expand Down Expand Up @@ -452,7 +460,6 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
}
}
}

fn visit_projection_elem(
&mut self,
place_base: &PlaceBase<'tcx>,
Expand Down
12 changes: 8 additions & 4 deletions src/librustc_mir/transform/qualify_min_const_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,14 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -
fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult {
for ty in ty.walk() {
match ty.kind {
ty::Ref(_, _, hir::Mutability::Mutable) => return Err((
span,
"mutable references in const fn are unstable".into(),
)),
ty::Ref(_, _, hir::Mutability::Mutable) => {
if !tcx.features().const_mut_refs {
return Err((
span,
"mutable references in const fn are unstable".into(),
))
}
}
ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
ty::FnPtr(..) => {
if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) {
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax_pos/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ symbols! {
const_indexing,
const_in_array_repeat_expressions,
const_let,
const_mut_refs,
const_panic,
const_raw_ptr_deref,
const_raw_ptr_to_usize_cast,
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/consts/const-fn-error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const fn f(x: usize) -> usize {
let mut sum = 0;
for i in 0..x {
//~^ ERROR E0015
//~| ERROR E0017
//~| ERROR E0658
//~| ERROR E0080
//~| ERROR E0744
//~| ERROR E0019
Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/check-static-immutable-mut-slices.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
error[E0017]: references in statics may only refer to immutable values
error[E0658]: references in statics may only refer to immutable values
--> $DIR/check-static-immutable-mut-slices.rs:3:37
|
LL | static TEST: &'static mut [isize] = &mut [];
| ^^^^^^^ statics require immutable values
|
= note: for more information, see https://github.com/rust-lang/rust/issues/57349
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0017`.
For more information about this error, try `rustc --explain E0658`.
9 changes: 6 additions & 3 deletions src/test/ui/consts/const-eval/issue-65394.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
error[E0017]: references in constants may only refer to immutable values
error[E0658]: references in constants may only refer to immutable values
--> $DIR/issue-65394.rs:8:13
|
LL | let r = &mut x;
| ^^^^^^ constants require immutable values
|
= note: for more information, see https://github.com/rust-lang/rust/issues/57349
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

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

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0017, E0493.
For more information about an error, try `rustc --explain E0017`.
Some errors have detailed explanations: E0493, E0658.
For more information about an error, try `rustc --explain E0493`.
9 changes: 6 additions & 3 deletions src/test/ui/consts/const-multi-ref.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
error[E0017]: references in constants may only refer to immutable values
error[E0658]: references in constants may only refer to immutable values
--> $DIR/const-multi-ref.rs:6:13
|
LL | let p = &mut a;
| ^^^^^^ constants require immutable values
|
= note: for more information, see https://github.com/rust-lang/rust/issues/57349
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

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

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0017, E0492.
For more information about an error, try `rustc --explain E0017`.
Some errors have detailed explanations: E0492, E0658.
For more information about an error, try `rustc --explain E0492`.
36 changes: 36 additions & 0 deletions src/test/ui/consts/const-mut-refs/const_mut_refs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// run-pass

#![feature(const_mut_refs)]

struct Foo {
x: usize
}

const fn foo() -> Foo {
Foo { x: 0 }
}

impl Foo {
const fn bar(&mut self) -> usize {
self.x = 1;
self.x
}

}

const fn baz(foo: &mut Foo) -> usize {
let x = &mut foo.x;
*x = 2;
*x
}

const fn bazz(foo: &mut Foo) -> usize {
foo.x = 3;
foo.x
}

fn main() {
let _: [(); foo().bar()] = [(); 1];
let _: [(); baz(&mut foo())] = [(); 2];
let _: [(); bazz(&mut foo())] = [(); 3];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn main() {
foo(&mut 5);
}

const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn are unstable
*x + 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0723]: mutable references in const fn are unstable
--> $DIR/feature-gate-const_mut_refs.rs:5:14
|
LL | const fn foo(x: &mut i32) -> i32 {
| ^
|
= note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
= help: add `#![feature(const_fn)]` to the crate attributes to enable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... it's quite unfortunate that the wrong feature gate is suggested.

Copy link
Contributor Author

@pvdrz pvdrz Nov 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes :( I'd like to fix it

Edit: I think I found how to do it, working on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was able to fix it when mutable borrows are done inside constant contexts but not when they are function arguments. This is because that check is done by the const fn qualification and it always suggests the const_fn flag.


error: aborting due to previous error

For more information about this error, try `rustc --explain E0723`.
14 changes: 10 additions & 4 deletions src/test/ui/consts/const_let_assign3.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,23 @@ error[E0019]: constant function contains unimplemented expression type
LL | self.state = x;
| ^^^^^^^^^^^^^^

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

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

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

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0017, E0019.
For more information about an error, try `rustc --explain E0017`.
Some errors have detailed explanations: E0019, E0658.
For more information about an error, try `rustc --explain E0019`.
5 changes: 2 additions & 3 deletions src/test/ui/consts/miri_unleashed/mutable_const.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// compile-flags: -Zunleash-the-miri-inside-of-you

#![feature(const_raw_ptr_deref)]
#![feature(const_mut_refs)]
#![deny(const_err)]

use std::cell::UnsafeCell;
Expand All @@ -12,9 +13,7 @@ const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
const MUTATING_BEHIND_RAW: () = {
// Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time.
unsafe {
*MUTABLE_BEHIND_RAW = 99 //~ WARN skipping const checks
//~^ ERROR any use of this value will cause an error
//~^^ tried to modify constant memory
*MUTABLE_BEHIND_RAW = 99 //~ ERROR any use of this value will cause an error
}
};

Expand Down
13 changes: 3 additions & 10 deletions src/test/ui/consts/miri_unleashed/mutable_const.stderr
Original file line number Diff line number Diff line change
@@ -1,30 +1,23 @@
warning: skipping const checks
--> $DIR/mutable_const.rs:9:38
--> $DIR/mutable_const.rs:10:38
|
LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
| ^^^^^^^^^^^^^^^^^^^^

warning: skipping const checks
--> $DIR/mutable_const.rs:15:9
|
LL | *MUTABLE_BEHIND_RAW = 99
| ^^^^^^^^^^^^^^^^^^^^^^^^

error: any use of this value will cause an error
--> $DIR/mutable_const.rs:15:9
--> $DIR/mutable_const.rs:16:9
|
LL | / const MUTATING_BEHIND_RAW: () = {
LL | | // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time.
LL | | unsafe {
LL | | *MUTABLE_BEHIND_RAW = 99
| | ^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify constant memory
... |
LL | | }
LL | | };
| |__-
|
note: lint level defined here
--> $DIR/mutable_const.rs:4:9
--> $DIR/mutable_const.rs:5:9
|
LL | #![deny(const_err)]
| ^^^^^^^^^
Expand Down
Loading