about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-01-04 02:15:57 +0000
committerbors <bors@rust-lang.org>2021-01-04 02:15:57 +0000
commit8989689e728895147e41c497e7ca69e7f82f69d7 (patch)
treeda32380e2bedfcf01e980eb67ecd7060d10313a4
parent80184183ba0a53aa4f491753de9502acd3d6920c (diff)
parent90b56b94f6925003c1879660530f9e0ebdb94fa9 (diff)
downloadrust-8989689e728895147e41c497e7ca69e7f82f69d7.tar.gz
rust-8989689e728895147e41c497e7ca69e7f82f69d7.zip
Auto merge of #80418 - oli-obk:this_could_have_been_so_simple, r=RalfJung
Allow references to interior mutable data behind a feature gate

supercedes #80373 by simply not checking for interior mutability on borrows of locals that have `StorageDead` and thus can never be leaked to the final value of the constant

tracking issue: https://github.com/rust-lang/rust/issues/80384

r? `@RalfJung`
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0492.md4
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/ops.rs53
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/validation.rs50
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--src/test/ui/consts/const-address-of-interior-mut.stderr22
-rw-r--r--src/test/ui/consts/const-multi-ref.rs2
-rw-r--r--src/test/ui/consts/const-multi-ref.stderr9
-rw-r--r--src/test/ui/consts/partial_qualif.rs2
-rw-r--r--src/test/ui/consts/partial_qualif.stderr4
-rw-r--r--src/test/ui/consts/qualif_overwrite.rs2
-rw-r--r--src/test/ui/consts/qualif_overwrite.stderr4
-rw-r--r--src/test/ui/consts/qualif_overwrite_2.rs2
-rw-r--r--src/test/ui/consts/qualif_overwrite_2.stderr4
-rw-r--r--src/test/ui/consts/std/cell.rs30
-rw-r--r--src/test/ui/consts/std/cell.stderr27
-rw-r--r--src/test/ui/error-codes/E0492.rs5
-rw-r--r--src/test/ui/error-codes/E0492.stderr18
-rw-r--r--src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs12
-rw-r--r--src/test/ui/issues/issue-17718-const-borrow.rs6
-rw-r--r--src/test/ui/issues/issue-17718-const-borrow.stderr12
-rw-r--r--src/test/ui/panic-handler/weak-lang-item.stderr4
-rw-r--r--src/test/ui/unsafe/ranged_ints3_const.rs4
-rw-r--r--src/test/ui/unsafe/ranged_ints3_const.stderr12
24 files changed, 230 insertions, 62 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0492.md b/compiler/rustc_error_codes/src/error_codes/E0492.md
index 1caa59999ae..79e7c069a91 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0492.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0492.md
@@ -6,7 +6,7 @@ Erroneous code example:
 use std::sync::atomic::AtomicUsize;
 
 const A: AtomicUsize = AtomicUsize::new(0);
-static B: &'static AtomicUsize = &A;
+const B: &'static AtomicUsize = &A;
 // error: cannot borrow a constant which may contain interior mutability,
 //        create a static instead
 ```
@@ -18,7 +18,7 @@ can't be changed via a shared `&` pointer, but interior mutability would allow
 it. That is, a constant value could be mutated. On the other hand, a `static` is
 explicitly a single memory location, which can be mutated at will.
 
-So, in order to solve this error, either use statics which are `Sync`:
+So, in order to solve this error, use statics which are `Sync`:
 
 ```
 use std::sync::atomic::AtomicUsize;
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 252e96b47c6..3b54ffbc3f0 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -626,6 +626,9 @@ declare_features! (
     /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`).
     (active, const_generics_defaults, "1.51.0", Some(44580), None),
 
+    /// Allows references to types with interior mutability within constants
+    (active, const_refs_to_cell, "1.51.0", Some(80384), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index d2e65abfbc7..9e90a7519cf 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -209,16 +209,61 @@ impl NonConstOp for LiveDrop {
 }
 
 #[derive(Debug)]
+/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
+/// the final value of the constant.
+pub struct TransientCellBorrow;
+impl NonConstOp for TransientCellBorrow {
+    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+        Status::Unstable(sym::const_refs_to_cell)
+    }
+    fn importance(&self) -> DiagnosticImportance {
+        // The cases that cannot possibly work will already emit a `CellBorrow`, so we should
+        // not additionally emit a feature gate error if activating the feature gate won't work.
+        DiagnosticImportance::Secondary
+    }
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        feature_err(
+            &ccx.tcx.sess.parse_sess,
+            sym::const_refs_to_cell,
+            span,
+            "cannot borrow here, since the borrowed element may contain interior mutability",
+        )
+    }
+}
+
+#[derive(Debug)]
+/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to
+/// the final value of the constant, and thus we cannot allow this (for now). We may allow
+/// it in the future for static items.
 pub struct CellBorrow;
 impl NonConstOp for CellBorrow {
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        struct_span_err!(
+        let mut err = struct_span_err!(
             ccx.tcx.sess,
             span,
             E0492,
-            "cannot borrow a constant which may contain \
-            interior mutability, create a static instead"
-        )
+            "{}s cannot refer to interior mutable data",
+            ccx.const_kind(),
+        );
+        err.span_label(
+            span,
+            format!("this borrow of an interior mutable value may end up in the final value"),
+        );
+        if let hir::ConstContext::Static(_) = ccx.const_kind() {
+            err.help(
+                "to fix this, the value can be extracted to a separate \
+                `static` item and then referenced",
+            );
+        }
+        if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
+            err.note(
+                "A constant containing interior mutable data behind a reference can allow you
+                 to modify that data. This would make multiple uses of a constant to be able to
+                 see different values and allow circumventing the `Send` and `Sync` requirements
+                 for shared mutable data, which is unsound.",
+            );
+        }
+        err
     }
 }
 
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index 90688ebbd0a..d1c07d1051d 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -3,6 +3,7 @@
 use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorReported};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, HirId, LangItem};
+use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
@@ -188,6 +189,9 @@ pub struct Validator<'mir, 'tcx> {
     /// The span of the current statement.
     span: Span,
 
+    /// A set that stores for each local whether it has a `StorageDead` for it somewhere.
+    local_has_storage_dead: Option<BitSet<Local>>,
+
     error_emitted: Option<ErrorReported>,
     secondary_errors: Vec<Diagnostic>,
 }
@@ -206,6 +210,7 @@ impl Validator<'mir, 'tcx> {
             span: ccx.body.span,
             ccx,
             qualifs: Default::default(),
+            local_has_storage_dead: None,
             error_emitted: None,
             secondary_errors: Vec::new(),
         }
@@ -282,6 +287,27 @@ impl Validator<'mir, 'tcx> {
         }
     }
 
+    fn local_has_storage_dead(&mut self, local: Local) -> bool {
+        let ccx = self.ccx;
+        self.local_has_storage_dead
+            .get_or_insert_with(|| {
+                struct StorageDeads {
+                    locals: BitSet<Local>,
+                }
+                impl Visitor<'tcx> for StorageDeads {
+                    fn visit_statement(&mut self, stmt: &Statement<'tcx>, _: Location) {
+                        if let StatementKind::StorageDead(l) = stmt.kind {
+                            self.locals.insert(l);
+                        }
+                    }
+                }
+                let mut v = StorageDeads { locals: BitSet::new_empty(ccx.body.local_decls.len()) };
+                v.visit_body(ccx.body);
+                v.locals
+            })
+            .contains(local)
+    }
+
     pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
         self.qualifs.in_return_place(self.ccx, self.error_emitted)
     }
@@ -556,7 +582,29 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 );
 
                 if borrowed_place_has_mut_interior {
-                    self.check_op(ops::CellBorrow);
+                    match self.const_kind() {
+                        // In a const fn all borrows are transient or point to the places given via
+                        // references in the arguments (so we already checked them with
+                        // TransientCellBorrow/CellBorrow as appropriate).
+                        // The borrow checker guarantees that no new non-transient borrows are created.
+                        // NOTE: Once we have heap allocations during CTFE we need to figure out
+                        // how to prevent `const fn` to create long-lived allocations that point
+                        // to (interior) mutable memory.
+                        hir::ConstContext::ConstFn => self.check_op(ops::TransientCellBorrow),
+                        _ => {
+                            // Locals with StorageDead are definitely not part of the final constant value, and
+                            // it is thus inherently safe to permit such locals to have their
+                            // address taken as we can't end up with a reference to them in the
+                            // final value.
+                            // Note: This is only sound if every local that has a `StorageDead` has a
+                            // `StorageDead` in every control flow path leading to a `return` terminator.
+                            if self.local_has_storage_dead(place.local) {
+                                self.check_op(ops::TransientCellBorrow);
+                            } else {
+                                self.check_op(ops::CellBorrow);
+                            }
+                        }
+                    }
                 }
             }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 64b50a9b70a..b6cf584d875 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -381,6 +381,7 @@ symbols! {
         const_ptr,
         const_raw_ptr_deref,
         const_raw_ptr_to_usize_cast,
+        const_refs_to_cell,
         const_slice_ptr,
         const_trait_bound_opt_out,
         const_trait_impl,
diff --git a/src/test/ui/consts/const-address-of-interior-mut.stderr b/src/test/ui/consts/const-address-of-interior-mut.stderr
index f15174c33b3..93120753b1a 100644
--- a/src/test/ui/consts/const-address-of-interior-mut.stderr
+++ b/src/test/ui/consts/const-address-of-interior-mut.stderr
@@ -1,27 +1,39 @@
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
   --> $DIR/const-address-of-interior-mut.rs:5:39
    |
 LL | const A: () = { let x = Cell::new(2); &raw const x; };
    |                                       ^^^^^^^^^^^^
+   |
+   = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
+   = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
 
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
   --> $DIR/const-address-of-interior-mut.rs:7:40
    |
 LL | static B: () = { let x = Cell::new(2); &raw const x; };
    |                                        ^^^^^^^^^^^^
+   |
+   = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
+   = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
 
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
   --> $DIR/const-address-of-interior-mut.rs:9:44
    |
 LL | static mut C: () = { let x = Cell::new(2); &raw const x; };
    |                                            ^^^^^^^^^^^^
+   |
+   = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
+   = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
 
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
   --> $DIR/const-address-of-interior-mut.rs:13:13
    |
 LL |     let y = &raw const x;
    |             ^^^^^^^^^^^^
+   |
+   = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
+   = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0492`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-multi-ref.rs b/src/test/ui/consts/const-multi-ref.rs
index 18645efc887..7e0f1a812fd 100644
--- a/src/test/ui/consts/const-multi-ref.rs
+++ b/src/test/ui/consts/const-multi-ref.rs
@@ -13,7 +13,7 @@ const _: i32 = {
 
 const _: std::cell::Cell<i32> = {
     let mut a = std::cell::Cell::new(5);
-    let p = &a; //~ ERROR cannot borrow a constant which may contain interior mutability
+    let p = &a; //~ ERROR borrowed element may contain interior mutability
 
     let reborrow = {p};
     let pp = &reborrow;
diff --git a/src/test/ui/consts/const-multi-ref.stderr b/src/test/ui/consts/const-multi-ref.stderr
index 9a7914b4588..c0a320d46cb 100644
--- a/src/test/ui/consts/const-multi-ref.stderr
+++ b/src/test/ui/consts/const-multi-ref.stderr
@@ -4,13 +4,16 @@ error[E0764]: mutable references are not allowed in constants
 LL |     let p = &mut a;
    |             ^^^^^^ `&mut` is only allowed in `const fn`
 
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
   --> $DIR/const-multi-ref.rs:16:13
    |
 LL |     let p = &a;
    |             ^^
+   |
+   = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
+   = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0492, E0764.
-For more information about an error, try `rustc --explain E0492`.
+Some errors have detailed explanations: E0658, E0764.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/partial_qualif.rs b/src/test/ui/consts/partial_qualif.rs
index 32c68e69f4b..7c28b8b8a62 100644
--- a/src/test/ui/consts/partial_qualif.rs
+++ b/src/test/ui/consts/partial_qualif.rs
@@ -3,7 +3,7 @@ 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
+    &{a} //~ ERROR cannot refer to interior mutable
 };
 
 fn main() {}
diff --git a/src/test/ui/consts/partial_qualif.stderr b/src/test/ui/consts/partial_qualif.stderr
index 221e449b6f9..32c25be2173 100644
--- a/src/test/ui/consts/partial_qualif.stderr
+++ b/src/test/ui/consts/partial_qualif.stderr
@@ -1,8 +1,8 @@
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0492]: constants cannot refer to interior mutable data
   --> $DIR/partial_qualif.rs:6:5
    |
 LL |     &{a}
-   |     ^^^^
+   |     ^^^^ this borrow of an interior mutable value may end up in the final value
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/qualif_overwrite.rs b/src/test/ui/consts/qualif_overwrite.rs
index 430eea37de7..aae4e41ffd7 100644
--- a/src/test/ui/consts/qualif_overwrite.rs
+++ b/src/test/ui/consts/qualif_overwrite.rs
@@ -7,7 +7,7 @@ use std::cell::Cell;
 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
+    &{a} //~ ERROR cannot refer to interior mutable
 };
 
 fn main() {}
diff --git a/src/test/ui/consts/qualif_overwrite.stderr b/src/test/ui/consts/qualif_overwrite.stderr
index fbaae711d7c..86a669c433d 100644
--- a/src/test/ui/consts/qualif_overwrite.stderr
+++ b/src/test/ui/consts/qualif_overwrite.stderr
@@ -1,8 +1,8 @@
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0492]: constants cannot refer to interior mutable data
   --> $DIR/qualif_overwrite.rs:10:5
    |
 LL |     &{a}
-   |     ^^^^
+   |     ^^^^ this borrow of an interior mutable value may end up in the final value
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/qualif_overwrite_2.rs b/src/test/ui/consts/qualif_overwrite_2.rs
index fa79b5c14a7..1819d9a6d20 100644
--- a/src/test/ui/consts/qualif_overwrite_2.rs
+++ b/src/test/ui/consts/qualif_overwrite_2.rs
@@ -5,7 +5,7 @@ use std::cell::Cell;
 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
+    &{a.0} //~ ERROR cannot refer to interior mutable
 };
 
 fn main() {}
diff --git a/src/test/ui/consts/qualif_overwrite_2.stderr b/src/test/ui/consts/qualif_overwrite_2.stderr
index a393c4e336d..9eb123d0b01 100644
--- a/src/test/ui/consts/qualif_overwrite_2.stderr
+++ b/src/test/ui/consts/qualif_overwrite_2.stderr
@@ -1,8 +1,8 @@
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0492]: constants cannot refer to interior mutable data
   --> $DIR/qualif_overwrite_2.rs:8:5
    |
 LL |     &{a.0}
-   |     ^^^^^^
+   |     ^^^^^^ this borrow of an interior mutable value may end up in the final value
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/std/cell.rs b/src/test/ui/consts/std/cell.rs
index cf6c0f2379d..f1ef541319a 100644
--- a/src/test/ui/consts/std/cell.rs
+++ b/src/test/ui/consts/std/cell.rs
@@ -1,18 +1,31 @@
+#![feature(const_refs_to_cell)]
+
 use std::cell::*;
 
-// not ok, because this would create a silent constant with interior mutability.
-// the rules could be relaxed in the future
+// not ok, because this creates a dangling pointer, just like `let x = Cell::new(42).as_ptr()` would
 static FOO: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr());
-//~^ ERROR cannot borrow a constant which may contain interior mutability
+//~^ ERROR encountered dangling pointer
+const FOO_CONST: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr());
+//~^ ERROR encountered dangling pointer
 
+// Ok, these are just base values and it is the `Wrap` author's job to uphold `Send` and `Sync`
+// invariants, since they used `unsafe impl`.
 static FOO3: Wrap<Cell<u32>> = Wrap(Cell::new(42));
-// ok
+const FOO3_CONST: Wrap<Cell<u32>> = Wrap(Cell::new(42));
+
+// ok, we are referring to the memory of another static item.
 static FOO4: Wrap<*mut u32> = Wrap(FOO3.0.as_ptr());
 
-// not ok, because the `as_ptr` call takes a reference to a type with interior mutability
-// which is not allowed in constants
+// not ok, the use of a constant here is equivalent to an inline declaration of the value, so
+// its memory will get freed before the constant is finished evaluating, thus creating a dangling
+// pointer. This would happen exactly the same at runtime.
+const FOO4_CONST: Wrap<*mut u32> = Wrap(FOO3_CONST.0.as_ptr());
+//~^ ERROR encountered dangling pointer
+
+// not ok, because the `as_ptr` call takes a reference to a temporary that will get freed
+// before the constant is finished evaluating.
 const FOO2: *mut u32 = Cell::new(42).as_ptr();
-//~^ ERROR cannot borrow a constant which may contain interior mutability
+//~^ ERROR encountered dangling pointer
 
 struct IMSafeTrustMe(UnsafeCell<u32>);
 unsafe impl Send for IMSafeTrustMe {}
@@ -21,10 +34,13 @@ unsafe impl Sync for IMSafeTrustMe {}
 static BAR: IMSafeTrustMe = IMSafeTrustMe(UnsafeCell::new(5));
 
 
+
 struct Wrap<T>(T);
 unsafe impl<T> Send for Wrap<T> {}
 unsafe impl<T> Sync for Wrap<T> {}
 
 static BAR_PTR: Wrap<*mut u32> = Wrap(BAR.0.get());
 
+const fn fst_ref<T, U>(x: &(T, U)) -> &T { &x.0 }
+
 fn main() {}
diff --git a/src/test/ui/consts/std/cell.stderr b/src/test/ui/consts/std/cell.stderr
index f75aadff6d5..355c326f0b6 100644
--- a/src/test/ui/consts/std/cell.stderr
+++ b/src/test/ui/consts/std/cell.stderr
@@ -1,15 +1,26 @@
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
-  --> $DIR/cell.rs:5:35
+error: encountered dangling pointer in final constant
+  --> $DIR/cell.rs:6:1
    |
 LL | static FOO: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr());
-   |                                   ^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
-  --> $DIR/cell.rs:14:24
+error: encountered dangling pointer in final constant
+  --> $DIR/cell.rs:8:1
+   |
+LL | const FOO_CONST: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr());
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: encountered dangling pointer in final constant
+  --> $DIR/cell.rs:22:1
+   |
+LL | const FOO4_CONST: Wrap<*mut u32> = Wrap(FOO3_CONST.0.as_ptr());
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: encountered dangling pointer in final constant
+  --> $DIR/cell.rs:27:1
    |
 LL | const FOO2: *mut u32 = Cell::new(42).as_ptr();
-   |                        ^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0492`.
diff --git a/src/test/ui/error-codes/E0492.rs b/src/test/ui/error-codes/E0492.rs
index 2de4c12eb64..2c735fcc9f9 100644
--- a/src/test/ui/error-codes/E0492.rs
+++ b/src/test/ui/error-codes/E0492.rs
@@ -1,7 +1,10 @@
 use std::sync::atomic::AtomicUsize;
 
 const A: AtomicUsize = AtomicUsize::new(0);
-static B: &'static AtomicUsize = &A; //~ ERROR E0492
+const B: &'static AtomicUsize = &A; //~ ERROR E0492
+static C: &'static AtomicUsize = &A; //~ ERROR E0492
+
+const NONE: &'static Option<AtomicUsize> = &None;
 
 fn main() {
 }
diff --git a/src/test/ui/error-codes/E0492.stderr b/src/test/ui/error-codes/E0492.stderr
index 5f337dd7f42..557c977e87d 100644
--- a/src/test/ui/error-codes/E0492.stderr
+++ b/src/test/ui/error-codes/E0492.stderr
@@ -1,9 +1,17 @@
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
-  --> $DIR/E0492.rs:4:34
+error[E0492]: constants cannot refer to interior mutable data
+  --> $DIR/E0492.rs:4:33
    |
-LL | static B: &'static AtomicUsize = &A;
-   |                                  ^^
+LL | const B: &'static AtomicUsize = &A;
+   |                                 ^^ this borrow of an interior mutable value may end up in the final value
 
-error: aborting due to previous error
+error[E0492]: statics cannot refer to interior mutable data
+  --> $DIR/E0492.rs:5:34
+   |
+LL | static C: &'static AtomicUsize = &A;
+   |                                  ^^ this borrow of an interior mutable value may end up in the final value
+   |
+   = help: to fix this, the value can be extracted to a separate `static` item and then referenced
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0492`.
diff --git a/src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs b/src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs
new file mode 100644
index 00000000000..63159ed0553
--- /dev/null
+++ b/src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(const_refs_to_cell)]
+
+const FOO: () = {
+    let x = std::cell::Cell::new(42);
+    let y = &x;
+};
+
+fn main() {
+    FOO;
+}
diff --git a/src/test/ui/issues/issue-17718-const-borrow.rs b/src/test/ui/issues/issue-17718-const-borrow.rs
index 8a31bd0c66a..89316dbd5c4 100644
--- a/src/test/ui/issues/issue-17718-const-borrow.rs
+++ b/src/test/ui/issues/issue-17718-const-borrow.rs
@@ -2,13 +2,13 @@ use std::cell::UnsafeCell;
 
 const A: UnsafeCell<usize> = UnsafeCell::new(1);
 const B: &'static UnsafeCell<usize> = &A;
-//~^ ERROR: cannot borrow a constant which may contain interior mutability
+//~^ ERROR: cannot refer to interior mutable
 
 struct C { a: UnsafeCell<usize> }
 const D: C = C { a: UnsafeCell::new(1) };
 const E: &'static UnsafeCell<usize> = &D.a;
-//~^ ERROR: cannot borrow a constant which may contain interior mutability
+//~^ ERROR: cannot refer to interior mutable
 const F: &'static C = &D;
-//~^ ERROR: cannot borrow a constant which may contain interior mutability
+//~^ ERROR: cannot refer to interior mutable
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-17718-const-borrow.stderr b/src/test/ui/issues/issue-17718-const-borrow.stderr
index b4330049689..e3ff6c923ad 100644
--- a/src/test/ui/issues/issue-17718-const-borrow.stderr
+++ b/src/test/ui/issues/issue-17718-const-borrow.stderr
@@ -1,20 +1,20 @@
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0492]: constants cannot refer to interior mutable data
   --> $DIR/issue-17718-const-borrow.rs:4:39
    |
 LL | const B: &'static UnsafeCell<usize> = &A;
-   |                                       ^^
+   |                                       ^^ this borrow of an interior mutable value may end up in the final value
 
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0492]: constants cannot refer to interior mutable data
   --> $DIR/issue-17718-const-borrow.rs:9:39
    |
 LL | const E: &'static UnsafeCell<usize> = &D.a;
-   |                                       ^^^^
+   |                                       ^^^^ this borrow of an interior mutable value may end up in the final value
 
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0492]: constants cannot refer to interior mutable data
   --> $DIR/issue-17718-const-borrow.rs:11:23
    |
 LL | const F: &'static C = &D;
-   |                       ^^
+   |                       ^^ this borrow of an interior mutable value may end up in the final value
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/panic-handler/weak-lang-item.stderr b/src/test/ui/panic-handler/weak-lang-item.stderr
index b7c040c7a85..68e3e21df3e 100644
--- a/src/test/ui/panic-handler/weak-lang-item.stderr
+++ b/src/test/ui/panic-handler/weak-lang-item.stderr
@@ -10,10 +10,10 @@ help: you can use `as` to change the binding name of the import
 LL | extern crate core as other_core;
    |
 
-error: `#[panic_handler]` function required, but not found
-
 error: language item required, but not found: `eh_personality`
 
+error: `#[panic_handler]` function required, but not found
+
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0259`.
diff --git a/src/test/ui/unsafe/ranged_ints3_const.rs b/src/test/ui/unsafe/ranged_ints3_const.rs
index 7b03d8eda93..c069ae7da02 100644
--- a/src/test/ui/unsafe/ranged_ints3_const.rs
+++ b/src/test/ui/unsafe/ranged_ints3_const.rs
@@ -9,13 +9,13 @@ fn main() {}
 
 const fn foo() -> NonZero<Cell<u32>> {
     let mut x = unsafe { NonZero(Cell::new(1)) };
-    let y = &x.0; //~ ERROR cannot borrow a constant which may contain interior mutability
+    let y = &x.0; //~ ERROR the borrowed element may contain interior mutability
     //~^ ERROR borrow of layout constrained field with interior mutability
     unsafe { NonZero(Cell::new(1)) }
 }
 
 const fn bar() -> NonZero<Cell<u32>> {
     let mut x = unsafe { NonZero(Cell::new(1)) };
-    let y = unsafe { &x.0 }; //~ ERROR cannot borrow a constant which may contain interior mut
+    let y = unsafe { &x.0 }; //~ ERROR the borrowed element may contain interior mutability
     unsafe { NonZero(Cell::new(1)) }
 }
diff --git a/src/test/ui/unsafe/ranged_ints3_const.stderr b/src/test/ui/unsafe/ranged_ints3_const.stderr
index d2eb3bc5360..215005571f6 100644
--- a/src/test/ui/unsafe/ranged_ints3_const.stderr
+++ b/src/test/ui/unsafe/ranged_ints3_const.stderr
@@ -1,14 +1,20 @@
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
   --> $DIR/ranged_ints3_const.rs:12:13
    |
 LL |     let y = &x.0;
    |             ^^^^
+   |
+   = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
+   = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
 
-error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
   --> $DIR/ranged_ints3_const.rs:19:22
    |
 LL |     let y = unsafe { &x.0 };
    |                      ^^^^
+   |
+   = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
+   = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
 
 error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
   --> $DIR/ranged_ints3_const.rs:12:13
@@ -20,5 +26,5 @@ LL |     let y = &x.0;
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0133, E0492.
+Some errors have detailed explanations: E0133, E0658.
 For more information about an error, try `rustc --explain E0133`.