about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-11-26 08:17:36 +0000
committerbors <bors@rust-lang.org>2018-11-26 08:17:36 +0000
commitb51632e3f0856ea444f5e59819538e85947673fc (patch)
tree781797013c772397ae09f3fdbb1aa2d9ff07395e /src
parent423291f14bbb820265b2bbf33d6fffb044035b86 (diff)
parent6db8c6c6d9fd1f8226b3afd9e18c6fb3cd2f1176 (diff)
downloadrust-b51632e3f0856ea444f5e59819538e85947673fc.tar.gz
rust-b51632e3f0856ea444f5e59819538e85947673fc.zip
Auto merge of #56070 - oli-obk:const_let, r=eddyb
Allow assignments in const contexts

fixes https://github.com/rust-lang/rust/issues/54098
fixes https://github.com/rust-lang/rust/issues/51251
fixes https://github.com/rust-lang/rust/issues/52613
Diffstat (limited to 'src')
-rw-r--r--src/librustc/ich/impls_ty.rs1
-rw-r--r--src/librustc/mir/interpret/error.rs3
-rw-r--r--src/librustc_mir/interpret/machine.rs3
-rw-r--r--src/librustc_mir/interpret/memory.rs8
-rw-r--r--src/librustc_mir/transform/const_prop.rs1
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs61
-rw-r--r--src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs30
-rw-r--r--src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr9
-rw-r--r--src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs24
-rw-r--r--src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr8
-rw-r--r--src/test/ui/consts/const-eval/mod-static-with-const-fn.rs8
-rw-r--r--src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr13
-rw-r--r--src/test/ui/consts/const_let_assign.rs12
-rw-r--r--src/test/ui/consts/const_let_assign2.rs25
-rw-r--r--src/test/ui/consts/const_let_assign3.rs22
-rw-r--r--src/test/ui/consts/const_let_assign3.stderr9
-rw-r--r--src/test/ui/consts/partial_qualif.rs11
-rw-r--r--src/test/ui/consts/partial_qualif.stderr9
-rw-r--r--src/test/ui/consts/projection_qualif.rs14
-rw-r--r--src/test/ui/consts/projection_qualif.stderr18
-rw-r--r--src/test/ui/consts/promote_const_let.nll.stderr14
-rw-r--r--src/test/ui/consts/promote_const_let.rs8
-rw-r--r--src/test/ui/consts/promote_const_let.stderr13
-rw-r--r--src/test/ui/consts/qualif_overwrite.rs15
-rw-r--r--src/test/ui/consts/qualif_overwrite.stderr9
-rw-r--r--src/test/ui/consts/qualif_overwrite_2.rs13
-rw-r--r--src/test/ui/consts/qualif_overwrite_2.stderr9
-rw-r--r--src/test/ui/error-codes/E0017.nll.stderr10
-rw-r--r--src/test/ui/error-codes/E0017.rs1
-rw-r--r--src/test/ui/error-codes/E0017.stderr10
-rw-r--r--src/test/ui/error-codes/E0388.nll.stderr10
-rw-r--r--src/test/ui/error-codes/E0388.rs1
-rw-r--r--src/test/ui/error-codes/E0388.stderr10
-rw-r--r--src/test/ui/write-to-static-mut-in-static.rs4
-rw-r--r--src/test/ui/write-to-static-mut-in-static.stderr9
35 files changed, 382 insertions, 43 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index ad317a96590..e6a7c20f793 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -429,6 +429,7 @@ impl_stable_hash_for!(
         CalledClosureAsFunction,
         VtableForArgumentlessMethod,
         ModifiedConstantMemory,
+        ModifiedStatic,
         AssumptionNotHeld,
         InlineAsm,
         ReallocateNonBasePtr,
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 7477343891e..503e0abdbf3 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -308,6 +308,7 @@ pub enum EvalErrorKind<'tcx, O> {
     CalledClosureAsFunction,
     VtableForArgumentlessMethod,
     ModifiedConstantMemory,
+    ModifiedStatic,
     AssumptionNotHeld,
     InlineAsm,
     TypeNotPrimitive(Ty<'tcx>),
@@ -412,6 +413,8 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
                 "tried to call a vtable function without arguments",
             ModifiedConstantMemory =>
                 "tried to modify constant memory",
+            ModifiedStatic =>
+                "tried to modify a static's initial value from another static's initializer",
             AssumptionNotHeld =>
                 "`assume` argument was false",
             InlineAsm =>
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index 57640dc48f1..dd247a96fa4 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -89,7 +89,8 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
         Default +
         Clone;
 
-    /// The memory kind to use for copied statics -- or None if those are not supported.
+    /// The memory kind to use for copied statics -- or None if statics should not be mutated
+    /// and thus any such attempt will cause a `ModifiedStatic` error to be raised.
     /// Statics are copied under two circumstances: When they are mutated, and when
     /// `static_with_default_tag` or `find_foreign_static` (see below) returns an owned allocation
     /// that is added to the memory so that the work is not done twice.
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index c673b57a66f..57d79bfc9fe 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -397,10 +397,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             if alloc.mutability == Mutability::Immutable {
                 return err!(ModifiedConstantMemory);
             }
-            let kind = M::STATIC_KIND.expect(
-                "An allocation is being mutated but the machine does not expect that to happen"
-            );
-            Ok((MemoryKind::Machine(kind), alloc.into_owned()))
+            match M::STATIC_KIND {
+                Some(kind) => Ok((MemoryKind::Machine(kind), alloc.into_owned())),
+                None => err!(ModifiedStatic),
+            }
         });
         // Unpack the error type manually because type inference doesn't
         // work otherwise (and we cannot help it because `impl Trait`)
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 661ca4773b4..f21efaa048b 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -199,6 +199,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
                     | CalledClosureAsFunction
                     | VtableForArgumentlessMethod
                     | ModifiedConstantMemory
+                    | ModifiedStatic
                     | AssumptionNotHeld
                     // FIXME: should probably be removed and turned into a bug! call
                     | TypeNotPrimitive(_)
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 816e8594885..fc2c6c3ab1f 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -243,13 +243,52 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
             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);
+        if self.tcx.features().const_let {
+            let mut dest = dest;
+            let index = loop {
+                match dest {
+                    // with `const_let` active, we treat all locals equal
+                    Place::Local(index) => break *index,
+                    // projections are transparent for assignments
+                    // we qualify the entire destination at once, even if just a field would have
+                    // stricter qualification
+                    Place::Projection(proj) => {
+                        // Catch more errors in the destination. `visit_place` also checks various
+                        // projection rules like union field access and raw pointer deref
+                        self.visit_place(
+                            dest,
+                            PlaceContext::MutatingUse(MutatingUseContext::Store),
+                            location
+                        );
+                        dest = &proj.base;
+                    },
+                    Place::Promoted(..) => bug!("promoteds don't exist yet during promotion"),
+                    Place::Static(..) => {
+                        // Catch more errors in the destination. `visit_place` also checks that we
+                        // do not try to access statics from constants or try to mutate statics
+                        self.visit_place(
+                            dest,
+                            PlaceContext::MutatingUse(MutatingUseContext::Store),
+                            location
+                        );
+                        return;
+                    }
+                }
+            };
+            debug!("store to var {:?}", index);
+            match &mut self.local_qualif[index] {
+                // this is overly restrictive, because even full assignments do not clear the qualif
+                // While we could special case full assignments, this would be inconsistent with
+                // aggregates where we overwrite all fields via assignments, which would not get
+                // that feature.
+                Some(ref mut qualif) => *qualif = *qualif | self.qualif,
+                // insert new qualification
+                qualif @ None => *qualif = Some(self.qualif),
             }
+            return;
+        }
+
+        match *dest {
             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 +517,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);
diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs
new file mode 100644
index 00000000000..ef0de61d219
--- /dev/null
+++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs
@@ -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() {}
diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr
new file mode 100644
index 00000000000..0892b05a69d
--- /dev/null
+++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr
@@ -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`.
diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs
new file mode 100644
index 00000000000..6f16f644eec
--- /dev/null
+++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs
@@ -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() {}
diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr
new file mode 100644
index 00000000000..ca652c9df32
--- /dev/null
+++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr
@@ -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
+
diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs
index 4136a7b6a72..01fcc8307c0 100644
--- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs
+++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // New test for #53818: modifying static memory at compile-time is not allowed.
-// The test should never succeed.
+// The test should never compile successfully
 
 #![feature(const_raw_ptr_deref)]
 #![feature(const_let)]
@@ -27,9 +27,9 @@ fn foo() {}
 
 static BAR: () = unsafe {
     *FOO.0.get() = 5;
-    //~^ ERROR statements in statics are unstable (see issue #48821)
-    // This error is caused by a separate bug that the feature gate error is reported
-    // even though the feature gate "const_let" is active.
+    // we do not error on the above access, because that is not detectable statically. Instead,
+    // const evaluation will error when trying to evaluate it. Due to the error below, we never even
+    // attempt to const evaluate `BAR`, so we don't see the error
 
     foo();
     //~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants
diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr
index c2bba27e4d1..01ad1fc9a21 100644
--- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr
+++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr
@@ -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
    |
 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`.
diff --git a/src/test/ui/consts/const_let_assign.rs b/src/test/ui/consts/const_let_assign.rs
new file mode 100644
index 00000000000..a3c53a451e1
--- /dev/null
+++ b/src/test/ui/consts/const_let_assign.rs
@@ -0,0 +1,12 @@
+// compile-pass
+
+#![feature(const_let)]
+
+struct S(i32);
+
+const A: () = {
+    let mut s = S(0);
+    s.0 = 1;
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const_let_assign2.rs b/src/test/ui/consts/const_let_assign2.rs
new file mode 100644
index 00000000000..0de7396501a
--- /dev/null
+++ b/src/test/ui/consts/const_let_assign2.rs
@@ -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);
+    }
+}
diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs
new file mode 100644
index 00000000000..83825456b5c
--- /dev/null
+++ b/src/test/ui/consts/const_let_assign3.rs
@@ -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);
+}
diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr
new file mode 100644
index 00000000000..7f9a953c10f
--- /dev/null
+++ b/src/test/ui/consts/const_let_assign3.stderr
@@ -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`.
diff --git a/src/test/ui/consts/partial_qualif.rs b/src/test/ui/consts/partial_qualif.rs
new file mode 100644
index 00000000000..4ce41f80f82
--- /dev/null
+++ b/src/test/ui/consts/partial_qualif.rs
@@ -0,0 +1,11 @@
+#![feature(const_let)]
+
+use std::cell::Cell;
+
+const FOO: &(Cell<usize>, bool) = {
+    let mut a = (Cell::new(0), false);
+    a.1 = true; // sets `qualif(a)` to `qualif(a) | qualif(true)`
+    &{a} //~ ERROR cannot borrow a constant which may contain interior mutability
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/partial_qualif.stderr b/src/test/ui/consts/partial_qualif.stderr
new file mode 100644
index 00000000000..d695f64e2c3
--- /dev/null
+++ b/src/test/ui/consts/partial_qualif.stderr
@@ -0,0 +1,9 @@
+error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+  --> $DIR/partial_qualif.rs:8:5
+   |
+LL |     &{a} //~ ERROR cannot borrow a constant which may contain interior mutability
+   |     ^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0492`.
diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs
new file mode 100644
index 00000000000..34e8eaba9f2
--- /dev/null
+++ b/src/test/ui/consts/projection_qualif.rs
@@ -0,0 +1,14 @@
+#![feature(const_let)]
+
+use std::cell::Cell;
+
+const FOO: &u32 = {
+    let mut a = 42;
+    {
+        let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values
+        unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants
+    }
+    &{a}
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/projection_qualif.stderr b/src/test/ui/consts/projection_qualif.stderr
new file mode 100644
index 00000000000..d5252f199be
--- /dev/null
+++ b/src/test/ui/consts/projection_qualif.stderr
@@ -0,0 +1,18 @@
+error[E0017]: references in constants may only refer to immutable values
+  --> $DIR/projection_qualif.rs:8:27
+   |
+LL |         let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values
+   |                           ^^^^^^ constants require immutable values
+
+error[E0658]: dereferencing raw pointers in constants is unstable (see issue #51911)
+  --> $DIR/projection_qualif.rs:9:18
+   |
+LL |         unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants
+   |                  ^^^^^^
+   |
+   = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0017, E0658.
+For more information about an error, try `rustc --explain E0017`.
diff --git a/src/test/ui/consts/promote_const_let.nll.stderr b/src/test/ui/consts/promote_const_let.nll.stderr
new file mode 100644
index 00000000000..d8749bb5fd9
--- /dev/null
+++ b/src/test/ui/consts/promote_const_let.nll.stderr
@@ -0,0 +1,14 @@
+error[E0597]: `y` does not live long enough
+  --> $DIR/promote_const_let.rs:6:9
+   |
+LL |     let x: &'static u32 = {
+   |            ------------ type annotation requires that `y` is borrowed for `'static`
+LL |         let y = 42;
+LL |         &y //~ ERROR does not live long enough
+   |         ^^ borrowed value does not live long enough
+LL |     };
+   |     - `y` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/consts/promote_const_let.rs b/src/test/ui/consts/promote_const_let.rs
new file mode 100644
index 00000000000..8de9b00eb11
--- /dev/null
+++ b/src/test/ui/consts/promote_const_let.rs
@@ -0,0 +1,8 @@
+#![feature(const_let)]
+
+fn main() {
+    let x: &'static u32 = {
+        let y = 42;
+        &y //~ ERROR does not live long enough
+    };
+}
diff --git a/src/test/ui/consts/promote_const_let.stderr b/src/test/ui/consts/promote_const_let.stderr
new file mode 100644
index 00000000000..6bbb7495fb0
--- /dev/null
+++ b/src/test/ui/consts/promote_const_let.stderr
@@ -0,0 +1,13 @@
+error[E0597]: `y` does not live long enough
+  --> $DIR/promote_const_let.rs:6:10
+   |
+LL |         &y //~ ERROR does not live long enough
+   |          ^ borrowed value does not live long enough
+LL |     };
+   |     - borrowed value only lives until here
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/consts/qualif_overwrite.rs b/src/test/ui/consts/qualif_overwrite.rs
new file mode 100644
index 00000000000..806a74ee453
--- /dev/null
+++ b/src/test/ui/consts/qualif_overwrite.rs
@@ -0,0 +1,15 @@
+#![feature(const_let)]
+
+use std::cell::Cell;
+
+// this is overly conservative. The reset to `None` should clear `a` of all qualifications
+// while we could fix this, it would be inconsistent with `qualif_overwrite_2.rs`.
+// We can fix this properly in the future by allowing constants that do not depend on generics
+// to be checked by an analysis on the final value instead of looking at the body.
+const FOO: &Option<Cell<usize>> = {
+    let mut a = Some(Cell::new(0));
+    a = None; // sets `qualif(a)` to `qualif(a) | qualif(None)`
+    &{a} //~ ERROR cannot borrow a constant which may contain interior mutability
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/qualif_overwrite.stderr b/src/test/ui/consts/qualif_overwrite.stderr
new file mode 100644
index 00000000000..4fac64bf806
--- /dev/null
+++ b/src/test/ui/consts/qualif_overwrite.stderr
@@ -0,0 +1,9 @@
+error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+  --> $DIR/qualif_overwrite.rs:12:5
+   |
+LL |     &{a} //~ ERROR cannot borrow a constant which may contain interior mutability
+   |     ^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0492`.
diff --git a/src/test/ui/consts/qualif_overwrite_2.rs b/src/test/ui/consts/qualif_overwrite_2.rs
new file mode 100644
index 00000000000..29557a3da47
--- /dev/null
+++ b/src/test/ui/consts/qualif_overwrite_2.rs
@@ -0,0 +1,13 @@
+#![feature(const_let)]
+
+use std::cell::Cell;
+
+// const qualification is not smart enough to know about fields and always assumes that there might
+// be other fields that caused the qualification
+const FOO: &Option<Cell<usize>> = {
+    let mut a = (Some(Cell::new(0)),);
+    a.0 = None; // sets `qualif(a)` to `qualif(a) | qualif(None)`
+    &{a.0} //~ ERROR cannot borrow a constant which may contain interior mutability
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/qualif_overwrite_2.stderr b/src/test/ui/consts/qualif_overwrite_2.stderr
new file mode 100644
index 00000000000..181b728c7b7
--- /dev/null
+++ b/src/test/ui/consts/qualif_overwrite_2.stderr
@@ -0,0 +1,9 @@
+error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+  --> $DIR/qualif_overwrite_2.rs:10:5
+   |
+LL |     &{a.0} //~ ERROR cannot borrow a constant which may contain interior mutability
+   |     ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0492`.
diff --git a/src/test/ui/error-codes/E0017.nll.stderr b/src/test/ui/error-codes/E0017.nll.stderr
index 08708d213d3..8f8d87739b8 100644
--- a/src/test/ui/error-codes/E0017.nll.stderr
+++ b/src/test/ui/error-codes/E0017.nll.stderr
@@ -4,6 +4,12 @@ error[E0017]: references in constants may only refer to immutable values
 LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017
    |                              ^^^^^^ constants require immutable values
 
+error: cannot mutate statics in the initializer of another static
+  --> $DIR/E0017.rs:15:39
+   |
+LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
+   |                                       ^^^^^^
+
 error[E0017]: references in statics may only refer to immutable values
   --> $DIR/E0017.rs:15:39
    |
@@ -17,12 +23,12 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
    |                                       ^^^^^^ cannot borrow as mutable
 
 error[E0017]: references in statics may only refer to immutable values
-  --> $DIR/E0017.rs:17:38
+  --> $DIR/E0017.rs:18:38
    |
 LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
    |                                      ^^^^^^ statics require immutable values
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors occurred: E0017, E0596.
 For more information about an error, try `rustc --explain E0017`.
diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs
index c98c35a1442..bf400fde365 100644
--- a/src/test/ui/error-codes/E0017.rs
+++ b/src/test/ui/error-codes/E0017.rs
@@ -14,5 +14,6 @@ const C: i32 = 2;
 const CR: &'static mut i32 = &mut C; //~ ERROR E0017
 static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
                                               //~| ERROR cannot borrow
+                                              //~| ERROR cannot mutate statics
 static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
 fn main() {}
diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr
index 411b9f31397..94a90d92d3e 100644
--- a/src/test/ui/error-codes/E0017.stderr
+++ b/src/test/ui/error-codes/E0017.stderr
@@ -4,6 +4,12 @@ error[E0017]: references in constants may only refer to immutable values
 LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017
    |                              ^^^^^^ constants require immutable values
 
+error: cannot mutate statics in the initializer of another static
+  --> $DIR/E0017.rs:15:39
+   |
+LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
+   |                                       ^^^^^^
+
 error[E0017]: references in statics may only refer to immutable values
   --> $DIR/E0017.rs:15:39
    |
@@ -17,12 +23,12 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
    |                                            ^
 
 error[E0017]: references in statics may only refer to immutable values
-  --> $DIR/E0017.rs:17:38
+  --> $DIR/E0017.rs:18:38
    |
 LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
    |                                      ^^^^^^ statics require immutable values
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors occurred: E0017, E0596.
 For more information about an error, try `rustc --explain E0017`.
diff --git a/src/test/ui/error-codes/E0388.nll.stderr b/src/test/ui/error-codes/E0388.nll.stderr
index a048374a497..7d25d41f18b 100644
--- a/src/test/ui/error-codes/E0388.nll.stderr
+++ b/src/test/ui/error-codes/E0388.nll.stderr
@@ -4,6 +4,12 @@ error[E0017]: references in constants may only refer to immutable values
 LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017
    |                              ^^^^^^ constants require immutable values
 
+error: cannot mutate statics in the initializer of another static
+  --> $DIR/E0388.rs:15:39
+   |
+LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
+   |                                       ^^^^^^
+
 error[E0017]: references in statics may only refer to immutable values
   --> $DIR/E0388.rs:15:39
    |
@@ -17,12 +23,12 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
    |                                       ^^^^^^ cannot borrow as mutable
 
 error[E0017]: references in statics may only refer to immutable values
-  --> $DIR/E0388.rs:17:38
+  --> $DIR/E0388.rs:18:38
    |
 LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
    |                                      ^^^^^^ statics require immutable values
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors occurred: E0017, E0596.
 For more information about an error, try `rustc --explain E0017`.
diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs
index c002badfef6..3203798c709 100644
--- a/src/test/ui/error-codes/E0388.rs
+++ b/src/test/ui/error-codes/E0388.rs
@@ -14,6 +14,7 @@ const C: i32 = 2;
 const CR: &'static mut i32 = &mut C; //~ ERROR E0017
 static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
                                               //~| ERROR cannot borrow
+                                              //~| ERROR cannot mutate statics
 static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
 
 fn main() {}
diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr
index d2263cd4034..46efda9147b 100644
--- a/src/test/ui/error-codes/E0388.stderr
+++ b/src/test/ui/error-codes/E0388.stderr
@@ -4,6 +4,12 @@ error[E0017]: references in constants may only refer to immutable values
 LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017
    |                              ^^^^^^ constants require immutable values
 
+error: cannot mutate statics in the initializer of another static
+  --> $DIR/E0388.rs:15:39
+   |
+LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
+   |                                       ^^^^^^
+
 error[E0017]: references in statics may only refer to immutable values
   --> $DIR/E0388.rs:15:39
    |
@@ -17,12 +23,12 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
    |                                            ^
 
 error[E0017]: references in statics may only refer to immutable values
-  --> $DIR/E0388.rs:17:38
+  --> $DIR/E0388.rs:18:38
    |
 LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
    |                                      ^^^^^^ statics require immutable values
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors occurred: E0017, E0596.
 For more information about an error, try `rustc --explain E0017`.
diff --git a/src/test/ui/write-to-static-mut-in-static.rs b/src/test/ui/write-to-static-mut-in-static.rs
index 1ea74f73723..191f09b54ee 100644
--- a/src/test/ui/write-to-static-mut-in-static.rs
+++ b/src/test/ui/write-to-static-mut-in-static.rs
@@ -12,10 +12,10 @@
 
 pub static mut A: u32 = 0;
 pub static mut B: () = unsafe { A = 1; };
-//~^ ERROR statements in statics are unstable
+//~^ ERROR cannot mutate statics in the initializer of another static
 
 pub static mut C: u32 = unsafe { C = 1; 0 };
-//~^ ERROR statements in statics are unstable
+//~^ ERROR cannot mutate statics in the initializer of another static
 
 pub static D: u32 = D;
 
diff --git a/src/test/ui/write-to-static-mut-in-static.stderr b/src/test/ui/write-to-static-mut-in-static.stderr
index f07d240746f..673a71b4642 100644
--- a/src/test/ui/write-to-static-mut-in-static.stderr
+++ b/src/test/ui/write-to-static-mut-in-static.stderr
@@ -1,19 +1,14 @@
-error[E0658]: statements in statics are unstable (see issue #48821)
+error: cannot mutate statics in the initializer of another static
   --> $DIR/write-to-static-mut-in-static.rs:14:33
    |
 LL | pub static mut B: () = unsafe { A = 1; };
    |                                 ^^^^^
-   |
-   = help: add #![feature(const_let)] to the crate attributes to enable
 
-error[E0658]: statements in statics are unstable (see issue #48821)
+error: cannot mutate statics in the initializer of another static
   --> $DIR/write-to-static-mut-in-static.rs:17:34
    |
 LL | pub static mut C: u32 = unsafe { C = 1; 0 };
    |                                  ^^^^^
-   |
-   = help: add #![feature(const_let)] to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.