diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
index 0b68991fce2a1..ea560a6d70915 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -468,12 +468,17 @@ Here is the list of currently supported register classes:
 | ARM | `qreg` | `q[0-15]` | `w` |
 | ARM | `qreg_low8` | `q[0-7]` | `t` |
 | ARM | `qreg_low4` | `q[0-3]` | `x` |
+| NVPTX | `reg16` | None\* | `h` |
+| NVPTX | `reg32` | None\* | `r` |
+| NVPTX | `reg64` | None\* | `l` |
 | RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
 | RISC-V | `freg` | `f[0-31]` | `f` |
 
 > **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
 >
 > Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register.
+>
+> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
 
 Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
 
@@ -495,6 +500,9 @@ Each register class has constraints on which value types they can be used with.
 | ARM | `sreg` | `vfp2` | `i32`, `f32` |
 | ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` |
 | ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` |
+| NVPTX | `reg16` | None | `i8`, `i16` |
+| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |
+| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
 | RISC-V32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
 | RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
 | RISC-V | `freg` | `f` | `f32` |
@@ -610,6 +618,9 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen
 | ARM | `dreg` | None | `d0` | `P` |
 | ARM | `qreg` | None | `q0` | `q` |
 | ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` |
+| NVPTX | `reg16` | None | `rs0` | None |
+| NVPTX | `reg32` | None | `r0` | None |
+| NVPTX | `reg64` | None | `rd0` | None |
 | RISC-V | `reg` | None | `x1` | None |
 | RISC-V | `freg` | None | `f0` | None |
 
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 9006e4cfaf7bb..2d97fecf8a766 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1314,6 +1314,7 @@ extern "rust-intrinsic" {
     /// The stabilized version of this intrinsic is
     /// [`std::pointer::offset`](../../std/primitive.pointer.html#method.offset).
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     pub fn offset<T>(dst: *const T, offset: isize) -> *const T;
 
     /// Calculates the offset from a pointer, potentially wrapping.
@@ -1331,6 +1332,7 @@ extern "rust-intrinsic" {
     /// The stabilized version of this intrinsic is
     /// [`std::pointer::wrapping_offset`](../../std/primitive.pointer.html#method.wrapping_offset).
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
 
     /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index ca13433caec8d..7d21f9a9a66d0 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -85,6 +85,7 @@
 #![feature(const_panic)]
 #![feature(const_fn_union)]
 #![feature(const_generics)]
+#![feature(const_ptr_offset)]
 #![feature(const_ptr_offset_from)]
 #![feature(const_result)]
 #![feature(const_slice_from_raw_parts)]
diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs
index 85ba5fc0638ea..835183d171a79 100644
--- a/src/libcore/ptr/const_ptr.rs
+++ b/src/libcore/ptr/const_ptr.rs
@@ -151,8 +151,9 @@ impl<T: ?Sized> *const T {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
-    pub unsafe fn offset(self, count: isize) -> *const T
+    pub const unsafe fn offset(self, count: isize) -> *const T
     where
         T: Sized,
     {
@@ -210,8 +211,9 @@ impl<T: ?Sized> *const T {
     /// ```
     #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
-    pub fn wrapping_offset(self, count: isize) -> *const T
+    pub const fn wrapping_offset(self, count: isize) -> *const T
     where
         T: Sized,
     {
@@ -393,8 +395,9 @@ impl<T: ?Sized> *const T {
     /// ```
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
-    pub unsafe fn add(self, count: usize) -> Self
+    pub const unsafe fn add(self, count: usize) -> Self
     where
         T: Sized,
     {
@@ -455,8 +458,9 @@ impl<T: ?Sized> *const T {
     /// ```
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
-    pub unsafe fn sub(self, count: usize) -> Self
+    pub const unsafe fn sub(self, count: usize) -> Self
     where
         T: Sized,
     {
@@ -511,8 +515,9 @@ impl<T: ?Sized> *const T {
     /// ```
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
-    pub fn wrapping_add(self, count: usize) -> Self
+    pub const fn wrapping_add(self, count: usize) -> Self
     where
         T: Sized,
     {
@@ -567,8 +572,9 @@ impl<T: ?Sized> *const T {
     /// ```
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
-    pub fn wrapping_sub(self, count: usize) -> Self
+    pub const fn wrapping_sub(self, count: usize) -> Self
     where
         T: Sized,
     {
diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs
index 0781d7e6cac45..40b5e4e22340e 100644
--- a/src/libcore/ptr/mut_ptr.rs
+++ b/src/libcore/ptr/mut_ptr.rs
@@ -145,8 +145,9 @@ impl<T: ?Sized> *mut T {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
-    pub unsafe fn offset(self, count: isize) -> *mut T
+    pub const unsafe fn offset(self, count: isize) -> *mut T
     where
         T: Sized,
     {
@@ -203,8 +204,9 @@ impl<T: ?Sized> *mut T {
     /// ```
     #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
-    pub fn wrapping_offset(self, count: isize) -> *mut T
+    pub const fn wrapping_offset(self, count: isize) -> *mut T
     where
         T: Sized,
     {
@@ -439,8 +441,9 @@ impl<T: ?Sized> *mut T {
     /// ```
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
-    pub unsafe fn add(self, count: usize) -> Self
+    pub const unsafe fn add(self, count: usize) -> Self
     where
         T: Sized,
     {
@@ -501,8 +504,9 @@ impl<T: ?Sized> *mut T {
     /// ```
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
-    pub unsafe fn sub(self, count: usize) -> Self
+    pub const unsafe fn sub(self, count: usize) -> Self
     where
         T: Sized,
     {
@@ -557,8 +561,9 @@ impl<T: ?Sized> *mut T {
     /// ```
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
-    pub fn wrapping_add(self, count: usize) -> Self
+    pub const fn wrapping_add(self, count: usize) -> Self
     where
         T: Sized,
     {
@@ -613,8 +618,9 @@ impl<T: ?Sized> *mut T {
     /// ```
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
+    #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
-    pub fn wrapping_sub(self, count: usize) -> Self
+    pub const fn wrapping_sub(self, count: usize) -> Self
     where
         T: Sized,
     {
diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs
index 8986ab322c07f..f3b46dd322a39 100644
--- a/src/librustc_codegen_llvm/asm.rs
+++ b/src/librustc_codegen_llvm/asm.rs
@@ -254,6 +254,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                     ]);
                 }
                 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {}
+                InlineAsmArch::Nvptx64 => {}
             }
         }
         if !options.contains(InlineAsmOptions::NOMEM) {
@@ -410,6 +411,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass) -> String {
             | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => "x",
             InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
             | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w",
+            InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
+            InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
+            InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
             InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
@@ -452,6 +456,7 @@ fn modifier_to_llvm(
                 modifier
             }
         }
+        InlineAsmRegClass::Nvptx(_) => None,
         InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
         | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None,
         InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
@@ -502,6 +507,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
         | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
             cx.type_vector(cx.type_i64(), 2)
         }
+        InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
+        InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
+        InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
         InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 9a7c4907754b0..dcce1d45298cc 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -1194,9 +1194,10 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
     };
 
     // Adjust the output kind to target capabilities.
-    let pic_exe_supported = sess.target.target.options.position_independent_executables;
-    let static_pic_exe_supported = false; // FIXME: Add this option to target specs.
-    let static_dylib_supported = sess.target.target.options.crt_static_allows_dylibs;
+    let opts = &sess.target.target.options;
+    let pic_exe_supported = opts.position_independent_executables;
+    let static_pic_exe_supported = opts.static_position_independent_executables;
+    let static_dylib_supported = opts.crt_static_allows_dylibs;
     match kind {
         LinkOutputKind::DynamicPicExe if !pic_exe_supported => LinkOutputKind::DynamicNoPicExe,
         LinkOutputKind::StaticPicExe if !static_pic_exe_supported => LinkOutputKind::StaticNoPicExe,
@@ -1580,16 +1581,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     }
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    // FIXME: Support `StaticPicExe` correctly.
-    match link_output_kind {
-        LinkOutputKind::DynamicPicExe | LinkOutputKind::StaticPicExe => {
-            cmd.position_independent_executable()
-        }
-        LinkOutputKind::DynamicNoPicExe | LinkOutputKind::StaticNoPicExe => {
-            cmd.no_position_independent_executable()
-        }
-        _ => {}
-    }
+    cmd.set_output_kind(link_output_kind, out_filename);
 
     // OBJECT-FILES-NO, AUDIT-ORDER
     add_relro_args(cmd, sess);
@@ -1618,17 +1610,6 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
         tmpdir,
     );
 
-    // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    // FIXME: Merge with the previous `link_output_kind` match,
-    // and support `StaticPicExe` and `StaticDylib` correctly.
-    match link_output_kind {
-        LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => {
-            cmd.build_static_executable()
-        }
-        LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => cmd.build_dylib(out_filename),
-        _ => {}
-    }
-
     // OBJECT-FILES-NO, AUDIT-ORDER
     if sess.opts.cg.profile_generate.enabled() {
         cmd.pgo_gen();
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index 49de8c5e28ab5..46c365efdb5fa 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -17,7 +17,7 @@ use rustc_serialize::{json, Encoder};
 use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
-use rustc_target::spec::{LinkerFlavor, LldFlavor};
+use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
 
 /// Disables non-English messages from localized linkers.
 /// Such messages may cause issues with text encoding on Windows (#35785)
@@ -101,6 +101,7 @@ impl LinkerInfo {
 /// MSVC linker (e.g., `link.exe`) is being used.
 pub trait Linker {
     fn cmd(&mut self) -> &mut Command;
+    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
     fn link_dylib(&mut self, lib: Symbol);
     fn link_rust_dylib(&mut self, lib: Symbol, path: &Path);
     fn link_framework(&mut self, framework: Symbol);
@@ -113,8 +114,6 @@ pub trait Linker {
     fn output_filename(&mut self, path: &Path);
     fn add_object(&mut self, path: &Path);
     fn gc_sections(&mut self, keep_metadata: bool);
-    fn position_independent_executable(&mut self);
-    fn no_position_independent_executable(&mut self);
     fn full_relro(&mut self);
     fn partial_relro(&mut self);
     fn no_relro(&mut self);
@@ -124,8 +123,6 @@ pub trait Linker {
     fn debuginfo(&mut self, strip: Strip);
     fn no_crt_objects(&mut self);
     fn no_default_libraries(&mut self);
-    fn build_dylib(&mut self, out_filename: &Path);
-    fn build_static_executable(&mut self);
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
     fn subsystem(&mut self, subsystem: &str);
     fn group_start(&mut self);
@@ -232,12 +229,94 @@ impl<'a> GccLinker<'a> {
         let target_cpu = self.target_cpu;
         self.linker_arg(&format!("-plugin-opt=mcpu={}", target_cpu));
     }
+
+    fn build_dylib(&mut self, out_filename: &Path) {
+        // On mac we need to tell the linker to let this library be rpathed
+        if self.sess.target.target.options.is_like_osx {
+            self.cmd.arg("-dynamiclib");
+            self.linker_arg("-dylib");
+
+            // Note that the `osx_rpath_install_name` option here is a hack
+            // purely to support rustbuild right now, we should get a more
+            // principled solution at some point to force the compiler to pass
+            // the right `-Wl,-install_name` with an `@rpath` in it.
+            if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
+                self.linker_arg("-install_name");
+                let mut v = OsString::from("@rpath/");
+                v.push(out_filename.file_name().unwrap());
+                self.linker_arg(&v);
+            }
+        } else {
+            self.cmd.arg("-shared");
+            if self.sess.target.target.options.is_like_windows {
+                // The output filename already contains `dll_suffix` so
+                // the resulting import library will have a name in the
+                // form of libfoo.dll.a
+                let implib_name =
+                    out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
+                        format!(
+                            "{}{}{}",
+                            self.sess.target.target.options.staticlib_prefix,
+                            file,
+                            self.sess.target.target.options.staticlib_suffix
+                        )
+                    });
+                if let Some(implib_name) = implib_name {
+                    let implib = out_filename.parent().map(|dir| dir.join(&implib_name));
+                    if let Some(implib) = implib {
+                        self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap()));
+                    }
+                }
+            }
+        }
+    }
 }
 
 impl<'a> Linker for GccLinker<'a> {
     fn cmd(&mut self) -> &mut Command {
         &mut self.cmd
     }
+
+    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
+        match output_kind {
+            LinkOutputKind::DynamicNoPicExe => {
+                if !self.is_ld {
+                    self.cmd.arg("-no-pie");
+                }
+            }
+            LinkOutputKind::DynamicPicExe => {
+                // `-pie` works for both gcc wrapper and ld.
+                self.cmd.arg("-pie");
+            }
+            LinkOutputKind::StaticNoPicExe => {
+                // `-static` works for both gcc wrapper and ld.
+                self.cmd.arg("-static");
+                if !self.is_ld {
+                    self.cmd.arg("-no-pie");
+                }
+            }
+            LinkOutputKind::StaticPicExe => {
+                if !self.is_ld {
+                    // Note that combination `-static -pie` doesn't work as expected
+                    // for the gcc wrapper, `-static` in that case suppresses `-pie`.
+                    self.cmd.arg("-static-pie");
+                } else {
+                    // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing
+                    // a static pie, but currently passed because gcc and clang pass them.
+                    // The former suppresses the `INTERP` ELF header specifying dynamic linker,
+                    // which is otherwise implicitly injected by ld (but not lld).
+                    // The latter doesn't change anything, only ensures that everything is pic.
+                    self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
+                }
+            }
+            LinkOutputKind::DynamicDylib => self.build_dylib(out_filename),
+            LinkOutputKind::StaticDylib => {
+                self.cmd.arg("-static");
+                self.build_dylib(out_filename);
+            }
+        }
+    }
+
     fn link_dylib(&mut self, lib: Symbol) {
         self.hint_dynamic();
         self.cmd.arg(format!("-l{}", lib));
@@ -262,14 +341,6 @@ impl<'a> Linker for GccLinker<'a> {
     fn add_object(&mut self, path: &Path) {
         self.cmd.arg(path);
     }
-    fn position_independent_executable(&mut self) {
-        self.cmd.arg("-pie");
-    }
-    fn no_position_independent_executable(&mut self) {
-        if !self.is_ld {
-            self.cmd.arg("-no-pie");
-        }
-    }
     fn full_relro(&mut self) {
         self.linker_arg("-zrelro");
         self.linker_arg("-znow");
@@ -280,9 +351,6 @@ impl<'a> Linker for GccLinker<'a> {
     fn no_relro(&mut self) {
         self.linker_arg("-znorelro");
     }
-    fn build_static_executable(&mut self) {
-        self.cmd.arg("-static");
-    }
 
     fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
         self.hint_dynamic();
@@ -418,47 +486,6 @@ impl<'a> Linker for GccLinker<'a> {
         }
     }
 
-    fn build_dylib(&mut self, out_filename: &Path) {
-        // On mac we need to tell the linker to let this library be rpathed
-        if self.sess.target.target.options.is_like_osx {
-            self.cmd.arg("-dynamiclib");
-            self.linker_arg("-dylib");
-
-            // Note that the `osx_rpath_install_name` option here is a hack
-            // purely to support rustbuild right now, we should get a more
-            // principled solution at some point to force the compiler to pass
-            // the right `-Wl,-install_name` with an `@rpath` in it.
-            if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
-                self.linker_arg("-install_name");
-                let mut v = OsString::from("@rpath/");
-                v.push(out_filename.file_name().unwrap());
-                self.linker_arg(&v);
-            }
-        } else {
-            self.cmd.arg("-shared");
-            if self.sess.target.target.options.is_like_windows {
-                // The output filename already contains `dll_suffix` so
-                // the resulting import library will have a name in the
-                // form of libfoo.dll.a
-                let implib_name =
-                    out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
-                        format!(
-                            "{}{}{}",
-                            self.sess.target.target.options.staticlib_prefix,
-                            file,
-                            self.sess.target.target.options.staticlib_suffix
-                        )
-                    });
-                if let Some(implib_name) = implib_name {
-                    let implib = out_filename.parent().map(|dir| dir.join(&implib_name));
-                    if let Some(implib) = implib {
-                        self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap()));
-                    }
-                }
-            }
-        }
-    }
-
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
         // Symbol visibility in object files typically takes care of this.
         if crate_type == CrateType::Executable
@@ -582,6 +609,22 @@ impl<'a> Linker for MsvcLinker<'a> {
     fn cmd(&mut self) -> &mut Command {
         &mut self.cmd
     }
+
+    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
+        match output_kind {
+            LinkOutputKind::DynamicNoPicExe
+            | LinkOutputKind::DynamicPicExe
+            | LinkOutputKind::StaticNoPicExe
+            | LinkOutputKind::StaticPicExe => {}
+            LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
+                self.cmd.arg("/DLL");
+                let mut arg: OsString = "/IMPLIB:".into();
+                arg.push(out_filename.with_extension("dll.lib"));
+                self.cmd.arg(arg);
+            }
+        }
+    }
+
     fn link_rlib(&mut self, lib: &Path) {
         self.cmd.arg(lib);
     }
@@ -589,17 +632,6 @@ impl<'a> Linker for MsvcLinker<'a> {
         self.cmd.arg(path);
     }
 
-    fn build_dylib(&mut self, out_filename: &Path) {
-        self.cmd.arg("/DLL");
-        let mut arg: OsString = "/IMPLIB:".into();
-        arg.push(out_filename.with_extension("dll.lib"));
-        self.cmd.arg(arg);
-    }
-
-    fn build_static_executable(&mut self) {
-        // noop
-    }
-
     fn gc_sections(&mut self, _keep_metadata: bool) {
         // MSVC's ICF (Identical COMDAT Folding) link optimization is
         // slow for Rust and thus we disable it by default when not in
@@ -632,14 +664,6 @@ impl<'a> Linker for MsvcLinker<'a> {
         self.cmd.arg(&format!("{}.lib", lib));
     }
 
-    fn position_independent_executable(&mut self) {
-        // noop
-    }
-
-    fn no_position_independent_executable(&mut self) {
-        // noop
-    }
-
     fn full_relro(&mut self) {
         // noop
     }
@@ -817,6 +841,9 @@ impl<'a> Linker for EmLinker<'a> {
     fn cmd(&mut self) -> &mut Command {
         &mut self.cmd
     }
+
+    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+
     fn include_path(&mut self, path: &Path) {
         self.cmd.arg("-L").arg(path);
     }
@@ -856,14 +883,6 @@ impl<'a> Linker for EmLinker<'a> {
         self.add_object(lib);
     }
 
-    fn position_independent_executable(&mut self) {
-        // noop
-    }
-
-    fn no_position_independent_executable(&mut self) {
-        // noop
-    }
-
     fn full_relro(&mut self) {
         // noop
     }
@@ -925,14 +944,6 @@ impl<'a> Linker for EmLinker<'a> {
         self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
     }
 
-    fn build_dylib(&mut self, _out_filename: &Path) {
-        bug!("building dynamic library is unsupported on Emscripten")
-    }
-
-    fn build_static_executable(&mut self) {
-        // noop
-    }
-
     fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
         let symbols = &self.info.exports[&crate_type];
 
@@ -1031,6 +1042,18 @@ impl<'a> Linker for WasmLd<'a> {
         &mut self.cmd
     }
 
+    fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) {
+        match output_kind {
+            LinkOutputKind::DynamicNoPicExe
+            | LinkOutputKind::DynamicPicExe
+            | LinkOutputKind::StaticNoPicExe
+            | LinkOutputKind::StaticPicExe => {}
+            LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
+                self.cmd.arg("--no-entry");
+            }
+        }
+    }
+
     fn link_dylib(&mut self, lib: Symbol) {
         self.cmd.arg("-l").sym_arg(lib);
     }
@@ -1059,16 +1082,12 @@ impl<'a> Linker for WasmLd<'a> {
         self.cmd.arg(path);
     }
 
-    fn position_independent_executable(&mut self) {}
-
     fn full_relro(&mut self) {}
 
     fn partial_relro(&mut self) {}
 
     fn no_relro(&mut self) {}
 
-    fn build_static_executable(&mut self) {}
-
     fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
         self.cmd.arg("-l").sym_arg(lib);
     }
@@ -1124,10 +1143,6 @@ impl<'a> Linker for WasmLd<'a> {
 
     fn no_default_libraries(&mut self) {}
 
-    fn build_dylib(&mut self, _out_filename: &Path) {
-        self.cmd.arg("--no-entry");
-    }
-
     fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
         for sym in self.info.exports[&crate_type].iter() {
             self.cmd.arg("--export").arg(&sym);
@@ -1143,8 +1158,6 @@ impl<'a> Linker for WasmLd<'a> {
 
     fn subsystem(&mut self, _subsystem: &str) {}
 
-    fn no_position_independent_executable(&mut self) {}
-
     fn finalize(&mut self) {}
 
     // Not needed for now with LLD
@@ -1207,6 +1220,8 @@ impl<'a> Linker for PtxLinker<'a> {
         &mut self.cmd
     }
 
+    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+
     fn link_rlib(&mut self, path: &Path) {
         self.cmd.arg("--rlib").arg(path);
     }
@@ -1273,16 +1288,12 @@ impl<'a> Linker for PtxLinker<'a> {
         panic!("frameworks not supported")
     }
 
-    fn position_independent_executable(&mut self) {}
-
     fn full_relro(&mut self) {}
 
     fn partial_relro(&mut self) {}
 
     fn no_relro(&mut self) {}
 
-    fn build_static_executable(&mut self) {}
-
     fn gc_sections(&mut self, _keep_metadata: bool) {}
 
     fn pgo_gen(&mut self) {}
@@ -1295,14 +1306,10 @@ impl<'a> Linker for PtxLinker<'a> {
         self.sess.warn("Windows Control Flow Guard is not supported by this linker.");
     }
 
-    fn build_dylib(&mut self, _out_filename: &Path) {}
-
     fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {}
 
     fn subsystem(&mut self, _subsystem: &str) {}
 
-    fn no_position_independent_executable(&mut self) {}
-
     fn group_start(&mut self) {}
 
     fn group_end(&mut self) {}
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index 1cc5daafed14e..cff83c3d5cda2 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -193,9 +193,18 @@ impl Diagnostic {
         expected_extra: &dyn fmt::Display,
         found_extra: &dyn fmt::Display,
     ) -> &mut Self {
-        let expected_label = format!("expected {}", expected_label);
-
-        let found_label = format!("found {}", found_label);
+        let expected_label = expected_label.to_string();
+        let expected_label = if expected_label.is_empty() {
+            "expected".to_string()
+        } else {
+            format!("expected {}", expected_label)
+        };
+        let found_label = found_label.to_string();
+        let found_label = if found_label.is_empty() {
+            "found".to_string()
+        } else {
+            format!("found {}", found_label)
+        };
         let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
             (expected_label.len() - found_label.len(), 0)
         } else {
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index 90b2380d86450..fd35cb6c3f785 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -571,6 +571,9 @@ declare_features! (
     /// Allows the use of `#[ffi_const]` on foreign functions.
     (active, ffi_const, "1.45.0", Some(58328), None),
 
+    /// No longer treat an unsafe function as an unsafe block.
+    (active, unsafe_block_in_unsafe_fn, "1.45.0", Some(71668), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs
index cc479aa17ce95..ae9019828170f 100644
--- a/src/librustc_infer/infer/error_reporting/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/mod.rs
@@ -987,12 +987,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
 
         fn push_ty_ref<'tcx>(
-            r: &ty::Region<'tcx>,
+            region: &ty::Region<'tcx>,
             ty: Ty<'tcx>,
             mutbl: hir::Mutability,
             s: &mut DiagnosticStyledString,
         ) {
-            let mut r = r.to_string();
+            let mut r = region.to_string();
             if r == "'_" {
                 r.clear();
             } else {
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index 695f3e47fb5d7..5f14f799fc7aa 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -2,11 +2,16 @@
 
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::{Subtype, ValuePairs};
+use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs};
 use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
 use rustc_errors::ErrorReported;
-use rustc_middle::ty::Ty;
-use rustc_span::Span;
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
+use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::{MultiSpan, Span};
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
@@ -36,7 +41,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                                 var_origin.span(),
                                 sub_expected_found.expected,
                                 sub_expected_found.found,
-                                self.tcx().def_span(*trait_item_def_id),
+                                *trait_item_def_id,
                             );
                             return Some(ErrorReported);
                         }
@@ -47,14 +52,100 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         None
     }
 
-    fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, impl_sp: Span) {
+    fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id: DefId) {
+        let tcx = self.tcx();
+        let trait_sp = self.tcx().def_span(trait_def_id);
         let mut err = self
             .tcx()
             .sess
             .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
-        err.note(&format!("expected `{:?}`\n   found `{:?}`", expected, found));
-        err.span_label(sp, &format!("found {:?}", found));
-        err.span_label(impl_sp, &format!("expected {:?}", expected));
+        err.span_label(sp, &format!("found `{:?}`", found));
+        err.span_label(trait_sp, &format!("expected `{:?}`", expected));
+
+        // Get the span of all the used type parameters in the method.
+        let assoc_item = self.tcx().associated_item(trait_def_id);
+        let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
+        match assoc_item.kind {
+            ty::AssocKind::Fn => {
+                let hir = self.tcx().hir();
+                if let Some(hir_id) = assoc_item.def_id.as_local().map(|id| hir.as_local_hir_id(id))
+                {
+                    if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) {
+                        visitor.visit_fn_decl(decl);
+                    }
+                }
+            }
+            _ => {}
+        }
+        let mut type_param_span: MultiSpan =
+            visitor.types.iter().cloned().collect::<Vec<_>>().into();
+        for &span in &visitor.types {
+            type_param_span.push_span_label(
+                span,
+                "consider borrowing this type parameter in the trait".to_string(),
+            );
+        }
+
+        if let Some((expected, found)) = tcx
+            .infer_ctxt()
+            .enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found }))
+        {
+            // Highlighted the differences when showing the "expected/found" note.
+            err.note_expected_found(&"", expected, &"", found);
+        } else {
+            // This fallback shouldn't be necessary, but let's keep it in just in case.
+            err.note(&format!("expected `{:?}`\n   found `{:?}`", expected, found));
+        }
+        err.span_help(
+            type_param_span,
+            "the lifetime requirements from the `impl` do not correspond to the requirements in \
+             the `trait`",
+        );
+        if visitor.types.is_empty() {
+            err.help(
+                "verify the lifetime relationships in the `trait` and `impl` between the `self` \
+                 argument, the other inputs and its output",
+            );
+        }
         err.emit();
     }
 }
+
+struct TypeParamSpanVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    types: Vec<Span>,
+}
+
+impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
+    type Map = rustc_middle::hir::map::Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
+        hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    }
+
+    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
+        match arg.kind {
+            hir::TyKind::Rptr(_, ref mut_ty) => {
+                // We don't want to suggest looking into borrowing `&T` or `&Self`.
+                hir::intravisit::walk_ty(self, mut_ty.ty);
+                return;
+            }
+            hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
+                [segment]
+                    if segment
+                        .res
+                        .map(|res| match res {
+                            Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true,
+                            _ => false,
+                        })
+                        .unwrap_or(false) =>
+                {
+                    self.types.push(path.span);
+                }
+                _ => {}
+            },
+            _ => {}
+        }
+        hir::intravisit::walk_ty(self, arg);
+    }
+}
diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs
index 274e57ae64cac..3d2ddf12a0a1f 100644
--- a/src/librustc_lint/levels.rs
+++ b/src/librustc_lint/levels.rs
@@ -14,11 +14,11 @@ use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::lint::{builtin, Level, Lint};
+use rustc_session::lint::{builtin, Level, Lint, LintId};
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
-use rustc_span::source_map::MultiSpan;
 use rustc_span::symbol::{sym, Symbol};
+use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP};
 
 use std::cmp;
 
@@ -80,11 +80,13 @@ impl<'s> LintLevelsBuilder<'s> {
             let level = cmp::min(level, self.sets.lint_cap);
 
             let lint_flag_val = Symbol::intern(lint_name);
+
             let ids = match store.find_lints(&lint_name) {
                 Ok(ids) => ids,
                 Err(_) => continue, // errors handled in check_lint_name_cmdline above
             };
             for id in ids {
+                self.check_gated_lint(id, DUMMY_SP);
                 let src = LintSource::CommandLine(lint_flag_val);
                 specs.insert(id, (level, src));
             }
@@ -213,6 +215,7 @@ impl<'s> LintLevelsBuilder<'s> {
                     CheckLintNameResult::Ok(ids) => {
                         let src = LintSource::Node(name, li.span(), reason);
                         for id in ids {
+                            self.check_gated_lint(*id, attr.span);
                             specs.insert(*id, (level, src));
                         }
                     }
@@ -383,6 +386,20 @@ impl<'s> LintLevelsBuilder<'s> {
         BuilderPush { prev, changed: prev != self.cur }
     }
 
+    fn check_gated_lint(&self, id: LintId, span: Span) {
+        if id == LintId::of(builtin::UNSAFE_OP_IN_UNSAFE_FN)
+            && !self.sess.features_untracked().unsafe_block_in_unsafe_fn
+        {
+            feature_err(
+                &self.sess.parse_sess,
+                sym::unsafe_block_in_unsafe_fn,
+                span,
+                "the `unsafe_op_in_unsafe_fn` lint is unstable",
+            )
+            .emit();
+        }
+    }
+
     /// Called after `push` when the scope of a set of attributes are exited.
     pub fn pop(&mut self, push: BuilderPush) {
         self.cur = push.prev;
diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs
index d32a147344992..fc588e049d7d8 100644
--- a/src/librustc_middle/mir/interpret/error.rs
+++ b/src/librustc_middle/mir/interpret/error.rs
@@ -1,4 +1,4 @@
-use super::{AllocId, Pointer, RawConst, ScalarMaybeUninit};
+use super::{AllocId, Pointer, RawConst, Scalar};
 
 use crate::mir::interpret::ConstValue;
 use crate::ty::layout::LayoutError;
@@ -391,7 +391,7 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     /// Using a non-character `u32` as character.
     InvalidChar(u32),
     /// An enum discriminant was set to a value which was outside the range of valid values.
-    InvalidDiscriminant(ScalarMaybeUninit),
+    InvalidDiscriminant(Scalar),
     /// Using a pointer-not-to-a-function as function pointer.
     InvalidFunctionPointer(Pointer),
     /// Using a string that is not valid UTF-8,
diff --git a/src/librustc_middle/mir/interpret/mod.rs b/src/librustc_middle/mir/interpret/mod.rs
index d9e52af89007c..061bc9750e1c2 100644
--- a/src/librustc_middle/mir/interpret/mod.rs
+++ b/src/librustc_middle/mir/interpret/mod.rs
@@ -598,3 +598,12 @@ pub fn truncate(value: u128, size: Size) -> u128 {
     // Truncate (shift left to drop out leftover values, shift right to fill with zeroes).
     (value << shift) >> shift
 }
+
+/// Computes the unsigned absolute value without wrapping or panicking.
+#[inline]
+pub fn uabs(value: i64) -> u64 {
+    // The only tricky part here is if value == i64::MIN. In that case,
+    // wrapping_abs() returns i64::MIN == -2^63. Casting this value to a u64
+    // gives 2^63, the correct value.
+    value.wrapping_abs() as u64
+}
diff --git a/src/librustc_middle/mir/interpret/pointer.rs b/src/librustc_middle/mir/interpret/pointer.rs
index 70cc546199b79..ccad4f0a135a1 100644
--- a/src/librustc_middle/mir/interpret/pointer.rs
+++ b/src/librustc_middle/mir/interpret/pointer.rs
@@ -1,4 +1,4 @@
-use super::{AllocId, InterpResult};
+use super::{uabs, AllocId, InterpResult};
 
 use rustc_macros::HashStable;
 use rustc_target::abi::{HasDataLayout, Size};
@@ -24,6 +24,12 @@ pub trait PointerArithmetic: HasDataLayout {
         u64::try_from(max_usize_plus_1 - 1).unwrap()
     }
 
+    #[inline]
+    fn machine_isize_min(&self) -> i64 {
+        let max_isize_plus_1 = 1i128 << (self.pointer_size().bits() - 1);
+        i64::try_from(-max_isize_plus_1).unwrap()
+    }
+
     #[inline]
     fn machine_isize_max(&self) -> i64 {
         let max_isize_plus_1 = 1u128 << (self.pointer_size().bits() - 1);
@@ -42,21 +48,23 @@ pub trait PointerArithmetic: HasDataLayout {
 
     #[inline]
     fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
+        // We do not need to check if i fits in a machine usize. If it doesn't,
+        // either the wrapping_add will wrap or res will not fit in a pointer.
         let res = val.overflowing_add(i);
         self.truncate_to_ptr(res)
     }
 
     #[inline]
     fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) {
-        if i < 0 {
-            // Trickery to ensure that `i64::MIN` works fine: compute `n = -i`.
-            // This formula only works for true negative values; it overflows for zero!
-            let n = u64::MAX - (i as u64) + 1;
-            let res = val.overflowing_sub(n);
-            self.truncate_to_ptr(res)
+        // We need to make sure that i fits in a machine isize.
+        let n = uabs(i);
+        if i >= 0 {
+            let (val, over) = self.overflowing_offset(val, n);
+            (val, over || i > self.machine_isize_max())
         } else {
-            // `i >= 0`, so the cast is safe.
-            self.overflowing_offset(val, i as u64)
+            let res = val.overflowing_sub(n);
+            let (val, over) = self.truncate_to_ptr(res);
+            (val, over || i < self.machine_isize_min())
         }
     }
 
diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs
index 47cfa62abb14d..20c64d40fabbd 100644
--- a/src/librustc_middle/mir/mod.rs
+++ b/src/librustc_middle/mir/mod.rs
@@ -408,7 +408,7 @@ impl<'tcx> Body<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub enum Safety {
     Safe,
     /// Unsafe because of a PushUnsafeBlock
diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs
index 63b8d8c8da782..99bfb74c243b4 100644
--- a/src/librustc_middle/mir/query.rs
+++ b/src/librustc_middle/mir/query.rs
@@ -15,15 +15,27 @@ use super::{Field, SourceInfo};
 
 #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
 pub enum UnsafetyViolationKind {
+    /// Only permitted in regular `fn`s, prohibitted in `const fn`s.
     General,
     /// Permitted both in `const fn`s and regular `fn`s.
     GeneralAndConstFn,
-    BorrowPacked(hir::HirId),
+    /// Borrow of packed field.
+    /// Has to be handled as a lint for backwards compatibility.
+    BorrowPacked,
+    /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block.
+    /// Has to be handled as a lint for backwards compatibility.
+    /// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`.
+    UnsafeFn,
+    /// Borrow of packed field in an `unsafe fn` but outside an `unsafe` block.
+    /// Has to be handled as a lint for backwards compatibility.
+    /// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`.
+    UnsafeFnBorrowPacked,
 }
 
 #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
 pub struct UnsafetyViolation {
     pub source_info: SourceInfo,
+    pub lint_root: hir::HirId,
     pub description: Symbol,
     pub details: Symbol,
     pub kind: UnsafetyViolationKind,
diff --git a/src/librustc_middle/mir/tcx.rs b/src/librustc_middle/mir/tcx.rs
index 4747aec2d5c24..4059bfedc6da4 100644
--- a/src/librustc_middle/mir/tcx.rs
+++ b/src/librustc_middle/mir/tcx.rs
@@ -5,7 +5,6 @@
 
 use crate::mir::*;
 use crate::ty::subst::Subst;
-use crate::ty::util::IntTypeExt;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_hir as hir;
 use rustc_target::abi::VariantIdx;
@@ -174,17 +173,7 @@ impl<'tcx> Rvalue<'tcx> {
                 tcx.intern_tup(&[ty, tcx.types.bool])
             }
             Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
-            Rvalue::Discriminant(ref place) => {
-                let ty = place.ty(local_decls, tcx).ty;
-                match ty.kind {
-                    ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx),
-                    ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx),
-                    _ => {
-                        // This can only be `0`, for now, so `u8` will suffice.
-                        tcx.types.u8
-                    }
-                }
-            }
+            Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
             Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
             Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize,
             Rvalue::Aggregate(ref ak, ref ops) => match **ak {
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 01517ab25a24a..4cd3be932def0 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -2037,6 +2037,8 @@ impl ReprOptions {
         self.flags.contains(ReprFlags::HIDE_NICHE)
     }
 
+    /// Returns the discriminant type, given these `repr` options.
+    /// This must only be called on enums!
     pub fn discr_type(&self) -> attr::IntType {
         self.int.unwrap_or(attr::SignedInt(ast::IntTy::Isize))
     }
@@ -2269,6 +2271,7 @@ impl<'tcx> AdtDef {
 
     #[inline]
     pub fn eval_explicit_discr(&self, tcx: TyCtxt<'tcx>, expr_did: DefId) -> Option<Discr<'tcx>> {
+        assert!(self.is_enum());
         let param_env = tcx.param_env(expr_did);
         let repr_type = self.repr.discr_type();
         match tcx.const_eval_poly(expr_did) {
@@ -2305,6 +2308,7 @@ impl<'tcx> AdtDef {
         &'tcx self,
         tcx: TyCtxt<'tcx>,
     ) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> + Captures<'tcx> {
+        assert!(self.is_enum());
         let repr_type = self.repr.discr_type();
         let initial = repr_type.initial_discriminant(tcx);
         let mut prev_discr = None::<Discr<'tcx>>;
@@ -2337,6 +2341,7 @@ impl<'tcx> AdtDef {
         tcx: TyCtxt<'tcx>,
         variant_index: VariantIdx,
     ) -> Discr<'tcx> {
+        assert!(self.is_enum());
         let (val, offset) = self.discriminant_def_for_variant(variant_index);
         let explicit_value = val
             .and_then(|expr_did| self.eval_explicit_discr(tcx, expr_did))
diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs
index ef77d1b5b3f81..f4962ced6c03a 100644
--- a/src/librustc_middle/ty/sty.rs
+++ b/src/librustc_middle/ty/sty.rs
@@ -29,6 +29,7 @@ use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::marker::PhantomData;
 use std::ops::Range;
+use ty::util::IntTypeExt;
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
 #[derive(HashStable, TypeFoldable, Lift)]
@@ -2096,7 +2097,9 @@ impl<'tcx> TyS<'tcx> {
         variant_index: VariantIdx,
     ) -> Option<Discr<'tcx>> {
         match self.kind {
-            TyKind::Adt(adt, _) => Some(adt.discriminant_for_variant(tcx, variant_index)),
+            TyKind::Adt(adt, _) if adt.is_enum() => {
+                Some(adt.discriminant_for_variant(tcx, variant_index))
+            }
             TyKind::Generator(def_id, substs, _) => {
                 Some(substs.as_generator().discriminant_for_variant(def_id, tcx, variant_index))
             }
@@ -2104,6 +2107,18 @@ impl<'tcx> TyS<'tcx> {
         }
     }
 
+    /// Returns the type of the discriminant of this type.
+    pub fn discriminant_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+        match self.kind {
+            ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx),
+            ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx),
+            _ => {
+                // This can only be `0`, for now, so `u8` will suffice.
+                tcx.types.u8
+            }
+        }
+    }
+
     /// When we create a closure, we record its kind (i.e., what trait
     /// it implements) into its `ClosureSubsts` using a type
     /// parameter. This is kind of a phantom type, except that the
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index 5f1c0911da2bf..d0050f801fc6b 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 67254811ec52a..b49e4187fb810 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 402eac47c462b..e04ed8b83debd 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 e19fab89eabfe..727c4d0605e12 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 e912ef7b20202..2240eb81e1fa7 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 a0c1d96bb4743..710f8c0fb9005 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 b820b79c47fe8..1d3733371473b 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 fc4be82ad90ad..115a472cabe5e 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;
@@ -218,15 +220,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             sym::discriminant_value => {
                 let place = self.deref_operand(args[0])?;
                 let discr_val = self.read_discriminant(place.into())?.0;
-                let scalar = match dest.layout.ty.kind {
-                    ty::Int(_) => Scalar::from_int(
-                        self.sign_extend(discr_val, dest.layout) as i128,
-                        dest.layout.size,
-                    ),
-                    ty::Uint(_) => Scalar::from_uint(discr_val, dest.layout.size),
-                    _ => bug!("invalid `discriminant_value` return layout: {:?}", dest.layout),
-                };
-                self.write_scalar(scalar, dest)?;
+                self.write_scalar(discr_val, dest)?;
             }
             sym::unchecked_shl
             | sym::unchecked_shr
@@ -279,7 +273,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 +420,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/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 95bc9810dab80..e359c7795c013 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -7,16 +7,16 @@ use std::fmt::Write;
 use rustc_errors::ErrorReported;
 use rustc_hir::def::Namespace;
 use rustc_macros::HashStable;
-use rustc_middle::ty::layout::{IntegerExt, PrimitiveExt, TyAndLayout};
+use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
 use rustc_middle::ty::Ty;
 use rustc_middle::{mir, ty};
-use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, Integer, LayoutOf, Size};
+use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, LayoutOf, Size};
 use rustc_target::abi::{VariantIdx, Variants};
 
 use super::{
-    from_known_layout, sign_extend, truncate, ConstValue, GlobalId, InterpCx, InterpResult,
-    MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Scalar, ScalarMaybeUninit,
+    from_known_layout, ConstValue, GlobalId, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace,
+    Place, PlaceTy, Pointer, Scalar, ScalarMaybeUninit,
 };
 
 /// An `Immediate` represents a single immediate self-contained Rust value.
@@ -469,6 +469,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             .try_fold(base_op, |op, elem| self.operand_projection(op, elem))?;
 
         trace!("eval_place_to_op: got {:?}", *op);
+        // Sanity-check the type we ended up with.
+        debug_assert_eq!(
+            self.subst_from_current_frame_and_normalize_erasing_regions(
+                place.ty(&self.frame().body.local_decls, *self.tcx).ty
+            ),
+            op.layout.ty,
+        );
         Ok(op)
     }
 
@@ -576,98 +583,113 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Read discriminant, return the runtime value as well as the variant index.
     pub fn read_discriminant(
         &self,
-        rval: OpTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, (u128, VariantIdx)> {
-        trace!("read_discriminant_value {:#?}", rval.layout);
-
-        let (discr_layout, discr_kind, discr_index) = match rval.layout.variants {
+        op: OpTy<'tcx, M::PointerTag>,
+    ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> {
+        trace!("read_discriminant_value {:#?}", op.layout);
+
+        // Get type and layout of the discriminant.
+        let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
+        trace!("discriminant type: {:?}", discr_layout.ty);
+
+        // We use "discriminant" to refer to the value associated with a particular enum variant.
+        // This is not to be confused with its "variant index", which is just determining its position in the
+        // declared list of variants -- they can differ with explicitly assigned discriminants.
+        // We use "tag" to refer to how the discriminant is encoded in memory, which can be either
+        // straight-forward (`DiscriminantKind::Tag`) or with a niche (`DiscriminantKind::Niche`).
+        // Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things
+        // rather confusing.
+        let (tag_scalar_layout, tag_kind, tag_index) = match op.layout.variants {
             Variants::Single { index } => {
-                let discr_val = rval
-                    .layout
-                    .ty
-                    .discriminant_for_variant(*self.tcx, index)
-                    .map_or(u128::from(index.as_u32()), |discr| discr.val);
-                return Ok((discr_val, index));
+                let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) {
+                    Some(discr) => {
+                        // This type actually has discriminants.
+                        assert_eq!(discr.ty, discr_layout.ty);
+                        Scalar::from_uint(discr.val, discr_layout.size)
+                    }
+                    None => {
+                        // On a type without actual discriminants, variant is 0.
+                        assert_eq!(index.as_u32(), 0);
+                        Scalar::from_uint(index.as_u32(), discr_layout.size)
+                    }
+                };
+                return Ok((discr, index));
             }
-            Variants::Multiple { discr: ref discr_layout, ref discr_kind, discr_index, .. } => {
-                (discr_layout, discr_kind, discr_index)
+            Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
+                (discr, discr_kind, discr_index)
             }
         };
 
-        // read raw discriminant value
-        let discr_op = self.operand_field(rval, discr_index)?;
-        let discr_val = self.read_immediate(discr_op)?;
-        let raw_discr = discr_val.to_scalar_or_undef();
-        trace!("discr value: {:?}", raw_discr);
-        // post-process
-        Ok(match *discr_kind {
+        // There are *three* layouts that come into play here:
+        // - The discriminant has a type for typechecking. This is `discr_layout`, and is used for
+        //   the `Scalar` we return.
+        // - The tag (encoded discriminant) has layout `tag_layout`. This is always an integer type,
+        //   and used to interpret the value we read from the tag field.
+        //   For the return value, a cast to `discr_layout` is performed.
+        // - The field storing the tag has a layout, which is very similar to `tag_layout` but
+        //   may be a pointer. This is `tag_val.layout`; we just use it for sanity checks.
+
+        // Get layout for tag.
+        let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
+
+        // Read tag and sanity-check `tag_layout`.
+        let tag_val = self.read_immediate(self.operand_field(op, tag_index)?)?;
+        assert_eq!(tag_layout.size, tag_val.layout.size);
+        assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
+        let tag_val = tag_val.to_scalar()?;
+        trace!("tag value: {:?}", tag_val);
+
+        // Figure out which discriminant and variant this corresponds to.
+        Ok(match *tag_kind {
             DiscriminantKind::Tag => {
-                let bits_discr = raw_discr
-                    .not_undef()
-                    .and_then(|raw_discr| self.force_bits(raw_discr, discr_val.layout.size))
-                    .map_err(|_| err_ub!(InvalidDiscriminant(raw_discr.erase_tag())))?;
-                let real_discr = if discr_val.layout.abi.is_signed() {
-                    // going from layout tag type to typeck discriminant type
-                    // requires first sign extending with the discriminant layout
-                    let sexted = sign_extend(bits_discr, discr_val.layout.size);
-                    // and then zeroing with the typeck discriminant type
-                    let discr_ty = rval
-                        .layout
-                        .ty
-                        .ty_adt_def()
-                        .expect("tagged layout corresponds to adt")
-                        .repr
-                        .discr_type();
-                    let size = Integer::from_attr(self, discr_ty).size();
-                    truncate(sexted, size)
-                } else {
-                    bits_discr
-                };
-                // Make sure we catch invalid discriminants
-                let index = match rval.layout.ty.kind {
+                let tag_bits = self
+                    .force_bits(tag_val, tag_layout.size)
+                    .map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
+                // Cast bits from tag layout to discriminant layout.
+                let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
+                let discr_bits = discr_val_cast.assert_bits(discr_layout.size);
+                // Convert discriminant to variant index, and catch invalid discriminants.
+                let index = match op.layout.ty.kind {
                     ty::Adt(adt, _) => {
-                        adt.discriminants(self.tcx.tcx).find(|(_, var)| var.val == real_discr)
+                        adt.discriminants(self.tcx.tcx).find(|(_, var)| var.val == discr_bits)
                     }
                     ty::Generator(def_id, substs, _) => {
                         let substs = substs.as_generator();
                         substs
                             .discriminants(def_id, self.tcx.tcx)
-                            .find(|(_, var)| var.val == real_discr)
+                            .find(|(_, var)| var.val == discr_bits)
                     }
                     _ => bug!("tagged layout for non-adt non-generator"),
                 }
-                .ok_or_else(|| err_ub!(InvalidDiscriminant(raw_discr.erase_tag())))?;
-                (real_discr, index.0)
+                .ok_or_else(|| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
+                // Return the cast value, and the index.
+                (discr_val_cast, index.0)
             }
             DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => {
+                // Compute the variant this niche value/"tag" corresponds to. With niche layout,
+                // discriminant (encoded in niche/tag) and variant index are the same.
                 let variants_start = niche_variants.start().as_u32();
                 let variants_end = niche_variants.end().as_u32();
-                let raw_discr = raw_discr
-                    .not_undef()
-                    .map_err(|_| err_ub!(InvalidDiscriminant(ScalarMaybeUninit::Uninit)))?;
-                match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) {
+                let variant = match tag_val.to_bits_or_ptr(tag_layout.size, self) {
                     Err(ptr) => {
                         // The niche must be just 0 (which an inbounds pointer value never is)
                         let ptr_valid = niche_start == 0
                             && variants_start == variants_end
                             && !self.memory.ptr_may_be_null(ptr);
                         if !ptr_valid {
-                            throw_ub!(InvalidDiscriminant(raw_discr.erase_tag().into()))
+                            throw_ub!(InvalidDiscriminant(tag_val.erase_tag()))
                         }
-                        (u128::from(dataful_variant.as_u32()), dataful_variant)
+                        dataful_variant
                     }
-                    Ok(raw_discr) => {
+                    Ok(tag_bits) => {
                         // We need to use machine arithmetic to get the relative variant idx:
-                        // variant_index_relative = discr_val - niche_start_val
-                        let discr_layout =
-                            self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?;
-                        let discr_val = ImmTy::from_uint(raw_discr, discr_layout);
-                        let niche_start_val = ImmTy::from_uint(niche_start, discr_layout);
+                        // variant_index_relative = tag_val - niche_start_val
+                        let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
+                        let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
                         let variant_index_relative_val =
-                            self.binary_op(mir::BinOp::Sub, discr_val, niche_start_val)?;
+                            self.binary_op(mir::BinOp::Sub, tag_val, niche_start_val)?;
                         let variant_index_relative = variant_index_relative_val
                             .to_scalar()?
-                            .assert_bits(discr_val.layout.size);
+                            .assert_bits(tag_val.layout.size);
                         // Check if this is in the range that indicates an actual discriminant.
                         if variant_index_relative <= u128::from(variants_end - variants_start) {
                             let variant_index_relative = u32::try_from(variant_index_relative)
@@ -676,7 +698,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                             let variant_index = variants_start
                                 .checked_add(variant_index_relative)
                                 .expect("overflow computing absolute variant idx");
-                            let variants_len = rval
+                            let variants_len = op
                                 .layout
                                 .ty
                                 .ty_adt_def()
@@ -684,12 +706,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                                 .variants
                                 .len();
                             assert!(usize::try_from(variant_index).unwrap() < variants_len);
-                            (u128::from(variant_index), VariantIdx::from_u32(variant_index))
+                            VariantIdx::from_u32(variant_index)
                         } else {
-                            (u128::from(dataful_variant.as_u32()), dataful_variant)
+                            dataful_variant
                         }
                     }
-                }
+                };
+                // Compute the size of the scalar we need to return.
+                // No need to cast, because the variant index directly serves as discriminant and is
+                // encoded in the tag.
+                (Scalar::from_uint(variant.as_u32(), discr_layout.size), variant)
             }
         })
     }
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index dc6967c2c49e5..36765ea7a8c46 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -638,6 +638,13 @@ where
         }
 
         self.dump_place(place_ty.place);
+        // Sanity-check the type we ended up with.
+        debug_assert_eq!(
+            self.subst_from_current_frame_and_normalize_erasing_regions(
+                place.ty(&self.frame().body.local_decls, *self.tcx).ty
+            ),
+            place_ty.layout.ty,
+        );
         Ok(place_ty)
     }
 
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index fd9815975c19f..bd4df788057e2 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -262,8 +262,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Discriminant(place) => {
                 let op = self.eval_place_to_op(place, None)?;
                 let discr_val = self.read_discriminant(op)?.0;
-                let size = dest.layout.size;
-                self.write_scalar(Scalar::from_uint(discr_val, size), dest)?;
+                self.write_scalar(discr_val, dest)?;
             }
         }
 
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index a335fa2de411b..1f01bc0e19513 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
+}
diff --git a/src/librustc_mir_build/build/block.rs b/src/librustc_mir_build/build/block.rs
index fa783ddcf409a..4e4f0dc74cb7c 100644
--- a/src/librustc_mir_build/build/block.rs
+++ b/src/librustc_mir_build/build/block.rs
@@ -4,6 +4,8 @@ use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use crate::hair::*;
 use rustc_hir as hir;
 use rustc_middle::mir::*;
+use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
+use rustc_session::lint::Level;
 use rustc_span::Span;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -217,6 +219,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 assert_eq!(self.push_unsafe_count, 0);
                 match self.unpushed_unsafe {
                     Safety::Safe => {}
+                    // no longer treat `unsafe fn`s as `unsafe` contexts (see RFC #2585)
+                    Safety::FnUnsafe
+                        if self.hir.tcx().lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, hir_id).0
+                            != Level::Allow => {}
                     _ => return,
                 }
                 self.unpushed_unsafe = Safety::ExplicitUnsafe(hir_id);
@@ -231,7 +237,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     .push_unsafe_count
                     .checked_sub(1)
                     .unwrap_or_else(|| span_bug!(span, "unsafe count underflow"));
-                if self.push_unsafe_count == 0 { Some(self.unpushed_unsafe) } else { None }
+                if self.push_unsafe_count == 0 {
+                    Some(self.unpushed_unsafe)
+                } else {
+                    None
+                }
             }
         };
 
diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs
index e55ddc26a9441..7112ac35b082b 100644
--- a/src/librustc_session/lint/builtin.rs
+++ b/src/librustc_session/lint/builtin.rs
@@ -526,6 +526,12 @@ declare_lint! {
     "using only a subset of a register for inline asm inputs",
 }
 
+declare_lint! {
+    pub UNSAFE_OP_IN_UNSAFE_FN,
+    Allow,
+    "unsafe operations in unsafe functions without an explicit unsafe block are deprecated",
+}
+
 declare_lint_pass! {
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// that are used by other parts of the compiler.
@@ -597,6 +603,7 @@ declare_lint_pass! {
         SOFT_UNSTABLE,
         INLINE_NO_SANITIZE,
         ASM_SUB_REGISTER,
+        UNSAFE_OP_IN_UNSAFE_FN,
     ]
 }
 
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index 6a6098710e828..0f2d52c2264fd 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -147,6 +147,7 @@ symbols! {
         Arc,
         Arguments,
         ArgumentV1,
+        arith_offset,
         arm_target_feature,
         asm,
         assert,
@@ -516,6 +517,7 @@ symbols! {
         not,
         note,
         object_safe_for_dispatch,
+        offset,
         Ok,
         omit_gdb_pretty_printer_section,
         on,
@@ -806,6 +808,7 @@ symbols! {
         unmarked_api,
         unreachable_code,
         unrestricted_attribute_tokens,
+        unsafe_block_in_unsafe_fn,
         unsafe_no_drop_flag,
         unsized_locals,
         unsized_tuple_coercion,
diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs
index 774146a679ab8..a18a4dbd3e214 100644
--- a/src/librustc_target/asm/mod.rs
+++ b/src/librustc_target/asm/mod.rs
@@ -60,6 +60,7 @@ macro_rules! def_regs {
             #error = [$($bad_reg:literal),+] => $error:literal,
         )*
     }) => {
+        #[allow(unreachable_code)]
         #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
         #[allow(non_camel_case_types)]
         pub enum $arch_reg {
@@ -102,19 +103,20 @@ macro_rules! def_regs {
         pub(super) fn fill_reg_map(
             _arch: super::InlineAsmArch,
             mut _has_feature: impl FnMut(&str) -> bool,
-            map: &mut rustc_data_structures::fx::FxHashMap<
+            _map: &mut rustc_data_structures::fx::FxHashMap<
                 super::InlineAsmRegClass,
                 rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
             >,
         ) {
+            #[allow(unused_imports)]
             use super::{InlineAsmReg, InlineAsmRegClass};
             $(
                 if $($filter(_arch, &mut _has_feature, true).is_ok() &&)? true {
-                    if let Some(set) = map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
+                    if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
                         set.insert(InlineAsmReg::$arch($arch_reg::$reg));
                     }
                     $(
-                        if let Some(set) = map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
+                        if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
                             set.insert(InlineAsmReg::$arch($arch_reg::$reg));
                         }
                     )*
@@ -146,11 +148,13 @@ macro_rules! types {
 
 mod aarch64;
 mod arm;
+mod nvptx;
 mod riscv;
 mod x86;
 
 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
+pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
 
@@ -162,6 +166,7 @@ pub enum InlineAsmArch {
     AArch64,
     RiscV32,
     RiscV64,
+    Nvptx64,
 }
 
 impl FromStr for InlineAsmArch {
@@ -175,6 +180,7 @@ impl FromStr for InlineAsmArch {
             "aarch64" => Ok(Self::AArch64),
             "riscv32" => Ok(Self::RiscV32),
             "riscv64" => Ok(Self::RiscV64),
+            "nvptx64" => Ok(Self::Nvptx64),
             _ => Err(()),
         }
     }
@@ -196,6 +202,7 @@ pub enum InlineAsmReg {
     Arm(ArmInlineAsmReg),
     AArch64(AArch64InlineAsmReg),
     RiscV(RiscVInlineAsmReg),
+    Nvptx(NvptxInlineAsmReg),
 }
 
 impl InlineAsmReg {
@@ -236,6 +243,9 @@ impl InlineAsmReg {
             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
                 Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, &name)?)
             }
+            InlineAsmArch::Nvptx64 => {
+                Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?)
+            }
         })
     }
 
@@ -281,6 +291,7 @@ pub enum InlineAsmRegClass {
     Arm(ArmInlineAsmRegClass),
     AArch64(AArch64InlineAsmRegClass),
     RiscV(RiscVInlineAsmRegClass),
+    Nvptx(NvptxInlineAsmRegClass),
 }
 
 impl InlineAsmRegClass {
@@ -290,6 +301,7 @@ impl InlineAsmRegClass {
             Self::Arm(r) => r.name(),
             Self::AArch64(r) => r.name(),
             Self::RiscV(r) => r.name(),
+            Self::Nvptx(r) => r.name(),
         }
     }
 
@@ -302,6 +314,7 @@ impl InlineAsmRegClass {
             Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
             Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
             Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
+            Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
         }
     }
 
@@ -321,6 +334,7 @@ impl InlineAsmRegClass {
             Self::Arm(r) => r.suggest_modifier(arch, ty),
             Self::AArch64(r) => r.suggest_modifier(arch, ty),
             Self::RiscV(r) => r.suggest_modifier(arch, ty),
+            Self::Nvptx(r) => r.suggest_modifier(arch, ty),
         }
     }
 
@@ -336,6 +350,7 @@ impl InlineAsmRegClass {
             Self::Arm(r) => r.default_modifier(arch),
             Self::AArch64(r) => r.default_modifier(arch),
             Self::RiscV(r) => r.default_modifier(arch),
+            Self::Nvptx(r) => r.default_modifier(arch),
         }
     }
 
@@ -350,6 +365,7 @@ impl InlineAsmRegClass {
             Self::Arm(r) => r.supported_types(arch),
             Self::AArch64(r) => r.supported_types(arch),
             Self::RiscV(r) => r.supported_types(arch),
+            Self::Nvptx(r) => r.supported_types(arch),
         }
     }
 
@@ -367,6 +383,7 @@ impl InlineAsmRegClass {
                 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
                     Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
                 }
+                InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
             })
         })
     }
@@ -379,6 +396,7 @@ impl InlineAsmRegClass {
             Self::Arm(r) => r.valid_modifiers(arch),
             Self::AArch64(r) => r.valid_modifiers(arch),
             Self::RiscV(r) => r.valid_modifiers(arch),
+            Self::Nvptx(r) => r.valid_modifiers(arch),
         }
     }
 }
@@ -518,5 +536,10 @@ pub fn allocatable_registers(
             riscv::fill_reg_map(arch, has_feature, &mut map);
             map
         }
+        InlineAsmArch::Nvptx64 => {
+            let mut map = nvptx::regclass_map();
+            nvptx::fill_reg_map(arch, has_feature, &mut map);
+            map
+        }
     }
 }
diff --git a/src/librustc_target/asm/nvptx.rs b/src/librustc_target/asm/nvptx.rs
new file mode 100644
index 0000000000000..43d16ae0f5d10
--- /dev/null
+++ b/src/librustc_target/asm/nvptx.rs
@@ -0,0 +1,49 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+
+def_reg_class! {
+    Nvptx NvptxInlineAsmRegClass {
+        reg16,
+        reg32,
+        reg64,
+    }
+}
+
+impl NvptxInlineAsmRegClass {
+    pub fn valid_modifiers(self, _arch: InlineAsmArch) -> &'static [char] {
+        &[]
+    }
+
+    pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+        None
+    }
+
+    pub fn suggest_modifier(
+        self,
+        _arch: InlineAsmArch,
+        _ty: InlineAsmType,
+    ) -> Option<(char, &'static str)> {
+        None
+    }
+
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+        None
+    }
+
+    pub fn supported_types(
+        self,
+        _arch: InlineAsmArch,
+    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+        match self {
+            Self::reg16 => types! { _: I8, I16; },
+            Self::reg32 => types! { _: I8, I16, I32, F32; },
+            Self::reg64 => types! { _: I8, I16, I32, F32, I64, F64; },
+        }
+    }
+}
+
+def_regs! {
+    // Registers in PTX are declared in the assembly.
+    // There are no predefined registers that one can use.
+    Nvptx NvptxInlineAsmReg NvptxInlineAsmRegClass {}
+}
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index df17231633ebe..c9558879a1c6e 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -856,6 +856,8 @@ pub struct TargetOptions {
     /// the functions in the executable are not randomized and can be used
     /// during an exploit of a vulnerability in any code.
     pub position_independent_executables: bool,
+    /// Executables that are both statically linked and position-independent are supported.
+    pub static_position_independent_executables: bool,
     /// Determines if the target always requires using the PLT for indirect
     /// library calls or not. This controls the default value of the `-Z plt` flag.
     pub needs_plt: bool,
@@ -1029,6 +1031,7 @@ impl Default for TargetOptions {
             has_rpath: false,
             no_default_libraries: true,
             position_independent_executables: false,
+            static_position_independent_executables: false,
             needs_plt: false,
             relro_level: RelroLevel::None,
             pre_link_objects: Default::default(),
@@ -1433,6 +1436,7 @@ impl Target {
         key!(has_rpath, bool);
         key!(no_default_libraries, bool);
         key!(position_independent_executables, bool);
+        key!(static_position_independent_executables, bool);
         key!(needs_plt, bool);
         key!(relro_level, RelroLevel)?;
         key!(archive_format);
@@ -1664,6 +1668,7 @@ impl ToJson for Target {
         target_option_val!(has_rpath);
         target_option_val!(no_default_libraries);
         target_option_val!(position_independent_executables);
+        target_option_val!(static_position_independent_executables);
         target_option_val!(needs_plt);
         target_option_val!(relro_level);
         target_option_val!(archive_format);
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index bf59b3f25734d..99ca7084c30dd 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -226,6 +226,11 @@ where
 {
     let warnings_lint_name = lint::builtin::WARNINGS.name;
 
+    // Whitelist feature-gated lints to avoid feature errors when trying to
+    // allow all lints.
+    // FIXME(#72694): handle feature-gated lints properly.
+    let unsafe_op_in_unsafe_fn_name = rustc_lint::builtin::UNSAFE_OP_IN_UNSAFE_FN.name;
+
     whitelisted_lints.push(warnings_lint_name.to_owned());
     whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
 
@@ -236,7 +241,13 @@ where
     };
 
     let lint_opts = lints()
-        .filter_map(|lint| if lint.name == warnings_lint_name { None } else { filter_call(lint) })
+        .filter_map(|lint| {
+            if lint.name == warnings_lint_name || lint.name == unsafe_op_in_unsafe_fn_name {
+                None
+            } else {
+                filter_call(lint)
+            }
+        })
         .chain(lint_opts.into_iter())
         .collect::<Vec<_>>();
 
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
index 6e2478b8308af..0f0be2c488314 100644
--- a/src/libstd/net/ip.rs
+++ b/src/libstd/net/ip.rs
@@ -7,9 +7,9 @@
 )]
 
 use crate::cmp::Ordering;
-use crate::fmt;
+use crate::fmt::{self, Write as FmtWrite};
 use crate::hash;
-use crate::io::Write;
+use crate::io::Write as IoWrite;
 use crate::sys::net::netc as c;
 use crate::sys_common::{AsInner, FromInner};
 
@@ -1532,102 +1532,100 @@ impl Ipv6Addr {
     }
 }
 
+/// Write an Ipv6Addr, conforming to the canonical style described by
+/// [RFC 5952](https://tools.ietf.org/html/rfc5952).
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for Ipv6Addr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // Note: The calls to write should never fail, hence the unwraps in the function
-        // Long enough for the longest possible IPv6: 39
-        const IPV6_BUF_LEN: usize = 39;
-        let mut buf = [0u8; IPV6_BUF_LEN];
-        let mut buf_slice = &mut buf[..];
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // If there are no alignment requirements, write out the IP address to
+        // f. Otherwise, write it to a local buffer, then use f.pad.
+        if f.precision().is_none() && f.width().is_none() {
+            let segments = self.segments();
+
+            // Special case for :: and ::1; otherwise they get written with the
+            // IPv4 formatter
+            if self.is_unspecified() {
+                f.write_str("::")
+            } else if self.is_loopback() {
+                f.write_str("::1")
+            } else if let Some(ipv4) = self.to_ipv4() {
+                match segments[5] {
+                    // IPv4 Compatible address
+                    0 => write!(f, "::{}", ipv4),
+                    // IPv4 Mapped address
+                    0xffff => write!(f, "::ffff:{}", ipv4),
+                    _ => unreachable!(),
+                }
+            } else {
+                #[derive(Copy, Clone, Default)]
+                struct Span {
+                    start: usize,
+                    len: usize,
+                }
 
-        match self.segments() {
-            // We need special cases for :: and ::1, otherwise they're formatted
-            // as ::0.0.0.[01]
-            [0, 0, 0, 0, 0, 0, 0, 0] => write!(buf_slice, "::").unwrap(),
-            [0, 0, 0, 0, 0, 0, 0, 1] => write!(buf_slice, "::1").unwrap(),
-            // Ipv4 Compatible address
-            [0, 0, 0, 0, 0, 0, g, h] => {
-                write!(
-                    buf_slice,
-                    "::{}.{}.{}.{}",
-                    (g >> 8) as u8,
-                    g as u8,
-                    (h >> 8) as u8,
-                    h as u8
-                )
-                .unwrap();
-            }
-            // Ipv4-Mapped address
-            [0, 0, 0, 0, 0, 0xffff, g, h] => {
-                write!(
-                    buf_slice,
-                    "::ffff:{}.{}.{}.{}",
-                    (g >> 8) as u8,
-                    g as u8,
-                    (h >> 8) as u8,
-                    h as u8
-                )
-                .unwrap();
-            }
-            _ => {
-                fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) {
-                    let mut longest_span_len = 0;
-                    let mut longest_span_at = 0;
-                    let mut cur_span_len = 0;
-                    let mut cur_span_at = 0;
-
-                    for i in 0..8 {
-                        if segments[i] == 0 {
-                            if cur_span_len == 0 {
-                                cur_span_at = i;
+                // Find the inner 0 span
+                let zeroes = {
+                    let mut longest = Span::default();
+                    let mut current = Span::default();
+
+                    for (i, &segment) in segments.iter().enumerate() {
+                        if segment == 0 {
+                            if current.len == 0 {
+                                current.start = i;
                             }
 
-                            cur_span_len += 1;
+                            current.len += 1;
 
-                            if cur_span_len > longest_span_len {
-                                longest_span_len = cur_span_len;
-                                longest_span_at = cur_span_at;
+                            if current.len > longest.len {
+                                longest = current;
                             }
                         } else {
-                            cur_span_len = 0;
-                            cur_span_at = 0;
+                            current = Span::default();
                         }
                     }
 
-                    (longest_span_at, longest_span_len)
-                }
-
-                let (zeros_at, zeros_len) = find_zero_slice(&self.segments());
-
-                if zeros_len > 1 {
-                    fn fmt_subslice(segments: &[u16], buf: &mut &mut [u8]) {
-                        if !segments.is_empty() {
-                            write!(*buf, "{:x}", segments[0]).unwrap();
-                            for &seg in &segments[1..] {
-                                write!(*buf, ":{:x}", seg).unwrap();
-                            }
+                    longest
+                };
+
+                /// Write a colon-separated part of the address
+                #[inline]
+                fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result {
+                    if let Some(first) = chunk.first() {
+                        fmt::LowerHex::fmt(first, f)?;
+                        for segment in &chunk[1..] {
+                            f.write_char(':')?;
+                            fmt::LowerHex::fmt(segment, f)?;
                         }
                     }
+                    Ok(())
+                }
 
-                    fmt_subslice(&self.segments()[..zeros_at], &mut buf_slice);
-                    write!(buf_slice, "::").unwrap();
-                    fmt_subslice(&self.segments()[zeros_at + zeros_len..], &mut buf_slice);
+                if zeroes.len > 1 {
+                    fmt_subslice(f, &segments[..zeroes.start])?;
+                    f.write_str("::")?;
+                    fmt_subslice(f, &segments[zeroes.start + zeroes.len..])
                 } else {
-                    let &[a, b, c, d, e, f, g, h] = &self.segments();
-                    write!(
-                        buf_slice,
-                        "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
-                        a, b, c, d, e, f, g, h
-                    )
-                    .unwrap();
+                    fmt_subslice(f, &segments)
                 }
             }
+        } else {
+            // Slow path: write the address to a local buffer, the use f.pad.
+            // Defined recursively by using the fast path to write to the
+            // buffer.
+
+            // This is the largest possible size of an IPv6 address
+            const IPV6_BUF_LEN: usize = (4 * 8) + 7;
+            let mut buf = [0u8; IPV6_BUF_LEN];
+            let mut buf_slice = &mut buf[..];
+
+            // Note: This call to write should never fail, so unwrap is okay.
+            write!(buf_slice, "{}", self).unwrap();
+            let len = IPV6_BUF_LEN - buf_slice.len();
+
+            // This is safe because we know exactly what can be in this buffer
+            let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
+            f.pad(buf)
         }
-        let len = IPV6_BUF_LEN - buf_slice.len();
-        // This is safe because we know exactly what can be in this buffer
-        let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
-        fmt.pad(buf)
     }
 }
 
diff --git a/src/test/assembly/asm/nvptx-types.rs b/src/test/assembly/asm/nvptx-types.rs
new file mode 100644
index 0000000000000..4ee79d1bcc839
--- /dev/null
+++ b/src/test/assembly/asm/nvptx-types.rs
@@ -0,0 +1,133 @@
+// no-system-llvm
+// assembly-output: emit-asm
+// compile-flags: --target nvptx64-nvidia-cuda
+// compile-flags: --crate-type cdylib
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! concat {
+    () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+type ptr = *mut u8;
+
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for f32 {}
+impl Copy for i64 {}
+impl Copy for f64 {}
+impl Copy for ptr {}
+
+// NVPTX does not support static variables
+#[no_mangle]
+fn extern_func() {}
+
+// CHECK-LABEL: .visible .func sym_fn()
+// CHECK: // begin inline asm
+// CHECK: call extern_func;
+// CHECK: // end inline asm
+#[no_mangle]
+pub unsafe fn sym_fn() {
+    asm!("call {};", sym extern_func);
+}
+
+macro_rules! check {
+    ($func:ident $ty:ident $class:ident $mov:literal) => {
+        #[no_mangle]
+        pub unsafe fn $func(x: $ty) -> $ty {
+            let y;
+            asm!(concat!($mov, " {}, {};"), out($class) y, in($class) x);
+            y
+        }
+    };
+}
+
+// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg16_i8
+// CHECK: // begin inline asm
+// CHECK: mov.i16 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg16_i8 i8 reg16 "mov.i16");
+
+// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg16_i16
+// CHECK: // begin inline asm
+// CHECK: mov.i16 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg16_i16 i16 reg16 "mov.i16");
+
+// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i8
+// CHECK: // begin inline asm
+// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg32_i8 i8 reg32 "mov.i32");
+
+// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i16
+// CHECK: // begin inline asm
+// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg32_i16 i16 reg32 "mov.i32");
+
+// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i32
+// CHECK: // begin inline asm
+// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg32_i32 i32 reg32 "mov.i32");
+
+// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_f32
+// CHECK: // begin inline asm
+// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg32_f32 f32 reg32 "mov.i32");
+
+// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i8
+// CHECK: // begin inline asm
+// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg64_i8 i8 reg64 "mov.i64");
+
+// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i16
+// CHECK: // begin inline asm
+// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg64_i16 i16 reg64 "mov.i64");
+
+// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i32
+// CHECK: // begin inline asm
+// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg64_i32 i32 reg64 "mov.i64");
+
+// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_f32
+// CHECK: // begin inline asm
+// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg64_f32 f32 reg64 "mov.i64");
+
+// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_i64
+// CHECK: // begin inline asm
+// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg64_i64 i64 reg64 "mov.i64");
+
+// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_f64
+// CHECK: // begin inline asm
+// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg64_f64 f64 reg64 "mov.i64");
+
+// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_ptr
+// CHECK: // begin inline asm
+// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}};
+// CHECK: // end inline asm
+check!(reg64_ptr ptr reg64 "mov.i64");
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
index 3e39c8a792446..137cb83ccd327 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
@@ -14,16 +14,16 @@ note: ...so that the expression is assignable
    |
 LL |    bar(foo, x)
    |             ^
-   = note: expected  `Type<'_>`
-              found  `Type<'a>`
+   = note: expected `Type<'_>`
+              found `Type<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the expression is assignable
   --> $DIR/project-fn-ret-invariant.rs:48:4
    |
 LL |    bar(foo, x)
    |    ^^^^^^^^^^^
-   = note: expected  `Type<'static>`
-              found  `Type<'_>`
+   = note: expected `Type<'static>`
+              found `Type<'_>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.rs b/src/test/ui/consts/miri_unleashed/ptr_arith.rs
index 81985f9f625a5..65fc49c0b27a6 100644
--- a/src/test/ui/consts/miri_unleashed/ptr_arith.rs
+++ b/src/test/ui/consts/miri_unleashed/ptr_arith.rs
@@ -2,8 +2,7 @@
 #![feature(core_intrinsics)]
 #![allow(const_err)]
 
-// A test demonstrating that we prevent doing even trivial
-// pointer arithmetic or comparison during CTFE.
+// During CTFE, we prevent pointer comparison and pointer-to-int casts.
 
 static CMP: () = {
     let x = &0 as *const _;
@@ -19,11 +18,4 @@ static INT_PTR_ARITH: () = unsafe {
     //~| NOTE pointer-to-integer cast
 };
 
-static PTR_ARITH: () = unsafe {
-    let x = &0 as *const _;
-    let _v = core::intrinsics::offset(x, 0);
-    //~^ ERROR could not evaluate static initializer
-    //~| NOTE calling intrinsic `offset`
-};
-
 fn main() {}
diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
index 5bd534a16b863..805ba9c6b0307 100644
--- a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
+++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
@@ -1,39 +1,28 @@
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ptr_arith.rs:10:14
+  --> $DIR/ptr_arith.rs:9:14
    |
 LL |     let _v = x == x;
    |              ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ptr_arith.rs:17:14
+  --> $DIR/ptr_arith.rs:16:14
    |
 LL |     let _v = x + 0;
    |              ^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
 
-error[E0080]: could not evaluate static initializer
-  --> $DIR/ptr_arith.rs:24:14
-   |
-LL |     let _v = core::intrinsics::offset(x, 0);
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "calling intrinsic `offset`" needs an rfc before being allowed inside constants
-
 warning: skipping const checks
    |
 help: skipping check for `const_compare_raw_pointers` feature
-  --> $DIR/ptr_arith.rs:10:14
+  --> $DIR/ptr_arith.rs:9:14
    |
 LL |     let _v = x == x;
    |              ^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/ptr_arith.rs:16:20
+  --> $DIR/ptr_arith.rs:15:20
    |
 LL |     let x: usize = std::mem::transmute(&0);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check that does not even have a feature gate
-  --> $DIR/ptr_arith.rs:24:14
-   |
-LL |     let _v = core::intrinsics::offset(x, 0);
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/offset.rs b/src/test/ui/consts/offset.rs
new file mode 100644
index 0000000000000..f64242d568e31
--- /dev/null
+++ b/src/test/ui/consts/offset.rs
@@ -0,0 +1,115 @@
+// run-pass
+#![feature(const_ptr_offset)]
+#![feature(const_ptr_offset_from)]
+#![feature(ptr_offset_from)]
+use std::ptr;
+
+#[repr(C)]
+struct Struct {
+    a: u32,
+    b: u32,
+    c: u32,
+}
+static S: Struct = Struct { a: 0, b: 0, c: 0 };
+
+// For these tests we use offset_from to check that two pointers are equal.
+// Rust doesn't currently support comparing pointers in const fn.
+
+static OFFSET_NO_CHANGE: bool = unsafe {
+    let p1 = &S.b as *const u32;
+    let p2 = p1.offset(2).offset(-2);
+    p1.offset_from(p2) == 0
+};
+static OFFSET_MIDDLE: bool = unsafe {
+    let p1 = (&S.a as *const u32).offset(1);
+    let p2 = (&S.c as *const u32).offset(-1);
+    p1.offset_from(p2) == 0
+};
+// Pointing to the end of the allocation is OK
+static OFFSET_END: bool = unsafe {
+    let p1 = (&S.a as *const u32).offset(3);
+    let p2 = (&S.c as *const u32).offset(1);
+    p1.offset_from(p2) == 0
+};
+// Casting though a differently sized type is OK
+static OFFSET_U8_PTR: bool = unsafe {
+    let p1 = (&S.a as *const u32 as *const u8).offset(5);
+    let p2 = (&S.c as *const u32 as *const u8).offset(-3);
+    p1.offset_from(p2) == 0
+};
+// Any offset with a ZST does nothing
+const OFFSET_ZST: bool = unsafe {
+    let pz = &() as *const ();
+    // offset_from can't work with ZSTs, so cast to u8 ptr
+    let p1 = pz.offset(5) as *const u8;
+    let p2 = pz.offset(isize::MIN) as *const u8;
+    p1.offset_from(p2) == 0
+};
+const OFFSET_ZERO: bool = unsafe {
+    let p = [0u8; 0].as_ptr();
+    p.offset(0).offset_from(p) == 0
+};
+const OFFSET_ONE: bool = unsafe {
+    let p = &42u32 as *const u32;
+    p.offset(1).offset_from(p) == 1
+};
+const OFFSET_DANGLING: bool = unsafe {
+    let p = ptr::NonNull::<u8>::dangling().as_ptr();
+    p.offset(0).offset_from(p) == 0
+};
+const OFFSET_UNALIGNED: bool = unsafe {
+    let arr = [0u8; 32];
+    let p1 = arr.as_ptr();
+    let p2 = (p1.offset(2) as *const u32).offset(1);
+    (p2 as *const u8).offset_from(p1) == 6
+};
+
+const WRAP_OFFSET_NO_CHANGE: bool = unsafe {
+    let p1 = &42u32 as *const u32;
+    let p2 = p1.wrapping_offset(1000).wrapping_offset(-1000);
+    let p3 = p1.wrapping_offset(-1000).wrapping_offset(1000);
+    (p1.offset_from(p2) == 0) & (p1.offset_from(p3) == 0)
+};
+const WRAP_ADDRESS_SPACE: bool = unsafe {
+    let p1 = &42u8 as *const u8;
+    let p2 = p1.wrapping_offset(isize::MIN).wrapping_offset(isize::MIN);
+    p1.offset_from(p2) == 0
+};
+// Wrap on the count*size_of::<T>() calculation.
+const WRAP_SIZE_OF: bool = unsafe {
+    // Make sure that if p1 moves backwards, we are still in range
+    let arr = [0u32; 2];
+    let p = &arr[1] as *const u32;
+    // With wrapping arithmetic, isize::MAX * 4 == -4
+    let wrapped = p.wrapping_offset(isize::MAX);
+    let backward = p.wrapping_offset(-1);
+    wrapped.offset_from(backward) == 0
+};
+const WRAP_INTEGER_POINTER: bool = unsafe {
+    let p1 = (0x42 as *const u32).wrapping_offset(4);
+    let p2 = 0x52 as *const u32;
+    p1.offset_from(p2) == 0
+};
+const WRAP_NULL: bool = unsafe {
+    let p1 = ptr::null::<u32>().wrapping_offset(1);
+    let p2 = 0x4 as *const u32;
+    p1.offset_from(p2) == 0
+};
+
+fn main() {
+    assert!(OFFSET_NO_CHANGE);
+    assert!(OFFSET_MIDDLE);
+    assert!(OFFSET_END);
+    assert!(OFFSET_U8_PTR);
+    assert!(OFFSET_ZST);
+    assert!(OFFSET_ZERO);
+    assert!(OFFSET_ONE);
+    assert!(OFFSET_DANGLING);
+    assert!(OFFSET_UNALIGNED);
+
+    assert!(WRAP_OFFSET_NO_CHANGE);
+    assert!(WRAP_ADDRESS_SPACE);
+    assert!(WRAP_SIZE_OF);
+    assert!(WRAP_INTEGER_POINTER);
+    assert!(WRAP_NULL);
+}
diff --git a/src/test/ui/consts/offset_ub.rs b/src/test/ui/consts/offset_ub.rs
new file mode 100644
index 0000000000000..4f943ed9ad194
--- /dev/null
+++ b/src/test/ui/consts/offset_ub.rs
@@ -0,0 +1,25 @@
+// ignore-tidy-linelength
+#![feature(const_ptr_offset)]
+use std::ptr;
+
+// normalize-stderr-test "alloc\d+" -> "allocN"
+
+pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~NOTE
+pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~NOTE
+pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~NOTE
+
+pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~NOTE
+pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~NOTE
+pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; //~NOTE
+pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; //~NOTE
+
+pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~NOTE
+pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) }; //~NOTE
+
+// Right now, a zero offset from null is UB
+pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) }; //~NOTE
+
+// Make sure that we don't panic when computing abs(offset*size_of::<T>())
+pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; //~NOTE
+
+fn main() {}
diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr
new file mode 100644
index 0000000000000..0ab81cc0c5b31
--- /dev/null
+++ b/src/test/ui/consts/offset_ub.stderr
@@ -0,0 +1,169 @@
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |
+LL |         intrinsics::offset(self, count)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         overflowing in-bounds pointer arithmetic
+   |         inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |         inside `BEFORE_START` at $DIR/offset_ub.rs:7:46
+   | 
+  ::: $DIR/offset_ub.rs:7:1
+   |
+LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) };
+   | ------------------------------------------------------------------------------
+   |
+   = note: `#[deny(const_err)]` on by default
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |
+LL |         intrinsics::offset(self, count)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         inbounds test failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1
+   |         inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |         inside `AFTER_END` at $DIR/offset_ub.rs:8:43
+   | 
+  ::: $DIR/offset_ub.rs:8:1
+   |
+LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) };
+   | --------------------------------------------------------------------------
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |
+LL |         intrinsics::offset(self, count)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         inbounds test failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100
+   |         inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |         inside `AFTER_ARRAY` at $DIR/offset_ub.rs:9:45
+   | 
+  ::: $DIR/offset_ub.rs:9:1
+   |
+LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) };
+   | ------------------------------------------------------------------------------
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |
+LL |         intrinsics::offset(self, count)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         overflowing in-bounds pointer arithmetic
+   |         inside `std::ptr::const_ptr::<impl *const u16>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |         inside `OVERFLOW` at $DIR/offset_ub.rs:11:43
+   | 
+  ::: $DIR/offset_ub.rs:11:1
+   |
+LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) };
+   | ----------------------------------------------------------------------------------
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |
+LL |         intrinsics::offset(self, count)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         overflowing in-bounds pointer arithmetic
+   |         inside `std::ptr::const_ptr::<impl *const u16>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |         inside `UNDERFLOW` at $DIR/offset_ub.rs:12:44
+   | 
+  ::: $DIR/offset_ub.rs:12:1
+   |
+LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) };
+   | -----------------------------------------------------------------------------------
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |
+LL |         intrinsics::offset(self, count)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         overflowing in-bounds pointer arithmetic
+   |         inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |         inside `OVERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:13:56
+   | 
+  ::: $DIR/offset_ub.rs:13:1
+   |
+LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) };
+   | ---------------------------------------------------------------------------------------------
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |
+LL |         intrinsics::offset(self, count)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         overflowing in-bounds pointer arithmetic
+   |         inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |         inside `UNDERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:14:57
+   | 
+  ::: $DIR/offset_ub.rs:14:1
+   |
+LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) };
+   | --------------------------------------------------------------------------------------
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |
+LL |         intrinsics::offset(self, count)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         inbounds test failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0
+   |         inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |         inside `ZERO_SIZED_ALLOC` at $DIR/offset_ub.rs:16:50
+   | 
+  ::: $DIR/offset_ub.rs:16:1
+   |
+LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) };
+   | -------------------------------------------------------------------------------
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL
+   |
+LL |         intrinsics::offset(self, count) as *mut T
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         unable to turn bytes into a pointer
+   |         inside `std::ptr::mut_ptr::<impl *mut u8>::offset` at $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL
+   |         inside `DANGLING` at $DIR/offset_ub.rs:17:42
+   | 
+  ::: $DIR/offset_ub.rs:17:1
+   |
+LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) };
+   | ---------------------------------------------------------------------------------------------
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |
+LL |         intrinsics::offset(self, count)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         inbounds test failed: 0x0 is not a valid pointer
+   |         inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |         inside `NULL_OFFSET_ZERO` at $DIR/offset_ub.rs:20:50
+   | 
+  ::: $DIR/offset_ub.rs:20:1
+   |
+LL | pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) };
+   | -------------------------------------------------------------------------------
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |
+LL |         intrinsics::offset(self, count)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         unable to turn bytes into a pointer
+   |         inside `std::ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
+   |         inside `UNDERFLOW_ABS` at $DIR/offset_ub.rs:23:47
+   | 
+  ::: $DIR/offset_ub.rs:23:1
+   |
+LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) };
+   | ---------------------------------------------------------------------------------------------
+
+error: aborting due to 11 previous errors
+
diff --git a/src/test/ui/error-codes/E0490.stderr b/src/test/ui/error-codes/E0490.stderr
index 03fce213605e3..9ba5bc330ea93 100644
--- a/src/test/ui/error-codes/E0490.stderr
+++ b/src/test/ui/error-codes/E0490.stderr
@@ -58,8 +58,8 @@ note: ...so that the expression is assignable
    |
 LL |     let x: &'a _ = &y;
    |                    ^^
-   = note: expected  `&'a &()`
-              found  `&'a &'b ()`
+   = note: expected `&'a &()`
+              found `&'a &'b ()`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 1:6...
   --> $DIR/E0490.rs:1:6
    |
diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs
new file mode 100644
index 0000000000000..61e512a12a18d
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs
@@ -0,0 +1,6 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+//~^ ERROR the `unsafe_op_in_unsafe_fn` lint is unstable
+//~| ERROR the `unsafe_op_in_unsafe_fn` lint is unstable
+//~| ERROR the `unsafe_op_in_unsafe_fn` lint is unstable
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr
new file mode 100644
index 0000000000000..c5cad4a98d9ca
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr
@@ -0,0 +1,30 @@
+error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable
+  --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1
+   |
+LL | #![deny(unsafe_op_in_unsafe_fn)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #71668 <https://github.com/rust-lang/rust/issues/71668> for more information
+   = help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable
+
+error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable
+  --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1
+   |
+LL | #![deny(unsafe_op_in_unsafe_fn)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #71668 <https://github.com/rust-lang/rust/issues/71668> for more information
+   = help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable
+
+error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable
+  --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1
+   |
+LL | #![deny(unsafe_op_in_unsafe_fn)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #71668 <https://github.com/rust-lang/rust/issues/71668> for more information
+   = help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
index 3300293bb36ca..268008c211129 100644
--- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
+++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
@@ -14,16 +14,16 @@ note: ...so that the expression is assignable
    |
 LL |     static_val(x);
    |                ^
-   = note: expected  `std::boxed::Box<dyn std::fmt::Debug>`
-              found  `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
+   = note: expected `std::boxed::Box<dyn std::fmt::Debug>`
+              found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the types are compatible
   --> $DIR/dyn-trait.rs:20:5
    |
 LL |     static_val(x);
    |     ^^^^^^^^^^
-   = note: expected  `StaticTrait`
-              found  `StaticTrait`
+   = note: expected `StaticTrait`
+              found `StaticTrait`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
index c1c4ec9ed7b92..b93d98ca39f47 100644
--- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
+++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
@@ -2,15 +2,17 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/mismatched_trait_impl-2.rs:8:5
    |
 LL |     fn deref(&self) -> &dyn Trait {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Struct) -> &dyn Trait
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Struct) -> &dyn Trait`
    | 
   ::: $SRC_DIR/libcore/ops/deref.rs:LL:COL
    |
 LL |     fn deref(&self) -> &Self::Target;
-   |     --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static)
+   |     --------------------------------- expected `fn(&Struct) -> &(dyn Trait + 'static)`
    |
    = note: expected `fn(&Struct) -> &(dyn Trait + 'static)`
               found `fn(&Struct) -> &dyn Trait`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
index c245d78ae828f..149c2aeb958c0 100644
--- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
+++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
@@ -2,13 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/mismatched_trait_impl.rs:9:5
    |
 LL |     fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
-   |     ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32
+   |     ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
 ...
 LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
    |
    = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
               found `fn(&i32, &u32, &u32) -> &u32`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
index 15891c9e7a62d..9a0bd827850cf 100644
--- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
+++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
@@ -2,13 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/mismatched_trait_impl.rs:9:5
    |
 LL |     fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
-   |     ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32
+   |     ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
 ...
 LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
    |
    = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
               found `fn(&i32, &u32, &u32) -> &u32`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
 error[E0623]: lifetime mismatch
   --> $DIR/mismatched_trait_impl.rs:10:9
diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr
index 99700f2084e4a..4f65833075814 100644
--- a/src/test/ui/issues/issue-16683.stderr
+++ b/src/test/ui/issues/issue-16683.stderr
@@ -26,8 +26,8 @@ note: ...so that the types are compatible
    |
 LL |         self.a();
    |              ^
-   = note: expected  `&'a Self`
-              found  `&Self`
+   = note: expected `&'a Self`
+              found `&Self`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr
index adfc3f5085826..31788cfa61c4c 100644
--- a/src/test/ui/issues/issue-17758.stderr
+++ b/src/test/ui/issues/issue-17758.stderr
@@ -27,8 +27,8 @@ note: ...so that the types are compatible
    |
 LL |         self.foo();
    |              ^^^
-   = note: expected  `&'a Self`
-              found  `&Self`
+   = note: expected `&'a Self`
+              found `&Self`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr
index a785a956ca9f5..e7c1dcc5d698c 100644
--- a/src/test/ui/issues/issue-20831-debruijn.stderr
+++ b/src/test/ui/issues/issue-20831-debruijn.stderr
@@ -87,8 +87,8 @@ note: ...so that the types are compatible
    |
 LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `Publisher<'_>`
-              found  `Publisher<'_>`
+   = note: expected `Publisher<'_>`
+              found `Publisher<'_>`
 
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
   --> $DIR/issue-20831-debruijn.rs:28:33
@@ -117,8 +117,8 @@ note: ...so that the types are compatible
    |
 LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `Publisher<'_>`
-              found  `Publisher<'_>`
+   = note: expected `Publisher<'_>`
+              found `Publisher<'_>`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issues/issue-52213.stderr b/src/test/ui/issues/issue-52213.stderr
index a8960f7756367..7463af9332a76 100644
--- a/src/test/ui/issues/issue-52213.stderr
+++ b/src/test/ui/issues/issue-52213.stderr
@@ -14,8 +14,8 @@ note: ...so that the types are compatible
    |
 LL |     match (&t,) {
    |           ^^^^^
-   = note: expected  `(&&(T,),)`
-              found  `(&&'a (T,),)`
+   = note: expected `(&&(T,),)`
+              found `(&&'a (T,),)`
 note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 1:27...
   --> $DIR/issue-52213.rs:1:27
    |
diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr
index b8cafdc5c14b5..6bfb7af54446d 100644
--- a/src/test/ui/issues/issue-55796.stderr
+++ b/src/test/ui/issues/issue-55796.stderr
@@ -20,8 +20,8 @@ note: ...so that the expression is assignable
    |
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
-              found  `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
+   = note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
+              found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/issue-55796.rs:21:9
@@ -45,8 +45,8 @@ note: ...so that the expression is assignable
    |
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
-              found  `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
+   = note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
+              found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr
index d07f305954b6e..060e6954403c0 100644
--- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr
+++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr
@@ -2,13 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/lifetime-mismatch-between-trait-and-impl.rs:6:5
    |
 LL |     fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32;
-   |     ------------------------------------------- expected fn(&i32, &'a i32) -> &'a i32
+   |     ------------------------------------------- expected `fn(&i32, &'a i32) -> &'a i32`
 ...
 LL |     fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &i32) -> &i32`
    |
    = note: expected `fn(&i32, &'a i32) -> &'a i32`
               found `fn(&i32, &i32) -> &i32`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-55394.stderr b/src/test/ui/nll/issue-55394.stderr
index 69a6ab004fd91..ba8d91b8455bf 100644
--- a/src/test/ui/nll/issue-55394.stderr
+++ b/src/test/ui/nll/issue-55394.stderr
@@ -26,8 +26,8 @@ note: ...so that the expression is assignable
    |
 LL |         Foo { bar }
    |         ^^^^^^^^^^^
-   = note: expected  `Foo<'_>`
-              found  `Foo<'_>`
+   = note: expected `Foo<'_>`
+              found `Foo<'_>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/normalization-bounds-error.stderr b/src/test/ui/nll/normalization-bounds-error.stderr
index 58f206742f4f5..d003acd879a77 100644
--- a/src/test/ui/nll/normalization-bounds-error.stderr
+++ b/src/test/ui/nll/normalization-bounds-error.stderr
@@ -19,8 +19,8 @@ note: ...so that the types are compatible
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `Visitor<'d>`
-              found  `Visitor<'_>`
+   = note: expected `Visitor<'d>`
+              found `Visitor<'_>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr
index 5191deca281cc..3317aae83bb08 100644
--- a/src/test/ui/nll/type-alias-free-regions.stderr
+++ b/src/test/ui/nll/type-alias-free-regions.stderr
@@ -16,8 +16,8 @@ note: ...so that the expression is assignable
    |
 LL |         C { f: b }
    |                ^
-   = note: expected  `std::boxed::Box<std::boxed::Box<&isize>>`
-              found  `std::boxed::Box<std::boxed::Box<&isize>>`
+   = note: expected `std::boxed::Box<std::boxed::Box<&isize>>`
+              found `std::boxed::Box<std::boxed::Box<&isize>>`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6...
   --> $DIR/type-alias-free-regions.rs:15:6
    |
@@ -28,8 +28,8 @@ note: ...so that the expression is assignable
    |
 LL |         C { f: b }
    |         ^^^^^^^^^^
-   = note: expected  `C<'a>`
-              found  `C<'_>`
+   = note: expected `C<'a>`
+              found `C<'_>`
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/type-alias-free-regions.rs:27:16
@@ -49,8 +49,8 @@ note: ...so that the expression is assignable
    |
 LL |         C { f: Box::new(b.0) }
    |                         ^^^
-   = note: expected  `std::boxed::Box<&isize>`
-              found  `std::boxed::Box<&isize>`
+   = note: expected `std::boxed::Box<&isize>`
+              found `std::boxed::Box<&isize>`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6...
   --> $DIR/type-alias-free-regions.rs:25:6
    |
@@ -61,8 +61,8 @@ note: ...so that the expression is assignable
    |
 LL |         C { f: Box::new(b.0) }
    |         ^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `C<'a>`
-              found  `C<'_>`
+   = note: expected `C<'a>`
+              found `C<'_>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
index 37be450fd0a79..8421dc1d0c130 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
@@ -14,8 +14,8 @@ note: ...so that the types are compatible
    |
 LL |     <Foo<'a>>::C
    |     ^^^^^^^^^^^^
-   = note: expected  `Foo<'_>`
-              found  `Foo<'a>`
+   = note: expected `Foo<'_>`
+              found `Foo<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that reference does not outlive borrowed content
   --> $DIR/constant-in-expr-inherent-1.rs:8:5
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
index 4ee32847c5ec8..ba0a1748c5e9f 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
@@ -14,8 +14,8 @@ note: ...so that the types are compatible
    |
 LL |     T::C
    |     ^^^^
-   = note: expected  `Foo<'_>`
-              found  `Foo<'a>`
+   = note: expected `Foo<'_>`
+              found `Foo<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that reference does not outlive borrowed content
   --> $DIR/constant-in-expr-trait-item-3.rs:10:5
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
index 1952ee8269d5b..79ded5fc875a2 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
@@ -24,8 +24,8 @@ note: ...so that the expression is assignable
    |
 LL |     ss
    |     ^^
-   = note: expected  `&'b (dyn SomeTrait + 'b)`
-              found  `&dyn SomeTrait`
+   = note: expected `&'b (dyn SomeTrait + 'b)`
+              found `&dyn SomeTrait`
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/object-lifetime-default-elision.rs:71:5
@@ -53,8 +53,8 @@ note: ...so that the expression is assignable
    |
 LL |     ss
    |     ^^
-   = note: expected  `&'b (dyn SomeTrait + 'b)`
-              found  `&dyn SomeTrait`
+   = note: expected `&'b (dyn SomeTrait + 'b)`
+              found `&dyn SomeTrait`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
index e889651647034..069b897603cb9 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
@@ -39,8 +39,8 @@ note: ...so that the expression is assignable
    |
 LL |     Box::new(v)
    |              ^
-   = note: expected  `&[u8]`
-              found  `&'a [u8]`
+   = note: expected `&[u8]`
+              found `&'a [u8]`
 note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9...
   --> $DIR/region-object-lifetime-in-coercion.rs:25:9
    |
@@ -51,8 +51,8 @@ note: ...so that the expression is assignable
    |
 LL |     Box::new(v)
    |     ^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn Foo + 'b)>`
-              found  `std::boxed::Box<dyn Foo>`
+   = note: expected `std::boxed::Box<(dyn Foo + 'b)>`
+              found `std::boxed::Box<dyn Foo>`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
index 865e967fba32e..c134b3b3ed554 100644
--- a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
+++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
@@ -14,8 +14,8 @@ note: ...so that the types are compatible
    |
 LL | impl<'a> Foo<'static> for &'a i32 {
    |          ^^^^^^^^^^^^
-   = note: expected  `Foo<'static>`
-              found  `Foo<'static>`
+   = note: expected `Foo<'static>`
+              found `Foo<'static>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the type `&i32` will meet its required lifetime bounds
   --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:10
@@ -39,8 +39,8 @@ note: ...so that the types are compatible
    |
 LL | impl<'a,'b> Foo<'b> for &'a i64 {
    |             ^^^^^^^
-   = note: expected  `Foo<'b>`
-              found  `Foo<'_>`
+   = note: expected `Foo<'b>`
+              found `Foo<'_>`
 note: but, the lifetime must be valid for the lifetime `'b` as defined on the impl at 19:9...
   --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:9
    |
diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
index 6a34871c07efd..ac8c55ccc8fd4 100644
--- a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
+++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
@@ -14,8 +14,8 @@ note: ...so that the types are compatible
    |
 LL | impl<'a> Foo for &'a i32 {
    |          ^^^
-   = note: expected  `Foo`
-              found  `Foo`
+   = note: expected `Foo`
+              found `Foo`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the type `&i32` will meet its required lifetime bounds
   --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:10
diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr
index 28873ab807f8d..147f7f3541816 100644
--- a/src/test/ui/regions/regions-close-object-into-object-2.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr
@@ -20,8 +20,8 @@ note: ...so that the expression is assignable
    |
 LL |     box B(&*v) as Box<dyn X>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn X + 'static)>`
-              found  `std::boxed::Box<dyn X>`
+   = note: expected `std::boxed::Box<(dyn X + 'static)>`
+              found `std::boxed::Box<dyn X>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr
index 449a5b5fdd4d6..6e7d6152cd09a 100644
--- a/src/test/ui/regions/regions-close-object-into-object-4.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr
@@ -20,8 +20,8 @@ note: ...so that the expression is assignable
    |
 LL |     box B(&*v) as Box<dyn X>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn X + 'static)>`
-              found  `std::boxed::Box<dyn X>`
+   = note: expected `std::boxed::Box<(dyn X + 'static)>`
+              found `std::boxed::Box<dyn X>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
index b2a7afaf1b452..2070ce257b18d 100644
--- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
+++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
@@ -24,8 +24,8 @@ note: ...so that the expression is assignable
    |
 LL |     box v as Box<dyn SomeTrait + 'a>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn SomeTrait + 'c)>`
-              found  `std::boxed::Box<dyn SomeTrait>`
+   = note: expected `std::boxed::Box<(dyn SomeTrait + 'c)>`
+              found `std::boxed::Box<dyn SomeTrait>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-creating-enums4.stderr b/src/test/ui/regions/regions-creating-enums4.stderr
index 58f74e4ee142d..b24db1df18b0a 100644
--- a/src/test/ui/regions/regions-creating-enums4.stderr
+++ b/src/test/ui/regions/regions-creating-enums4.stderr
@@ -14,8 +14,8 @@ note: ...so that the expression is assignable
    |
 LL |     Ast::Add(x, y)
    |              ^
-   = note: expected  `&Ast<'_>`
-              found  `&Ast<'a>`
+   = note: expected `&Ast<'_>`
+              found `&Ast<'a>`
 note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:19...
   --> $DIR/regions-creating-enums4.rs:6:19
    |
@@ -26,8 +26,8 @@ note: ...so that the expression is assignable
    |
 LL |     Ast::Add(x, y)
    |     ^^^^^^^^^^^^^^
-   = note: expected  `Ast<'b>`
-              found  `Ast<'_>`
+   = note: expected `Ast<'b>`
+              found `Ast<'_>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr
index 8fce1609d7830..9e405d83140d8 100644
--- a/src/test/ui/regions/regions-nested-fns.stderr
+++ b/src/test/ui/regions/regions-nested-fns.stderr
@@ -39,8 +39,8 @@ LL | |         if false { return ay; }
 LL | |         return z;
 LL | |     }));
    | |_____^
-   = note: expected  `&isize`
-              found  `&isize`
+   = note: expected `&isize`
+              found `&isize`
 
 error[E0312]: lifetime of reference outlives lifetime of borrowed content...
   --> $DIR/regions-nested-fns.rs:14:27
diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
index c35516d2c0871..dc93d620ca637 100644
--- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
+++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
@@ -29,8 +29,8 @@ LL | |     where <() as Project<'a, 'b>>::Item : Eq
 LL | | {
 LL | | }
    | |_^
-   = note: expected  `Project<'a, 'b>`
-              found  `Project<'_, '_>`
+   = note: expected `Project<'a, 'b>`
+              found `Project<'_, '_>`
 
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
   --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
@@ -63,8 +63,8 @@ LL | |     where <() as Project<'a, 'b>>::Item : Eq
 LL | | {
 LL | | }
    | |_^
-   = note: expected  `Project<'a, 'b>`
-              found  `Project<'_, '_>`
+   = note: expected `Project<'a, 'b>`
+              found `Project<'_, '_>`
 
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
   --> $DIR/regions-normalize-in-where-clause-list.rs:22:4
@@ -87,8 +87,8 @@ note: ...so that the types are compatible
    |
 LL | fn bar<'a, 'b>()
    |    ^^^
-   = note: expected  `Project<'a, 'b>`
-              found  `Project<'_, '_>`
+   = note: expected `Project<'a, 'b>`
+              found `Project<'_, '_>`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr
index 2895a0ccdeec8..2c4769d8e3751 100644
--- a/src/test/ui/regions/regions-ret-borrowed-1.stderr
+++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr
@@ -14,8 +14,8 @@ note: ...so that the expression is assignable
    |
 LL |     with(|o| o)
    |              ^
-   = note: expected  `&isize`
-              found  `&isize`
+   = note: expected `&isize`
+              found `&isize`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14...
   --> $DIR/regions-ret-borrowed-1.rs:9:14
    |
diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr
index b74f10f5075eb..da560107cea99 100644
--- a/src/test/ui/regions/regions-ret-borrowed.stderr
+++ b/src/test/ui/regions/regions-ret-borrowed.stderr
@@ -14,8 +14,8 @@ note: ...so that the expression is assignable
    |
 LL |     with(|o| o)
    |              ^
-   = note: expected  `&isize`
-              found  `&isize`
+   = note: expected `&isize`
+              found `&isize`
 note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14...
   --> $DIR/regions-ret-borrowed.rs:12:14
    |
diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr
index 58b79d212700c..7478b53bd3ccc 100644
--- a/src/test/ui/regions/regions-trait-object-subtyping.stderr
+++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr
@@ -41,8 +41,8 @@ note: ...so that the expression is assignable
    |
 LL |     x
    |     ^
-   = note: expected  `&'b mut (dyn Dummy + 'b)`
-              found  `&mut (dyn Dummy + 'b)`
+   = note: expected `&'b mut (dyn Dummy + 'b)`
+              found `&mut (dyn Dummy + 'b)`
 
 error[E0308]: mismatched types
   --> $DIR/regions-trait-object-subtyping.rs:22:5
diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr
index c09418de51830..f819faa278995 100644
--- a/src/test/ui/reject-specialized-drops-8142.stderr
+++ b/src/test/ui/reject-specialized-drops-8142.stderr
@@ -118,8 +118,8 @@ note: ...so that the types are compatible
    |
 LL | impl<'lw>         Drop for W<'lw,'lw>     { fn drop(&mut self) { } } // REJECT
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `W<'l1, 'l2>`
-              found  `W<'_, '_>`
+   = note: expected `W<'l1, 'l2>`
+              found `W<'_, '_>`
 
 error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not
   --> $DIR/reject-specialized-drops-8142.rs:61:14
diff --git a/src/test/ui/traits/self-without-lifetime-constraint.rs b/src/test/ui/traits/self-without-lifetime-constraint.rs
new file mode 100644
index 0000000000000..99013d32ab8d0
--- /dev/null
+++ b/src/test/ui/traits/self-without-lifetime-constraint.rs
@@ -0,0 +1,53 @@
+use std::error::Error;
+use std::fmt;
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum ValueRef<'a> {
+    Null,
+    Integer(i64),
+    Real(f64),
+    Text(&'a [u8]),
+    Blob(&'a [u8]),
+}
+
+impl<'a> ValueRef<'a> {
+    pub fn as_str(&self) -> FromSqlResult<&'a str, &'a &'a str> {
+        match *self {
+            ValueRef::Text(t) => {
+                std::str::from_utf8(t).map_err(|_| FromSqlError::InvalidType).map(|x| (x, &x))
+            }
+            _ => Err(FromSqlError::InvalidType),
+        }
+    }
+}
+
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum FromSqlError {
+    InvalidType
+}
+
+impl fmt::Display for FromSqlError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "InvalidType")
+    }
+}
+
+impl Error for FromSqlError {}
+
+pub type FromSqlResult<T, K> = Result<(T, K), FromSqlError>;
+
+pub trait FromSql: Sized {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
+}
+
+impl FromSql for &str {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
+    //~^ ERROR `impl` item signature doesn't match `trait` item signature
+        value.as_str()
+    }
+}
+
+pub fn main() {
+    println!("{}", "Hello World");
+}
diff --git a/src/test/ui/traits/self-without-lifetime-constraint.stderr b/src/test/ui/traits/self-without-lifetime-constraint.stderr
new file mode 100644
index 0000000000000..6c7abe753e2bf
--- /dev/null
+++ b/src/test/ui/traits/self-without-lifetime-constraint.stderr
@@ -0,0 +1,19 @@
+error: `impl` item signature doesn't match `trait` item signature
+  --> $DIR/self-without-lifetime-constraint.rs:45:5
+   |
+LL |     fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
+   |     -------------------------------------------------------------------- expected `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), FromSqlError>`
+...
+LL |     fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), FromSqlError>`
+   |
+   = note: expected `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), _>`
+              found `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), _>`
+help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+  --> $DIR/self-without-lifetime-constraint.rs:41:60
+   |
+LL |     fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
+   |                                                            ^^^^ consider borrowing this type parameter in the trait
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
index 9fdcd4de495c0..46aa7db967ad4 100644
--- a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
+++ b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
@@ -19,8 +19,8 @@ note: ...so that the types are compatible
    |
 LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
    |             ^^^^^^^^^^
-   = note: expected  `T1<'a>`
-              found  `T1<'_>`
+   = note: expected `T1<'a>`
+              found `T1<'_>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.rs b/src/test/ui/traits/trait-param-without-lifetime-constraint.rs
new file mode 100644
index 0000000000000..a79b74dcddead
--- /dev/null
+++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.rs
@@ -0,0 +1,20 @@
+struct Article {
+    proof_reader: ProofReader,
+}
+
+struct ProofReader {
+    name: String,
+}
+
+pub trait HaveRelationship<To> {
+    fn get_relation(&self) -> To;
+}
+
+impl HaveRelationship<&ProofReader> for Article {
+    fn get_relation(&self) -> &ProofReader {
+    //~^ ERROR `impl` item signature doesn't match `trait` item signature
+        &self.proof_reader
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr
new file mode 100644
index 0000000000000..4942dbe480ba3
--- /dev/null
+++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr
@@ -0,0 +1,19 @@
+error: `impl` item signature doesn't match `trait` item signature
+  --> $DIR/trait-param-without-lifetime-constraint.rs:14:5
+   |
+LL |     fn get_relation(&self) -> To;
+   |     ----------------------------- expected `fn(&Article) -> &ProofReader`
+...
+LL |     fn get_relation(&self) -> &ProofReader {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader`
+   |
+   = note: expected `fn(&Article) -> &ProofReader`
+              found `fn(&Article) -> &ProofReader`
+help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+  --> $DIR/trait-param-without-lifetime-constraint.rs:10:31
+   |
+LL |     fn get_relation(&self) -> To;
+   |                               ^^ consider borrowing this type parameter in the trait
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
index e6029e0d4623a..e3c9d50dfe5b3 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
@@ -23,8 +23,8 @@ note: ...so that the expression is assignable
    |
 LL |     Box::new(items.iter())
    |     ^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected  `std::boxed::Box<(dyn std::iter::Iterator<Item = &T> + 'static)>`
-              found  `std::boxed::Box<dyn std::iter::Iterator<Item = &T>>`
+   = note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = &T> + 'static)>`
+              found `std::boxed::Box<dyn std::iter::Iterator<Item = &T>>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs
new file mode 100644
index 0000000000000..540612a7dce05
--- /dev/null
+++ b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs
@@ -0,0 +1,67 @@
+#![feature(unsafe_block_in_unsafe_fn)]
+
+#[repr(packed)]
+pub struct Packed {
+    data: &'static u32,
+}
+
+const PACKED: Packed = Packed { data: &0 };
+
+#[allow(safe_packed_borrows)]
+#[allow(unsafe_op_in_unsafe_fn)]
+unsafe fn allow_allow() {
+    &PACKED.data; // allowed
+}
+
+#[allow(safe_packed_borrows)]
+#[warn(unsafe_op_in_unsafe_fn)]
+unsafe fn allow_warn() {
+    &PACKED.data; // allowed
+}
+
+#[allow(safe_packed_borrows)]
+#[deny(unsafe_op_in_unsafe_fn)]
+unsafe fn allow_deny() {
+    &PACKED.data; // allowed
+}
+
+#[warn(safe_packed_borrows)]
+#[allow(unsafe_op_in_unsafe_fn)]
+unsafe fn warn_allow() {
+    &PACKED.data; // allowed
+}
+
+#[warn(safe_packed_borrows)]
+#[warn(unsafe_op_in_unsafe_fn)]
+unsafe fn warn_warn() {
+    &PACKED.data; //~ WARN
+    //~| WARNING this was previously accepted by the compiler but is being phased out
+}
+
+#[warn(safe_packed_borrows)]
+#[deny(unsafe_op_in_unsafe_fn)]
+unsafe fn warn_deny() {
+    &PACKED.data; //~ WARN
+    //~| WARNING this was previously accepted by the compiler but is being phased out
+}
+
+#[deny(safe_packed_borrows)]
+#[allow(unsafe_op_in_unsafe_fn)]
+unsafe fn deny_allow() {
+    &PACKED.data; // allowed
+}
+
+#[deny(safe_packed_borrows)]
+#[warn(unsafe_op_in_unsafe_fn)]
+unsafe fn deny_warn() {
+    &PACKED.data; //~ WARN
+}
+
+#[deny(safe_packed_borrows)]
+#[deny(unsafe_op_in_unsafe_fn)]
+unsafe fn deny_deny() {
+    &PACKED.data; //~ ERROR
+    //~| WARNING this was previously accepted by the compiler but is being phased out
+}
+
+fn main() {}
diff --git a/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr
new file mode 100644
index 0000000000000..fda15159643b6
--- /dev/null
+++ b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr
@@ -0,0 +1,60 @@
+warning: borrow of packed field is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:37:5
+   |
+LL |     &PACKED.data;
+   |     ^^^^^^^^^^^^ borrow of packed field
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:34:8
+   |
+LL | #[warn(safe_packed_borrows)]
+   |        ^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
+   = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
+
+warning: borrow of packed field is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:44:5
+   |
+LL |     &PACKED.data;
+   |     ^^^^^^^^^^^^ borrow of packed field
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:41:8
+   |
+LL | #[warn(safe_packed_borrows)]
+   |        ^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
+   = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
+
+warning: borrow of packed field is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:57:5
+   |
+LL |     &PACKED.data;
+   |     ^^^^^^^^^^^^ borrow of packed field
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:55:8
+   |
+LL | #[warn(unsafe_op_in_unsafe_fn)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^
+   = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
+
+error: borrow of packed field is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:63:5
+   |
+LL |     &PACKED.data;
+   |     ^^^^^^^^^^^^ borrow of packed field
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:60:8
+   |
+LL | #[deny(safe_packed_borrows)]
+   |        ^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
+   = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
+
+error: aborting due to previous error; 3 warnings emitted
+
diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs
new file mode 100644
index 0000000000000..1e57b03ced48b
--- /dev/null
+++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs
@@ -0,0 +1,76 @@
+#![feature(unsafe_block_in_unsafe_fn)]
+#![deny(unsafe_op_in_unsafe_fn)]
+#![deny(unused_unsafe)]
+
+unsafe fn unsf() {}
+const PTR: *const () = std::ptr::null();
+static mut VOID: () = ();
+
+unsafe fn deny_level() {
+    unsf();
+    //~^ ERROR call to unsafe function is unsafe and requires unsafe block
+    *PTR;
+    //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block
+    VOID = ();
+    //~^ ERROR use of mutable static is unsafe and requires unsafe block
+}
+
+// Check that `unsafe_op_in_unsafe_fn` works starting from the `warn` level.
+#[warn(unsafe_op_in_unsafe_fn)]
+#[deny(warnings)]
+unsafe fn warning_level() {
+    unsf();
+    //~^ ERROR call to unsafe function is unsafe and requires unsafe block
+    *PTR;
+    //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block
+    VOID = ();
+    //~^ ERROR use of mutable static is unsafe and requires unsafe block
+}
+
+unsafe fn explicit_block() {
+    // no error
+    unsafe {
+        unsf();
+        *PTR;
+        VOID = ();
+    }
+}
+
+unsafe fn two_explicit_blocks() {
+    unsafe { unsafe { unsf() } }
+    //~^ ERROR unnecessary `unsafe` block
+}
+
+#[allow(unsafe_op_in_unsafe_fn)]
+unsafe fn allow_level() {
+    // lint allowed -> no error
+    unsf();
+    *PTR;
+    VOID = ();
+
+    unsafe { unsf() }
+    //~^ ERROR unnecessary `unsafe` block
+}
+
+unsafe fn nested_allow_level() {
+    #[allow(unsafe_op_in_unsafe_fn)]
+    {
+        // lint allowed -> no error
+        unsf();
+        *PTR;
+        VOID = ();
+
+        unsafe { unsf() }
+        //~^ ERROR unnecessary `unsafe` block
+    }
+}
+
+fn main() {
+    unsf();
+    //~^ ERROR call to unsafe function is unsafe and requires unsafe block
+    #[allow(unsafe_op_in_unsafe_fn)]
+    {
+        unsf();
+        //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+    }
+}
diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr
new file mode 100644
index 0000000000000..cc595df12cc44
--- /dev/null
+++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr
@@ -0,0 +1,104 @@
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:10:5
+   |
+LL |     unsf();
+   |     ^^^^^^ call to unsafe function
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9
+   |
+LL | #![deny(unsafe_op_in_unsafe_fn)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
+   |
+LL |     *PTR;
+   |     ^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
+   |
+LL |     VOID = ();
+   |     ^^^^^^^^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:5
+   |
+LL |     unsf();
+   |     ^^^^^^ call to unsafe function
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:8
+   |
+LL | #[deny(warnings)]
+   |        ^^^^^^^^
+   = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5
+   |
+LL |     *PTR;
+   |     ^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:5
+   |
+LL |     VOID = ();
+   |     ^^^^^^^^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:40:14
+   |
+LL |     unsafe { unsafe { unsf() } }
+   |     ------   ^^^^^^ unnecessary `unsafe` block
+   |     |
+   |     because it's nested under this `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:3:9
+   |
+LL | #![deny(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:51:5
+   |
+LL |     unsafe { unsf() }
+   |     ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:63:9
+   |
+LL |         unsafe { unsf() }
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:69:5
+   |
+LL |     unsf();
+   |     ^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:73:9
+   |
+LL |         unsf();
+   |         ^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0133`.