about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-01-22 19:26:42 +0000
committerbors <bors@rust-lang.org>2022-01-22 19:26:42 +0000
commitbfe15646761a75f0259e204cab071565eed2b1e5 (patch)
tree526c09cd8b590b1ad045318c273cb3e01d6e95a3
parentecf72996eda4f8af19b0ca7235c6f62e0245a313 (diff)
parent19e414a9dc99568560741c696eb67aa511385725 (diff)
downloadrust-bfe15646761a75f0259e204cab071565eed2b1e5.tar.gz
rust-bfe15646761a75f0259e204cab071565eed2b1e5.zip
Auto merge of #93202 - matthiaskrgr:rollup-rki39xg, r=matthiaskrgr
Rollup of 9 pull requests

Successful merges:

 - #85967 (add support for the l4-bender linker on the x86_64-unknown-l4re-uclibc tier 3 target)
 - #92828 (Print a helpful message if unwinding aborts when it reaches a nounwind function)
 - #93012 (Update pulldown-cmark version to fix markdown list issue)
 - #93116 (Simplify use of `map_or`)
 - #93132 (Increase the format version of rustdoc-json-types)
 - #93147 (Interner cleanups)
 - #93153 (Reject unsupported naked functions)
 - #93170 (Add missing GUI test explanations)
 - #93172 (rustdoc: remove dashed underline under main heading)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock25
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs154
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs27
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0787.md28
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_lint/src/lib.rs5
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs47
-rw-r--r--compiler/rustc_middle/src/ty/context.rs96
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs17
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs10
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs92
-rw-r--r--compiler/rustc_session/src/config.rs12
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/l4re_base.rs17
-rw-r--r--compiler/rustc_target/src/spec/mod.rs2
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs5
-rw-r--r--library/core/src/panic/panic_info.rs16
-rw-r--r--library/core/src/panicking.rs27
-rw-r--r--library/panic_unwind/src/lib.rs4
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/panicking.rs22
-rw-r--r--library/std/src/sys/unix/process/process_unix/tests.rs7
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css1
-rw-r--r--src/rustdoc-json-types/lib.rs6
-rw-r--r--src/test/codegen/naked-functions.rs40
-rw-r--r--src/test/codegen/naked-noinline.rs1
-rw-r--r--src/test/codegen/unwind-and-panic-abort.rs2
-rw-r--r--src/test/rustdoc-gui/check_info_sign_position.goml2
-rw-r--r--src/test/rustdoc-gui/code-sidebar-toggle.goml1
-rw-r--r--src/test/rustdoc-gui/escape-key.goml2
-rw-r--r--src/test/rustdoc-gui/font-weight.goml2
-rw-r--r--src/test/rustdoc-gui/huge-collection-of-constants.goml4
-rw-r--r--src/test/rustdoc-gui/list_code_block.goml1
-rw-r--r--src/test/rustdoc-gui/search-filter.goml1
-rw-r--r--src/test/rustdoc-gui/search-result-colors.goml1
-rw-r--r--src/test/rustdoc-gui/search-result-display.goml1
-rw-r--r--src/test/rustdoc-gui/search-result-keyword.goml1
-rw-r--r--src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml2
-rw-r--r--src/test/rustdoc-gui/sidebar.goml1
-rw-r--r--src/test/rustdoc-gui/source-code-page.goml1
-rw-r--r--src/test/rustdoc-gui/theme-change.goml1
-rw-r--r--src/test/rustdoc-gui/toggle-docs-mobile.goml2
-rw-r--r--src/test/rustdoc-gui/toggle-docs.goml1
-rw-r--r--src/test/rustdoc-gui/trait-sidebar-item-order.goml1
-rw-r--r--src/test/ui/asm/naked-functions.rs71
-rw-r--r--src/test/ui/asm/naked-functions.stderr181
49 files changed, 560 insertions, 387 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1e7c9ee029b..eabbf8c987c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -689,7 +689,7 @@ dependencies = [
  "clippy_utils",
  "if_chain",
  "itertools 0.10.1",
- "pulldown-cmark 0.9.0",
+ "pulldown-cmark",
  "quine-mc_cluskey",
  "regex-syntax",
  "rustc-semver",
@@ -2186,9 +2186,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.14"
+version = "0.4.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6e77253c46a90eb7e96b2807201dab941a4db5ea05eca5aaaf7027395f352b3"
+checksum = "241f10687eb3b4e0634b3b4e423f97c5f1efbd69dc9522e24a8b94583eeec3c6"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -2201,7 +2201,7 @@ dependencies = [
  "log",
  "memchr",
  "opener",
- "pulldown-cmark 0.8.0",
+ "pulldown-cmark",
  "regex",
  "serde",
  "serde_derive",
@@ -2865,9 +2865,9 @@ dependencies = [
 
 [[package]]
 name = "pulldown-cmark"
-version = "0.8.0"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
+checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
 dependencies = [
  "bitflags",
  "getopts",
@@ -2876,17 +2876,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "pulldown-cmark"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acd16514d1af5f7a71f909a44ef253cdb712a376d7ebc8ae4a471a9be9743548"
-dependencies = [
- "bitflags",
- "memchr",
- "unicase",
-]
-
-[[package]]
 name = "punycode"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4440,7 +4429,7 @@ dependencies = [
  "expect-test",
  "itertools 0.9.0",
  "minifier",
- "pulldown-cmark 0.9.0",
+ "pulldown-cmark",
  "rayon",
  "regex",
  "rustdoc-json-types",
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index acf65259f61..ec9fc22bc4d 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1159,6 +1159,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
                     LinkerFlavor::Lld(_) => "lld",
                     LinkerFlavor::PtxLinker => "rust-ptx-linker",
                     LinkerFlavor::BpfLinker => "bpf-linker",
+                    LinkerFlavor::L4Bender => "l4-bender",
                 }),
                 flavor,
             )),
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 15d16e7d3d6..3fb56f42b8c 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -126,7 +126,6 @@ pub fn get_linker<'a>(
     // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
     // to the linker args construction.
     assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
-
     match flavor {
         LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
             Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>
@@ -149,6 +148,8 @@ pub fn get_linker<'a>(
         LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
 
         LinkerFlavor::BpfLinker => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
+
+        LinkerFlavor::L4Bender => Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>,
     }
 }
 
@@ -1355,6 +1356,157 @@ impl<'a> Linker for WasmLd<'a> {
     }
 }
 
+/// Linker shepherd script for L4Re (Fiasco)
+pub struct L4Bender<'a> {
+    cmd: Command,
+    sess: &'a Session,
+    hinted_static: bool,
+}
+
+impl<'a> Linker for L4Bender<'a> {
+    fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
+        bug!("dylibs are not supported on L4Re");
+    }
+    fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
+        self.hint_static();
+        self.cmd.arg(format!("-PC{}", lib));
+    }
+    fn link_rlib(&mut self, lib: &Path) {
+        self.hint_static();
+        self.cmd.arg(lib);
+    }
+    fn include_path(&mut self, path: &Path) {
+        self.cmd.arg("-L").arg(path);
+    }
+    fn framework_path(&mut self, _: &Path) {
+        bug!("frameworks are not supported on L4Re");
+    }
+    fn output_filename(&mut self, path: &Path) {
+        self.cmd.arg("-o").arg(path);
+    }
+
+    fn add_object(&mut self, path: &Path) {
+        self.cmd.arg(path);
+    }
+
+    fn full_relro(&mut self) {
+        self.cmd.arg("-zrelro");
+        self.cmd.arg("-znow");
+    }
+
+    fn partial_relro(&mut self) {
+        self.cmd.arg("-zrelro");
+    }
+
+    fn no_relro(&mut self) {
+        self.cmd.arg("-znorelro");
+    }
+
+    fn cmd(&mut self) -> &mut Command {
+        &mut self.cmd
+    }
+
+    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+
+    fn link_rust_dylib(&mut self, _: Symbol, _: &Path) {
+        panic!("Rust dylibs not supported");
+    }
+
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
+        bug!("frameworks not supported on L4Re");
+    }
+
+    fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
+        self.hint_static();
+        self.cmd.arg("--whole-archive").arg(format!("-l{}", lib));
+        self.cmd.arg("--no-whole-archive");
+    }
+
+    fn link_whole_rlib(&mut self, lib: &Path) {
+        self.hint_static();
+        self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive");
+    }
+
+    fn gc_sections(&mut self, keep_metadata: bool) {
+        if !keep_metadata {
+            self.cmd.arg("--gc-sections");
+        }
+    }
+
+    fn no_gc_sections(&mut self) {
+        self.cmd.arg("--no-gc-sections");
+    }
+
+    fn optimize(&mut self) {
+        // GNU-style linkers support optimization with -O. GNU ld doesn't
+        // need a numeric argument, but other linkers do.
+        if self.sess.opts.optimize == config::OptLevel::Default
+            || self.sess.opts.optimize == config::OptLevel::Aggressive
+        {
+            self.cmd.arg("-O1");
+        }
+    }
+
+    fn pgo_gen(&mut self) {}
+
+    fn debuginfo(&mut self, strip: Strip) {
+        match strip {
+            Strip::None => {}
+            Strip::Debuginfo => {
+                self.cmd().arg("--strip-debug");
+            }
+            Strip::Symbols => {
+                self.cmd().arg("--strip-all");
+            }
+        }
+    }
+
+    fn no_default_libraries(&mut self) {
+        self.cmd.arg("-nostdlib");
+    }
+
+    fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
+        // ToDo, not implemented, copy from GCC
+        self.sess.warn("exporting symbols not implemented yet for L4Bender");
+        return;
+    }
+
+    fn subsystem(&mut self, subsystem: &str) {
+        self.cmd.arg(&format!("--subsystem {}", subsystem));
+    }
+
+    fn reset_per_library_state(&mut self) {
+        self.hint_static(); // Reset to default before returning the composed command line.
+    }
+
+    fn group_start(&mut self) {
+        self.cmd.arg("--start-group");
+    }
+
+    fn group_end(&mut self) {
+        self.cmd.arg("--end-group");
+    }
+
+    fn linker_plugin_lto(&mut self) {}
+
+    fn control_flow_guard(&mut self) {}
+
+    fn no_crt_objects(&mut self) {}
+}
+
+impl<'a> L4Bender<'a> {
+    pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> {
+        L4Bender { cmd: cmd, sess: sess, hinted_static: false }
+    }
+
+    fn hint_static(&mut self) {
+        if !self.hinted_static {
+            self.cmd.arg("-static");
+            self.hinted_static = true;
+        }
+    }
+}
+
 pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
     if let Some(ref exports) = tcx.sess.target.override_export_symbols {
         return exports.clone();
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 5ce4e606fd2..b1a76b80002 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -477,6 +477,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup);
     }
 
+    fn codegen_abort_terminator(
+        &mut self,
+        helper: TerminatorCodegenHelper<'tcx>,
+        mut bx: Bx,
+        terminator: &mir::Terminator<'tcx>,
+    ) {
+        let span = terminator.source_info.span;
+        self.set_debug_loc(&mut bx, terminator.source_info);
+
+        // Get the location information.
+        let location = self.get_caller_location(&mut bx, terminator.source_info).immediate();
+
+        // Obtain the panic entry point.
+        let def_id = common::langcall(bx.tcx(), Some(span), "", LangItem::PanicNoUnwind);
+        let instance = ty::Instance::mono(bx.tcx(), def_id);
+        let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
+        let llfn = bx.get_fn_addr(instance);
+
+        // Codegen the actual panic invoke/call.
+        helper.do_call(self, &mut bx, fn_abi, llfn, &[location], None, None);
+    }
+
     /// Returns `true` if this is indeed a panic intrinsic and codegen is done.
     fn codegen_panic_intrinsic(
         &mut self,
@@ -1014,10 +1036,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::TerminatorKind::Resume => self.codegen_resume_terminator(helper, bx),
 
             mir::TerminatorKind::Abort => {
-                bx.abort();
-                // `abort` does not terminate the block, so we still need to generate
-                // an `unreachable` terminator after it.
-                bx.unreachable();
+                self.codegen_abort_terminator(helper, bx, terminator);
             }
 
             mir::TerminatorKind::Goto { target } => {
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 79d9c55b547..d4b12d00f1f 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -486,6 +486,7 @@ E0783: include_str!("./error_codes/E0783.md"),
 E0784: include_str!("./error_codes/E0784.md"),
 E0785: include_str!("./error_codes/E0785.md"),
 E0786: include_str!("./error_codes/E0786.md"),
+E0787: include_str!("./error_codes/E0787.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
diff --git a/compiler/rustc_error_codes/src/error_codes/E0787.md b/compiler/rustc_error_codes/src/error_codes/E0787.md
new file mode 100644
index 00000000000..cee50829270
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0787.md
@@ -0,0 +1,28 @@
+An unsupported naked function definition.
+
+Erroneous code example:
+
+```compile_fail,E0787
+#![feature(naked_functions)]
+
+#[naked]
+pub extern "C" fn f() -> u32 {
+    42
+}
+```
+
+The naked functions must be defined using a single inline assembly
+block.
+
+The execution must never fall through past the end of the assembly
+code so the block must use `noreturn` option. The asm block can also
+use `att_syntax` and `raw` options, but others options are not allowed.
+
+The asm block must not contain any operands other than `const` and
+`sym`.
+
+### Additional information
+
+For more information, please see [RFC 2972].
+
+[RFC 2972]: https://github.com/rust-lang/rfcs/blob/master/text/2972-constrained-naked.md
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index def0c1d0687..be4849d0b84 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -283,6 +283,7 @@ language_item_table! {
     PanicInfo,               sym::panic_info,          panic_info,                 Target::Struct,         GenericRequirement::None;
     PanicLocation,           sym::panic_location,      panic_location,             Target::Struct,         GenericRequirement::None;
     PanicImpl,               sym::panic_impl,          panic_impl,                 Target::Fn,             GenericRequirement::None;
+    PanicNoUnwind,           sym::panic_no_unwind,     panic_no_unwind,            Target::Fn,             GenericRequirement::Exact(0);
     /// libstd panic entry point. Necessary for const eval to be able to catch it
     BeginPanic,              sym::begin_panic,         begin_panic_fn,             Target::Fn,             GenericRequirement::None;
 
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 4aa8505c940..dde47c1e4c4 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -481,6 +481,11 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
          <https://github.com/rust-lang/rust/issues/59014> for more information",
     );
     store.register_removed("plugin_as_library", "plugins have been deprecated and retired");
+    store.register_removed(
+        "unsupported_naked_functions",
+        "converted into hard error, see RFC 2972 \
+         <https://github.com/rust-lang/rfcs/blob/master/text/2972-constrained-naked.md> for more information",
+    );
 }
 
 fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index c2f6118227a..4096815c6a4 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2760,52 +2760,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `unsupported_naked_functions` lint detects naked function
-    /// definitions that are unsupported but were previously accepted.
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// #![feature(naked_functions)]
-    ///
-    /// #[naked]
-    /// pub extern "C" fn f() -> u32 {
-    ///     42
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// The naked functions must be defined using a single inline assembly
-    /// block.
-    ///
-    /// The execution must never fall through past the end of the assembly
-    /// code so the block must use `noreturn` option. The asm block can also
-    /// use `att_syntax` option, but other options are not allowed.
-    ///
-    /// The asm block must not contain any operands other than `const` and
-    /// `sym`. Additionally, naked function should specify a non-Rust ABI.
-    ///
-    /// Naked functions cannot be inlined. All forms of the `inline` attribute
-    /// are prohibited.
-    ///
-    /// While other definitions of naked functions were previously accepted,
-    /// they are unsupported and might not work reliably. This is a
-    /// [future-incompatible] lint that will transition into hard error in
-    /// the future.
-    ///
-    /// [future-incompatible]: ../index.md#future-incompatible-lints
-    pub UNSUPPORTED_NAKED_FUNCTIONS,
-    Warn,
-    "unsupported naked function definitions",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #32408 <https://github.com/rust-lang/rust/issues/32408>",
-    };
-}
-
-declare_lint! {
     /// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used.
     ///
     /// ### Example
@@ -3070,7 +3024,6 @@ declare_lint_pass! {
         UNINHABITED_STATIC,
         FUNCTION_ITEM_REFERENCES,
         USELESS_DEPRECATED,
-        UNSUPPORTED_NAKED_FUNCTIONS,
         MISSING_ABI,
         INVALID_DOC_ATTRIBUTES,
         SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index a7d7ee5efc8..f613cd0d450 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -113,6 +113,12 @@ pub struct CtxtInterners<'tcx> {
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
     layout: InternedSet<'tcx, Layout>,
     adt_def: InternedSet<'tcx, AdtDef>,
+
+    /// `#[stable]` and `#[unstable]` attributes
+    stability: InternedSet<'tcx, attr::Stability>,
+
+    /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes
+    const_stability: InternedSet<'tcx, attr::ConstStability>,
 }
 
 impl<'tcx> CtxtInterners<'tcx> {
@@ -134,6 +140,8 @@ impl<'tcx> CtxtInterners<'tcx> {
             bound_variable_kinds: Default::default(),
             layout: Default::default(),
             adt_def: Default::default(),
+            stability: Default::default(),
+            const_stability: Default::default(),
         }
     }
 
@@ -1035,12 +1043,6 @@ pub struct GlobalCtxt<'tcx> {
     /// Data layout specification for the current target.
     pub data_layout: TargetDataLayout,
 
-    /// `#[stable]` and `#[unstable]` attributes
-    stability_interner: ShardedHashMap<&'tcx attr::Stability, ()>,
-
-    /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes
-    const_stability_interner: ShardedHashMap<&'tcx attr::ConstStability, ()>,
-
     /// Stores memory for globals (statics/consts).
     pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
 
@@ -1092,16 +1094,6 @@ impl<'tcx> TyCtxt<'tcx> {
         self.create_memory_alloc(alloc)
     }
 
-    // FIXME(eddyb) move to `direct_interners!`.
-    pub fn intern_stability(self, stab: attr::Stability) -> &'tcx attr::Stability {
-        self.stability_interner.intern(stab, |stab| self.arena.alloc(stab))
-    }
-
-    // FIXME(eddyb) move to `direct_interners!`.
-    pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability {
-        self.const_stability_interner.intern(stab, |stab| self.arena.alloc(stab))
-    }
-
     /// Returns a range of the start/end indices specified with the
     /// `rustc_layout_scalar_valid_range` attribute.
     // FIXME(eddyb) this is an awkward spot for this method, maybe move it?
@@ -1185,8 +1177,6 @@ impl<'tcx> TyCtxt<'tcx> {
             evaluation_cache: Default::default(),
             crate_name: Symbol::intern(crate_name),
             data_layout,
-            stability_interner: Default::default(),
-            const_stability_interner: Default::default(),
             alloc_map: Lock::new(interpret::AllocMap::new()),
             output_filenames: Arc::new(output_filenames),
         }
@@ -1952,11 +1942,11 @@ impl<'tcx> TyCtxt<'tcx> {
 
                 writeln!(fmt, "InternalSubsts interner: #{}", self.0.interners.substs.len())?;
                 writeln!(fmt, "Region interner: #{}", self.0.interners.region.len())?;
-                writeln!(fmt, "Stability interner: #{}", self.0.stability_interner.len())?;
+                writeln!(fmt, "Stability interner: #{}", self.0.interners.stability.len())?;
                 writeln!(
                     fmt,
                     "Const Stability interner: #{}",
-                    self.0.const_stability_interner.len()
+                    self.0.interners.const_stability.len()
                 )?;
                 writeln!(
                     fmt,
@@ -1973,7 +1963,10 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 }
 
-/// An entry in an interner.
+// This type holds a `T` in the interner. The `T` is stored in the arena and
+// this type just holds a pointer to it, but it still effectively owns it. It
+// impls `Borrow` so that it can be looked up using the original
+// (non-arena-memory-owning) types.
 struct Interned<'tcx, T: ?Sized>(&'tcx T);
 
 impl<'tcx, T: 'tcx + ?Sized> Clone for Interned<'tcx, T> {
@@ -1981,6 +1974,7 @@ impl<'tcx, T: 'tcx + ?Sized> Clone for Interned<'tcx, T> {
         Interned(self.0)
     }
 }
+
 impl<'tcx, T: 'tcx + ?Sized> Copy for Interned<'tcx, T> {}
 
 impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> {
@@ -1988,9 +1982,18 @@ impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> {
         self.0 as *const _ as *const ()
     }
 }
-// N.B., an `Interned<Ty>` compares and hashes as a `TyKind`.
+
+#[allow(rustc::usage_of_ty_tykind)]
+impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
+        &self.0.kind()
+    }
+}
+
 impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> {
     fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool {
+        // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+        // `x == y`.
         self.0.kind() == other.0.kind()
     }
 }
@@ -1999,19 +2002,21 @@ impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {}
 
 impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> {
     fn hash<H: Hasher>(&self, s: &mut H) {
+        // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
         self.0.kind().hash(s)
     }
 }
 
-#[allow(rustc::usage_of_ty_tykind)]
-impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
-        &self.0.kind()
+impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
+        &self.0.kind
     }
 }
-// N.B., an `Interned<PredicateInner>` compares and hashes as a `PredicateKind`.
+
 impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> {
     fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool {
+        // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+        // `x == y`.
         self.0.kind == other.0.kind
     }
 }
@@ -2020,19 +2025,21 @@ impl<'tcx> Eq for Interned<'tcx, PredicateInner<'tcx>> {}
 
 impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> {
     fn hash<H: Hasher>(&self, s: &mut H) {
+        // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
         self.0.kind.hash(s)
     }
 }
 
-impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
-        &self.0.kind
+impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> {
+    fn borrow<'a>(&'a self) -> &'a [T] {
+        &self.0[..]
     }
 }
 
-// N.B., an `Interned<List<T>>` compares and hashes as its elements.
 impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> {
     fn eq(&self, other: &Interned<'tcx, List<T>>) -> bool {
+        // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+        // `x == y`.
         self.0[..] == other.0[..]
     }
 }
@@ -2041,20 +2048,23 @@ impl<'tcx, T: Eq> Eq for Interned<'tcx, List<T>> {}
 
 impl<'tcx, T: Hash> Hash for Interned<'tcx, List<T>> {
     fn hash<H: Hasher>(&self, s: &mut H) {
+        // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
         self.0[..].hash(s)
     }
 }
 
-impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> {
-    fn borrow<'a>(&'a self) -> &'a [T] {
-        &self.0[..]
-    }
-}
-
 macro_rules! direct_interners {
     ($($name:ident: $method:ident($ty:ty),)+) => {
-        $(impl<'tcx> PartialEq for Interned<'tcx, $ty> {
+        $(impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
+            fn borrow<'a>(&'a self) -> &'a $ty {
+                &self.0
+            }
+        }
+
+        impl<'tcx> PartialEq for Interned<'tcx, $ty> {
             fn eq(&self, other: &Self) -> bool {
+                // The `Borrow` trait requires that `x.borrow() == y.borrow()`
+                // equals `x == y`.
                 self.0 == other.0
             }
         }
@@ -2063,16 +2073,12 @@ macro_rules! direct_interners {
 
         impl<'tcx> Hash for Interned<'tcx, $ty> {
             fn hash<H: Hasher>(&self, s: &mut H) {
+                // The `Borrow` trait requires that `x.borrow().hash(s) ==
+                // x.hash(s)`.
                 self.0.hash(s)
             }
         }
 
-        impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
-            fn borrow<'a>(&'a self) -> &'a $ty {
-                &self.0
-            }
-        }
-
         impl<'tcx> TyCtxt<'tcx> {
             pub fn $method(self, v: $ty) -> &'tcx $ty {
                 self.interners.$name.intern(v, |v| {
@@ -2089,6 +2095,8 @@ direct_interners! {
     const_allocation: intern_const_alloc(Allocation),
     layout: intern_layout(Layout),
     adt_def: intern_adt_def(AdtDef),
+    stability: intern_stability(attr::Stability),
+    const_stability: intern_const_stability(attr::ConstStability),
 }
 
 macro_rules! slice_interners {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 4bc3e23f4a5..8ed1533436e 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -376,15 +376,28 @@ pub struct CReaderCacheKey {
     pub pos: usize,
 }
 
+/// Represents a type.
+///
+/// IMPORTANT: Every `TyS` is *required* to have unique contents. The type's
+/// correctness relies on this, *but it does not enforce it*. Therefore, any
+/// code that creates a `TyS` must ensure uniqueness itself. In practice this
+/// is achieved by interning.
 #[allow(rustc::usage_of_ty_tykind)]
 pub struct TyS<'tcx> {
     /// This field shouldn't be used directly and may be removed in the future.
     /// Use `TyS::kind()` instead.
     kind: TyKind<'tcx>,
+
+    /// This field provides fast access to information that is also contained
+    /// in `kind`.
+    ///
     /// This field shouldn't be used directly and may be removed in the future.
     /// Use `TyS::flags()` instead.
     flags: TypeFlags,
 
+    /// This field provides fast access to information that is also contained
+    /// in `kind`.
+    ///
     /// This is a kind of confusing thing: it stores the smallest
     /// binder such that
     ///
@@ -436,6 +449,8 @@ impl<'tcx> PartialOrd for TyS<'tcx> {
 impl<'tcx> PartialEq for TyS<'tcx> {
     #[inline]
     fn eq(&self, other: &TyS<'tcx>) -> bool {
+        // Pointer equality implies equality (due to the unique contents
+        // assumption).
         ptr::eq(self, other)
     }
 }
@@ -443,6 +458,8 @@ impl<'tcx> Eq for TyS<'tcx> {}
 
 impl<'tcx> Hash for TyS<'tcx> {
     fn hash<H: Hasher>(&self, s: &mut H) {
+        // Pointer hashing is sufficient (due to the unique contents
+        // assumption).
         (self as *const TyS<'_>).hash(s)
     }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index a25402a1ff9..f7cd95785ea 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -418,7 +418,7 @@ impl BasicCoverageBlockData {
     pub fn take_edge_counters(
         &mut self,
     ) -> Option<impl Iterator<Item = (BasicCoverageBlock, CoverageKind)>> {
-        self.edge_from_bcbs.take().map_or(None, |m| Some(m.into_iter()))
+        self.edge_from_bcbs.take().map(|m| m.into_iter())
     }
 
     pub fn id(&self) -> String {
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 7e7f6938706..7f13da5d38f 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -807,10 +807,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                     self.output.push(create_fn_mono_item(tcx, instance, source));
                 }
             }
+            mir::TerminatorKind::Abort { .. } => {
+                let instance = Instance::mono(
+                    tcx,
+                    tcx.require_lang_item(LangItem::PanicNoUnwind, Some(source)),
+                );
+                if should_codegen_locally(tcx, &instance) {
+                    self.output.push(create_fn_mono_item(tcx, instance, source));
+                }
+            }
             mir::TerminatorKind::Goto { .. }
             | mir::TerminatorKind::SwitchInt { .. }
             | mir::TerminatorKind::Resume
-            | mir::TerminatorKind::Abort
             | mir::TerminatorKind::Return
             | mir::TerminatorKind::Unreachable => {}
             mir::TerminatorKind::GeneratorDrop
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 0228196d1a1..00a93ccc9aa 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -1,6 +1,7 @@
 //! Checks validity of naked functions.
 
 use rustc_ast::{Attribute, InlineAsmOptions};
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{FnKind, Visitor};
@@ -8,7 +9,6 @@ use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
-use rustc_session::lint::builtin::UNSUPPORTED_NAKED_FUNCTIONS;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
@@ -64,18 +64,16 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
             check_abi(self.tcx, hir_id, fn_header.abi, ident_span);
             check_no_patterns(self.tcx, body.params);
             check_no_parameters_use(self.tcx, body);
-            check_asm(self.tcx, hir_id, body, span);
-            check_inline(self.tcx, hir_id, attrs);
+            check_asm(self.tcx, body, span);
+            check_inline(self.tcx, attrs);
         }
     }
 }
 
 /// Check that the function isn't inlined.
-fn check_inline(tcx: TyCtxt<'_>, hir_id: HirId, attrs: &[Attribute]) {
+fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
     for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) {
-        tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, attr.span, |lint| {
-            lint.build("naked functions cannot be inlined").emit();
-        });
+        tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
     }
 }
 
@@ -146,31 +144,31 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
 }
 
 /// Checks that function body contains a single inline assembly block.
-fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
+fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
     let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
     this.visit_body(body);
     if let [(ItemKind::Asm, _)] = this.items[..] {
         // Ok.
     } else {
-        tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_span, |lint| {
-            let mut diag = lint.build("naked functions must contain a single asm block");
-            let mut has_asm = false;
-            for &(kind, span) in &this.items {
-                match kind {
-                    ItemKind::Asm if has_asm => {
-                        diag.span_label(
-                            span,
-                            "multiple asm blocks are unsupported in naked functions",
-                        );
-                    }
-                    ItemKind::Asm => has_asm = true,
-                    ItemKind::NonAsm => {
-                        diag.span_label(span, "non-asm is unsupported in naked functions");
-                    }
+        let mut diag = struct_span_err!(
+            tcx.sess,
+            fn_span,
+            E0787,
+            "naked functions must contain a single asm block"
+        );
+        let mut has_asm = false;
+        for &(kind, span) in &this.items {
+            match kind {
+                ItemKind::Asm if has_asm => {
+                    diag.span_label(span, "multiple asm blocks are unsupported in naked functions");
+                }
+                ItemKind::Asm => has_asm = true,
+                ItemKind::NonAsm => {
+                    diag.span_label(span, "non-asm is unsupported in naked functions");
                 }
             }
-            diag.emit();
-        });
+        }
+        diag.emit();
     }
 }
 
@@ -221,7 +219,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
 
             ExprKind::InlineAsm(ref asm) => {
                 self.items.push((ItemKind::Asm, span));
-                self.check_inline_asm(expr.hir_id, asm, span);
+                self.check_inline_asm(asm, span);
             }
 
             ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => {
@@ -230,7 +228,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
         }
     }
 
-    fn check_inline_asm(&self, hir_id: HirId, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
+    fn check_inline_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
         let unsupported_operands: Vec<Span> = asm
             .operands
             .iter()
@@ -243,18 +241,17 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
             })
             .collect();
         if !unsupported_operands.is_empty() {
-            self.tcx.struct_span_lint_hir(
-                UNSUPPORTED_NAKED_FUNCTIONS,
-                hir_id,
+            struct_span_err!(
+                self.tcx.sess,
                 unsupported_operands,
-                |lint| {
-                    lint.build("only `const` and `sym` operands are supported in naked functions")
-                        .emit();
-                },
-            );
+                E0787,
+                "only `const` and `sym` operands are supported in naked functions",
+            )
+            .emit();
         }
 
         let unsupported_options: Vec<&'static str> = [
+            (InlineAsmOptions::MAY_UNWIND, "`may_unwind`"),
             (InlineAsmOptions::NOMEM, "`nomem`"),
             (InlineAsmOptions::NOSTACK, "`nostack`"),
             (InlineAsmOptions::PRESERVES_FLAGS, "`preserves_flags`"),
@@ -266,19 +263,24 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
         .collect();
 
         if !unsupported_options.is_empty() {
-            self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
-                lint.build(&format!(
-                    "asm options unsupported in naked functions: {}",
-                    unsupported_options.join(", ")
-                ))
-                .emit();
-            });
+            struct_span_err!(
+                self.tcx.sess,
+                span,
+                E0787,
+                "asm options unsupported in naked functions: {}",
+                unsupported_options.join(", ")
+            )
+            .emit();
         }
 
         if !asm.options.contains(InlineAsmOptions::NORETURN) {
-            self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
-                lint.build("asm in naked functions must use `noreturn` option").emit();
-            });
+            struct_span_err!(
+                self.tcx.sess,
+                span,
+                E0787,
+                "asm in naked functions must use `noreturn` option"
+            )
+            .emit();
         }
     }
 }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 92ad0723f48..a756de4c0fc 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::impl_stable_hash_via_hash;
 
 use rustc_target::abi::{Align, TargetDataLayout};
-use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TargetWarnings};
+use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
 
 use rustc_serialize::json;
 
@@ -2237,6 +2237,16 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         }
     }
 
+    if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
+        && !nightly_options::is_unstable_enabled(matches)
+    {
+        early_error(
+            error_format,
+            "`l4-bender` linker flavor is unstable, `-Z unstable-options` \
+             flag must also be passed to explicitly use it",
+        );
+    }
+
     let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
 
     let cg = cg;
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 702e3594660..9870c90f2ec 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -990,6 +990,7 @@ symbols! {
         panic_implementation,
         panic_info,
         panic_location,
+        panic_no_unwind,
         panic_runtime,
         panic_str,
         panic_unwind,
diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs
index f6e3102f617..9e7973f63a9 100644
--- a/compiler/rustc_target/src/spec/l4re_base.rs
+++ b/compiler/rustc_target/src/spec/l4re_base.rs
@@ -1,25 +1,14 @@
 use crate::spec::{LinkerFlavor, PanicStrategy, TargetOptions};
-//use std::process::Command;
-
-// Use GCC to locate code for crt* libraries from the host, not from L4Re. Note
-// that a few files also come from L4Re, for these, the function shouldn't be
-// used. This uses GCC for the location of the file, but GCC is required for L4Re anyway.
-//fn get_path_or(filename: &str) -> String {
-//    let child = Command::new("gcc")
-//        .arg(format!("-print-file-name={}", filename)).output()
-//        .expect("Failed to execute GCC");
-//    String::from_utf8(child.stdout)
-//        .expect("Couldn't read path from GCC").trim().into()
-//}
+use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
         os: "l4re".to_string(),
         env: "uclibc".to_string(),
-        linker_flavor: LinkerFlavor::Ld,
+        linker_flavor: LinkerFlavor::L4Bender,
         executables: true,
         panic_strategy: PanicStrategy::Abort,
-        linker: Some("ld".to_string()),
+        linker: Some("l4-bender".to_string()),
         linker_is_gnu: false,
         families: vec!["unix".to_string()],
         ..Default::default()
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 2c149318730..4effb8bacf6 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -90,6 +90,7 @@ mod windows_uwp_msvc_base;
 pub enum LinkerFlavor {
     Em,
     Gcc,
+    L4Bender,
     Ld,
     Msvc,
     Lld(LldFlavor),
@@ -160,6 +161,7 @@ macro_rules! flavor_mappings {
 flavor_mappings! {
     ((LinkerFlavor::Em), "em"),
     ((LinkerFlavor::Gcc), "gcc"),
+    ((LinkerFlavor::L4Bender), "l4-bender"),
     ((LinkerFlavor::Ld), "ld"),
     ((LinkerFlavor::Msvc), "msvc"),
     ((LinkerFlavor::PtxLinker), "ptx-linker"),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
index 1fbd0bb4cec..64c7c1c5f6f 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
@@ -1,9 +1,12 @@
-use crate::spec::Target;
+use crate::spec::{PanicStrategy, Target};
 
 pub fn target() -> Target {
     let mut base = super::l4re_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
+    base.crt_static_allows_dylibs = false;
+    base.dynamic_linking = false;
+    base.panic_strategy = PanicStrategy::Abort;
 
     Target {
         llvm_target: "x86_64-unknown-l4re-uclibc".to_string(),
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index d8e421df5de..405224f8fb0 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -31,6 +31,7 @@ pub struct PanicInfo<'a> {
     payload: &'a (dyn Any + Send),
     message: Option<&'a fmt::Arguments<'a>>,
     location: &'a Location<'a>,
+    can_unwind: bool,
 }
 
 impl<'a> PanicInfo<'a> {
@@ -44,9 +45,10 @@ impl<'a> PanicInfo<'a> {
     pub fn internal_constructor(
         message: Option<&'a fmt::Arguments<'a>>,
         location: &'a Location<'a>,
+        can_unwind: bool,
     ) -> Self {
         struct NoPayload;
-        PanicInfo { location, message, payload: &NoPayload }
+        PanicInfo { location, message, payload: &NoPayload, can_unwind }
     }
 
     #[unstable(
@@ -127,6 +129,18 @@ impl<'a> PanicInfo<'a> {
         // deal with that case in std::panicking::default_hook and core::panicking::panic_fmt.
         Some(&self.location)
     }
+
+    /// Returns whether the panic handler is allowed to unwind the stack from
+    /// the point where the panic occurred.
+    ///
+    /// This is true for most kinds of panics with the exception of panics
+    /// caused by trying to unwind out of a `Drop` implementation or a function
+    /// whose ABI does not support unwinding.
+    #[must_use]
+    #[unstable(feature = "panic_can_unwind", issue = "92988")]
+    pub fn can_unwind(&self) -> bool {
+        self.can_unwind
+    }
 }
 
 #[stable(feature = "panic_hook_display", since = "1.26.0")]
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index ccb82cda54e..5078eea07a1 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -77,6 +77,31 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
     panic!("index out of bounds: the len is {} but the index is {}", len, index)
 }
 
+#[cfg(not(bootstrap))]
+#[cold]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[track_caller]
+#[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function
+fn panic_no_unwind() -> ! {
+    if cfg!(feature = "panic_immediate_abort") {
+        super::intrinsics::abort()
+    }
+
+    // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
+    // that gets resolved to the `#[panic_handler]` function.
+    extern "Rust" {
+        #[lang = "panic_impl"]
+        fn panic_impl(pi: &PanicInfo<'_>) -> !;
+    }
+
+    // PanicInfo with the `can_unwind` flag set to false forces an abort.
+    let fmt = format_args!("panic in a function that cannot unwind");
+    let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
+
+    // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
+    unsafe { panic_impl(&pi) }
+}
+
 /// The entry point for panicking with a formatted message.
 ///
 /// This is designed to reduce the amount of code required at the call
@@ -104,7 +129,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
         fn panic_impl(pi: &PanicInfo<'_>) -> !;
     }
 
-    let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller());
+    let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true);
 
     // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
     unsafe { panic_impl(&pi) }
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index e5753ccae2d..7f05c82ac28 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -39,6 +39,10 @@ cfg_if::cfg_if! {
     } else if #[cfg(target_os = "hermit")] {
         #[path = "hermit.rs"]
         mod real_imp;
+    } else if #[cfg(target_os = "l4re")] {
+        // L4Re is unix family but does not yet support unwinding.
+        #[path = "dummy.rs"]
+        mod real_imp;
     } else if #[cfg(target_env = "msvc")] {
         #[path = "seh.rs"]
         mod real_imp;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 17fe0011569..489d362be42 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -311,6 +311,7 @@
 #![feature(once_cell)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
+#![feature(panic_can_unwind)]
 #![feature(panic_unwind)]
 #![feature(pin_static_ref)]
 #![feature(portable_simd)]
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index d0f332fe5e8..83ab13c963d 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -576,9 +576,14 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
     let msg = info.message().unwrap(); // The current implementation always returns Some
     crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
         if let Some(msg) = msg.as_str() {
-            rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc);
+            rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind());
         } else {
-            rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+            rust_panic_with_hook(
+                &mut PanicPayload::new(msg),
+                info.message(),
+                loc,
+                info.can_unwind(),
+            );
         }
     })
 }
@@ -602,7 +607,7 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
 
     let loc = Location::caller();
     return crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
-        rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc)
+        rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc, true)
     });
 
     struct PanicPayload<A> {
@@ -647,6 +652,7 @@ fn rust_panic_with_hook(
     payload: &mut dyn BoxMeUp,
     message: Option<&fmt::Arguments<'_>>,
     location: &Location<'_>,
+    can_unwind: bool,
 ) -> ! {
     let (must_abort, panics) = panic_count::increase();
 
@@ -663,14 +669,14 @@ fn rust_panic_with_hook(
         } else {
             // Unfortunately, this does not print a backtrace, because creating
             // a `Backtrace` will allocate, which we must to avoid here.
-            let panicinfo = PanicInfo::internal_constructor(message, location);
+            let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
             rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo);
         }
-        intrinsics::abort()
+        crate::sys::abort_internal();
     }
 
     unsafe {
-        let mut info = PanicInfo::internal_constructor(message, location);
+        let mut info = PanicInfo::internal_constructor(message, location, can_unwind);
         let _guard = HOOK_LOCK.read();
         match HOOK {
             // Some platforms (like wasm) know that printing to stderr won't ever actually
@@ -691,13 +697,13 @@ fn rust_panic_with_hook(
         };
     }
 
-    if panics > 1 {
+    if panics > 1 || !can_unwind {
         // If a thread panics while it's already unwinding then we
         // have limited options. Currently our preference is to
         // just abort. In the future we may consider resuming
         // unwinding or otherwise exiting the thread cleanly.
         rtprintpanic!("thread panicked while panicking. aborting.\n");
-        intrinsics::abort()
+        crate::sys::abort_internal();
     }
 
     rust_panic(payload)
diff --git a/library/std/src/sys/unix/process/process_unix/tests.rs b/library/std/src/sys/unix/process/process_unix/tests.rs
index 157debf2d25..560c62155d9 100644
--- a/library/std/src/sys/unix/process/process_unix/tests.rs
+++ b/library/std/src/sys/unix/process/process_unix/tests.rs
@@ -53,5 +53,10 @@ fn test_command_fork_no_unwind() {
     let status = got.expect("panic unexpectedly propagated");
     dbg!(status);
     let signal = status.signal().expect("expected child process to die of signal");
-    assert!(signal == libc::SIGABRT || signal == libc::SIGILL || signal == libc::SIGTRAP);
+    assert!(
+        signal == libc::SIGABRT
+            || signal == libc::SIGILL
+            || signal == libc::SIGTRAP
+            || signal == libc::SIGSEGV
+    );
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 2c937aa0ec9..836cf3cd56a 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -150,7 +150,6 @@ h1.fqn {
 	display: flex;
 	flex-wrap: wrap;
 	justify-content: space-between;
-	border-bottom: 1px dashed #DDDDDD;
 	padding-bottom: 6px;
 	margin-bottom: 15px;
 }
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 618c8aab86a..600833664be 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -8,6 +8,9 @@ use std::path::PathBuf;
 
 use serde::{Deserialize, Serialize};
 
+/// rustdoc format-version.
+pub const FORMAT_VERSION: u32 = 10;
+
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
 /// tools to find or link to them.
@@ -517,8 +520,5 @@ pub struct Static {
     pub expr: String,
 }
 
-/// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 9;
-
 #[cfg(test)]
 mod tests;
diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs
index c8cd6923282..51c7a0c615d 100644
--- a/src/test/codegen/naked-functions.rs
+++ b/src/test/codegen/naked-functions.rs
@@ -1,42 +1,32 @@
 // compile-flags: -C no-prepopulate-passes
+// needs-asm-support
+// only-x86_64
 
 #![crate_type = "lib"]
 #![feature(naked_functions)]
+use std::arch::asm;
 
 // CHECK: Function Attrs: naked
 // CHECK-NEXT: define{{.*}}void @naked_empty()
 #[no_mangle]
 #[naked]
-pub fn naked_empty() {
+pub unsafe extern "C" fn naked_empty() {
     // CHECK-NEXT: {{.+}}:
-    // CHECK-NEXT: ret void
+    // CHECK-NEXT: call void asm
+    // CHECK-NEXT: unreachable
+    asm!("ret",
+         options(noreturn));
 }
 
 // CHECK: Function Attrs: naked
+// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 %a, i64 %b)
 #[no_mangle]
 #[naked]
-// CHECK-NEXT: define{{.*}}void @naked_with_args(i{{[0-9]+( %a)?}})
-pub fn naked_with_args(a: isize) {
+pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
     // CHECK-NEXT: {{.+}}:
-    // CHECK: ret void
-}
-
-// CHECK: Function Attrs: naked
-// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_return()
-#[no_mangle]
-#[naked]
-pub fn naked_with_return() -> isize {
-    // CHECK-NEXT: {{.+}}:
-    // CHECK-NEXT: ret i{{[0-9]+}} 0
-    0
-}
-
-// CHECK: Function Attrs: naked
-// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+( %a)?}})
-#[no_mangle]
-#[naked]
-pub fn naked_with_args_and_return(a: isize) -> isize {
-    // CHECK-NEXT: {{.+}}:
-    // CHECK: ret i{{[0-9]+}} 0
-    0
+    // CHECK-NEXT: call void asm
+    // CHECK-NEXT: unreachable
+    asm!("lea rax, [rdi + rsi]",
+         "ret",
+         options(noreturn));
 }
diff --git a/src/test/codegen/naked-noinline.rs b/src/test/codegen/naked-noinline.rs
index e34ccf5c5fe..13bc139ecd0 100644
--- a/src/test/codegen/naked-noinline.rs
+++ b/src/test/codegen/naked-noinline.rs
@@ -7,7 +7,6 @@
 
 use std::arch::asm;
 
-#[inline(always)]
 #[naked]
 #[no_mangle]
 pub unsafe extern "C" fn f() {
diff --git a/src/test/codegen/unwind-and-panic-abort.rs b/src/test/codegen/unwind-and-panic-abort.rs
index 05d97f3256a..f238741e599 100644
--- a/src/test/codegen/unwind-and-panic-abort.rs
+++ b/src/test/codegen/unwind-and-panic-abort.rs
@@ -9,7 +9,7 @@ extern "C-unwind" {
 
 // CHECK: Function Attrs:{{.*}}nounwind
 // CHECK-NEXT: define{{.*}}void @foo
-// CHECK: call void @llvm.trap()
+// CHECK: call void @_ZN4core9panicking15panic_no_unwind
 #[no_mangle]
 pub unsafe extern "C" fn foo() {
     bar();
diff --git a/src/test/rustdoc-gui/check_info_sign_position.goml b/src/test/rustdoc-gui/check_info_sign_position.goml
index 94e3fe79c94..3bed7a0a03e 100644
--- a/src/test/rustdoc-gui/check_info_sign_position.goml
+++ b/src/test/rustdoc-gui/check_info_sign_position.goml
@@ -1,3 +1,5 @@
+// This test checks the position of the information on the code blocks (like
+// `compile_fail` or `ignore`).
 goto: file://|DOC_PATH|/test_docs/index.html
 goto: ./fn.check_list_code_block.html
 // If the codeblock is the first element of the docblock, the information tooltip must have
diff --git a/src/test/rustdoc-gui/code-sidebar-toggle.goml b/src/test/rustdoc-gui/code-sidebar-toggle.goml
index 6fb92e19660..1818f0dbcdf 100644
--- a/src/test/rustdoc-gui/code-sidebar-toggle.goml
+++ b/src/test/rustdoc-gui/code-sidebar-toggle.goml
@@ -1,3 +1,4 @@
+// This test checks that the source code pages sidebar toggle is working as expected.
 goto: file://|DOC_PATH|/test_docs/index.html
 click: ".srclink"
 wait-for: "#sidebar-toggle"
diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml
index 712920b16a9..9cff12f3e41 100644
--- a/src/test/rustdoc-gui/escape-key.goml
+++ b/src/test/rustdoc-gui/escape-key.goml
@@ -1,3 +1,5 @@
+// This test ensures that the "Escape" shortcut is handled correctly based on the
+// current content displayed.
 goto: file://|DOC_PATH|/test_docs/index.html
 // First, we check that the search results are hidden when the Escape key is pressed.
 write: (".search-input", "test")
diff --git a/src/test/rustdoc-gui/font-weight.goml b/src/test/rustdoc-gui/font-weight.goml
index a64ac8b422f..5f29fde6689 100644
--- a/src/test/rustdoc-gui/font-weight.goml
+++ b/src/test/rustdoc-gui/font-weight.goml
@@ -1,5 +1,5 @@
-goto: file://|DOC_PATH|/lib2/struct.Foo.html
 // This test checks that the font weight is correctly applied.
+goto: file://|DOC_PATH|/lib2/struct.Foo.html
 assert-css: ("//*[@class='docblock item-decl']//a[text()='Alias']", {"font-weight": "400"})
 assert-css: (
     "//*[@class='structfield small-section-header']//a[text()='Alias']",
diff --git a/src/test/rustdoc-gui/huge-collection-of-constants.goml b/src/test/rustdoc-gui/huge-collection-of-constants.goml
index 4f7fe7a212c..4f75b5841ee 100644
--- a/src/test/rustdoc-gui/huge-collection-of-constants.goml
+++ b/src/test/rustdoc-gui/huge-collection-of-constants.goml
@@ -1,7 +1,7 @@
-goto: file://|DOC_PATH|/test_docs/huge_amount_of_consts/index.html
-
 // Make sure that the last two entries are more than 12 pixels apart and not stacked on each other.
 
+goto: file://|DOC_PATH|/test_docs/huge_amount_of_consts/index.html
+
 compare-elements-position-near-false: (
     "//*[@class='item-table']//div[last()-1]",
     "//*[@class='item-table']//div[last()-3]",
diff --git a/src/test/rustdoc-gui/list_code_block.goml b/src/test/rustdoc-gui/list_code_block.goml
index 7d3490e9d94..eba1a662b9f 100644
--- a/src/test/rustdoc-gui/list_code_block.goml
+++ b/src/test/rustdoc-gui/list_code_block.goml
@@ -1,3 +1,4 @@
+// This test checks that code blocks in list are supported.
 goto: file://|DOC_PATH|/test_docs/index.html
 goto: ./fn.check_list_code_block.html
 assert: ("pre.rust.fn")
diff --git a/src/test/rustdoc-gui/search-filter.goml b/src/test/rustdoc-gui/search-filter.goml
index e5cdf3ea7a1..98ca40512ee 100644
--- a/src/test/rustdoc-gui/search-filter.goml
+++ b/src/test/rustdoc-gui/search-filter.goml
@@ -1,3 +1,4 @@
+// Checks that the crate search filtering is handled correctly and changes the results.
 goto: file://|DOC_PATH|/test_docs/index.html
 show-text: true
 write: (".search-input", "test")
diff --git a/src/test/rustdoc-gui/search-result-colors.goml b/src/test/rustdoc-gui/search-result-colors.goml
index b4eb896af1c..872df5fc3f9 100644
--- a/src/test/rustdoc-gui/search-result-colors.goml
+++ b/src/test/rustdoc-gui/search-result-colors.goml
@@ -1,3 +1,4 @@
+// Checks that the result colors are as expected.
 goto: file://|DOC_PATH|/test_docs/index.html
 // We set the theme so we're sure that the correct values will be used, whatever the computer
 // this test is running on.
diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml
index 3162a067d21..823ea67b1b0 100644
--- a/src/test/rustdoc-gui/search-result-display.goml
+++ b/src/test/rustdoc-gui/search-result-display.goml
@@ -1,3 +1,4 @@
+// Checks that the search results have the expected width.
 goto: file://|DOC_PATH|/test_docs/index.html
 size: (900, 1000)
 write: (".search-input", "test")
diff --git a/src/test/rustdoc-gui/search-result-keyword.goml b/src/test/rustdoc-gui/search-result-keyword.goml
index 5342d431d99..8b50c5c5e1a 100644
--- a/src/test/rustdoc-gui/search-result-keyword.goml
+++ b/src/test/rustdoc-gui/search-result-keyword.goml
@@ -1,3 +1,4 @@
+// Checks that the "keyword" results have the expected text alongside them.
 goto: file://|DOC_PATH|/test_docs/index.html
 write: (".search-input", "CookieMonster")
 // Waiting for the search results to appear...
diff --git a/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml b/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml
index a61ec672ae6..52b3ceae7b1 100644
--- a/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml
+++ b/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml
@@ -1,3 +1,5 @@
+// Checks that the first non-empty search result tab is selected if the default/currently selected
+// one is empty.
 goto: file://|DOC_PATH|/test_docs/index.html
 write: (".search-input", "Foo")
 // Waiting for the search results to appear...
diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml
index a1175525858..c7abe896be1 100644
--- a/src/test/rustdoc-gui/sidebar.goml
+++ b/src/test/rustdoc-gui/sidebar.goml
@@ -1,3 +1,4 @@
+// Checks multiple things on the sidebar display (width of its elements, colors, etc).
 goto: file://|DOC_PATH|/test_docs/index.html
 show-text: true
 local-storage: {"rustdoc-theme": "light"}
diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml
index f3682f59d21..375ff4878e5 100644
--- a/src/test/rustdoc-gui/source-code-page.goml
+++ b/src/test/rustdoc-gui/source-code-page.goml
@@ -1,3 +1,4 @@
+// Checks that the interactions with the source code pages are workined as expected.
 goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
 // Check that we can click on the line number.
 click: ".line-numbers > span:nth-child(4)" // This is the span for line 4.
diff --git a/src/test/rustdoc-gui/theme-change.goml b/src/test/rustdoc-gui/theme-change.goml
index 5221cda2f1f..60d089ffa37 100644
--- a/src/test/rustdoc-gui/theme-change.goml
+++ b/src/test/rustdoc-gui/theme-change.goml
@@ -1,3 +1,4 @@
+// Ensures that the theme change is working as expected.
 goto: file://|DOC_PATH|/test_docs/index.html
 click: "#theme-picker"
 click: "#theme-choices > button:first-child"
diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml
index e7a75b43c5a..b5026923001 100644
--- a/src/test/rustdoc-gui/toggle-docs-mobile.goml
+++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml
@@ -1,3 +1,5 @@
+// Checks that the documentation toggles on mobile have the correct position, style and work
+// as expected.
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
 size: (433, 600)
 assert-attribute: (".top-doc", {"open": ""})
diff --git a/src/test/rustdoc-gui/toggle-docs.goml b/src/test/rustdoc-gui/toggle-docs.goml
index e11aae21e3f..480d6242ac6 100644
--- a/src/test/rustdoc-gui/toggle-docs.goml
+++ b/src/test/rustdoc-gui/toggle-docs.goml
@@ -1,3 +1,4 @@
+// Checks that the documentation toggles have the correct position, style and work as expected.
 goto: file://|DOC_PATH|/test_docs/index.html
 assert-attribute: ("#main-content > details.top-doc", {"open": ""})
 assert-text: ("#toggle-all-docs", "[−]")
diff --git a/src/test/rustdoc-gui/trait-sidebar-item-order.goml b/src/test/rustdoc-gui/trait-sidebar-item-order.goml
index 739745792c2..38942baa0b5 100644
--- a/src/test/rustdoc-gui/trait-sidebar-item-order.goml
+++ b/src/test/rustdoc-gui/trait-sidebar-item-order.goml
@@ -1,3 +1,4 @@
+// Checks that the elements in the sidebar are alphabetically sorted.
 goto: file://|DOC_PATH|/test_docs/trait.AnotherOne.html
 assert-text: (".sidebar-links a:nth-of-type(1)", "another")
 assert-text: (".sidebar-links a:nth-of-type(2)", "func1")
diff --git a/src/test/ui/asm/naked-functions.rs b/src/test/ui/asm/naked-functions.rs
index 32431d9e7c6..5b4293972ea 100644
--- a/src/test/ui/asm/naked-functions.rs
+++ b/src/test/ui/asm/naked-functions.rs
@@ -5,7 +5,7 @@
 
 #![feature(naked_functions)]
 #![feature(or_patterns)]
-#![feature(asm_const, asm_sym)]
+#![feature(asm_const, asm_sym, asm_unwind)]
 #![crate_type = "lib"]
 
 use std::arch::asm;
@@ -32,8 +32,7 @@ pub unsafe extern "C" fn patterns(
 
 #[naked]
 pub unsafe extern "C" fn inc(a: u32) -> u32 {
-    //~^ WARN naked functions must contain a single asm block
-    //~| WARN this was previously accepted
+    //~^ ERROR naked functions must contain a single asm block
     a + 1
     //~^ ERROR referencing function parameters is not allowed in naked functions
 }
@@ -42,21 +41,18 @@ pub unsafe extern "C" fn inc(a: u32) -> u32 {
 pub unsafe extern "C" fn inc_asm(a: u32) -> u32 {
     asm!("/* {0} */", in(reg) a, options(noreturn));
     //~^ ERROR referencing function parameters is not allowed in naked functions
-    //~| WARN only `const` and `sym` operands are supported in naked functions
-    //~| WARN this was previously accepted
+    //~| ERROR only `const` and `sym` operands are supported in naked functions
 }
 
 #[naked]
 pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
-    //~^ WARN naked functions must contain a single asm block
-    //~| WARN this was previously accepted
+    //~^ ERROR naked functions must contain a single asm block
     (|| a + 1)()
 }
 
 #[naked]
 pub unsafe extern "C" fn unsupported_operands() {
-    //~^ WARN naked functions must contain a single asm block
-    //~| WARN this was previously accepted
+    //~^ ERROR naked functions must contain a single asm block
     let mut a = 0usize;
     let mut b = 0usize;
     let mut c = 0usize;
@@ -65,11 +61,9 @@ pub unsafe extern "C" fn unsupported_operands() {
     const F: usize = 0usize;
     static G: usize = 0usize;
     asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
-         //~^ WARN asm in naked functions must use `noreturn` option
-         //~| WARN this was previously accepted
+         //~^ ERROR asm in naked functions must use `noreturn` option
          in(reg) a,
-         //~^ WARN only `const` and `sym` operands are supported in naked functions
-         //~| WARN this was previously accepted
+         //~^ ERROR only `const` and `sym` operands are supported in naked functions
          inlateout(reg) b,
          inout(reg) c,
          lateout(reg) d,
@@ -81,31 +75,25 @@ pub unsafe extern "C" fn unsupported_operands() {
 
 #[naked]
 pub extern "C" fn missing_assembly() {
-    //~^ WARN naked functions must contain a single asm block
-    //~| WARN this was previously accepted
+    //~^ ERROR naked functions must contain a single asm block
 }
 
 #[naked]
 pub extern "C" fn too_many_asm_blocks() {
-    //~^ WARN naked functions must contain a single asm block
-    //~| WARN this was previously accepted
+    //~^ ERROR naked functions must contain a single asm block
     asm!("");
-    //~^ WARN asm in naked functions must use `noreturn` option
-    //~| WARN this was previously accepted
+    //~^ ERROR asm in naked functions must use `noreturn` option
     asm!("");
-    //~^ WARN asm in naked functions must use `noreturn` option
-    //~| WARN this was previously accepted
+    //~^ ERROR asm in naked functions must use `noreturn` option
     asm!("");
-    //~^ WARN asm in naked functions must use `noreturn` option
-    //~| WARN this was previously accepted
+    //~^ ERROR asm in naked functions must use `noreturn` option
     asm!("", options(noreturn));
 }
 
 pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
     #[naked]
     pub extern "C" fn inner(y: usize) -> usize {
-        //~^ WARN naked functions must contain a single asm block
-        //~| WARN this was previously accepted
+        //~^ ERROR naked functions must contain a single asm block
         *&y
         //~^ ERROR referencing function parameters is not allowed in naked functions
     }
@@ -115,18 +103,21 @@ pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
 #[naked]
 unsafe extern "C" fn invalid_options() {
     asm!("", options(nomem, preserves_flags, noreturn));
-    //~^ WARN asm options unsupported in naked functions: `nomem`, `preserves_flags`
-    //~| WARN this was previously accepted
+    //~^ ERROR asm options unsupported in naked functions: `nomem`, `preserves_flags`
 }
 
 #[naked]
 unsafe extern "C" fn invalid_options_continued() {
     asm!("", options(readonly, nostack), options(pure));
     //~^ ERROR asm with the `pure` option must have at least one output
-    //~| WARN asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
-    //~| WARN this was previously accepted
-    //~| WARN asm in naked functions must use `noreturn` option
-    //~| WARN this was previously accepted
+    //~| ERROR asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
+    //~| ERROR asm in naked functions must use `noreturn` option
+}
+
+#[naked]
+unsafe extern "C" fn invalid_may_unwind() {
+    asm!("", options(noreturn, may_unwind));
+    //~^ ERROR asm options unsupported in naked functions: `may_unwind`
 }
 
 #[naked]
@@ -177,38 +168,32 @@ pub unsafe extern "C" fn inline_none() {
 
 #[naked]
 #[inline]
-//~^ WARN naked functions cannot be inlined
-//~| WARN this was previously accepted
+//~^ ERROR naked functions cannot be inlined
 pub unsafe extern "C" fn inline_hint() {
     asm!("", options(noreturn));
 }
 
 #[naked]
 #[inline(always)]
-//~^ WARN naked functions cannot be inlined
-//~| WARN this was previously accepted
+//~^ ERROR naked functions cannot be inlined
 pub unsafe extern "C" fn inline_always() {
     asm!("", options(noreturn));
 }
 
 #[naked]
 #[inline(never)]
-//~^ WARN naked functions cannot be inlined
-//~| WARN this was previously accepted
+//~^ ERROR naked functions cannot be inlined
 pub unsafe extern "C" fn inline_never() {
     asm!("", options(noreturn));
 }
 
 #[naked]
 #[inline]
-//~^ WARN naked functions cannot be inlined
-//~| WARN this was previously accepted
+//~^ ERROR naked functions cannot be inlined
 #[inline(always)]
-//~^ WARN naked functions cannot be inlined
-//~| WARN this was previously accepted
+//~^ ERROR naked functions cannot be inlined
 #[inline(never)]
-//~^ WARN naked functions cannot be inlined
-//~| WARN this was previously accepted
+//~^ ERROR naked functions cannot be inlined
 pub unsafe extern "C" fn inline_all() {
     asm!("", options(noreturn));
 }
diff --git a/src/test/ui/asm/naked-functions.stderr b/src/test/ui/asm/naked-functions.stderr
index c2dfe443d60..c1dcc433db6 100644
--- a/src/test/ui/asm/naked-functions.stderr
+++ b/src/test/ui/asm/naked-functions.stderr
@@ -1,5 +1,5 @@
 error: asm with the `pure` option must have at least one output
-  --> $DIR/naked-functions.rs:124:14
+  --> $DIR/naked-functions.rs:111:14
    |
 LL |     asm!("", options(readonly, nostack), options(pure));
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^
@@ -29,66 +29,54 @@ LL |     P { x, y }: P,
    |     ^^^^^^^^^^
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:37:5
+  --> $DIR/naked-functions.rs:36:5
    |
 LL |     a + 1
    |     ^
    |
    = help: follow the calling convention in asm block to use parameters
 
-warning: naked functions must contain a single asm block
+error[E0787]: naked functions must contain a single asm block
   --> $DIR/naked-functions.rs:34:1
    |
 LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
 LL | |
-LL | |
 LL | |     a + 1
    | |     ----- non-asm is unsupported in naked functions
 LL | |
 LL | | }
    | |_^
-   |
-   = note: `#[warn(unsupported_naked_functions)]` on by default
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:43:31
+  --> $DIR/naked-functions.rs:42:31
    |
 LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
    |                               ^
    |
    = help: follow the calling convention in asm block to use parameters
 
-warning: only `const` and `sym` operands are supported in naked functions
-  --> $DIR/naked-functions.rs:43:23
+error[E0787]: only `const` and `sym` operands are supported in naked functions
+  --> $DIR/naked-functions.rs:42:23
    |
 LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
    |                       ^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:50:1
+error[E0787]: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:48:1
    |
 LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
 LL | |
-LL | |
 LL | |     (|| a + 1)()
    | |     ------------ non-asm is unsupported in naked functions
 LL | | }
    | |_^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: only `const` and `sym` operands are supported in naked functions
-  --> $DIR/naked-functions.rs:70:10
+error[E0787]: only `const` and `sym` operands are supported in naked functions
+  --> $DIR/naked-functions.rs:65:10
    |
 LL |          in(reg) a,
    |          ^^^^^^^^^
-...
+LL |
 LL |          inlateout(reg) b,
    |          ^^^^^^^^^^^^^^^^
 LL |          inout(reg) c,
@@ -97,31 +85,24 @@ LL |          lateout(reg) d,
    |          ^^^^^^^^^^^^^^
 LL |          out(reg) e,
    |          ^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:67:5
+error[E0787]: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:63:5
    |
 LL | /     asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
 LL | |
-LL | |
 LL | |          in(reg) a,
+LL | |
 ...  |
 LL | |          sym G,
 LL | |     );
    | |_____^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:57:1
+error[E0787]: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:54:1
    |
 LL | / pub unsafe extern "C" fn unsupported_operands() {
 LL | |
-LL | |
 LL | |     let mut a = 0usize;
    | |     ------------------- non-asm is unsupported in naked functions
 LL | |     let mut b = 0usize;
@@ -136,123 +117,96 @@ LL | |     let mut e = 0usize;
 LL | |     );
 LL | | }
    | |_^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:83:1
+error[E0787]: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:77:1
    |
 LL | / pub extern "C" fn missing_assembly() {
 LL | |
-LL | |
 LL | | }
    | |_^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:92:5
+error[E0787]: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:84:5
    |
 LL |     asm!("");
    |     ^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:95:5
+error[E0787]: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:86:5
    |
 LL |     asm!("");
    |     ^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:98:5
+error[E0787]: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:88:5
    |
 LL |     asm!("");
    |     ^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:89:1
+error[E0787]: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:82:1
    |
 LL | / pub extern "C" fn too_many_asm_blocks() {
 LL | |
-LL | |
 LL | |     asm!("");
-...  |
+LL | |
 LL | |     asm!("");
    | |     -------- multiple asm blocks are unsupported in naked functions
-...  |
+LL | |
 LL | |     asm!("");
    | |     -------- multiple asm blocks are unsupported in naked functions
-...  |
+LL | |
 LL | |     asm!("", options(noreturn));
    | |     --------------------------- multiple asm blocks are unsupported in naked functions
 LL | | }
    | |_^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:109:11
+  --> $DIR/naked-functions.rs:97:11
    |
 LL |         *&y
    |           ^
    |
    = help: follow the calling convention in asm block to use parameters
 
-warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:106:5
+error[E0787]: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:95:5
    |
 LL | /     pub extern "C" fn inner(y: usize) -> usize {
 LL | |
-LL | |
 LL | |         *&y
    | |         --- non-asm is unsupported in naked functions
 LL | |
 LL | |     }
    | |_____^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
-  --> $DIR/naked-functions.rs:117:5
+error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags`
+  --> $DIR/naked-functions.rs:105:5
    |
 LL |     asm!("", options(nomem, preserves_flags, noreturn));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
-  --> $DIR/naked-functions.rs:124:5
+error[E0787]: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
+  --> $DIR/naked-functions.rs:111:5
    |
 LL |     asm!("", options(readonly, nostack), options(pure));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:124:5
+error[E0787]: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:111:5
    |
 LL |     asm!("", options(readonly, nostack), options(pure));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0787]: asm options unsupported in naked functions: `may_unwind`
+  --> $DIR/naked-functions.rs:119:5
    |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
+LL |     asm!("", options(noreturn, may_unwind));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: Rust ABI is unsupported in naked functions
-  --> $DIR/naked-functions.rs:133:15
+  --> $DIR/naked-functions.rs:124:15
    |
 LL | pub unsafe fn default_abi() {
    |               ^^^^^^^^^^^
@@ -260,64 +214,47 @@ LL | pub unsafe fn default_abi() {
    = note: `#[warn(undefined_naked_function_abi)]` on by default
 
 warning: Rust ABI is unsupported in naked functions
-  --> $DIR/naked-functions.rs:139:15
+  --> $DIR/naked-functions.rs:130:15
    |
 LL | pub unsafe fn rust_abi() {
    |               ^^^^^^^^
 
-warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:179:1
+error: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:170:1
    |
 LL | #[inline]
    | ^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:187:1
+error: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:177:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:195:1
+error: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:184:1
    |
 LL | #[inline(never)]
    | ^^^^^^^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:203:1
+error: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:191:1
    |
 LL | #[inline]
    | ^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:206:1
+error: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:193:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:209:1
+error: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:195:1
    |
 LL | #[inline(never)]
    | ^^^^^^^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-error: aborting due to 8 previous errors; 23 warnings emitted
+error: aborting due to 30 previous errors; 2 warnings emitted
 
+For more information about this error, try `rustc --explain E0787`.