about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2018-12-23 19:00:58 +0000
committerMatthew Jasper <mjjasper1@gmail.com>2019-12-18 20:09:10 +0000
commit3a19fbf95d3b289f4c17aba910051cd9afd75887 (patch)
tree79cf3df79e4705fe3390ef27ec54c609c88c9893
parent19bd93467617a447c22ec32cc1cf14d40cb84ccf (diff)
downloadrust-3a19fbf95d3b289f4c17aba910051cd9afd75887.tar.gz
rust-3a19fbf95d3b289f4c17aba910051cd9afd75887.zip
Add Rvalue::AddressOf to MIR
This operator creates a raw pointer to a Place directly, without first
creating a reference. See RFC #2582 for motivation.

The Rvalue is currently unused.
-rw-r--r--src/librustc/mir/mod.rs18
-rw-r--r--src/librustc/mir/tcx.rs7
-rw-r--r--src/librustc/mir/visit.rs16
-rw-r--r--src/librustc/ty/cast.rs3
-rw-r--r--src/librustc_codegen_ssa/mir/analyze.rs2
-rw-r--r--src/librustc_codegen_ssa/mir/place.rs2
-rw-r--r--src/librustc_codegen_ssa/mir/rvalue.rs58
-rw-r--r--src/librustc_mir/borrow_check/invalidation.rs18
-rw-r--r--src/librustc_mir/borrow_check/mod.rs25
-rw-r--r--src/librustc_mir/borrow_check/type_check/mod.rs49
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs1
-rw-r--r--src/librustc_mir/interpret/step.rs2
-rw-r--r--src/librustc_mir/transform/add_retag.rs18
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs17
-rw-r--r--src/librustc_mir/transform/check_consts/qualifs.rs18
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs112
-rw-r--r--src/librustc_mir/transform/promote_consts.rs24
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs8
-rw-r--r--src/librustc_mir/util/liveness.rs2
-rw-r--r--src/librustc_typeck/check/cast.rs76
20 files changed, 307 insertions, 169 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index ba8feb4ee73..3b4adbaf78c 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -2060,6 +2060,11 @@ pub enum Rvalue<'tcx> {
     /// &x or &mut x
     Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
 
+    /// Create a raw pointer to the given place
+    /// Can be generated by raw address of expressions (`&raw const x`),
+    /// or when casting a reference to a raw pointer.
+    AddressOf(Mutability, Place<'tcx>),
+
     /// length of a [X] or [X;n] value
     Len(Place<'tcx>),
 
@@ -2214,6 +2219,15 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                 write!(fmt, "&{}{}{:?}", region, kind_str, place)
             }
 
+            AddressOf(mutability, ref place) => {
+                let kind_str = match mutability {
+                    Mutability::Mut => "mut",
+                    Mutability::Not => "const",
+                };
+
+                write!(fmt, "&raw {} {:?}", kind_str, place)
+            }
+
             Aggregate(ref kind, ref places) => {
                 fn fmt_tuple(fmt: &mut Formatter<'_>, places: &[Operand<'_>]) -> fmt::Result {
                     let mut tuple_fmt = fmt.debug_tuple("");
@@ -3085,6 +3099,9 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
             Ref(region, bk, ref place) => {
                 Ref(region.fold_with(folder), bk, place.fold_with(folder))
             }
+            AddressOf(mutability, ref place) => {
+                AddressOf(mutability, place.fold_with(folder))
+            }
             Len(ref place) => Len(place.fold_with(folder)),
             Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
             BinaryOp(op, ref rhs, ref lhs) => {
@@ -3125,6 +3142,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
             Use(ref op) => op.visit_with(visitor),
             Repeat(ref op, _) => op.visit_with(visitor),
             Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor),
+            AddressOf(_, ref place) => place.visit_with(visitor),
             Len(ref place) => place.visit_with(visitor),
             Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor),
             BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => {
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 445fa6ea8ca..a24b1d863d6 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -172,6 +172,13 @@ impl<'tcx> Rvalue<'tcx> {
                     }
                 )
             }
+            Rvalue::AddressOf(mutability, ref place) => {
+                let place_ty = place.ty(local_decls, tcx).ty;
+                tcx.mk_ptr(ty::TypeAndMut {
+                    ty: place_ty,
+                    mutbl: mutability.into(),
+                })
+            }
             Rvalue::Len(..) => tcx.types.usize,
             Rvalue::Cast(.., ty) => ty,
             Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 5d273fe85b6..fa96b51347d 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -570,6 +570,18 @@ macro_rules! make_mir_visitor {
                         self.visit_place(path, ctx, location);
                     }
 
+                    Rvalue::AddressOf(m, path) => {
+                        let ctx = match m {
+                            Mutability::Mut => PlaceContext::MutatingUse(
+                                MutatingUseContext::AddressOf
+                            ),
+                            Mutability::Not => PlaceContext::NonMutatingUse(
+                                NonMutatingUseContext::AddressOf
+                            ),
+                        };
+                        self.visit_place(path, ctx, location);
+                    }
+
                     Rvalue::Len(path) => {
                         self.visit_place(
                             path,
@@ -1031,6 +1043,8 @@ pub enum NonMutatingUseContext {
     ShallowBorrow,
     /// Unique borrow.
     UniqueBorrow,
+    /// AddressOf for *const pointer.
+    AddressOf,
     /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
     /// For example, the projection `x.y` is not marked as a mutation in these cases:
     ///
@@ -1054,6 +1068,8 @@ pub enum MutatingUseContext {
     Drop,
     /// Mutable borrow.
     Borrow,
+    /// AddressOf for *mut pointer.
+    AddressOf,
     /// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
     /// For example, the projection `x.y` is marked as a mutation in these cases:
     ///
diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs
index bc12412312d..fca53db1475 100644
--- a/src/librustc/ty/cast.rs
+++ b/src/librustc/ty/cast.rs
@@ -28,8 +28,6 @@ pub enum CastTy<'tcx> {
     FnPtr,
     /// Raw pointers
     Ptr(ty::TypeAndMut<'tcx>),
-    /// References
-    RPtr(ty::TypeAndMut<'tcx>),
 }
 
 /// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs)
@@ -63,7 +61,6 @@ impl<'tcx> CastTy<'tcx> {
             ty::Adt(d,_) if d.is_enum() && d.is_payloadfree() =>
                 Some(CastTy::Int(IntTy::CEnum)),
             ty::RawPtr(mt) => Some(CastTy::Ptr(mt)),
-            ty::Ref(_, ty, mutbl) => Some(CastTy::RPtr(ty::TypeAndMut { ty, mutbl })),
             ty::FnPtr(..) => Some(CastTy::FnPtr),
             _ => None,
         }
diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs
index 6c627085b2e..7bcd9816786 100644
--- a/src/librustc_codegen_ssa/mir/analyze.rs
+++ b/src/librustc_codegen_ssa/mir/analyze.rs
@@ -340,10 +340,12 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
             PlaceContext::MutatingUse(MutatingUseContext::Store) |
             PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
             PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
+            PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
             PlaceContext::MutatingUse(MutatingUseContext::Projection) |
             PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
             PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
             PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
+            PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
             PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
                 self.not_ssa(local);
             }
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index 5e13cabced0..5b21dfbdf1c 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -448,7 +448,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let cx = self.cx;
         let tcx = self.cx.tcx();
 
-        let result = match &place_ref {
+        let result = match place_ref {
             mir::PlaceRef {
                 base: mir::PlaceBase::Local(index),
                 projection: [],
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index 488ae8dbf90..3a8d782aa73 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -7,7 +7,7 @@ use crate::MemFlags;
 use crate::common::{self, RealPredicate, IntPredicate};
 use crate::traits::*;
 
-use rustc::ty::{self, Ty, adjustment::{PointerCast}, Instance};
+use rustc::ty::{self, Ty, TyCtxt, adjustment::{PointerCast}, Instance};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
 use rustc::mir;
@@ -342,8 +342,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                 }
                             }
                             (CastTy::Ptr(_), CastTy::Ptr(_)) |
-                            (CastTy::FnPtr, CastTy::Ptr(_)) |
-                            (CastTy::RPtr(_), CastTy::Ptr(_)) =>
+                            (CastTy::FnPtr, CastTy::Ptr(_)) =>
                                 bx.pointercast(llval, ll_t_out),
                             (CastTy::Ptr(_), CastTy::Int(_)) |
                             (CastTy::FnPtr, CastTy::Int(_)) =>
@@ -370,24 +369,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
 
             mir::Rvalue::Ref(_, bk, ref place) => {
-                let cg_place = self.codegen_place(&mut bx, &place.as_ref());
-
-                let ty = cg_place.layout.ty;
+                let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| tcx.mk_ref(
+                    tcx.lifetimes.re_erased,
+                    ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() }
+                );
+                self.codegen_place_to_pointer(bx, place, mk_ref)
+            }
 
-                // Note: places are indirect, so storing the `llval` into the
-                // destination effectively creates a reference.
-                let val = if !bx.cx().type_has_metadata(ty) {
-                    OperandValue::Immediate(cg_place.llval)
-                } else {
-                    OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
-                };
-                (bx, OperandRef {
-                    val,
-                    layout: self.cx.layout_of(self.cx.tcx().mk_ref(
-                        self.cx.tcx().lifetimes.re_erased,
-                        ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() }
-                    )),
-                })
+            mir::Rvalue::AddressOf(mutability, ref place) => {
+                let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| tcx.mk_ptr(
+                    ty::TypeAndMut { ty, mutbl: mutability.into() }
+                );
+                self.codegen_place_to_pointer(bx, place, mk_ptr)
             }
 
             mir::Rvalue::Len(ref place) => {
@@ -543,6 +536,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         cg_value.len(bx.cx())
     }
 
+    /// Codegen an `Rvalue::AddressOf` or `Rvalue::Ref`
+    fn codegen_place_to_pointer(
+        &mut self,
+        mut bx: Bx,
+        place: &mir::Place<'tcx>,
+        mk_ptr_ty: impl FnOnce(TyCtxt<'tcx>, Ty<'tcx>) -> Ty<'tcx>,
+    ) -> (Bx, OperandRef<'tcx, Bx::Value>) {
+        let cg_place = self.codegen_place(&mut bx, &place.as_ref());
+
+        let ty = cg_place.layout.ty;
+
+        // Note: places are indirect, so storing the `llval` into the
+        // destination effectively creates a reference.
+        let val = if !bx.cx().type_has_metadata(ty) {
+            OperandValue::Immediate(cg_place.llval)
+        } else {
+            OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
+        };
+        (bx, OperandRef {
+            val,
+            layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)),
+        })
+    }
+
     pub fn codegen_scalar_binop(
         &mut self,
         bx: &mut Bx,
@@ -699,6 +716,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
         match *rvalue {
             mir::Rvalue::Ref(..) |
+            mir::Rvalue::AddressOf(..) |
             mir::Rvalue::Len(..) |
             mir::Rvalue::Cast(..) | // (*)
             mir::Rvalue::BinaryOp(..) |
diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs
index 58fac5512d9..d5b9aaf9511 100644
--- a/src/librustc_mir/borrow_check/invalidation.rs
+++ b/src/librustc_mir/borrow_check/invalidation.rs
@@ -3,7 +3,7 @@ use rustc::mir::visit::Visitor;
 use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyAndCache, Rvalue};
 use rustc::mir::{Statement, StatementKind};
 use rustc::mir::TerminatorKind;
-use rustc::mir::{Operand, BorrowKind};
+use rustc::mir::{Operand, BorrowKind, Mutability};
 use rustc_data_structures::graph::dominators::Dominators;
 
 use crate::dataflow::indexes::BorrowIndex;
@@ -337,6 +337,22 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
                 );
             }
 
+            Rvalue::AddressOf(mutability, ref place) => {
+                let access_kind = match mutability {
+                    Mutability::Mut => (Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut {
+                        allow_two_phase_borrow: false,
+                    }))),
+                    Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
+                };
+
+                self.access_place(
+                    location,
+                    place,
+                    access_kind,
+                    LocalMutationIsAllowed::No,
+                );
+            }
+
             Rvalue::Use(ref operand)
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 11012ef2fc7..2554d5e729d 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1233,6 +1233,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 );
             }
 
+
+            Rvalue::AddressOf(mutability, ref place) => {
+                let access_kind = match mutability {
+                    Mutability::Mut => (Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut {
+                        allow_two_phase_borrow: false,
+                    }))),
+                    Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
+                };
+
+                self.access_place(
+                    location,
+                    (place, span),
+                    access_kind,
+                    LocalMutationIsAllowed::No,
+                    flow_state,
+                );
+
+                self.check_if_path_or_subpath_is_moved(
+                    location,
+                    InitializationRequiringAction::Borrow,
+                    (place.as_ref(), span),
+                    flow_state,
+                );
+            }
+
             Rvalue::Use(ref operand)
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index 663536bc2b4..108279eeef4 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -2273,41 +2273,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(ty);
                         match (cast_ty_from, cast_ty_to) {
-                            (Some(CastTy::RPtr(ref_tm)), Some(CastTy::Ptr(ptr_tm))) => {
-                                if let hir::Mutability::Mutable = ptr_tm.mutbl {
-                                    if let Err(terr) = self.eq_types(
-                                        ref_tm.ty,
-                                        ptr_tm.ty,
-                                        location.to_locations(),
-                                        ConstraintCategory::Cast,
-                                    ) {
-                                        span_mirbug!(
-                                            self,
-                                            rvalue,
-                                            "equating {:?} with {:?} yields {:?}",
-                                            ref_tm.ty,
-                                            ptr_tm.ty,
-                                            terr
-                                        )
-                                    }
-                                } else {
-                                    if let Err(terr) = self.sub_types(
-                                        ref_tm.ty,
-                                        ptr_tm.ty,
-                                        location.to_locations(),
-                                        ConstraintCategory::Cast,
-                                    ) {
-                                        span_mirbug!(
-                                            self,
-                                            rvalue,
-                                            "relating {:?} with {:?} yields {:?}",
-                                            ref_tm.ty,
-                                            ptr_tm.ty,
-                                            terr
-                                        )
-                                    }
-                                }
-                            },
                             (None, _)
                             | (_, None)
                             | (_, Some(CastTy::FnPtr))
@@ -2320,7 +2285,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                 ty_from,
                                 ty,
                             ),
-                            _ => (),
+                            (Some(CastTy::Int(_)), Some(CastTy::Int(_)))
+                            | (Some(CastTy::Float), Some(CastTy::Int(_)))
+                            | (Some(CastTy::Int(_)), Some(CastTy::Float))
+                            | (Some(CastTy::Float), Some(CastTy::Float))
+                            | (Some(CastTy::Ptr(_)), Some(CastTy::Int(_)))
+                            | (Some(CastTy::FnPtr), Some(CastTy::Int(_)))
+                            | (Some(CastTy::Int(_)), Some(CastTy::Ptr(_)))
+                            | (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_)))
+                            | (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
                         }
                     }
                 }
@@ -2371,7 +2344,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
             }
 
-            Rvalue::Use(..)
+            Rvalue::AddressOf(..)
+            | Rvalue::Use(..)
             | Rvalue::Len(..)
             | Rvalue::BinaryOp(..)
             | Rvalue::CheckedBinaryOp(..)
@@ -2388,6 +2362,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             Rvalue::Use(_)
             | Rvalue::Repeat(..)
             | Rvalue::Ref(..)
+            | Rvalue::AddressOf(..)
             | Rvalue::Len(..)
             | Rvalue::Cast(..)
             | Rvalue::BinaryOp(..)
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index fa0864e0de7..5522da6fbf0 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -335,6 +335,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
                 }
             }
             Rvalue::Ref(..)
+            | Rvalue::AddressOf(..)
             | Rvalue::Discriminant(..)
             | Rvalue::Len(..)
             | Rvalue::NullaryOp(NullOp::SizeOf, _)
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 33ed69af6ba..33cdf1b27f8 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -248,7 +248,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 )?;
             }
 
-            Ref(_, _, ref place) => {
+            AddressOf(_, ref place) | Ref(_, _, ref place) => {
                 let src = self.eval_place(place)?;
                 let place = self.force_allocation(src)?;
                 if place.layout.size.bytes() > 0 {
diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs
index dc21c674eea..0e4fe3f7f40 100644
--- a/src/librustc_mir/transform/add_retag.rs
+++ b/src/librustc_mir/transform/add_retag.rs
@@ -136,21 +136,9 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
             // iterate backwards using indices.
             for i in (0..block_data.statements.len()).rev() {
                 let (retag_kind, place) = match block_data.statements[i].kind {
-                    // If we are casting *from* a reference, we may have to retag-as-raw.
-                    StatementKind::Assign(box(ref place, Rvalue::Cast(
-                        CastKind::Misc,
-                        ref src,
-                        dest_ty,
-                    ))) => {
-                        let src_ty = src.ty(&*local_decls, tcx);
-                        if src_ty.is_region_ptr() {
-                            // The only `Misc` casts on references are those creating raw pointers.
-                            assert!(dest_ty.is_unsafe_ptr());
-                            (RetagKind::Raw, place.clone())
-                        } else {
-                            // Some other cast, no retag
-                            continue
-                        }
+                    // Retag-as-raw after escaping to a raw pointer.
+                    StatementKind::Assign(box (ref place, Rvalue::AddressOf(..))) => {
+                        (RetagKind::Raw, place.clone())
                     }
                     // Assignments of reference or ptr type are the ones where we may have
                     // to update tags.  This includes `x = &[mut] ...` and hence
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index 3df60993d9a..e5f3003cd71 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -225,6 +225,23 @@ impl NonConstOp for MutBorrow {
 }
 
 #[derive(Debug)]
+pub struct MutAddressOf;
+impl NonConstOp for MutAddressOf {
+    fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
+        Some(tcx.features().const_mut_refs)
+    }
+
+    fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
+        feature_err(
+            &item.tcx.sess.parse_sess,
+            sym::const_mut_refs,
+            span,
+            &format!("`&raw mut` is not allowed in {}s", item.const_kind())
+        ).emit();
+    }
+}
+
+#[derive(Debug)]
 pub struct MutDeref;
 impl NonConstOp for MutDeref {
     fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs
index 223a5f8d605..28243bd71a2 100644
--- a/src/librustc_mir/transform/check_consts/qualifs.rs
+++ b/src/librustc_mir/transform/check_consts/qualifs.rs
@@ -151,17 +151,15 @@ pub trait Qualif {
                 Self::in_operand(cx, per_local, lhs) || Self::in_operand(cx, per_local, rhs)
             }
 
-            Rvalue::Ref(_, _, ref place) => {
+            Rvalue::Ref(_, _, ref place) | Rvalue::AddressOf(_, ref place) => {
                 // Special-case reborrows to be more like a copy of the reference.
-                if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
-                    if ProjectionElem::Deref == elem {
-                        let base_ty = Place::ty_from(&place.base, proj_base, *cx.body, cx.tcx).ty;
-                        if let ty::Ref(..) = base_ty.kind {
-                            return Self::in_place(cx, per_local, PlaceRef {
-                                base: &place.base,
-                                projection: proj_base,
-                            });
-                        }
+                if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
+                    let base_ty = Place::ty_from(&place.base, proj_base, *cx.body, cx.tcx).ty;
+                    if let ty::Ref(..) = base_ty.kind {
+                        return Self::in_place(cx, per_local, PlaceRef {
+                            base: &place.base,
+                            projection: proj_base,
+                        });
                     }
                 }
 
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index 6261315c711..0904264586c 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -276,6 +276,27 @@ impl Validator<'a, 'mir, 'tcx> {
             self.check_op_spanned(ops::StaticAccess, span)
         }
     }
+
+    fn check_immutable_borrow_like(
+        &mut self,
+        location: Location,
+        place: &Place<'tcx>,
+    ) {
+        // FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually
+        // seek the cursors beforehand.
+        self.qualifs.has_mut_interior.cursor.seek_before(location);
+        self.qualifs.indirectly_mutable.seek(location);
+
+        let borrowed_place_has_mut_interior = HasMutInterior::in_place(
+            &self.item,
+            &|local| self.qualifs.has_mut_interior_eager_seek(local),
+            place.as_ref(),
+        );
+
+        if borrowed_place_has_mut_interior {
+            self.check_op(ops::CellBorrow);
+        }
+    }
 }
 
 impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
@@ -302,26 +323,44 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
         trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
 
         // Special-case reborrows to be more like a copy of a reference.
-        if let Rvalue::Ref(_, kind, ref place) = *rvalue {
-            if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
-                let ctx = match kind {
-                    BorrowKind::Shared => PlaceContext::NonMutatingUse(
-                        NonMutatingUseContext::SharedBorrow,
-                    ),
-                    BorrowKind::Shallow => PlaceContext::NonMutatingUse(
-                        NonMutatingUseContext::ShallowBorrow,
-                    ),
-                    BorrowKind::Unique => PlaceContext::NonMutatingUse(
-                        NonMutatingUseContext::UniqueBorrow,
-                    ),
-                    BorrowKind::Mut { .. } => PlaceContext::MutatingUse(
-                        MutatingUseContext::Borrow,
-                    ),
-                };
-                self.visit_place_base(&place.base, ctx, location);
-                self.visit_projection(&place.base, reborrowed_proj, ctx, location);
-                return;
+        match *rvalue {
+            Rvalue::Ref(_, kind, ref place) => {
+                if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
+                    let ctx = match kind {
+                        BorrowKind::Shared => PlaceContext::NonMutatingUse(
+                            NonMutatingUseContext::SharedBorrow,
+                        ),
+                        BorrowKind::Shallow => PlaceContext::NonMutatingUse(
+                            NonMutatingUseContext::ShallowBorrow,
+                        ),
+                        BorrowKind::Unique => PlaceContext::NonMutatingUse(
+                            NonMutatingUseContext::UniqueBorrow,
+                        ),
+                        BorrowKind::Mut { .. } => PlaceContext::MutatingUse(
+                            MutatingUseContext::Borrow,
+                        ),
+                    };
+                    self.visit_place_base(&place.base, ctx, location);
+                    self.visit_projection(&place.base, reborrowed_proj, ctx, location);
+                    return;
+                }
             }
+            Rvalue::AddressOf(mutbl, ref place) => {
+                if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
+                    let ctx = match mutbl {
+                        Mutability::Not => PlaceContext::NonMutatingUse(
+                            NonMutatingUseContext::AddressOf,
+                        ),
+                        Mutability::Mut => PlaceContext::MutatingUse(
+                            MutatingUseContext::AddressOf,
+                        ),
+                    };
+                    self.visit_place_base(&place.base, ctx, location);
+                    self.visit_projection(&place.base, reborrowed_proj, ctx, location);
+                    return;
+                }
+            }
+            _ => {}
         }
 
         self.super_rvalue(rvalue, location);
@@ -367,34 +406,25 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
                 }
             }
 
+            Rvalue::AddressOf(Mutability::Mut, _) => {
+                self.check_op(ops::MutAddressOf)
+            }
+
             // At the moment, `PlaceBase::Static` is only used for promoted MIR.
             | Rvalue::Ref(_, BorrowKind::Shared, ref place)
             | Rvalue::Ref(_, BorrowKind::Shallow, ref place)
+            | Rvalue::AddressOf(Mutability::Not, ref place)
             if matches!(place.base, PlaceBase::Static(_))
             => bug!("Saw a promoted during const-checking, which must run before promotion"),
 
-            | Rvalue::Ref(_, kind @ BorrowKind::Shared, ref place)
-            | Rvalue::Ref(_, kind @ BorrowKind::Shallow, ref place)
-            => {
-                // FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually
-                // seek the cursors beforehand.
-                self.qualifs.has_mut_interior.cursor.seek_before(location);
-                self.qualifs.indirectly_mutable.seek(location);
-
-                let borrowed_place_has_mut_interior = HasMutInterior::in_place(
-                    &self.item,
-                    &|local| self.qualifs.has_mut_interior_eager_seek(local),
-                    place.as_ref(),
-                );
-
-                if borrowed_place_has_mut_interior {
-                    if let BorrowKind::Mut{ .. } = kind {
-                        self.check_op(ops::MutBorrow);
-                    } else {
-                        self.check_op(ops::CellBorrow);
-                    }
-                }
-            }
+            | Rvalue::Ref(_, BorrowKind::Shared, ref place)
+            | Rvalue::Ref(_, BorrowKind::Shallow, ref place) => {
+                self.check_immutable_borrow_like(location, place)
+            },
+
+            Rvalue::AddressOf(Mutability::Not, ref place) => {
+                self.check_immutable_borrow_like(location, place)
+            },
 
             Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
                 let operand_ty = operand.ty(*self.body, self.tcx);
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 4c723199102..4e5d8ae08fe 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -196,7 +196,12 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
         } else if let TempState::Defined { ref mut uses, .. } = *temp {
             // We always allow borrows, even mutable ones, as we need
             // to promote mutable borrows of some ZSTs e.g., `&mut []`.
-            let allowed_use = context.is_borrow() || context.is_nonmutating_use();
+            let allowed_use = match context {
+                PlaceContext::MutatingUse(MutatingUseContext::Borrow)
+                | PlaceContext::NonMutatingUse(_) => true,
+                PlaceContext::MutatingUse(_)
+                | PlaceContext::NonUse(_) => false,
+            };
             debug!("visit_local: allowed_use={:?}", allowed_use);
             if allowed_use {
                 *uses += 1;
@@ -618,6 +623,21 @@ impl<'tcx> Validator<'_, 'tcx> {
                 self.validate_operand(rhs)
             }
 
+            Rvalue::AddressOf(_, place) => {
+                // Raw reborrows can come from reference to pointer coercions,
+                // so are allowed.
+                if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
+                    let base_ty = Place::ty_from(&place.base, proj_base, *self.body, self.tcx).ty;
+                    if let ty::Ref(..) = base_ty.kind {
+                        return self.validate_place(PlaceRef {
+                            base: &place.base,
+                            projection: proj_base,
+                        });
+                    }
+                }
+                Err(Unpromotable)
+            }
+
             Rvalue::Ref(_, kind, place) => {
                 if let BorrowKind::Mut { .. } = kind {
                     let ty = place.ty(*self.body, self.tcx).ty;
@@ -950,7 +970,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                 Candidate::Ref(loc) => {
                     let ref mut statement = blocks[loc.block].statements[loc.statement_index];
                     match statement.kind {
-                        StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref mut place))) => {
+                        StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref mut place))) => {
                             // Use the underlying local for this (necessarily interior) borrow.
                             let ty = place.base.ty(local_decls).ty;
                             let span = statement.source_info.span;
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index e2530795749..a61bff37fc8 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -135,7 +135,10 @@ fn check_rvalue(
         Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
             check_operand(tcx, operand, span, def_id, body)
         }
-        Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => {
+        Rvalue::Len(place)
+        | Rvalue::Discriminant(place)
+        | Rvalue::Ref(_, _, place)
+        | Rvalue::AddressOf(_, place) => {
             check_place(tcx, place, span, def_id, body)
         }
         Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
@@ -147,9 +150,6 @@ fn check_rvalue(
                     span,
                     "casting pointers to ints is unstable in const fn".into(),
                 )),
-                (CastTy::RPtr(_), CastTy::Float) => bug!(),
-                (CastTy::RPtr(_), CastTy::Int(_)) => bug!(),
-                (CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(),
                 _ => check_operand(tcx, operand, span, def_id, body),
             }
         }
diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs
index 68c2e16399a..01eebeb8c55 100644
--- a/src/librustc_mir/util/liveness.rs
+++ b/src/librustc_mir/util/liveness.rs
@@ -167,6 +167,8 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
         PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
         PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
 
+        PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
+        PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
         PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
         PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
         PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) |
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 035ece23810..21ba02746c7 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -469,22 +469,48 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             (Some(t_from), Some(t_cast)) => (t_from, t_cast),
             // Function item types may need to be reified before casts.
             (None, Some(t_cast)) => {
-                if let ty::FnDef(..) = self.expr_ty.kind {
-                    // Attempt a coercion to a fn pointer type.
-                    let f = self.expr_ty.fn_sig(fcx.tcx);
-                    let res = fcx.try_coerce(self.expr,
-                                             self.expr_ty,
-                                             fcx.tcx.mk_fn_ptr(f),
-                                             AllowTwoPhase::No);
-                    if let Err(TypeError::IntrinsicCast) = res {
-                        return Err(CastError::IllegalCast);
+                match self.expr_ty.kind {
+                    ty::FnDef(..) => {
+                        // Attempt a coercion to a fn pointer type.
+                        let f = self.expr_ty.fn_sig(fcx.tcx);
+                        let res = fcx.try_coerce(self.expr,
+                                                 self.expr_ty,
+                                                 fcx.tcx.mk_fn_ptr(f),
+                                                 AllowTwoPhase::No);
+                        if let Err(TypeError::IntrinsicCast) = res {
+                            return Err(CastError::IllegalCast);
+                        }
+                        if res.is_err() {
+                            return Err(CastError::NonScalar);
+                        }
+                        (FnPtr, t_cast)
                     }
-                    if res.is_err() {
-                        return Err(CastError::NonScalar);
+                    // Special case some errors for references, and check for
+                    // array-ptr-casts. `Ref` is not a CastTy because the cast
+                    // is split into a coercion to a pointer type, followed by
+                    // a cast.
+                    ty::Ref(_, inner_ty, mutbl) => {
+                        return match t_cast {
+                            Int(_) | Float => match inner_ty.kind {
+                                ty::Int(_) |
+                                ty::Uint(_) |
+                                ty::Float(_) |
+                                ty::Infer(ty::InferTy::IntVar(_)) |
+                                ty::Infer(ty::InferTy::FloatVar(_)) => {
+                                    Err(CastError::NeedDeref)
+                                }
+                                _ => Err(CastError::NeedViaPtr),
+                            }
+                            // array-ptr-cast
+                            Ptr(mt) => self.check_ref_cast(
+                                fcx,
+                                TypeAndMut { mutbl, ty: inner_ty },
+                                mt,
+                            ),
+                            _ => Err(CastError::NonScalar),
+                        };
                     }
-                    (FnPtr, t_cast)
-                } else {
-                    return Err(CastError::NonScalar);
+                    _ => return Err(CastError::NonScalar),
                 }
             }
             _ => return Err(CastError::NonScalar),
@@ -492,7 +518,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
         match (t_from, t_cast) {
             // These types have invariants! can't cast into them.
-            (_, RPtr(_)) | (_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar),
+            (_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar),
 
             // * -> Bool
             (_, Int(Bool)) => Err(CastError::CastToBool),
@@ -517,28 +543,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
             (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
             (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
-            (RPtr(p), Int(_)) |
-            (RPtr(p), Float) => {
-                match p.ty.kind {
-                    ty::Int(_) |
-                    ty::Uint(_) |
-                    ty::Float(_) => {
-                        Err(CastError::NeedDeref)
-                    }
-                    ty::Infer(t) => {
-                        match t {
-                            ty::InferTy::IntVar(_) |
-                            ty::InferTy::FloatVar(_) => Err(CastError::NeedDeref),
-                            _ => Err(CastError::NeedViaPtr),
-                        }
-                    }
-                    _ => Err(CastError::NeedViaPtr),
-                }
-            }
+
             // * -> ptr
             (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
             (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
-            (RPtr(rmt), Ptr(mt)) => self.check_ref_cast(fcx, rmt, mt), // array-ptr-cast
 
             // prim -> prim
             (Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),