Skip to content

Commit fddf315

Browse files
authored
Rollup merge of rust-lang#75585 - RalfJung:demotion, r=oli-obk
Do not promote &mut of a non-ZST ever Since ~pre-1.0~ 1.36, we have accepted code like this: ```rust static mut TEST: &'static mut [i32] = { let x = &mut [1,2,3]; x }; ``` I tracked it back to rust-lang#21744, but unfortunately could not find any discussion or RFC that would explain why we thought this was a good idea. And it's not, it breaks all sorts of things -- see rust-lang#75556. To fix rust-lang#75556, we have to stop promoting non-ZST mutable references no matter the context, which is what this PR does. It's a breaking change. Notice that this still works, since it does not rely on promotion: ```rust static mut TEST: &'static mut [i32] = &mut [0,1,2]; ``` Cc @rust-lang/wg-const-eval
2 parents b5468e1 + 28ddda7 commit fddf315

File tree

4 files changed

+52
-16
lines changed

4 files changed

+52
-16
lines changed

compiler/rustc_mir/src/transform/promote_consts.rs

+2-16
Original file line numberDiff line numberDiff line change
@@ -364,15 +364,7 @@ impl<'tcx> Validator<'_, 'tcx> {
364364
// In theory, any zero-sized value could be borrowed
365365
// mutably without consequences. However, only &mut []
366366
// is allowed right now, and only in functions.
367-
if self.const_kind
368-
== Some(hir::ConstContext::Static(hir::Mutability::Mut))
369-
{
370-
// Inside a `static mut`, &mut [...] is also allowed.
371-
match ty.kind() {
372-
ty::Array(..) | ty::Slice(_) => {}
373-
_ => return Err(Unpromotable),
374-
}
375-
} else if let ty::Array(_, len) = ty.kind() {
367+
if let ty::Array(_, len) = ty.kind() {
376368
// FIXME(eddyb) the `self.is_non_const_fn` condition
377369
// seems unnecessary, given that this is merely a ZST.
378370
match len.try_eval_usize(self.tcx, self.param_env) {
@@ -673,13 +665,7 @@ impl<'tcx> Validator<'_, 'tcx> {
673665
// In theory, any zero-sized value could be borrowed
674666
// mutably without consequences. However, only &mut []
675667
// is allowed right now, and only in functions.
676-
if self.const_kind == Some(hir::ConstContext::Static(hir::Mutability::Mut)) {
677-
// Inside a `static mut`, &mut [...] is also allowed.
678-
match ty.kind() {
679-
ty::Array(..) | ty::Slice(_) => {}
680-
_ => return Err(Unpromotable),
681-
}
682-
} else if let ty::Array(_, len) = ty.kind() {
668+
if let ty::Array(_, len) = ty.kind() {
683669
// FIXME(eddyb): We only return `Unpromotable` for `&mut []` inside a
684670
// const context which seems unnecessary given that this is merely a ZST.
685671
match len.try_eval_usize(self.tcx, self.param_env) {

src/test/ui/consts/promote-no-mut.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// ignore-tidy-linelength
2+
// We do not promote mutable references.
3+
static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed
4+
5+
static mut TEST2: &'static mut [i32] = {
6+
let x = &mut [1,2,3]; //~ ERROR temporary value dropped while borrowed
7+
x
8+
};
9+
10+
fn main() {}
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0716]: temporary value dropped while borrowed
2+
--> $DIR/promote-no-mut.rs:3:50
3+
|
4+
LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]);
5+
| ----------^^^^^^^^^-
6+
| | | |
7+
| | | temporary value is freed at the end of this statement
8+
| | creates a temporary which is freed while still in use
9+
| using this value as a static requires that borrow lasts for `'static`
10+
11+
error[E0716]: temporary value dropped while borrowed
12+
--> $DIR/promote-no-mut.rs:6:18
13+
|
14+
LL | let x = &mut [1,2,3];
15+
| ^^^^^^^ creates a temporary which is freed while still in use
16+
LL | x
17+
| - using this value as a static requires that borrow lasts for `'static`
18+
LL | };
19+
| - temporary value is freed at the end of this statement
20+
21+
error: aborting due to 2 previous errors
22+
23+
For more information about this error, try `rustc --explain E0716`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// run-pass
2+
#![feature(const_mut_refs)]
3+
4+
static mut TEST: i32 = {
5+
// We must not promote this, as CTFE needs to be able to mutate it later.
6+
let x = &mut [1,2,3];
7+
x[0] += 1;
8+
x[0]
9+
};
10+
11+
// This still works -- it's not done via promotion.
12+
#[allow(unused)]
13+
static mut TEST2: &'static mut [i32] = &mut [0,1,2];
14+
15+
fn main() {
16+
assert_eq!(unsafe { TEST }, 2);
17+
}

0 commit comments

Comments
 (0)