about summary refs log tree commit diff
path: root/src/librustc_mir
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-05-29 23:43:20 +0000
committerbors <bors@rust-lang.org>2020-05-29 23:43:20 +0000
commit0e9e4083100aa3ebf09b8f1ace0348cb37475eb9 (patch)
tree1bb8b3fa49e034b12057f85edfa1e7ac0f5dda74 /src/librustc_mir
parent4bd32c98047a809ba5fd1fac2aa044638e5f2105 (diff)
parent37894559abd67dd9544f2d66b0e117573e38119c (diff)
downloadrust-0e9e4083100aa3ebf09b8f1ace0348cb37475eb9.tar.gz
rust-0e9e4083100aa3ebf09b8f1ace0348cb37475eb9.zip
Auto merge of #72756 - RalfJung:rollup-tbjmtx2, r=RalfJung
Rollup of 9 pull requests

Successful merges:

 - #67460 (Tweak impl signature mismatch errors involving `RegionKind::ReVar` lifetimes)
 - #71095 (impl From<[T; N]> for Box<[T]>)
 - #71500 (Make pointer offset methods/intrinsics const)
 - #71804 (linker: Support `-static-pie` and `-static -shared`)
 - #71862 (Implement RFC 2585: unsafe blocks in unsafe fn)
 - #72103 (borrowck `DefId` -> `LocalDefId`)
 - #72407 (Various minor improvements to Ipv6Addr::Display)
 - #72413 (impl Step for char (make Range*<char> iterable))
 - #72439 (NVPTX support for new asm!)

Failed merges:

r? @ghost
Diffstat (limited to 'src/librustc_mir')
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs89
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/move_errors.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/region_errors.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/region_name.rs9
-rw-r--r--src/librustc_mir/borrow_check/mod.rs14
-rw-r--r--src/librustc_mir/borrow_check/nll.rs6
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs57
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs140
9 files changed, 229 insertions, 92 deletions
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index 5f1c0911da2..d0050f801fc 100644
--- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
@@ -214,7 +214,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     let generics = tcx.generics_of(self.mir_def_id);
                     let param = generics.type_param(&param_ty, tcx);
                     if let Some(generics) =
-                        tcx.hir().get_generics(tcx.closure_base_def_id(self.mir_def_id))
+                        tcx.hir().get_generics(tcx.closure_base_def_id(self.mir_def_id.to_def_id()))
                     {
                         suggest_constraining_type_param(
                             tcx,
@@ -865,49 +865,42 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 format!("`{}` would have to be valid for `{}`...", name, region_name),
             );
 
-            if let Some(def_id) = self.mir_def_id.as_local() {
-                let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(def_id);
-                err.span_label(
-                    drop_span,
-                    format!(
-                        "...but `{}` will be dropped here, when the {} returns",
-                        name,
-                        self.infcx
-                            .tcx
-                            .hir()
-                            .opt_name(fn_hir_id)
-                            .map(|name| format!("function `{}`", name))
-                            .unwrap_or_else(|| {
-                                match &self
-                                    .infcx
-                                    .tcx
-                                    .typeck_tables_of(def_id)
-                                    .node_type(fn_hir_id)
-                                    .kind
-                                {
-                                    ty::Closure(..) => "enclosing closure",
-                                    ty::Generator(..) => "enclosing generator",
-                                    kind => bug!("expected closure or generator, found {:?}", kind),
-                                }
-                                .to_string()
-                            })
-                    ),
-                );
+            let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
+            err.span_label(
+                drop_span,
+                format!(
+                    "...but `{}` will be dropped here, when the {} returns",
+                    name,
+                    self.infcx
+                        .tcx
+                        .hir()
+                        .opt_name(fn_hir_id)
+                        .map(|name| format!("function `{}`", name))
+                        .unwrap_or_else(|| {
+                            match &self
+                                .infcx
+                                .tcx
+                                .typeck_tables_of(self.mir_def_id)
+                                .node_type(fn_hir_id)
+                                .kind
+                            {
+                                ty::Closure(..) => "enclosing closure",
+                                ty::Generator(..) => "enclosing generator",
+                                kind => bug!("expected closure or generator, found {:?}", kind),
+                            }
+                            .to_string()
+                        })
+                ),
+            );
 
-                err.note(
-                    "functions cannot return a borrow to data owned within the function's scope, \
-                     functions can only return borrows to data passed as arguments",
-                );
-                err.note(
-                    "to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
-                     references-and-borrowing.html#dangling-references>",
-                );
-            } else {
-                err.span_label(
-                    drop_span,
-                    format!("...but `{}` dropped here while still borrowed", name),
-                );
-            }
+            err.note(
+                "functions cannot return a borrow to data owned within the function's scope, \
+                    functions can only return borrows to data passed as arguments",
+            );
+            err.note(
+                "to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
+                    references-and-borrowing.html#dangling-references>",
+            );
 
             if let BorrowExplanation::MustBeValidFor { .. } = explanation {
             } else {
@@ -1237,7 +1230,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     ) -> DiagnosticBuilder<'cx> {
         let tcx = self.infcx.tcx;
 
-        let (_, escapes_from) = tcx.article_and_description(self.mir_def_id);
+        let (_, escapes_from) = tcx.article_and_description(self.mir_def_id.to_def_id());
 
         let mut err =
             borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from);
@@ -1572,14 +1565,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
         // Define a fallback for when we can't match a closure.
         let fallback = || {
-            let is_closure = self.infcx.tcx.is_closure(self.mir_def_id);
+            let is_closure = self.infcx.tcx.is_closure(self.mir_def_id.to_def_id());
             if is_closure {
                 None
             } else {
                 let ty = self.infcx.tcx.type_of(self.mir_def_id);
                 match ty.kind {
-                    ty::FnDef(_, _) | ty::FnPtr(_) => self
-                        .annotate_fn_sig(self.mir_def_id, self.infcx.tcx.fn_sig(self.mir_def_id)),
+                    ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
+                        self.mir_def_id.to_def_id(),
+                        self.infcx.tcx.fn_sig(self.mir_def_id),
+                    ),
                     _ => None,
                 }
             }
diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
index 67254811ec5..b49e4187fb8 100644
--- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
@@ -331,7 +331,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 self.cannot_move_out_of_interior_noncopy(span, ty, None)
             }
             ty::Closure(def_id, closure_substs)
-                if def_id == self.mir_def_id && upvar_field.is_some() =>
+                if def_id.as_local() == Some(self.mir_def_id) && upvar_field.is_some() =>
             {
                 let closure_kind_ty = closure_substs.as_closure().kind_ty();
                 let closure_kind = closure_kind_ty.to_opt_closure_kind();
diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
index 402eac47c46..e04ed8b83de 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
@@ -492,7 +492,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         err.span_label(sp, format!("cannot {}", act));
 
         let hir = self.infcx.tcx.hir();
-        let closure_id = hir.as_local_hir_id(self.mir_def_id.expect_local());
+        let closure_id = hir.as_local_hir_id(self.mir_def_id);
         let fn_call_id = hir.get_parent_node(closure_id);
         let node = hir.get(fn_call_id);
         let item_id = hir.get_parent_item(fn_call_id);
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
index e19fab89eab..727c4d0605e 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
@@ -498,7 +498,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         let mut diag =
             self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough");
 
-        let (_, mir_def_name) = self.infcx.tcx.article_and_description(self.mir_def_id);
+        let (_, mir_def_name) = self.infcx.tcx.article_and_description(self.mir_def_id.to_def_id());
 
         let fr_name = self.give_region_a_name(*fr).unwrap();
         fr_name.highlight_region_name(&mut diag);
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
index e912ef7b202..2240eb81e1f 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
@@ -237,8 +237,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                 }
 
                 ty::BoundRegion::BrEnv => {
-                    let mir_hir_id =
-                        self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id.expect_local());
+                    let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
                     let def_ty = self.regioncx.universal_regions().defining_ty;
 
                     if let DefiningTy::Closure(_, substs) = def_ty {
@@ -323,7 +322,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         argument_ty: Ty<'tcx>,
         argument_index: usize,
     ) -> Option<RegionName> {
-        let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id.as_local()?);
+        let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
         let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
         let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?;
         match argument_hir_ty.kind {
@@ -634,7 +633,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
         let type_name = self.infcx.extract_type_name(&return_ty, Some(highlight)).0;
 
-        let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id.expect_local());
+        let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id);
 
         let (return_span, mir_description) = match tcx.hir().get(mir_hir_id) {
             hir::Node::Expr(hir::Expr {
@@ -686,7 +685,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
         let type_name = self.infcx.extract_type_name(&yield_ty, Some(highlight)).0;
 
-        let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id.expect_local());
+        let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id);
 
         let yield_span = match tcx.hir().get(mir_hir_id) {
             hir::Node::Expr(hir::Expr {
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 65e62dbd9dd..e3098fc1cfc 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -4,10 +4,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported};
 use rustc_hir as hir;
-use rustc_hir::{
-    def_id::{DefId, LocalDefId},
-    HirId, Node,
-};
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::{HirId, Node};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -174,7 +172,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     let mut body = input_body.clone();
     let mut promoted = input_promoted.clone();
     let free_regions =
-        nll::replace_regions_in_mir(infcx, def_id.to_def_id(), param_env, &mut body, &mut promoted);
+        nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted);
     let body = &body; // no further changes
 
     let location_table = &LocationTable::new(&body);
@@ -275,7 +273,7 @@ fn do_mir_borrowck<'a, 'tcx>(
             let mut promoted_mbcx = MirBorrowckCtxt {
                 infcx,
                 body: promoted_body,
-                mir_def_id: def_id.to_def_id(),
+                mir_def_id: def_id,
                 move_data: &move_data,
                 location_table: &LocationTable::new(promoted_body),
                 movable_generator,
@@ -307,7 +305,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     let mut mbcx = MirBorrowckCtxt {
         infcx,
         body,
-        mir_def_id: def_id.to_def_id(),
+        mir_def_id: def_id,
         move_data: &mdpe.move_data,
         location_table,
         movable_generator,
@@ -459,7 +457,7 @@ fn do_mir_borrowck<'a, 'tcx>(
 crate struct MirBorrowckCtxt<'cx, 'tcx> {
     crate infcx: &'cx InferCtxt<'cx, 'tcx>,
     body: &'cx Body<'tcx>,
-    mir_def_id: DefId,
+    mir_def_id: LocalDefId,
     move_data: &'cx MoveData<'tcx>,
 
     /// Map from MIR `Location` to `LocationIndex`; created
diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs
index b820b79c47f..1d373337147 100644
--- a/src/librustc_mir/borrow_check/nll.rs
+++ b/src/librustc_mir/borrow_check/nll.rs
@@ -58,7 +58,7 @@ crate struct NllOutput<'tcx> {
 /// `compute_regions`.
 pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
-    def_id: DefId,
+    def_id: LocalDefId,
     param_env: ty::ParamEnv<'tcx>,
     body: &mut Body<'tcx>,
     promoted: &mut IndexVec<Promoted, Body<'tcx>>,
@@ -66,12 +66,12 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
     debug!("replace_regions_in_mir(def_id={:?})", def_id);
 
     // Compute named region information. This also renumbers the inputs/outputs.
-    let universal_regions = UniversalRegions::new(infcx, def_id.expect_local(), param_env);
+    let universal_regions = UniversalRegions::new(infcx, def_id, param_env);
 
     // Replace all remaining regions with fresh inference variables.
     renumber::renumber_mir(infcx, body, promoted);
 
-    let source = MirSource::item(def_id);
+    let source = MirSource::item(def_id.to_def_id());
     mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(()));
 
     universal_regions
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index fc4be82ad90..55f254f5732 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -2,19 +2,21 @@
 //! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
 //! and miri.
 
+use std::convert::TryFrom;
+
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{
     self,
-    interpret::{ConstValue, GlobalId, InterpResult, Scalar},
+    interpret::{uabs, ConstValue, GlobalId, InterpResult, Scalar},
     BinOp,
 };
 use rustc_middle::ty;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size};
 
-use super::{ImmTy, InterpCx, Machine, OpTy, PlaceTy};
+use super::{CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy};
 
 mod caller_location;
 mod type_name;
@@ -279,7 +281,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let result = Scalar::from_uint(truncated_bits, layout.size);
                 self.write_scalar(result, dest)?;
             }
+            sym::offset => {
+                let ptr = self.read_scalar(args[0])?.not_undef()?;
+                let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
+                let pointee_ty = substs.type_at(0);
+
+                let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?;
+                self.write_scalar(offset_ptr, dest)?;
+            }
+            sym::arith_offset => {
+                let ptr = self.read_scalar(args[0])?.not_undef()?;
+                let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
+                let pointee_ty = substs.type_at(0);
 
+                let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
+                let offset_bytes = offset_count.wrapping_mul(pointee_size);
+                let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
+                self.write_scalar(offset_ptr, dest)?;
+            }
             sym::ptr_offset_from => {
                 let a = self.read_immediate(args[0])?.to_scalar()?;
                 let b = self.read_immediate(args[1])?.to_scalar()?;
@@ -409,4 +428,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // `Rem` says this is all right, so we can let `Div` do its job.
         self.binop_ignore_overflow(BinOp::Div, a, b, dest)
     }
+
+    /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
+    /// allocation. For integer pointers, we consider each of them their own tiny allocation of size
+    /// 0, so offset-by-0 (and only 0) is okay -- except that NULL cannot be offset by _any_ value.
+    pub fn ptr_offset_inbounds(
+        &self,
+        ptr: Scalar<M::PointerTag>,
+        pointee_ty: Ty<'tcx>,
+        offset_count: i64,
+    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
+        // We cannot overflow i64 as a type's size must be <= isize::MAX.
+        let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
+        // The computed offset, in bytes, cannot overflow an isize.
+        let offset_bytes =
+            offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?;
+        // The offset being in bounds cannot rely on "wrapping around" the address space.
+        // So, first rule out overflows in the pointer arithmetic.
+        let offset_ptr = ptr.ptr_signed_offset(offset_bytes, self)?;
+        // ptr and offset_ptr must be in bounds of the same allocated object. This means all of the
+        // memory between these pointers must be accessible. Note that we do not require the
+        // pointers to be properly aligned (unlike a read/write operation).
+        let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr };
+        let size: u64 = uabs(offset_bytes);
+        // This call handles checking for integer/NULL pointers.
+        self.memory.check_ptr_access_align(
+            min_ptr,
+            Size::from_bytes(size),
+            None,
+            CheckInAllocMsg::InboundsTest,
+        )?;
+        Ok(offset_ptr)
+    }
 }
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index a335fa2de41..1f01bc0e195 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::hir_id::HirId;
 use rustc_hir::intravisit;
 use rustc_hir::Node;
 use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
@@ -9,7 +10,8 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNUSED_UNSAFE};
+use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
+use rustc_session::lint::Level;
 use rustc_span::symbol::{sym, Symbol};
 
 use std::ops::Bound;
@@ -202,25 +204,30 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
 
         if context.is_borrow() {
             if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
-                let source_info = self.source_info;
-                let lint_root = self.body.source_scopes[source_info.scope]
-                    .local_data
-                    .as_ref()
-                    .assert_crate_local()
-                    .lint_root;
                 self.require_unsafe(
                     "borrow of packed field",
                     "fields of packed structs might be misaligned: dereferencing a \
                     misaligned pointer or even just creating a misaligned reference \
                     is undefined behavior",
-                    UnsafetyViolationKind::BorrowPacked(lint_root),
+                    UnsafetyViolationKind::BorrowPacked,
                 );
             }
         }
 
         for (i, elem) in place.projection.iter().enumerate() {
             let proj_base = &place.projection[..i];
-            let old_source_info = self.source_info;
+            if context.is_borrow() {
+                if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
+                    self.require_unsafe(
+                        "borrow of packed field",
+                        "fields of packed structs might be misaligned: dereferencing a \
+                        misaligned pointer or even just creating a misaligned reference \
+                        is undefined behavior",
+                        UnsafetyViolationKind::BorrowPacked,
+                    );
+                }
+            }
+            let source_info = self.source_info;
             if let [] = proj_base {
                 let decl = &self.body.local_decls[place.local];
                 if decl.internal {
@@ -301,7 +308,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                 }
                 _ => {}
             }
-            self.source_info = old_source_info;
+            self.source_info = source_info;
         }
     }
 }
@@ -314,9 +321,15 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
         kind: UnsafetyViolationKind,
     ) {
         let source_info = self.source_info;
+        let lint_root = self.body.source_scopes[self.source_info.scope]
+            .local_data
+            .as_ref()
+            .assert_crate_local()
+            .lint_root;
         self.register_violations(
             &[UnsafetyViolation {
                 source_info,
+                lint_root,
                 description: Symbol::intern(description),
                 details: Symbol::intern(details),
                 kind,
@@ -343,7 +356,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                     match violation.kind {
                         UnsafetyViolationKind::GeneralAndConstFn
                         | UnsafetyViolationKind::General => {}
-                        UnsafetyViolationKind::BorrowPacked(_) => {
+                        UnsafetyViolationKind::BorrowPacked => {
                             if self.min_const_fn {
                                 // const fns don't need to be backwards compatible and can
                                 // emit these violations as a hard error instead of a backwards
@@ -351,6 +364,26 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                                 violation.kind = UnsafetyViolationKind::General;
                             }
                         }
+                        UnsafetyViolationKind::UnsafeFn
+                        | UnsafetyViolationKind::UnsafeFnBorrowPacked => {
+                            bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context")
+                        }
+                    }
+                    if !self.violations.contains(&violation) {
+                        self.violations.push(violation)
+                    }
+                }
+                false
+            }
+            // With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s
+            Safety::FnUnsafe if self.tcx.features().unsafe_block_in_unsafe_fn => {
+                for violation in violations {
+                    let mut violation = *violation;
+
+                    if violation.kind == UnsafetyViolationKind::BorrowPacked {
+                        violation.kind = UnsafetyViolationKind::UnsafeFnBorrowPacked;
+                    } else {
+                        violation.kind = UnsafetyViolationKind::UnsafeFn;
                     }
                     if !self.violations.contains(&violation) {
                         self.violations.push(violation)
@@ -358,7 +391,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                 }
                 false
             }
-            // `unsafe` function bodies allow unsafe without additional unsafe blocks
+            // `unsafe` function bodies allow unsafe without additional unsafe blocks (before RFC 2585)
             Safety::BuiltinUnsafe | Safety::FnUnsafe => true,
             Safety::ExplicitUnsafe(hir_id) => {
                 // mark unsafe block as used if there are any unsafe operations inside
@@ -373,7 +406,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                             UnsafetyViolationKind::GeneralAndConstFn => {}
                             // these things are forbidden in const fns
                             UnsafetyViolationKind::General
-                            | UnsafetyViolationKind::BorrowPacked(_) => {
+                            | UnsafetyViolationKind::BorrowPacked => {
                                 let mut violation = *violation;
                                 // const fns don't need to be backwards compatible and can
                                 // emit these violations as a hard error instead of a backwards
@@ -383,6 +416,10 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                                     self.violations.push(violation)
                                 }
                             }
+                            UnsafetyViolationKind::UnsafeFn
+                            | UnsafetyViolationKind::UnsafeFnBorrowPacked => bug!(
+                                "`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context"
+                            ),
                         }
                     }
                 }
@@ -575,9 +612,12 @@ fn is_enclosed(
             kind: hir::ItemKind::Fn(ref sig, _, _), ..
         })) = tcx.hir().find(parent_id)
         {
-            match sig.header.unsafety {
-                hir::Unsafety::Unsafe => Some(("fn".to_string(), parent_id)),
-                hir::Unsafety::Normal => None,
+            if sig.header.unsafety == hir::Unsafety::Unsafe
+                && !tcx.features().unsafe_block_in_unsafe_fn
+            {
+                Some(("fn".to_string(), parent_id))
+            } else {
+                None
             }
         } else {
             is_enclosed(tcx, used_unsafe, parent_id)
@@ -630,33 +670,40 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) {
     let UnsafetyCheckResult { violations, unsafe_blocks } =
         tcx.unsafety_check_result(def_id.expect_local());
 
-    for &UnsafetyViolation { source_info, description, details, kind } in violations.iter() {
+    for &UnsafetyViolation { source_info, lint_root, description, details, kind } in
+        violations.iter()
+    {
         // Report an error.
+        let unsafe_fn_msg =
+            if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" };
+
         match kind {
             UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => {
+                // once
                 struct_span_err!(
                     tcx.sess,
                     source_info.span,
                     E0133,
-                    "{} is unsafe and requires unsafe function or block",
-                    description
+                    "{} is unsafe and requires unsafe{} block",
+                    description,
+                    unsafe_fn_msg,
                 )
                 .span_label(source_info.span, &*description.as_str())
                 .note(&details.as_str())
                 .emit();
             }
-            UnsafetyViolationKind::BorrowPacked(lint_hir_id) => {
+            UnsafetyViolationKind::BorrowPacked => {
                 if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) {
                     tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id);
                 } else {
                     tcx.struct_span_lint_hir(
                         SAFE_PACKED_BORROWS,
-                        lint_hir_id,
+                        lint_root,
                         source_info.span,
                         |lint| {
                             lint.build(&format!(
-                                "{} is unsafe and requires unsafe function or block (error E0133)",
-                                description
+                                "{} is unsafe and requires unsafe{} block (error E0133)",
+                                description, unsafe_fn_msg,
                             ))
                             .note(&details.as_str())
                             .emit()
@@ -664,6 +711,49 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) {
                     )
                 }
             }
+            UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                lint_root,
+                source_info.span,
+                |lint| {
+                    lint.build(&format!(
+                        "{} is unsafe and requires unsafe block (error E0133)",
+                        description,
+                    ))
+                    .span_label(source_info.span, &*description.as_str())
+                    .note(&details.as_str())
+                    .emit();
+                },
+            ),
+            UnsafetyViolationKind::UnsafeFnBorrowPacked => {
+                // When `unsafe_op_in_unsafe_fn` is disallowed, the behavior of safe and unsafe functions
+                // should be the same in terms of warnings and errors. Therefore, with `#[warn(safe_packed_borrows)]`,
+                // a safe packed borrow should emit a warning *but not an error* in an unsafe function,
+                // just like in a safe function, even if `unsafe_op_in_unsafe_fn` is `deny`.
+                //
+                // Also, `#[warn(unsafe_op_in_unsafe_fn)]` can't cause any new errors. Therefore, with
+                // `#[deny(safe_packed_borrows)]` and `#[warn(unsafe_op_in_unsafe_fn)]`, a packed borrow
+                // should only issue a warning for the sake of backwards compatibility.
+                //
+                // The solution those 2 expectations is to always take the minimum of both lints.
+                // This prevent any new errors (unless both lints are explicitely set to `deny`).
+                let lint = if tcx.lint_level_at_node(SAFE_PACKED_BORROWS, lint_root).0
+                    <= tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, lint_root).0
+                {
+                    SAFE_PACKED_BORROWS
+                } else {
+                    UNSAFE_OP_IN_UNSAFE_FN
+                };
+                tcx.struct_span_lint_hir(&lint, lint_root, source_info.span, |lint| {
+                    lint.build(&format!(
+                        "{} is unsafe and requires unsafe block (error E0133)",
+                        description,
+                    ))
+                    .span_label(source_info.span, &*description.as_str())
+                    .note(&details.as_str())
+                    .emit();
+                })
+            }
         }
     }
 
@@ -683,3 +773,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) {
         report_unused_unsafe(tcx, &unsafe_used, block_id);
     }
 }
+
+fn unsafe_op_in_unsafe_fn_allowed(tcx: TyCtxt<'_>, id: HirId) -> bool {
+    tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, id).0 == Level::Allow
+}