about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-10-24 21:42:39 +0000
committerbors <bors@rust-lang.org>2020-10-24 21:42:39 +0000
commitf58ffc93815f76576eb56df4bdeec2fe8f12b766 (patch)
tree60e8bc7b8fe3ab206a1cedc66fc90627d4bfdb24
parentffa2e7ae8fbf9badc035740db949b9dae271c29f (diff)
parent58ae889779e761e35d3ca0c8c7beb92cde52dd7d (diff)
downloadrust-f58ffc93815f76576eb56df4bdeec2fe8f12b766.tar.gz
rust-f58ffc93815f76576eb56df4bdeec2fe8f12b766.zip
Auto merge of #78334 - jonas-schievink:rollup-z0gzbmm, r=jonas-schievink
Rollup of 12 pull requests

Successful merges:

 - #75115 (`#[deny(unsafe_op_in_unsafe_fn)]` in sys/cloudabi)
 - #76614 (change the order of type arguments on ControlFlow)
 - #77610 (revise Hermit's mutex interface to support the behaviour of StaticMutex)
 - #77830 (Simplify query proc-macros)
 - #77930 (Do not ICE with TraitPredicates containing [type error])
 - #78069 (Fix const core::panic!(non_literal_str).)
 - #78072 (Cleanup constant matching in exhaustiveness checking)
 - #78119 (Throw core::panic!("message") as &str instead of String.)
 - #78191 (Introduce a temporary for discriminant value in MatchBranchSimplification)
 - #78272 (const_evaluatable_checked: deal with unused nodes + div)
 - #78318 (TyCtxt: generate single impl block with `slice_interners` macro)
 - #78327 (resolve: Relax macro resolution consistency check to account for any errors)

Failed merges:

r? `@ghost`
-rw-r--r--Cargo.lock4
-rw-r--r--compiler/rustc_data_structures/src/graph/iterate/mod.rs5
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs11
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_macros/src/query.rs72
-rw-r--r--compiler/rustc_middle/src/ty/context.rs8
-rw-r--r--compiler/rustc_middle/src/ty/query/mod.rs70
-rw-r--r--compiler/rustc_middle/src/ty/query/plumbing.rs20
-rw-r--r--compiler/rustc_middle/src/ty/query/stats.rs10
-rw-r--r--compiler/rustc_mir/src/const_eval/machine.rs3
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/mod.rs4
-rw-r--r--compiler/rustc_mir/src/transform/match_branches.rs30
-rw-r--r--compiler/rustc_mir_build/src/lints.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/_match.rs450
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs12
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs7
-rw-r--r--compiler/rustc_query_system/src/query/config.rs2
-rw-r--r--compiler/rustc_resolve/src/macros.rs8
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs85
-rw-r--r--library/alloc/src/alloc.rs2
-rw-r--r--library/core/src/iter/adapters/mod.rs10
-rw-r--r--library/core/src/iter/traits/double_ended.rs4
-rw-r--r--library/core/src/iter/traits/iterator.rs14
-rw-r--r--library/core/src/macros/mod.rs2
-rw-r--r--library/core/src/ops/control_flow.rs12
-rw-r--r--library/core/src/panicking.rs7
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/panicking.rs18
-rw-r--r--library/std/src/sys/cloudabi/abi/cloudabi.rs133
-rw-r--r--library/std/src/sys/cloudabi/mod.rs2
-rw-r--r--library/std/src/sys/cloudabi/mutex.rs4
-rw-r--r--library/std/src/sys/hermit/fs.rs4
-rw-r--r--library/std/src/sys/hermit/mod.rs1
-rw-r--r--library/std/src/sys/hermit/mutex.rs190
-rw-r--r--library/std/src/sys/hermit/process.rs149
-rw-r--r--library/std/src/sys/mod.rs1
-rw-r--r--src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff8
-rw-r--r--src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff8
-rw-r--r--src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff6
-rw-r--r--src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff6
-rw-r--r--src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff116
-rw-r--r--src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff116
-rw-r--r--src/test/mir-opt/matches_reduce_branches.rs10
-rw-r--r--src/test/mir-opt/not_equal_false.opt.InstCombine.diff57
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/division.rs11
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/unused_expr.rs25
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/unused_expr.stderr32
-rw-r--r--src/test/ui/consts/const-eval/const_panic.rs8
-rw-r--r--src/test/ui/consts/const-eval/const_panic.stderr54
-rw-r--r--src/test/ui/consts/const_in_pattern/issue-44333.rs (renamed from src/test/ui/issues/issue-44333.rs)0
-rw-r--r--src/test/ui/consts/const_in_pattern/issue-44333.stderr (renamed from src/test/ui/issues/issue-44333.stderr)0
-rw-r--r--src/test/ui/consts/const_in_pattern/issue-53708.rs11
-rw-r--r--src/test/ui/consts/const_in_pattern/issue-78057.rs17
-rw-r--r--src/test/ui/consts/const_in_pattern/issue-78057.stderr20
-rw-r--r--src/test/ui/intrinsics/panic-uninitialized-zeroed.rs4
-rw-r--r--src/test/ui/issues/issue-77919.rs13
-rw-r--r--src/test/ui/issues/issue-77919.stderr46
-rw-r--r--src/test/ui/macros/issue-78325-inconsistent-resolution.rs12
-rw-r--r--src/test/ui/macros/issue-78325-inconsistent-resolution.stderr13
-rw-r--r--src/test/ui/pattern/usefulness/consts-opaque.rs114
-rw-r--r--src/test/ui/pattern/usefulness/consts-opaque.stderr158
-rw-r--r--src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr4
66 files changed, 1418 insertions, 820 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 94fbd52bcf0..8af442c8f4b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1366,9 +1366,9 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.1.15"
+version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
+checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
 dependencies = [
  "compiler_builtins",
  "libc",
diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
index bc3d1ce53ba..5f42d46e285 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
@@ -1,6 +1,7 @@
 use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
+use std::ops::ControlFlow;
 
 #[cfg(test)]
 mod tests;
@@ -86,10 +87,6 @@ where
     }
 }
 
-/// Allows searches to terminate early with a value.
-// FIXME (#75744): remove the alias once the generics are in a better order and `C=()`.
-pub type ControlFlow<T> = std::ops::ControlFlow<(), T>;
-
 /// The status of a node in the depth-first search.
 ///
 /// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 363879cbb1d..0ae3c75fcc2 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -111,17 +111,6 @@ cfg_if! {
 
 type Profiler = measureme::Profiler<SerializationSink>;
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
-pub enum ProfileCategory {
-    Parsing,
-    Expansion,
-    TypeChecking,
-    BorrowChecking,
-    Codegen,
-    Linking,
-    Other,
-}
-
 bitflags::bitflags! {
     struct EventFilter: u32 {
         const GENERIC_ACTIVITIES = 1 << 0;
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 5e4c03bec83..3e4eb9eafd7 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -263,6 +263,7 @@ language_item_table! {
     // is required to define it somewhere. Additionally, there are restrictions on crates that use
     // a weak lang item, but do not have it defined.
     Panic,                   sym::panic,               panic_fn,                   Target::Fn;
+    PanicStr,                sym::panic_str,           panic_str,                  Target::Fn;
     PanicBoundsCheck,        sym::panic_bounds_check,  panic_bounds_check_fn,      Target::Fn;
     PanicInfo,               sym::panic_info,          panic_info,                 Target::Struct;
     PanicLocation,           sym::panic_location,      panic_location,             Target::Struct;
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index e7c054653ac..fd859196369 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -190,7 +190,11 @@ impl<T: Parse> Parse for List<T> {
 }
 
 /// A named group containing queries.
+///
+/// For now, the name is not used any more, but the capability remains interesting for future
+/// developments of the query system.
 struct Group {
+    #[allow(unused)]
     name: Ident,
     queries: List<Query>,
 }
@@ -417,12 +421,9 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
     let mut query_stream = quote! {};
     let mut query_description_stream = quote! {};
     let mut dep_node_def_stream = quote! {};
-    let mut dep_node_force_stream = quote! {};
-    let mut try_load_from_on_disk_cache_stream = quote! {};
     let mut cached_queries = quote! {};
 
     for group in groups.0 {
-        let mut group_stream = quote! {};
         for mut query in group.queries.0 {
             let modifiers = process_modifiers(&mut query);
             let name = &query.name;
@@ -437,22 +438,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
                 cached_queries.extend(quote! {
                     #name,
                 });
-
-                try_load_from_on_disk_cache_stream.extend(quote! {
-                    ::rustc_middle::dep_graph::DepKind::#name => {
-                        if <#arg as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key() {
-                            debug_assert!($tcx.dep_graph
-                                            .node_color($dep_node)
-                                            .map(|c| c.is_green())
-                                            .unwrap_or(false));
-
-                            let key = <#arg as DepNodeParams<TyCtxt<'_>>>::recover($tcx, $dep_node).unwrap();
-                            if queries::#name::cache_on_disk($tcx, &key, None) {
-                                let _ = $tcx.#name(key);
-                            }
-                        }
-                    }
-                });
             }
 
             let mut attributes = Vec::new();
@@ -485,9 +470,9 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
             let attribute_stream = quote! {#(#attributes),*};
             let doc_comments = query.doc_comments.iter();
             // Add the query to the group
-            group_stream.extend(quote! {
+            query_stream.extend(quote! {
                 #(#doc_comments)*
-                [#attribute_stream] fn #name: #name(#arg) #result,
+                [#attribute_stream] fn #name(#arg) #result,
             });
 
             // Create a dep node for the query
@@ -495,37 +480,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
                 [#attribute_stream] #name(#arg),
             });
 
-            // Add a match arm to force the query given the dep node
-            dep_node_force_stream.extend(quote! {
-                ::rustc_middle::dep_graph::DepKind::#name => {
-                    if <#arg as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key() {
-                        if let Some(key) = <#arg as DepNodeParams<TyCtxt<'_>>>::recover($tcx, $dep_node) {
-                            force_query::<crate::ty::query::queries::#name<'_>, _>(
-                                $tcx,
-                                key,
-                                DUMMY_SP,
-                                *$dep_node
-                            );
-                            return true;
-                        }
-                    }
-                }
-            });
-
             add_query_description_impl(&query, modifiers, &mut query_description_stream);
         }
-        let name = &group.name;
-        query_stream.extend(quote! {
-            #name { #group_stream },
-        });
     }
 
-    dep_node_force_stream.extend(quote! {
-        ::rustc_middle::dep_graph::DepKind::Null => {
-            bug!("Cannot force dep node: {:?}", $dep_node)
-        }
-    });
-
     TokenStream::from(quote! {
         macro_rules! rustc_query_append {
             ([$($macro:tt)*][$($other:tt)*]) => {
@@ -546,15 +504,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
                 );
             }
         }
-        macro_rules! rustc_dep_node_force {
-            ([$dep_node:expr, $tcx:expr] $($other:tt)*) => {
-                match $dep_node.kind {
-                    $($other)*
-
-                    #dep_node_force_stream
-                }
-            }
-        }
         macro_rules! rustc_cached_queries {
             ($($macro:tt)*) => {
                 $($macro)*(#cached_queries);
@@ -562,14 +511,5 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
         }
 
         #query_description_stream
-
-        macro_rules! rustc_dep_node_try_load_from_on_disk_cache {
-            ($dep_node:expr, $tcx:expr) => {
-                match $dep_node.kind {
-                    #try_load_from_on_disk_cache_stream
-                    _ => (),
-                }
-            }
-        }
     })
 }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index ab92e5b745b..f6ea6743a0e 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -2036,13 +2036,13 @@ direct_interners! {
 
 macro_rules! slice_interners {
     ($($field:ident: $method:ident($ty:ty)),+ $(,)?) => (
-        $(impl<'tcx> TyCtxt<'tcx> {
-            pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> {
+        impl<'tcx> TyCtxt<'tcx> {
+            $(pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> {
                 self.interners.$field.intern_ref(v, || {
                     Interned(List::from_arena(&*self.arena, v))
                 }).0
-            }
-        })+
+            })+
+        }
     );
 }
 
diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs
index d3a7412ef14..7ba4d5a14df 100644
--- a/compiler/rustc_middle/src/ty/query/mod.rs
+++ b/compiler/rustc_middle/src/ty/query/mod.rs
@@ -34,7 +34,6 @@ use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_data_structures::profiling::ProfileCategory::*;
 use rustc_data_structures::stable_hasher::StableVec;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
@@ -169,26 +168,71 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool
         return false;
     }
 
-    rustc_dep_node_force!([dep_node, tcx]
-        // These are inputs that are expected to be pre-allocated and that
-        // should therefore always be red or green already.
-        DepKind::CrateMetadata |
+    macro_rules! force_from_dep_node {
+        ($($(#[$attr:meta])* [$($modifiers:tt)*] $name:ident($K:ty),)*) => {
+            match dep_node.kind {
+                // These are inputs that are expected to be pre-allocated and that
+                // should therefore always be red or green already.
+                DepKind::CrateMetadata |
 
-        // These are anonymous nodes.
-        DepKind::TraitSelect |
+                // These are anonymous nodes.
+                DepKind::TraitSelect |
 
-        // We don't have enough information to reconstruct the query key of
-        // these.
-        DepKind::CompileCodegenUnit => {
-            bug!("force_from_dep_node: encountered {:?}", dep_node)
+                // We don't have enough information to reconstruct the query key of
+                // these.
+                DepKind::CompileCodegenUnit |
+
+                // Forcing this makes no sense.
+                DepKind::Null => {
+                    bug!("force_from_dep_node: encountered {:?}", dep_node)
+                }
+
+                $(DepKind::$name => {
+                    debug_assert!(<$K as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key());
+
+                    if let Some(key) = <$K as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node) {
+                        force_query::<queries::$name<'_>, _>(
+                            tcx,
+                            key,
+                            DUMMY_SP,
+                            *dep_node
+                        );
+                        return true;
+                    }
+                })*
+            }
         }
-    );
+    }
+
+    rustc_dep_node_append! { [force_from_dep_node!][] }
 
     false
 }
 
 pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) {
-    rustc_dep_node_try_load_from_on_disk_cache!(dep_node, tcx)
+    macro_rules! try_load_from_on_disk_cache {
+        ($($name:ident,)*) => {
+            match dep_node.kind {
+                $(DepKind::$name => {
+                    if <query_keys::$name<'tcx> as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key() {
+                        debug_assert!(tcx.dep_graph
+                                         .node_color(dep_node)
+                                         .map(|c| c.is_green())
+                                         .unwrap_or(false));
+
+                        let key = <query_keys::$name<'tcx> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node).unwrap();
+                        if queries::$name::cache_on_disk(tcx, &key, None) {
+                            let _ = tcx.$name(key);
+                        }
+                    }
+                })*
+
+                _ => (),
+            }
+        }
+    }
+
+    rustc_cached_queries!(try_load_from_on_disk_cache!);
 }
 
 mod sealed {
diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs
index 1a8aacc4869..d038695283c 100644
--- a/compiler/rustc_middle/src/ty/query/plumbing.rs
+++ b/compiler/rustc_middle/src/ty/query/plumbing.rs
@@ -242,25 +242,15 @@ macro_rules! hash_result {
     };
 }
 
-macro_rules! define_queries {
-    (<$tcx:tt> $($category:tt {
-        $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($($K:tt)*) -> $V:ty,)*
-    },)*) => {
-        define_queries_inner! { <$tcx>
-            $($( $(#[$attr])* category<$category> [$($modifiers)*] fn $name: $node($($K)*) -> $V,)*)*
-        }
-    }
-}
-
 macro_rules! query_helper_param_ty {
     (DefId) => { impl IntoQueryParam<DefId> };
     ($K:ty) => { $K };
 }
 
-macro_rules! define_queries_inner {
+macro_rules! define_queries {
     (<$tcx:tt>
-     $($(#[$attr:meta])* category<$category:tt>
-        [$($modifiers:tt)*] fn $name:ident: $node:ident($($K:tt)*) -> $V:ty,)*) => {
+     $($(#[$attr:meta])*
+        [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
 
         use std::mem;
         use crate::{
@@ -268,7 +258,6 @@ macro_rules! define_queries_inner {
             rustc_data_structures::stable_hasher::StableHasher,
             ich::StableHashingContext
         };
-        use rustc_data_structures::profiling::ProfileCategory;
 
         define_queries_struct! {
             tcx: $tcx,
@@ -362,13 +351,12 @@ macro_rules! define_queries_inner {
                 as QueryStorage
             >::Stored;
             const NAME: &'static str = stringify!($name);
-            const CATEGORY: ProfileCategory = $category;
         }
 
         impl<$tcx> QueryAccessors<TyCtxt<$tcx>> for queries::$name<$tcx> {
             const ANON: bool = is_anon!([$($modifiers)*]);
             const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
-            const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$node;
+            const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$name;
 
             type Cache = query_storage!([$($modifiers)*][$($K)*, $V]);
 
diff --git a/compiler/rustc_middle/src/ty/query/stats.rs b/compiler/rustc_middle/src/ty/query/stats.rs
index 877f88d380a..e0b44ce23c9 100644
--- a/compiler/rustc_middle/src/ty/query/stats.rs
+++ b/compiler/rustc_middle/src/ty/query/stats.rs
@@ -120,13 +120,13 @@ pub fn print_stats(tcx: TyCtxt<'_>) {
 }
 
 macro_rules! print_stats {
-    (<$tcx:tt> $($category:tt {
-        $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*
-    },)*) => {
+    (<$tcx:tt>
+        $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($K:ty) -> $V:ty,)*
+    ) => {
         fn query_stats(tcx: TyCtxt<'_>) -> Vec<QueryStats> {
             let mut queries = Vec::new();
 
-            $($(
+            $(
                 queries.push(stats::<
                     crate::dep_graph::DepKind,
                     <TyCtxt<'_> as QueryContext>::Query,
@@ -135,7 +135,7 @@ macro_rules! print_stats {
                     stringify!($name),
                     &tcx.queries.$name,
                 ));
-            )*)*
+            )*
 
             queries
         }
diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs
index 73ca7e0d471..7e2cae09481 100644
--- a/compiler/rustc_mir/src/const_eval/machine.rs
+++ b/compiler/rustc_mir/src/const_eval/machine.rs
@@ -70,9 +70,10 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
     ) -> InterpResult<'tcx> {
         let def_id = instance.def_id();
         if Some(def_id) == self.tcx.lang_items().panic_fn()
+            || Some(def_id) == self.tcx.lang_items().panic_str()
             || Some(def_id) == self.tcx.lang_items().begin_panic_fn()
         {
-            // &'static str
+            // &str
             assert!(args.len() == 1);
 
             let msg_place = self.deref_operand(args[0])?;
diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs
index 33815ceba62..b93d63b4fdd 100644
--- a/compiler/rustc_mir/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs
@@ -74,7 +74,9 @@ impl ConstCx<'mir, 'tcx> {
 
 /// Returns `true` if this `DefId` points to one of the official `panic` lang items.
 pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
-    Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn()
+    Some(def_id) == tcx.lang_items().panic_fn()
+        || Some(def_id) == tcx.lang_items().panic_str()
+        || Some(def_id) == tcx.lang_items().begin_panic_fn()
 }
 
 pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool {
diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs
index 0f9b2ff5ab8..06690dcbf6e 100644
--- a/compiler/rustc_mir/src/transform/match_branches.rs
+++ b/compiler/rustc_mir/src/transform/match_branches.rs
@@ -38,19 +38,16 @@ pub struct MatchBranchSimplification;
 
 impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        // FIXME: This optimization can result in unsoundness, because it introduces
-        // additional uses of a place holding the discriminant value without ensuring that
-        // it is valid to do so.
-        if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
+        if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 {
             return;
         }
 
         let param_env = tcx.param_env(body.source.def_id());
-        let bbs = body.basic_blocks_mut();
+        let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut();
         'outer: for bb_idx in bbs.indices() {
             let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
                 TerminatorKind::SwitchInt {
-                    discr: Operand::Copy(ref place) | Operand::Move(ref place),
+                    discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)),
                     switch_ty,
                     ref targets,
                     ..
@@ -59,7 +56,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
                     if target == targets.otherwise() {
                         continue;
                     }
-                    (place, value, switch_ty, target, targets.otherwise())
+                    (discr, value, switch_ty, target, targets.otherwise())
                 }
                 // Only optimize switch int statements
                 _ => continue,
@@ -99,6 +96,10 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
             // Take ownership of items now that we know we can optimize.
             let discr = discr.clone();
 
+            // Introduce a temporary for the discriminant value.
+            let source_info = bbs[bb_idx].terminator().source_info;
+            let discr_local = local_decls.push(LocalDecl::new(switch_ty, source_info.span));
+
             // We already checked that first and second are different blocks,
             // and bb_idx has a different terminator from both of them.
             let (from, first, second) = bbs.pick3_mut(bb_idx, first, second);
@@ -127,7 +128,11 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
                                 rustc_span::DUMMY_SP,
                             );
                             let op = if f_b { BinOp::Eq } else { BinOp::Ne };
-                            let rhs = Rvalue::BinaryOp(op, Operand::Copy(discr.clone()), const_cmp);
+                            let rhs = Rvalue::BinaryOp(
+                                op,
+                                Operand::Copy(Place::from(discr_local)),
+                                const_cmp,
+                            );
                             Statement {
                                 source_info: f.source_info,
                                 kind: StatementKind::Assign(box (*lhs, rhs)),
@@ -138,7 +143,16 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
                     _ => unreachable!(),
                 }
             });
+
+            from.statements
+                .push(Statement { source_info, kind: StatementKind::StorageLive(discr_local) });
+            from.statements.push(Statement {
+                source_info,
+                kind: StatementKind::Assign(box (Place::from(discr_local), Rvalue::Use(discr))),
+            });
             from.statements.extend(new_stmts);
+            from.statements
+                .push(Statement { source_info, kind: StatementKind::StorageDead(discr_local) });
             from.terminator_mut().kind = first.terminator().kind.clone();
         }
     }
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index a9620b83124..576b537c017 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -1,5 +1,5 @@
 use rustc_data_structures::graph::iterate::{
-    ControlFlow, NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
+    NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
 };
 use rustc_hir::intravisit::FnKind;
 use rustc_middle::hir::map::blocks::FnLikeNode;
@@ -8,6 +8,7 @@ use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
 use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
 use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
 use rustc_span::Span;
+use std::ops::ControlFlow;
 
 crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     let def_id = body.source.def_id().expect_local();
diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
index 7216d1305fd..0449e149831 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
@@ -302,10 +302,9 @@ use super::{FieldPat, Pat, PatKind, PatRange};
 
 use rustc_arena::TypedArena;
 use rustc_attr::{SignedInt, UnsignedInt};
-use rustc_errors::ErrorReported;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{HirId, RangeEnd};
-use rustc_middle::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
+use rustc_middle::mir::interpret::{truncate, ConstValue};
 use rustc_middle::mir::Field;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{self, Const, Ty, TyCtxt};
@@ -314,108 +313,21 @@ use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{Integer, Size, VariantIdx};
 
 use smallvec::{smallvec, SmallVec};
-use std::borrow::Cow;
 use std::cmp::{self, max, min, Ordering};
-use std::convert::TryInto;
 use std::fmt;
 use std::iter::{FromIterator, IntoIterator};
 use std::ops::RangeInclusive;
 
-crate fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> {
-    LiteralExpander { tcx: cx.tcx, param_env: cx.param_env }.fold_pattern(&pat)
+crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> {
+    LiteralExpander.fold_pattern(&pat)
 }
 
-struct LiteralExpander<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-}
+struct LiteralExpander;
 
-impl<'tcx> LiteralExpander<'tcx> {
-    /// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice.
-    ///
-    /// `crty` and `rty` can differ because you can use array constants in the presence of slice
-    /// patterns. So the pattern may end up being a slice, but the constant is an array. We convert
-    /// the array to a slice in that case.
-    fn fold_const_value_deref(
-        &mut self,
-        val: ConstValue<'tcx>,
-        // the pattern's pointee type
-        rty: Ty<'tcx>,
-        // the constant's pointee type
-        crty: Ty<'tcx>,
-    ) -> ConstValue<'tcx> {
-        debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty);
-        match (val, &crty.kind(), &rty.kind()) {
-            // the easy case, deref a reference
-            (ConstValue::Scalar(p), x, y) if x == y => {
-                match p {
-                    Scalar::Ptr(p) => {
-                        let alloc = self.tcx.global_alloc(p.alloc_id).unwrap_memory();
-                        ConstValue::ByRef { alloc, offset: p.offset }
-                    }
-                    Scalar::Raw { .. } => {
-                        let layout = self.tcx.layout_of(self.param_env.and(rty)).unwrap();
-                        if layout.is_zst() {
-                            // Deref of a reference to a ZST is a nop.
-                            ConstValue::Scalar(Scalar::zst())
-                        } else {
-                            // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;`
-                            bug!("cannot deref {:#?}, {} -> {}", val, crty, rty);
-                        }
-                    }
-                }
-            }
-            // unsize array to slice if pattern is array but match value or other patterns are slice
-            (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
-                assert_eq!(t, u);
-                ConstValue::Slice {
-                    data: self.tcx.global_alloc(p.alloc_id).unwrap_memory(),
-                    start: p.offset.bytes().try_into().unwrap(),
-                    end: n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap(),
-                }
-            }
-            // fat pointers stay the same
-            (ConstValue::Slice { .. }, _, _)
-            | (_, ty::Slice(_), ty::Slice(_))
-            | (_, ty::Str, ty::Str) => val,
-            // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
-            _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
-        }
-    }
-}
-
-impl<'tcx> PatternFolder<'tcx> for LiteralExpander<'tcx> {
+impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
     fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> {
         debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind);
         match (pat.ty.kind(), &*pat.kind) {
-            (&ty::Ref(_, rty, _), &PatKind::Constant { value: Const { val, ty: const_ty } })
-                if const_ty.is_ref() =>
-            {
-                let crty =
-                    if let ty::Ref(_, crty, _) = const_ty.kind() { crty } else { unreachable!() };
-                if let ty::ConstKind::Value(val) = val {
-                    Pat {
-                        ty: pat.ty,
-                        span: pat.span,
-                        kind: box PatKind::Deref {
-                            subpattern: Pat {
-                                ty: rty,
-                                span: pat.span,
-                                kind: box PatKind::Constant {
-                                    value: Const::from_value(
-                                        self.tcx,
-                                        self.fold_const_value_deref(*val, rty, crty),
-                                        rty,
-                                    ),
-                                },
-                            },
-                        },
-                    }
-                } else {
-                    bug!("cannot deref {:#?}, {} -> {}", val, crty, rty)
-                }
-            }
-
             (_, &PatKind::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self),
             (_, &PatKind::AscribeUserType { subpattern: ref s, .. }) => s.fold_with(self),
             _ => pat.super_fold_with(self),
@@ -500,9 +412,15 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
         cx: &mut MatchCheckCtxt<'p, 'tcx>,
         constructor: &Constructor<'tcx>,
         ctor_wild_subpatterns: &Fields<'p, 'tcx>,
+        is_my_head_ctor: bool,
     ) -> Option<PatStack<'p, 'tcx>> {
-        let new_fields =
-            specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns)?;
+        let new_fields = specialize_one_pattern(
+            cx,
+            self.head(),
+            constructor,
+            ctor_wild_subpatterns,
+            is_my_head_ctor,
+        )?;
         Some(new_fields.push_on_patstack(&self.0[1..]))
     }
 }
@@ -680,6 +598,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
                                 cx,
                                 constructor,
                                 ctor_wild_subpatterns,
+                                false,
                             )
                         })
                         .collect()
@@ -705,7 +624,9 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
             SpecializationCache::Incompatible => self
                 .patterns
                 .iter()
-                .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
+                .filter_map(|r| {
+                    r.specialize_constructor(cx, constructor, ctor_wild_subpatterns, false)
+                })
                 .collect(),
         }
     }
@@ -725,6 +646,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
 /// +++++++++++++++++++++++++++++
 /// + _     + [_, _, tail @ ..] +
 /// +++++++++++++++++++++++++++++
+/// ```
 impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "\n")?;
@@ -926,42 +848,30 @@ enum Constructor<'tcx> {
     Single,
     /// Enum variants.
     Variant(DefId),
-    /// Literal values.
-    ConstantValue(&'tcx ty::Const<'tcx>),
     /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
     IntRange(IntRange<'tcx>),
     /// Ranges of floating-point literal values (`2.0..=5.2`).
     FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
+    /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
+    Str(&'tcx ty::Const<'tcx>),
     /// Array and slice patterns.
     Slice(Slice),
+    /// Constants that must not be matched structurally. They are treated as black
+    /// boxes for the purposes of exhaustiveness: we must not inspect them, and they
+    /// don't count towards making a match exhaustive.
+    Opaque,
     /// Fake extra constructor for enums that aren't allowed to be matched exhaustively.
     NonExhaustive,
 }
 
 impl<'tcx> Constructor<'tcx> {
-    fn is_slice(&self) -> bool {
-        match self {
-            Slice(_) => true,
-            _ => false,
-        }
-    }
-
-    fn variant_index_for_adt<'a>(
-        &self,
-        cx: &MatchCheckCtxt<'a, 'tcx>,
-        adt: &'tcx ty::AdtDef,
-    ) -> VariantIdx {
+    fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx {
         match *self {
             Variant(id) => adt.variant_index_with_id(id),
             Single => {
                 assert!(!adt.is_enum());
                 VariantIdx::new(0)
             }
-            ConstantValue(c) => cx
-                .tcx
-                .destructure_const(cx.param_env.and(c))
-                .variant
-                .expect("destructed const of adt without variant id"),
             _ => bug!("bad constructor {:?} for adt {:?}", self, adt),
         }
     }
@@ -975,7 +885,7 @@ impl<'tcx> Constructor<'tcx> {
 
         match self {
             // Those constructors can only match themselves.
-            Single | Variant(_) | ConstantValue(..) | FloatRange(..) => {
+            Single | Variant(_) | Str(..) | FloatRange(..) => {
                 if other_ctors.iter().any(|c| c == self) { vec![] } else { vec![self.clone()] }
             }
             &Slice(slice) => {
@@ -983,8 +893,6 @@ impl<'tcx> Constructor<'tcx> {
                     .iter()
                     .filter_map(|c: &Constructor<'_>| match c {
                         Slice(slice) => Some(*slice),
-                        // FIXME(oli-obk): implement `deref` for `ConstValue`
-                        ConstantValue(..) => None,
                         _ => bug!("bad slice pattern constructor {:?}", c),
                     })
                     .map(Slice::value_kind);
@@ -1048,6 +956,7 @@ impl<'tcx> Constructor<'tcx> {
             }
             // This constructor is never covered by anything else
             NonExhaustive => vec![NonExhaustive],
+            Opaque => bug!("unexpected opaque ctor {:?} found in all_ctors", self),
         }
     }
 
@@ -1087,7 +996,7 @@ impl<'tcx> Constructor<'tcx> {
                             PatKind::Variant {
                                 adt_def: adt,
                                 substs,
-                                variant_index: self.variant_index_for_adt(cx, adt),
+                                variant_index: self.variant_index_for_adt(adt),
                                 subpatterns,
                             }
                         } else {
@@ -1126,10 +1035,11 @@ impl<'tcx> Constructor<'tcx> {
                     PatKind::Slice { prefix, slice: Some(wild), suffix }
                 }
             },
-            &ConstantValue(value) => PatKind::Constant { value },
+            &Str(value) => PatKind::Constant { value },
             &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
             IntRange(range) => return range.to_pat(cx.tcx),
             NonExhaustive => PatKind::Wild,
+            Opaque => bug!("we should not try to apply an opaque constructor {:?}", self),
         };
 
         Pat { ty, span: DUMMY_SP, kind: Box::new(pat) }
@@ -1204,12 +1114,6 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
         Fields::Slice(std::slice::from_ref(pat))
     }
 
-    /// Construct a new `Fields` from the given patterns. You must be sure those patterns can't
-    /// contain fields that need to be filtered out. When in doubt, prefer `replace_fields`.
-    fn from_slice_unfiltered(pats: &'p [Pat<'tcx>]) -> Self {
-        Fields::Slice(pats)
-    }
-
     /// Convenience; internal use.
     fn wildcards_from_tys(
         cx: &MatchCheckCtxt<'p, 'tcx>,
@@ -1239,7 +1143,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
                         // Use T as the sub pattern type of Box<T>.
                         Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0)))
                     } else {
-                        let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)];
+                        let variant = &adt.variants[constructor.variant_index_for_adt(adt)];
                         // Whether we must not match the fields of this variant exhaustively.
                         let is_non_exhaustive =
                             variant.is_field_list_non_exhaustive() && !adt.did.is_local();
@@ -1287,7 +1191,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
                 }
                 _ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
             },
-            ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => Fields::empty(),
+            Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque => Fields::empty(),
         };
         debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
         ret
@@ -1600,9 +1504,7 @@ fn all_constructors<'a, 'tcx>(
         )
     };
     match *pcx.ty.kind() {
-        ty::Bool => {
-            [true, false].iter().map(|&b| ConstantValue(ty::Const::from_bool(cx.tcx, b))).collect()
-        }
+        ty::Bool => vec![make_range(0, 1)],
         ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
             let len = len.eval_usize(cx.tcx, cx.param_env);
             if len != 0 && cx.is_uninhabited(sub_ty) {
@@ -1717,7 +1619,7 @@ impl<'tcx> IntRange<'tcx> {
     #[inline]
     fn is_integral(ty: Ty<'_>) -> bool {
         match ty.kind() {
-            ty::Char | ty::Int(_) | ty::Uint(_) => true,
+            ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool => true,
             _ => false,
         }
     }
@@ -1739,6 +1641,7 @@ impl<'tcx> IntRange<'tcx> {
     #[inline]
     fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> {
         match *ty.kind() {
+            ty::Bool => Some((Size::from_bytes(1), 0)),
             ty::Char => Some((Size::from_bytes(4), 0)),
             ty::Int(ity) => {
                 let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
@@ -2230,7 +2133,7 @@ fn is_useful_specialized<'p, 'tcx>(
     // We cache the result of `Fields::wildcards` because it is used a lot.
     let ctor_wild_subpatterns = Fields::wildcards(cx, &ctor, ty);
     let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
-    v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns)
+    v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns, true)
         .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false))
         .map(|u| u.apply_constructor(cx, &ctor, ty, &ctor_wild_subpatterns))
         .unwrap_or(NotUseful)
@@ -2255,18 +2158,13 @@ fn pat_constructor<'tcx>(
             if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) {
                 Some(IntRange(int_range))
             } else {
-                match (value.val, &value.ty.kind()) {
-                    (_, ty::Array(_, n)) => {
-                        let len = n.eval_usize(tcx, param_env);
-                        Some(Slice(Slice { array_len: Some(len), kind: FixedLen(len) }))
-                    }
-                    (ty::ConstKind::Value(ConstValue::Slice { start, end, .. }), ty::Slice(_)) => {
-                        let len = (end - start) as u64;
-                        Some(Slice(Slice { array_len: None, kind: FixedLen(len) }))
-                    }
-                    // FIXME(oli-obk): implement `deref` for `ConstValue`
-                    // (ty::ConstKind::Value(ConstValue::ByRef { .. }), ty::Slice(_)) => { ... }
-                    _ => Some(ConstantValue(value)),
+                match value.ty.kind() {
+                    ty::Float(_) => Some(FloatRange(value, value, RangeEnd::Included)),
+                    ty::Ref(_, t, _) if t.is_str() => Some(Str(value)),
+                    // All constants that can be structurally matched have already been expanded
+                    // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
+                    // opaque.
+                    _ => Some(Opaque),
                 }
             }
         }
@@ -2302,75 +2200,6 @@ fn pat_constructor<'tcx>(
     }
 }
 
-// checks whether a constant is equal to a user-written slice pattern. Only supports byte slices,
-// meaning all other types will compare unequal and thus equal patterns often do not cause the
-// second pattern to lint about unreachable match arms.
-fn slice_pat_covered_by_const<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    _span: Span,
-    const_val: &'tcx ty::Const<'tcx>,
-    prefix: &[Pat<'tcx>],
-    slice: &Option<Pat<'tcx>>,
-    suffix: &[Pat<'tcx>],
-    param_env: ty::ParamEnv<'tcx>,
-) -> Result<bool, ErrorReported> {
-    let const_val_val = if let ty::ConstKind::Value(val) = const_val.val {
-        val
-    } else {
-        bug!(
-            "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
-            const_val,
-            prefix,
-            slice,
-            suffix,
-        )
-    };
-
-    let data: &[u8] = match (const_val_val, &const_val.ty.kind()) {
-        (ConstValue::ByRef { offset, alloc, .. }, ty::Array(t, n)) => {
-            assert_eq!(*t, tcx.types.u8);
-            let n = n.eval_usize(tcx, param_env);
-            let ptr = Pointer::new(AllocId(0), offset);
-            alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
-        }
-        (ConstValue::Slice { data, start, end }, ty::Slice(t)) => {
-            assert_eq!(*t, tcx.types.u8);
-            let ptr = Pointer::new(AllocId(0), Size::from_bytes(start));
-            data.get_bytes(&tcx, ptr, Size::from_bytes(end - start)).unwrap()
-        }
-        // FIXME(oli-obk): create a way to extract fat pointers from ByRef
-        (_, ty::Slice(_)) => return Ok(false),
-        _ => bug!(
-            "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
-            const_val,
-            prefix,
-            slice,
-            suffix,
-        ),
-    };
-
-    let pat_len = prefix.len() + suffix.len();
-    if data.len() < pat_len || (slice.is_none() && data.len() > pat_len) {
-        return Ok(false);
-    }
-
-    for (ch, pat) in data[..prefix.len()]
-        .iter()
-        .zip(prefix)
-        .chain(data[data.len() - suffix.len()..].iter().zip(suffix))
-    {
-        if let box PatKind::Constant { value } = pat.kind {
-            let b = value.eval_bits(tcx, param_env, pat.ty);
-            assert_eq!(b as u8 as u128, b);
-            if b as u8 != *ch {
-                return Ok(false);
-            }
-        }
-    }
-
-    Ok(true)
-}
-
 /// For exhaustive integer matching, some constructors are grouped within other constructors
 /// (namely integer typed values are grouped within ranges). However, when specialising these
 /// constructors, we want to be specialising for the underlying constructors (the integers), not
@@ -2668,35 +2497,6 @@ fn lint_overlapping_patterns<'tcx>(
     }
 }
 
-fn constructor_covered_by_range<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    ctor: &Constructor<'tcx>,
-    pat: &Pat<'tcx>,
-) -> Option<()> {
-    if let Single = ctor {
-        return Some(());
-    }
-
-    let (pat_from, pat_to, pat_end, ty) = match *pat.kind {
-        PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty),
-        PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty),
-        _ => bug!("`constructor_covered_by_range` called with {:?}", pat),
-    };
-    let (ctor_from, ctor_to, ctor_end) = match *ctor {
-        ConstantValue(value) => (value, value, RangeEnd::Included),
-        FloatRange(from, to, ctor_end) => (from, to, ctor_end),
-        _ => bug!("`constructor_covered_by_range` called with {:?}", ctor),
-    };
-    trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, pat_from, pat_to, ty);
-
-    let to = compare_const_vals(tcx, ctor_to, pat_to, param_env, ty)?;
-    let from = compare_const_vals(tcx, ctor_from, pat_from, param_env, ty)?;
-    let intersects = (from == Ordering::Greater || from == Ordering::Equal)
-        && (to == Ordering::Less || (pat_end == ctor_end && to == Ordering::Equal));
-    if intersects { Some(()) } else { None }
-}
-
 /// This is the main specialization step. It expands the pattern
 /// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
 /// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
@@ -2713,15 +2513,43 @@ fn specialize_one_pattern<'p, 'tcx>(
     pat: &'p Pat<'tcx>,
     constructor: &Constructor<'tcx>,
     ctor_wild_subpatterns: &Fields<'p, 'tcx>,
+    is_its_own_ctor: bool, // Whether `ctor` is known to be derived from `pat`
 ) -> Option<Fields<'p, 'tcx>> {
     if let NonExhaustive = constructor {
-        // Only a wildcard pattern can match the special extra constructor
+        // Only a wildcard pattern can match the special extra constructor.
         if !pat.is_wildcard() {
             return None;
         }
         return Some(Fields::empty());
     }
 
+    if let Opaque = constructor {
+        // Only a wildcard pattern can match an opaque constant, unless we're specializing the
+        // value against its own constructor. That happens when we call
+        // `v.specialize_constructor(ctor)` with `ctor` obtained from `pat_constructor(v.head())`.
+        // For example, in the following match, when we are dealing with the third branch, we will
+        // specialize with an `Opaque` ctor. We want to ignore the second branch because opaque
+        // constants should not be inspected, but we don't want to ignore the current (third)
+        // branch, as that would cause us to always conclude that such a branch is unreachable.
+        // ```rust
+        // #[derive(PartialEq)]
+        // struct Foo(i32);
+        // impl Eq for Foo {}
+        // const FOO: Foo = Foo(42);
+        //
+        // match (Foo(0), true) {
+        //     (_, true) => {}
+        //     (FOO, true) => {}
+        //     (FOO, false) => {}
+        // }
+        // ```
+        if is_its_own_ctor || pat.is_wildcard() {
+            return Some(Fields::empty());
+        } else {
+            return None;
+        }
+    }
+
     let result = match *pat.kind {
         PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
 
@@ -2741,93 +2569,52 @@ fn specialize_one_pattern<'p, 'tcx>(
 
         PatKind::Deref { ref subpattern } => Some(Fields::from_single_pattern(subpattern)),
 
-        PatKind::Constant { value } if constructor.is_slice() => {
-            // We extract an `Option` for the pointer because slices of zero
-            // elements don't necessarily point to memory, they are usually
-            // just integers. The only time they should be pointing to memory
-            // is when they are subslices of nonzero slices.
-            let (alloc, offset, n, ty) = match value.ty.kind() {
-                ty::Array(t, n) => {
-                    let n = n.eval_usize(cx.tcx, cx.param_env);
-                    // Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce,
-                    // the result would be exactly what we early return here.
-                    if n == 0 {
-                        if ctor_wild_subpatterns.len() as u64 != n {
-                            return None;
-                        }
-                        return Some(Fields::empty());
-                    }
-                    match value.val {
-                        ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
-                            (Cow::Borrowed(alloc), offset, n, t)
-                        }
-                        _ => span_bug!(pat.span, "array pattern is {:?}", value,),
+        PatKind::Constant { .. } | PatKind::Range { .. } => {
+            match constructor {
+                IntRange(ctor) => {
+                    let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?;
+                    ctor.intersection(cx.tcx, &pat)?;
+                    // Constructor splitting should ensure that all intersections we encounter
+                    // are actually inclusions.
+                    assert!(ctor.is_subrange(&pat));
+                }
+                FloatRange(ctor_from, ctor_to, ctor_end) => {
+                    let (pat_from, pat_to, pat_end, ty) = match *pat.kind {
+                        PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty),
+                        PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty),
+                        _ => unreachable!(), // This is ensured by the branch we're in
+                    };
+                    let to = compare_const_vals(cx.tcx, ctor_to, pat_to, cx.param_env, ty)?;
+                    let from = compare_const_vals(cx.tcx, ctor_from, pat_from, cx.param_env, ty)?;
+                    let intersects = (from == Ordering::Greater || from == Ordering::Equal)
+                        && (to == Ordering::Less
+                            || (pat_end == *ctor_end && to == Ordering::Equal));
+                    if !intersects {
+                        return None;
                     }
                 }
-                ty::Slice(t) => {
-                    match value.val {
-                        ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
-                            let offset = Size::from_bytes(start);
-                            let n = (end - start) as u64;
-                            (Cow::Borrowed(data), offset, n, t)
-                        }
-                        ty::ConstKind::Value(ConstValue::ByRef { .. }) => {
-                            // FIXME(oli-obk): implement `deref` for `ConstValue`
-                            return None;
-                        }
+                Str(ctor_value) => {
+                    let pat_value = match *pat.kind {
+                        PatKind::Constant { value } => value,
                         _ => span_bug!(
                             pat.span,
-                            "slice pattern constant must be scalar pair but is {:?}",
-                            value,
+                            "unexpected range pattern {:?} for constant value ctor",
+                            pat
                         ),
+                    };
+
+                    // FIXME: there's probably a more direct way of comparing for equality
+                    if compare_const_vals(cx.tcx, ctor_value, pat_value, cx.param_env, pat.ty)?
+                        != Ordering::Equal
+                    {
+                        return None;
                     }
                 }
-                _ => span_bug!(
-                    pat.span,
-                    "unexpected const-val {:?} with ctor {:?}",
-                    value,
-                    constructor,
-                ),
-            };
-            if ctor_wild_subpatterns.len() as u64 != n {
-                return None;
-            }
-
-            // Convert a constant slice/array pattern to a list of patterns.
-            let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
-            let ptr = Pointer::new(AllocId(0), offset);
-            let pats = cx.pattern_arena.alloc_from_iter((0..n).filter_map(|i| {
-                let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
-                let scalar = alloc.read_scalar(&cx.tcx, ptr, layout.size).ok()?;
-                let scalar = scalar.check_init().ok()?;
-                let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
-                let pattern = Pat { ty, span: pat.span, kind: box PatKind::Constant { value } };
-                Some(pattern)
-            }));
-            // Ensure none of the dereferences failed.
-            if pats.len() as u64 != n {
-                return None;
-            }
-            Some(Fields::from_slice_unfiltered(pats))
-        }
-
-        PatKind::Constant { .. } | PatKind::Range { .. } => {
-            // If the constructor is a:
-            // - Single value: add a row if the pattern contains the constructor.
-            // - Range: add a row if the constructor intersects the pattern.
-            if let IntRange(ctor) = constructor {
-                let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?;
-                ctor.intersection(cx.tcx, &pat)?;
-                // Constructor splitting should ensure that all intersections we encounter
-                // are actually inclusions.
-                assert!(ctor.is_subrange(&pat));
-            } else {
-                // Fallback for non-ranges and ranges that involve
-                // floating-point numbers, which are not conveniently handled
-                // by `IntRange`. For these cases, the constructor may not be a
-                // range so intersection actually devolves into being covered
-                // by the pattern.
-                constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat)?;
+                _ => {
+                    // If we reach here, we must be trying to inspect an opaque constant. Thus we skip
+                    // the row.
+                    return None;
+                }
             }
             Some(Fields::empty())
         }
@@ -2850,21 +2637,6 @@ fn specialize_one_pattern<'p, 'tcx>(
                 let suffix = suffix.iter().enumerate().map(|(i, p)| (arity - suffix.len() + i, p));
                 Some(ctor_wild_subpatterns.replace_fields_indexed(prefix.chain(suffix)))
             }
-            ConstantValue(cv) => {
-                match slice_pat_covered_by_const(
-                    cx.tcx,
-                    pat.span,
-                    cv,
-                    prefix,
-                    slice,
-                    suffix,
-                    cx.param_env,
-                ) {
-                    Ok(true) => Some(Fields::empty()),
-                    Ok(false) => None,
-                    Err(ErrorReported) => None,
-                }
-            }
             _ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
         },
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 69de7c7e2ee..30b700a1d4f 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -137,7 +137,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
         patcx.include_lint_checks();
         let pattern = patcx.lower_pattern(pat);
         let pattern_ty = pattern.ty;
-        let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
+        let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(pattern));
         if !patcx.errors.is_empty() {
             *have_errors = true;
             patcx.report_inlining_errors(pat.span);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index a203b3a1428..6370f8c375b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -387,14 +387,16 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                 // `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this
                 // optimization for now.
                 ty::Str => PatKind::Constant { value: cv },
-                ty::Slice(elem_ty) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv },
                 // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
                 // matching against references, you can only use byte string literals.
-                // FIXME: clean this up, likely by permitting array patterns when matching on slices
-                ty::Array(elem_ty, _) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv },
+                // The typechecker has a special case for byte string literals, by treating them
+                // as slices. This means we turn `&[T; N]` constants into slice patterns, which
+                // has no negative effects on pattern matching, even if we're actually matching on
+                // arrays.
+                ty::Array(..) |
                 // Cannot merge this with the catch all branch below, because the `const_deref`
-                // changes the type from slice to array, and slice patterns behave differently from
-                // array patterns.
+                // changes the type from slice to array, we need to keep the original type in the
+                // pattern.
                 ty::Slice(..) => {
                     let old = self.behind_reference.replace(true);
                     let array = tcx.deref_const(self.param_env.and(cv));
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index b05ddb3b464..25e18724341 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -158,6 +158,13 @@ crate enum PatKind<'tcx> {
         subpattern: Pat<'tcx>,
     },
 
+    /// One of the following:
+    /// * `&str`, which will be handled as a string pattern and thus exhaustiveness
+    ///   checking will detect if you use the same string twice in different patterns.
+    /// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly
+    ///   its own value, similar to `&str`, but these values are much simpler.
+    /// * Opaque constants, that must not be matched structurally. So anything that does not derive
+    ///   `PartialEq` and `Eq`.
     Constant {
         value: &'tcx ty::Const<'tcx>,
     },
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index 6c9849e8708..0f0684b3547 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -5,7 +5,6 @@ use crate::dep_graph::SerializedDepNodeIndex;
 use crate::query::caches::QueryCache;
 use crate::query::plumbing::CycleError;
 use crate::query::{QueryContext, QueryState};
-use rustc_data_structures::profiling::ProfileCategory;
 
 use rustc_data_structures::fingerprint::Fingerprint;
 use std::borrow::Cow;
@@ -14,7 +13,6 @@ use std::hash::Hash;
 
 pub trait QueryConfig {
     const NAME: &'static str;
-    const CATEGORY: ProfileCategory;
 
     type Key: Eq + Hash + Clone + Debug;
     type Value;
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index bea71389647..b5b281b93bc 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -19,7 +19,7 @@ use rustc_feature::is_builtin_attr_name;
 use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
 use rustc_hir::def_id;
 use rustc_middle::middle::stability;
-use rustc_middle::{span_bug, ty};
+use rustc_middle::ty;
 use rustc_session::lint::builtin::UNUSED_MACROS;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
@@ -885,11 +885,11 @@ impl<'a> Resolver<'a> {
                                  initial_res: Option<Res>,
                                  res: Res| {
             if let Some(initial_res) = initial_res {
-                if res != initial_res && res != Res::Err && this.ambiguity_errors.is_empty() {
+                if res != initial_res {
                     // Make sure compilation does not succeed if preferred macro resolution
                     // has changed after the macro had been expanded. In theory all such
-                    // situations should be reported as ambiguity errors, so this is a bug.
-                    span_bug!(span, "inconsistent resolution for a macro");
+                    // situations should be reported as errors, so this is a bug.
+                    this.session.delay_span_bug(span, "inconsistent resolution for a macro");
                 }
             } else {
                 // It's possible that the macro was unresolved (indeterminate) and silently
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9cf530d57c0..3133090575e 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -777,6 +777,7 @@ symbols! {
         panic_info,
         panic_location,
         panic_runtime,
+        panic_str,
         panic_unwind,
         param_attrs,
         parent_trait,
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 05e6c4804ff..3cb6ec86261 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -121,7 +121,10 @@ where
     // contains unbound type parameters. It could be a slight
     // optimization to stop iterating early.
     if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
-        bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
+        infcx.tcx.sess.delay_span_bug(
+            rustc_span::DUMMY_SP,
+            &format!("Encountered errors `{:?}` resolving bounds after type-checking", errors),
+        );
     }
 
     let result = infcx.resolve_vars_if_possible(result);
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 1e1eb16faf4..c79b2624f8c 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -223,11 +223,23 @@ impl AbstractConst<'tcx> {
     }
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+struct WorkNode<'tcx> {
+    node: Node<'tcx>,
+    span: Span,
+    used: bool,
+}
+
 struct AbstractConstBuilder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'a mir::Body<'tcx>,
     /// The current WIP node tree.
-    nodes: IndexVec<NodeId, Node<'tcx>>,
+    ///
+    /// We require all nodes to be used in the final abstract const,
+    /// so we store this here. Note that we also consider nodes as used
+    /// if they are mentioned in an assert, so some used nodes are never
+    /// actually reachable by walking the [`AbstractConst`].
+    nodes: IndexVec<NodeId, WorkNode<'tcx>>,
     locals: IndexVec<mir::Local, NodeId>,
     /// We only allow field accesses if they access
     /// the result of a checked operation.
@@ -274,6 +286,27 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
         Ok(Some(builder))
     }
 
+    fn add_node(&mut self, node: Node<'tcx>, span: Span) -> NodeId {
+        // Mark used nodes.
+        match node {
+            Node::Leaf(_) => (),
+            Node::Binop(_, lhs, rhs) => {
+                self.nodes[lhs].used = true;
+                self.nodes[rhs].used = true;
+            }
+            Node::UnaryOp(_, input) => {
+                self.nodes[input].used = true;
+            }
+            Node::FunctionCall(func, nodes) => {
+                self.nodes[func].used = true;
+                nodes.iter().for_each(|&n| self.nodes[n].used = true);
+            }
+        }
+
+        // Nodes start as unused.
+        self.nodes.push(WorkNode { node, span, used: false })
+    }
+
     fn place_to_local(
         &mut self,
         span: Span,
@@ -311,7 +344,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 let local = self.place_to_local(span, p)?;
                 Ok(self.locals[local])
             }
-            mir::Operand::Constant(ct) => Ok(self.nodes.push(Node::Leaf(ct.literal))),
+            mir::Operand::Constant(ct) => Ok(self.add_node(Node::Leaf(ct.literal), span)),
         }
     }
 
@@ -336,19 +369,19 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
 
     fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> {
         debug!("AbstractConstBuilder: stmt={:?}", stmt);
+        let span = stmt.source_info.span;
         match stmt.kind {
             StatementKind::Assign(box (ref place, ref rvalue)) => {
-                let local = self.place_to_local(stmt.source_info.span, place)?;
+                let local = self.place_to_local(span, place)?;
                 match *rvalue {
                     Rvalue::Use(ref operand) => {
-                        self.locals[local] =
-                            self.operand_to_node(stmt.source_info.span, operand)?;
+                        self.locals[local] = self.operand_to_node(span, operand)?;
                         Ok(())
                     }
                     Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
-                        let lhs = self.operand_to_node(stmt.source_info.span, lhs)?;
-                        let rhs = self.operand_to_node(stmt.source_info.span, rhs)?;
-                        self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs));
+                        let lhs = self.operand_to_node(span, lhs)?;
+                        let rhs = self.operand_to_node(span, rhs)?;
+                        self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span);
                         if op.is_checkable() {
                             bug!("unexpected unchecked checkable binary operation");
                         } else {
@@ -356,18 +389,18 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                         }
                     }
                     Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
-                        let lhs = self.operand_to_node(stmt.source_info.span, lhs)?;
-                        let rhs = self.operand_to_node(stmt.source_info.span, rhs)?;
-                        self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs));
+                        let lhs = self.operand_to_node(span, lhs)?;
+                        let rhs = self.operand_to_node(span, rhs)?;
+                        self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span);
                         self.checked_op_locals.insert(local);
                         Ok(())
                     }
                     Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => {
-                        let operand = self.operand_to_node(stmt.source_info.span, operand)?;
-                        self.locals[local] = self.nodes.push(Node::UnaryOp(op, operand));
+                        let operand = self.operand_to_node(span, operand)?;
+                        self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span);
                         Ok(())
                     }
-                    _ => self.error(Some(stmt.source_info.span), "unsupported rvalue")?,
+                    _ => self.error(Some(span), "unsupported rvalue")?,
                 }
             }
             // These are not actually relevant for us here, so we can ignore them.
@@ -415,13 +448,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                         .map(|arg| self.operand_to_node(terminator.source_info.span, arg))
                         .collect::<Result<Vec<NodeId>, _>>()?,
                 );
-                self.locals[local] = self.nodes.push(Node::FunctionCall(func, args));
+                self.locals[local] = self.add_node(Node::FunctionCall(func, args), fn_span);
                 Ok(Some(target))
             }
-            // We only allow asserts for checked operations.
-            //
-            // These asserts seem to all have the form `!_local.0` so
-            // we only allow exactly that.
             TerminatorKind::Assert { ref cond, expected: false, target, .. } => {
                 let p = match cond {
                     mir::Operand::Copy(p) | mir::Operand::Move(p) => p,
@@ -430,7 +459,15 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
 
                 const ONE_FIELD: mir::Field = mir::Field::from_usize(1);
                 debug!("proj: {:?}", p.projection);
-                if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
+                if let Some(p) = p.as_local() {
+                    debug_assert!(!self.checked_op_locals.contains(p));
+                    // Mark locals directly used in asserts as used.
+                    //
+                    // This is needed because division does not use `CheckedBinop` but instead
+                    // adds an explicit assert for `divisor != 0`.
+                    self.nodes[self.locals[p]].used = true;
+                    return Ok(Some(target));
+                } else if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
                     // Only allow asserts checking the result of a checked operation.
                     if self.checked_op_locals.contains(p.local) {
                         return Ok(Some(target));
@@ -457,7 +494,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             if let Some(next) = self.build_terminator(block.terminator())? {
                 block = &self.body.basic_blocks()[next];
             } else {
-                return Ok(self.tcx.arena.alloc_from_iter(self.nodes));
+                assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap());
+                self.nodes[self.locals[mir::RETURN_PLACE]].used = true;
+                if let Some(&unused) = self.nodes.iter().find(|n| !n.used) {
+                    self.error(Some(unused.span), "dead code")?;
+                }
+
+                return Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node)));
             }
         }
     }
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index 109c3a0e683..dd7dcfbc4aa 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -372,7 +372,7 @@ pub fn handle_alloc_error(layout: Layout) -> ! {
     unsafe { oom_impl(layout) }
 }
 
-#[cfg(not(any(test, bootstrap)))]
+#[cfg(not(any(target_os = "hermit", test, bootstrap)))]
 #[doc(hidden)]
 #[allow(unused_attributes)]
 #[unstable(feature = "alloc_internals", issue = "none")]
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index bf30dcb7689..9c8e639c2d8 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -1280,7 +1280,7 @@ where
         #[inline]
         fn find<T, B>(
             f: &mut impl FnMut(T) -> Option<B>,
-        ) -> impl FnMut((), T) -> ControlFlow<(), B> + '_ {
+        ) -> impl FnMut((), T) -> ControlFlow<B> + '_ {
             move |(), x| match f(x) {
                 Some(x) => ControlFlow::Break(x),
                 None => ControlFlow::CONTINUE,
@@ -2059,7 +2059,7 @@ where
             flag: &'a mut bool,
             p: &'a mut impl FnMut(&T) -> bool,
             mut fold: impl FnMut(Acc, T) -> R + 'a,
-        ) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> + 'a {
+        ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
             move |acc, x| {
                 if p(&x) {
                     ControlFlow::from_try(fold(acc, x))
@@ -2372,7 +2372,7 @@ where
         fn check<T, Acc, R: Try<Ok = Acc>>(
             mut n: usize,
             mut fold: impl FnMut(Acc, T) -> R,
-        ) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> {
+        ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> {
             move |acc, x| {
                 n -= 1;
                 let r = fold(acc, x);
@@ -2496,7 +2496,7 @@ where
         fn check<'a, T, Acc, R: Try<Ok = Acc>>(
             n: &'a mut usize,
             mut fold: impl FnMut(Acc, T) -> R + 'a,
-        ) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> + 'a {
+        ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
             move |acc, x| {
                 *n -= 1;
                 let r = fold(acc, x);
@@ -2681,7 +2681,7 @@ where
             state: &'a mut St,
             f: &'a mut impl FnMut(&mut St, T) -> Option<B>,
             mut fold: impl FnMut(Acc, B) -> R + 'a,
-        ) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> + 'a {
+        ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
             move |acc, x| match f(state, x) {
                 None => ControlFlow::Break(try { acc }),
                 Some(x) => ControlFlow::from_try(fold(acc, x)),
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index 87fe3c21040..6f8cb6b5a65 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -339,9 +339,7 @@ pub trait DoubleEndedIterator: Iterator {
         P: FnMut(&Self::Item) -> bool,
     {
         #[inline]
-        fn check<T>(
-            mut predicate: impl FnMut(&T) -> bool,
-        ) -> impl FnMut((), T) -> ControlFlow<(), T> {
+        fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow<T> {
             move |(), x| {
                 if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE }
             }
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 18b4adc23e8..7fc60caec2a 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -2109,7 +2109,7 @@ pub trait Iterator {
         F: FnMut(Self::Item) -> bool,
     {
         #[inline]
-        fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> {
+        fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()> {
             move |(), x| {
                 if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK }
             }
@@ -2162,7 +2162,7 @@ pub trait Iterator {
         F: FnMut(Self::Item) -> bool,
     {
         #[inline]
-        fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> {
+        fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()> {
             move |(), x| {
                 if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE }
             }
@@ -2222,9 +2222,7 @@ pub trait Iterator {
         P: FnMut(&Self::Item) -> bool,
     {
         #[inline]
-        fn check<T>(
-            mut predicate: impl FnMut(&T) -> bool,
-        ) -> impl FnMut((), T) -> ControlFlow<(), T> {
+        fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow<T> {
             move |(), x| {
                 if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE }
             }
@@ -2255,9 +2253,7 @@ pub trait Iterator {
         F: FnMut(Self::Item) -> Option<B>,
     {
         #[inline]
-        fn check<T, B>(
-            mut f: impl FnMut(T) -> Option<B>,
-        ) -> impl FnMut((), T) -> ControlFlow<(), B> {
+        fn check<T, B>(mut f: impl FnMut(T) -> Option<B>) -> impl FnMut((), T) -> ControlFlow<B> {
             move |(), x| match f(x) {
                 Some(x) => ControlFlow::Break(x),
                 None => ControlFlow::CONTINUE,
@@ -2296,7 +2292,7 @@ pub trait Iterator {
         R: Try<Ok = bool>,
     {
         #[inline]
-        fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<(), Result<T, R::Error>>
+        fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Error>>
         where
             F: FnMut(&T) -> R,
             R: Try<Ok = bool>,
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 4c62c16f506..ac45e819cf6 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -10,7 +10,7 @@ macro_rules! panic {
         $crate::panicking::panic($msg)
     );
     ($msg:expr) => (
-        $crate::panic!("{}", $crate::convert::identity::<&str>($msg))
+        $crate::panicking::panic_str($msg)
     );
     ($msg:expr,) => (
         $crate::panic!($msg)
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index 3bca3ff9733..5ede1ba8e2c 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -3,7 +3,7 @@ use crate::ops::Try;
 /// Used to make try_fold closures more like normal loops
 #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
 #[derive(Debug, Clone, Copy, PartialEq)]
-pub enum ControlFlow<C, B> {
+pub enum ControlFlow<B, C = ()> {
     /// Continue in the loop, using the given value for the next iteration
     Continue(C),
     /// Exit the loop, yielding the given value
@@ -11,7 +11,7 @@ pub enum ControlFlow<C, B> {
 }
 
 #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
-impl<C, B> Try for ControlFlow<C, B> {
+impl<B, C> Try for ControlFlow<B, C> {
     type Ok = C;
     type Error = B;
     #[inline]
@@ -31,7 +31,7 @@ impl<C, B> Try for ControlFlow<C, B> {
     }
 }
 
-impl<C, B> ControlFlow<C, B> {
+impl<B, C> ControlFlow<B, C> {
     /// Returns `true` if this is a `Break` variant.
     #[inline]
     #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
@@ -58,7 +58,7 @@ impl<C, B> ControlFlow<C, B> {
     }
 }
 
-impl<R: Try> ControlFlow<R::Ok, R> {
+impl<R: Try> ControlFlow<R, R::Ok> {
     /// Create a `ControlFlow` from any type implementing `Try`.
     #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
     #[inline]
@@ -80,7 +80,7 @@ impl<R: Try> ControlFlow<R::Ok, R> {
     }
 }
 
-impl<B> ControlFlow<(), B> {
+impl<B> ControlFlow<B, ()> {
     /// It's frequently the case that there's no value needed with `Continue`,
     /// so this provides a way to avoid typing `(())`, if you prefer it.
     ///
@@ -102,7 +102,7 @@ impl<B> ControlFlow<(), B> {
     pub const CONTINUE: Self = ControlFlow::Continue(());
 }
 
-impl<C> ControlFlow<C, ()> {
+impl<C> ControlFlow<(), C> {
     /// APIs like `try_for_each` don't need values with `Break`,
     /// so this provides a way to avoid typing `(())`, if you prefer it.
     ///
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 15fd638bef8..09dd19b8f5f 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -50,6 +50,13 @@ pub fn panic(expr: &'static str) -> ! {
     panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
 }
 
+#[inline]
+#[track_caller]
+#[cfg_attr(not(bootstrap), lang = "panic_str")] // needed for const-evaluated panics
+pub fn panic_str(expr: &str) -> ! {
+    panic_fmt(format_args!("{}", expr));
+}
+
 #[cold]
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[track_caller]
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 47b59d4a677..5925aa87a3f 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -42,7 +42,7 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
 fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
 
 [target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies]
-hermit-abi = { version = "0.1.15", features = ['rustc-dep-of-std'] }
+hermit-abi = { version = "0.1.17", features = ['rustc-dep-of-std'] }
 
 [target.wasm32-wasi.dependencies]
 wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 30e7a7f3c3b..3da0ebdd498 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -259,6 +259,7 @@
 #![feature(exhaustive_patterns)]
 #![feature(extend_one)]
 #![feature(external_doc)]
+#![feature(fmt_as_str)]
 #![feature(fn_traits)]
 #![feature(format_args_nl)]
 #![feature(gen_future)]
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 8dceb12de87..221ae809e23 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -478,10 +478,26 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
         }
     }
 
+    struct StrPanicPayload(&'static str);
+
+    unsafe impl BoxMeUp for StrPanicPayload {
+        fn take_box(&mut self) -> *mut (dyn Any + Send) {
+            Box::into_raw(Box::new(self.0))
+        }
+
+        fn get(&mut self) -> &(dyn Any + Send) {
+            &self.0
+        }
+    }
+
     let loc = info.location().unwrap(); // The current implementation always returns Some
     let msg = info.message().unwrap(); // The current implementation always returns Some
     crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
-        rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+        if let Some(msg) = msg.as_str() {
+            rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc);
+        } else {
+            rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+        }
     })
 }
 
diff --git a/library/std/src/sys/cloudabi/abi/cloudabi.rs b/library/std/src/sys/cloudabi/abi/cloudabi.rs
index b02faf1830c..5c4e3fd85c4 100644
--- a/library/std/src/sys/cloudabi/abi/cloudabi.rs
+++ b/library/std/src/sys/cloudabi/abi/cloudabi.rs
@@ -1910,7 +1910,7 @@ extern "C" {
 /// The resolution of the clock.
 #[inline]
 pub unsafe fn clock_res_get(clock_id_: clockid, resolution_: &mut timestamp) -> errno {
-    cloudabi_sys_clock_res_get(clock_id_, resolution_)
+    unsafe { cloudabi_sys_clock_res_get(clock_id_, resolution_) }
 }
 
 /// Obtains the time value of a clock.
@@ -1934,7 +1934,7 @@ pub unsafe fn clock_time_get(
     precision_: timestamp,
     time_: *mut timestamp,
 ) -> errno {
-    cloudabi_sys_clock_time_get(clock_id_, precision_, time_)
+    unsafe { cloudabi_sys_clock_time_get(clock_id_, precision_, time_) }
 }
 
 /// Wakes up threads waiting on a userspace condition variable.
@@ -1961,7 +1961,7 @@ pub unsafe fn clock_time_get(
 /// threads, all threads are woken up.
 #[inline]
 pub unsafe fn condvar_signal(condvar_: *mut condvar, scope_: scope, nwaiters_: nthreads) -> errno {
-    cloudabi_sys_condvar_signal(condvar_, scope_, nwaiters_)
+    unsafe { cloudabi_sys_condvar_signal(condvar_, scope_, nwaiters_) }
 }
 
 /// Closes a file descriptor.
@@ -1972,7 +1972,7 @@ pub unsafe fn condvar_signal(condvar_: *mut condvar, scope_: scope, nwaiters_: n
 /// The file descriptor that needs to be closed.
 #[inline]
 pub unsafe fn fd_close(fd_: fd) -> errno {
-    cloudabi_sys_fd_close(fd_)
+    unsafe { cloudabi_sys_fd_close(fd_) }
 }
 
 /// Creates a file descriptor.
@@ -1990,7 +1990,7 @@ pub unsafe fn fd_close(fd_: fd) -> errno {
 /// The file descriptor that has been created.
 #[inline]
 pub unsafe fn fd_create1(type_: filetype, fd_: &mut fd) -> errno {
-    cloudabi_sys_fd_create1(type_, fd_)
+    unsafe { cloudabi_sys_fd_create1(type_, fd_) }
 }
 
 /// Creates a pair of file descriptors.
@@ -2013,7 +2013,8 @@ pub unsafe fn fd_create1(type_: filetype, fd_: &mut fd) -> errno {
 /// The second file descriptor of the pair.
 #[inline]
 pub unsafe fn fd_create2(type_: filetype, fd1_: &mut fd, fd2_: &mut fd) -> errno {
-    cloudabi_sys_fd_create2(type_, fd1_, fd2_)
+    // SAFETY: the caller must uphold the safety contract for `cloudabi_sys_fd_create2`.
+    unsafe { cloudabi_sys_fd_create2(type_, fd1_, fd2_) }
 }
 
 /// Synchronizes the data of a file to disk.
@@ -2025,7 +2026,9 @@ pub unsafe fn fd_create2(type_: filetype, fd1_: &mut fd, fd2_: &mut fd) -> errno
 /// needs to be synchronized to disk.
 #[inline]
 pub unsafe fn fd_datasync(fd_: fd) -> errno {
-    cloudabi_sys_fd_datasync(fd_)
+    // SAFETY: the caller must guarantee that `fd` is valid
+    // for synchronization.
+    unsafe { cloudabi_sys_fd_datasync(fd_) }
 }
 
 /// Duplicates a file descriptor.
@@ -2040,7 +2043,7 @@ pub unsafe fn fd_datasync(fd_: fd) -> errno {
 /// The new file descriptor.
 #[inline]
 pub unsafe fn fd_dup(from_: fd, fd_: &mut fd) -> errno {
-    cloudabi_sys_fd_dup(from_, fd_)
+    unsafe { cloudabi_sys_fd_dup(from_, fd_) }
 }
 
 /// Reads from a file descriptor, without using and updating the
@@ -2064,7 +2067,7 @@ pub unsafe fn fd_dup(from_: fd, fd_: &mut fd) -> errno {
 /// The number of bytes read.
 #[inline]
 pub unsafe fn fd_pread(fd_: fd, iovs_: &[iovec], offset_: filesize, nread_: &mut usize) -> errno {
-    cloudabi_sys_fd_pread(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nread_)
+    unsafe { cloudabi_sys_fd_pread(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nread_) }
 }
 
 /// Writes to a file descriptor, without using and updating the
@@ -2093,7 +2096,7 @@ pub unsafe fn fd_pwrite(
     offset_: filesize,
     nwritten_: &mut usize,
 ) -> errno {
-    cloudabi_sys_fd_pwrite(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nwritten_)
+    unsafe { cloudabi_sys_fd_pwrite(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nwritten_) }
 }
 
 /// Reads from a file descriptor.
@@ -2112,7 +2115,7 @@ pub unsafe fn fd_pwrite(
 /// The number of bytes read.
 #[inline]
 pub unsafe fn fd_read(fd_: fd, iovs_: &[iovec], nread_: &mut usize) -> errno {
-    cloudabi_sys_fd_read(fd_, iovs_.as_ptr(), iovs_.len(), nread_)
+    unsafe { cloudabi_sys_fd_read(fd_, iovs_.as_ptr(), iovs_.len(), nread_) }
 }
 
 /// Atomically replaces a file descriptor by a copy of another
@@ -2138,7 +2141,7 @@ pub unsafe fn fd_read(fd_: fd, iovs_: &[iovec], nread_: &mut usize) -> errno {
 /// overwritten.
 #[inline]
 pub unsafe fn fd_replace(from_: fd, to_: fd) -> errno {
-    cloudabi_sys_fd_replace(from_, to_)
+    unsafe { cloudabi_sys_fd_replace(from_, to_) }
 }
 
 /// Moves the offset of the file descriptor.
@@ -2166,7 +2169,7 @@ pub unsafe fn fd_seek(
     whence_: whence,
     newoffset_: &mut filesize,
 ) -> errno {
-    cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_)
+    unsafe { cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_) }
 }
 
 /// Gets attributes of a file descriptor.
@@ -2182,7 +2185,7 @@ pub unsafe fn fd_seek(
 /// attributes are stored.
 #[inline]
 pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno {
-    cloudabi_sys_fd_stat_get(fd_, buf_)
+    unsafe { cloudabi_sys_fd_stat_get(fd_, buf_) }
 }
 
 /// Adjusts attributes of a file descriptor.
@@ -2202,7 +2205,7 @@ pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno {
 /// be adjusted.
 #[inline]
 pub unsafe fn fd_stat_put(fd_: fd, buf_: *const fdstat, flags_: fdsflags) -> errno {
-    cloudabi_sys_fd_stat_put(fd_, buf_, flags_)
+    unsafe { cloudabi_sys_fd_stat_put(fd_, buf_, flags_) }
 }
 
 /// Synchronizes the data and metadata of a file to disk.
@@ -2214,7 +2217,7 @@ pub unsafe fn fd_stat_put(fd_: fd, buf_: *const fdstat, flags_: fdsflags) -> err
 /// and metadata needs to be synchronized to disk.
 #[inline]
 pub unsafe fn fd_sync(fd_: fd) -> errno {
-    cloudabi_sys_fd_sync(fd_)
+    unsafe { cloudabi_sys_fd_sync(fd_) }
 }
 
 /// Writes to a file descriptor.
@@ -2233,7 +2236,7 @@ pub unsafe fn fd_sync(fd_: fd) -> errno {
 /// The number of bytes written.
 #[inline]
 pub unsafe fn fd_write(fd_: fd, iovs_: &[ciovec], nwritten_: &mut usize) -> errno {
-    cloudabi_sys_fd_write(fd_, iovs_.as_ptr(), iovs_.len(), nwritten_)
+    unsafe { cloudabi_sys_fd_write(fd_, iovs_.as_ptr(), iovs_.len(), nwritten_) }
 }
 
 /// Provides file advisory information on a file descriptor.
@@ -2256,7 +2259,7 @@ pub unsafe fn fd_write(fd_: fd, iovs_: &[ciovec], nwritten_: &mut usize) -> errn
 /// The advice.
 #[inline]
 pub unsafe fn file_advise(fd_: fd, offset_: filesize, len_: filesize, advice_: advice) -> errno {
-    cloudabi_sys_file_advise(fd_, offset_, len_, advice_)
+    unsafe { cloudabi_sys_file_advise(fd_, offset_, len_, advice_) }
 }
 
 /// Forces the allocation of space in a file.
@@ -2275,7 +2278,7 @@ pub unsafe fn file_advise(fd_: fd, offset_: filesize, len_: filesize, advice_: a
 /// The length of the area that is allocated.
 #[inline]
 pub unsafe fn file_allocate(fd_: fd, offset_: filesize, len_: filesize) -> errno {
-    cloudabi_sys_file_allocate(fd_, offset_, len_)
+    unsafe { cloudabi_sys_file_allocate(fd_, offset_, len_) }
 }
 
 /// Creates a file of a specified type.
@@ -2296,7 +2299,7 @@ pub unsafe fn file_allocate(fd_: fd, offset_: filesize, len_: filesize) -> errno
 ///     Creates a directory.
 #[inline]
 pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno {
-    cloudabi_sys_file_create(fd_, path_.as_ptr(), path_.len(), type_)
+    unsafe { cloudabi_sys_file_create(fd_, path_.as_ptr(), path_.len(), type_)}
 }
 
 /// Creates a hard link.
@@ -2320,7 +2323,7 @@ pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno {
 /// should be created.
 #[inline]
 pub unsafe fn file_link(fd1_: lookup, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno {
-    cloudabi_sys_file_link(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len())
+    unsafe { cloudabi_sys_file_link(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len()) }
 }
 
 /// Opens a file.
@@ -2362,7 +2365,7 @@ pub unsafe fn file_open(
     fds_: *const fdstat,
     fd_: &mut fd,
 ) -> errno {
-    cloudabi_sys_file_open(dirfd_, path_.as_ptr(), path_.len(), oflags_, fds_, fd_)
+    unsafe { cloudabi_sys_file_open(dirfd_, path_.as_ptr(), path_.len(), oflags_, fds_, fd_) }
 }
 
 /// Reads directory entries from a directory.
@@ -2402,7 +2405,7 @@ pub unsafe fn file_readdir(
     cookie_: dircookie,
     bufused_: &mut usize,
 ) -> errno {
-    cloudabi_sys_file_readdir(fd_, buf_.as_mut_ptr() as *mut (), buf_.len(), cookie_, bufused_)
+    unsafe { cloudabi_sys_file_readdir(fd_, buf_.as_mut_ptr() as *mut (), buf_.len(), cookie_, bufused_) }
 }
 
 /// Reads the contents of a symbolic link.
@@ -2425,14 +2428,16 @@ pub unsafe fn file_readdir(
 /// The number of bytes placed in the buffer.
 #[inline]
 pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &mut usize) -> errno {
-    cloudabi_sys_file_readlink(
-        fd_,
-        path_.as_ptr(),
-        path_.len(),
-        buf_.as_mut_ptr(),
-        buf_.len(),
-        bufused_,
-    )
+    unsafe {
+        cloudabi_sys_file_readlink(
+            fd_,
+            path_.as_ptr(),
+            path_.len(),
+            buf_.as_mut_ptr(),
+            buf_.len(),
+            bufused_,
+        )
+    }
 }
 
 /// Renames a file.
@@ -2456,14 +2461,16 @@ pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &m
 /// be renamed.
 #[inline]
 pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno {
-    cloudabi_sys_file_rename(
-        fd1_,
-        path1_.as_ptr(),
-        path1_.len(),
-        fd2_,
-        path2_.as_ptr(),
-        path2_.len(),
-    )
+    unsafe {
+        cloudabi_sys_file_rename(
+            fd1_,
+            path1_.as_ptr(),
+            path1_.len(),
+            fd2_,
+            path2_.as_ptr(),
+            path2_.len(),
+        )
+    }
 }
 
 /// Gets attributes of a file by file descriptor.
@@ -2479,7 +2486,7 @@ pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> e
 /// stored.
 #[inline]
 pub unsafe fn file_stat_fget(fd_: fd, buf_: *mut filestat) -> errno {
-    cloudabi_sys_file_stat_fget(fd_, buf_)
+    unsafe { cloudabi_sys_file_stat_fget(fd_, buf_) }
 }
 
 /// Adjusts attributes of a file by file descriptor.
@@ -2499,7 +2506,7 @@ pub unsafe fn file_stat_fget(fd_: fd, buf_: *mut filestat) -> errno {
 /// be adjusted.
 #[inline]
 pub unsafe fn file_stat_fput(fd_: fd, buf_: *const filestat, flags_: fsflags) -> errno {
-    cloudabi_sys_file_stat_fput(fd_, buf_, flags_)
+    unsafe { cloudabi_sys_file_stat_fput(fd_, buf_, flags_) }
 }
 
 /// Gets attributes of a file by path.
@@ -2520,7 +2527,7 @@ pub unsafe fn file_stat_fput(fd_: fd, buf_: *const filestat, flags_: fsflags) ->
 /// stored.
 #[inline]
 pub unsafe fn file_stat_get(fd_: lookup, path_: &[u8], buf_: *mut filestat) -> errno {
-    cloudabi_sys_file_stat_get(fd_, path_.as_ptr(), path_.len(), buf_)
+    unsafe { cloudabi_sys_file_stat_get(fd_, path_.as_ptr(), path_.len(), buf_) }
 }
 
 /// Adjusts attributes of a file by path.
@@ -2550,7 +2557,7 @@ pub unsafe fn file_stat_put(
     buf_: *const filestat,
     flags_: fsflags,
 ) -> errno {
-    cloudabi_sys_file_stat_put(fd_, path_.as_ptr(), path_.len(), buf_, flags_)
+    unsafe { cloudabi_sys_file_stat_put(fd_, path_.as_ptr(), path_.len(), buf_, flags_) }
 }
 
 /// Creates a symbolic link.
@@ -2569,7 +2576,7 @@ pub unsafe fn file_stat_put(
 /// link should be created.
 #[inline]
 pub unsafe fn file_symlink(path1_: &[u8], fd_: fd, path2_: &[u8]) -> errno {
-    cloudabi_sys_file_symlink(path1_.as_ptr(), path1_.len(), fd_, path2_.as_ptr(), path2_.len())
+    unsafe { cloudabi_sys_file_symlink(path1_.as_ptr(), path1_.len(), fd_, path2_.as_ptr(), path2_.len()) }
 }
 
 /// Unlinks a file, or removes a directory.
@@ -2591,7 +2598,7 @@ pub unsafe fn file_symlink(path1_: &[u8], fd_: fd, path2_: &[u8]) -> errno {
 ///     Otherwise, unlink a file.
 #[inline]
 pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno {
-    cloudabi_sys_file_unlink(fd_, path_.as_ptr(), path_.len(), flags_)
+    unsafe { cloudabi_sys_file_unlink(fd_, path_.as_ptr(), path_.len(), flags_) }
 }
 
 /// Unlocks a write-locked userspace lock.
@@ -2618,7 +2625,7 @@ pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno {
 /// shared memory.
 #[inline]
 pub unsafe fn lock_unlock(lock_: *mut lock, scope_: scope) -> errno {
-    cloudabi_sys_lock_unlock(lock_, scope_)
+    unsafe { cloudabi_sys_lock_unlock(lock_, scope_) }
 }
 
 /// Provides memory advisory information on a region of memory.
@@ -2633,7 +2640,7 @@ pub unsafe fn lock_unlock(lock_: *mut lock, scope_: scope) -> errno {
 /// The advice.
 #[inline]
 pub unsafe fn mem_advise(mapping_: &mut [u8], advice_: advice) -> errno {
-    cloudabi_sys_mem_advise(mapping_.as_mut_ptr() as *mut (), mapping_.len(), advice_)
+    unsafe { cloudabi_sys_mem_advise(mapping_.as_mut_ptr() as *mut (), mapping_.len(), advice_) }
 }
 
 /// Creates a memory mapping, making the contents of a file
@@ -2682,7 +2689,7 @@ pub unsafe fn mem_map(
     off_: filesize,
     mem_: &mut *mut (),
 ) -> errno {
-    cloudabi_sys_mem_map(addr_, len_, prot_, flags_, fd_, off_, mem_)
+    unsafe { cloudabi_sys_mem_map(addr_, len_, prot_, flags_, fd_, off_, mem_) }
 }
 
 /// Changes the protection of a memory mapping.
@@ -2696,7 +2703,7 @@ pub unsafe fn mem_map(
 /// New protection options.
 #[inline]
 pub unsafe fn mem_protect(mapping_: &mut [u8], prot_: mprot) -> errno {
-    cloudabi_sys_mem_protect(mapping_.as_mut_ptr() as *mut (), mapping_.len(), prot_)
+    unsafe { cloudabi_sys_mem_protect(mapping_.as_mut_ptr() as *mut (), mapping_.len(), prot_) }
 }
 
 /// Synchronizes a region of memory with its physical storage.
@@ -2710,7 +2717,7 @@ pub unsafe fn mem_protect(mapping_: &mut [u8], prot_: mprot) -> errno {
 /// The method of synchronization.
 #[inline]
 pub unsafe fn mem_sync(mapping_: &mut [u8], flags_: msflags) -> errno {
-    cloudabi_sys_mem_sync(mapping_.as_mut_ptr() as *mut (), mapping_.len(), flags_)
+    unsafe { cloudabi_sys_mem_sync(mapping_.as_mut_ptr() as *mut (), mapping_.len(), flags_) }
 }
 
 /// Unmaps a region of memory.
@@ -2721,7 +2728,7 @@ pub unsafe fn mem_sync(mapping_: &mut [u8], flags_: msflags) -> errno {
 /// The pages that needs to be unmapped.
 #[inline]
 pub unsafe fn mem_unmap(mapping_: &mut [u8]) -> errno {
-    cloudabi_sys_mem_unmap(mapping_.as_mut_ptr() as *mut (), mapping_.len())
+    unsafe { cloudabi_sys_mem_unmap(mapping_.as_mut_ptr() as *mut (), mapping_.len()) }
 }
 
 /// Concurrently polls for the occurrence of a set of events.
@@ -2746,7 +2753,7 @@ pub unsafe fn poll(
     nsubscriptions_: usize,
     nevents_: *mut usize,
 ) -> errno {
-    cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_)
+    unsafe { cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_) }
 }
 
 /// Replaces the process by a new executable.
@@ -2784,7 +2791,7 @@ pub unsafe fn poll(
 /// execution.
 #[inline]
 pub unsafe fn proc_exec(fd_: fd, data_: &[u8], fds_: &[fd]) -> errno {
-    cloudabi_sys_proc_exec(fd_, data_.as_ptr() as *const (), data_.len(), fds_.as_ptr(), fds_.len())
+    unsafe { cloudabi_sys_proc_exec(fd_, data_.as_ptr() as *const (), data_.len(), fds_.as_ptr(), fds_.len()) }
 }
 
 /// Terminates the process normally.
@@ -2797,7 +2804,7 @@ pub unsafe fn proc_exec(fd_: fd, data_: &[u8], fds_: &[fd]) -> errno {
 /// through [`event.union.proc_terminate.exitcode`](struct.event_proc_terminate.html#structfield.exitcode).
 #[inline]
 pub unsafe fn proc_exit(rval_: exitcode) -> ! {
-    cloudabi_sys_proc_exit(rval_)
+    unsafe { cloudabi_sys_proc_exit(rval_) }
 }
 
 /// Forks the process of the calling thread.
@@ -2822,7 +2829,7 @@ pub unsafe fn proc_exit(rval_: exitcode) -> ! {
 /// initial thread of the child process.
 #[inline]
 pub unsafe fn proc_fork(fd_: &mut fd, tid_: &mut tid) -> errno {
-    cloudabi_sys_proc_fork(fd_, tid_)
+    unsafe { cloudabi_sys_proc_fork(fd_, tid_) }
 }
 
 /// Sends a signal to the process of the calling thread.
@@ -2837,7 +2844,7 @@ pub unsafe fn proc_fork(fd_: &mut fd, tid_: &mut tid) -> errno {
 /// [`event.union.proc_terminate.signal`](struct.event_proc_terminate.html#structfield.signal).
 #[inline]
 pub unsafe fn proc_raise(sig_: signal) -> errno {
-    cloudabi_sys_proc_raise(sig_)
+    unsafe { cloudabi_sys_proc_raise(sig_) }
 }
 
 /// Obtains random data from the kernel random number generator.
@@ -2853,7 +2860,7 @@ pub unsafe fn proc_raise(sig_: signal) -> errno {
 /// data.
 #[inline]
 pub unsafe fn random_get(buf_: &mut [u8]) -> errno {
-    cloudabi_sys_random_get(buf_.as_mut_ptr() as *mut (), buf_.len())
+    unsafe { cloudabi_sys_random_get(buf_.as_mut_ptr() as *mut (), buf_.len()) }
 }
 
 /// Receives a message on a socket.
@@ -2871,7 +2878,7 @@ pub unsafe fn random_get(buf_: &mut [u8]) -> errno {
 /// Output parameters.
 #[inline]
 pub unsafe fn sock_recv(sock_: fd, in_: *const recv_in, out_: *mut recv_out) -> errno {
-    cloudabi_sys_sock_recv(sock_, in_, out_)
+    unsafe { cloudabi_sys_sock_recv(sock_, in_, out_) }
 }
 
 /// Sends a message on a socket.
@@ -2888,7 +2895,7 @@ pub unsafe fn sock_recv(sock_: fd, in_: *const recv_in, out_: *mut recv_out) ->
 /// Output parameters.
 #[inline]
 pub unsafe fn sock_send(sock_: fd, in_: *const send_in, out_: *mut send_out) -> errno {
-    cloudabi_sys_sock_send(sock_, in_, out_)
+    unsafe { cloudabi_sys_sock_send(sock_, in_, out_) }
 }
 
 /// Shuts down socket send and receive channels.
@@ -2903,7 +2910,7 @@ pub unsafe fn sock_send(sock_: fd, in_: *const send_in, out_: *mut send_out) ->
 /// down.
 #[inline]
 pub unsafe fn sock_shutdown(sock_: fd, how_: sdflags) -> errno {
-    cloudabi_sys_sock_shutdown(sock_, how_)
+    unsafe { cloudabi_sys_sock_shutdown(sock_, how_) }
 }
 
 /// Creates a new thread within the current process.
@@ -2917,7 +2924,7 @@ pub unsafe fn sock_shutdown(sock_: fd, how_: sdflags) -> errno {
 /// The thread ID of the new thread.
 #[inline]
 pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno {
-    cloudabi_sys_thread_create(attr_, tid_)
+    unsafe { cloudabi_sys_thread_create(attr_, tid_) }
 }
 
 /// Terminates the calling thread.
@@ -2937,11 +2944,11 @@ pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno {
 /// shared memory.
 #[inline]
 pub unsafe fn thread_exit(lock_: *mut lock, scope_: scope) -> ! {
-    cloudabi_sys_thread_exit(lock_, scope_)
+    unsafe { cloudabi_sys_thread_exit(lock_, scope_) }
 }
 
 /// Temporarily yields execution of the calling thread.
 #[inline]
 pub unsafe fn thread_yield() -> errno {
-    cloudabi_sys_thread_yield()
+    unsafe { cloudabi_sys_thread_yield() }
 }
diff --git a/library/std/src/sys/cloudabi/mod.rs b/library/std/src/sys/cloudabi/mod.rs
index f7dd2c8d00f..13f1bc8826e 100644
--- a/library/std/src/sys/cloudabi/mod.rs
+++ b/library/std/src/sys/cloudabi/mod.rs
@@ -1,3 +1,5 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+
 use crate::io::ErrorKind;
 use crate::mem;
 
diff --git a/library/std/src/sys/cloudabi/mutex.rs b/library/std/src/sys/cloudabi/mutex.rs
index 1203d8de0c5..9dafcbc1fba 100644
--- a/library/std/src/sys/cloudabi/mutex.rs
+++ b/library/std/src/sys/cloudabi/mutex.rs
@@ -103,7 +103,9 @@ impl ReentrantMutex {
             };
             let mut event = MaybeUninit::<abi::event>::uninit();
             let mut nevents = MaybeUninit::<usize>::uninit();
-            let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr());
+            // SAFE: The caller must to ensure that `event` and `nevents` are initialized.
+            let ret =
+                unsafe { abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr()) };
             assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire mutex");
             let event = event.assume_init();
             assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex");
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index 82ccab1462b..829d4c943f1 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -334,10 +334,6 @@ impl File {
     pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
         Err(Error::from_raw_os_error(22))
     }
-
-    pub fn diverge(&self) -> ! {
-        loop {}
-    }
 }
 
 impl DirBuilder {
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 8eaf07e52d6..af05310a8d3 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -31,6 +31,7 @@ pub mod net;
 pub mod os;
 pub mod path;
 pub mod pipe;
+#[path = "../unsupported/process.rs"]
 pub mod process;
 pub mod rwlock;
 pub mod stack_overflow;
diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs
index 3d4813209cb..f988a019cfe 100644
--- a/library/std/src/sys/hermit/mutex.rs
+++ b/library/std/src/sys/hermit/mutex.rs
@@ -1,44 +1,214 @@
+use crate::cell::UnsafeCell;
+use crate::collections::VecDeque;
 use crate::ffi::c_void;
+use crate::ops::{Deref, DerefMut, Drop};
 use crate::ptr;
+use crate::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
 use crate::sys::hermit::abi;
 
+/// This type provides a lock based on busy waiting to realize mutual exclusion
+///
+/// # Description
+///
+/// This structure behaves a lot like a common mutex. There are some differences:
+///
+/// - By using busy waiting, it can be used outside the runtime.
+/// - It is a so called ticket lock and is completly fair.
+#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
+#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
+struct Spinlock<T: ?Sized> {
+    queue: AtomicUsize,
+    dequeue: AtomicUsize,
+    data: UnsafeCell<T>,
+}
+
+unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
+unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}
+
+/// A guard to which the protected data can be accessed
+///
+/// When the guard falls out of scope it will release the lock.
+struct SpinlockGuard<'a, T: ?Sized + 'a> {
+    dequeue: &'a AtomicUsize,
+    data: &'a mut T,
+}
+
+impl<T> Spinlock<T> {
+    pub const fn new(user_data: T) -> Spinlock<T> {
+        Spinlock {
+            queue: AtomicUsize::new(0),
+            dequeue: AtomicUsize::new(1),
+            data: UnsafeCell::new(user_data),
+        }
+    }
+
+    #[inline]
+    fn obtain_lock(&self) {
+        let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
+        while self.dequeue.load(Ordering::SeqCst) != ticket {
+            spin_loop_hint();
+        }
+    }
+
+    #[inline]
+    pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
+        self.obtain_lock();
+        SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
+    }
+}
+
+impl<T: ?Sized + Default> Default for Spinlock<T> {
+    fn default() -> Spinlock<T> {
+        Spinlock::new(Default::default())
+    }
+}
+
+impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        &*self.data
+    }
+}
+
+impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
+    fn deref_mut(&mut self) -> &mut T {
+        &mut *self.data
+    }
+}
+
+impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
+    /// The dropping of the SpinlockGuard will release the lock it was created from.
+    fn drop(&mut self) {
+        self.dequeue.fetch_add(1, Ordering::SeqCst);
+    }
+}
+
+/// Realize a priority queue for tasks
+struct PriorityQueue {
+    queues: [Option<VecDeque<abi::Tid>>; abi::NO_PRIORITIES],
+    prio_bitmap: u64,
+}
+
+impl PriorityQueue {
+    pub const fn new() -> PriorityQueue {
+        PriorityQueue {
+            queues: [
+                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
+                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
+                None, None, None,
+            ],
+            prio_bitmap: 0,
+        }
+    }
+
+    /// Add a task id by its priority to the queue
+    pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
+        let i: usize = prio.into().into();
+        self.prio_bitmap |= (1 << i) as u64;
+        if let Some(queue) = &mut self.queues[i] {
+            queue.push_back(id);
+        } else {
+            let mut queue = VecDeque::new();
+            queue.push_back(id);
+            self.queues[i] = Some(queue);
+        }
+    }
+
+    fn pop_from_queue(&mut self, queue_index: usize) -> Option<abi::Tid> {
+        if let Some(queue) = &mut self.queues[queue_index] {
+            let id = queue.pop_front();
+
+            if queue.is_empty() {
+                self.prio_bitmap &= !(1 << queue_index as u64);
+            }
+
+            id
+        } else {
+            None
+        }
+    }
+
+    /// Pop the task handle with the highest priority from the queue
+    pub fn pop(&mut self) -> Option<abi::Tid> {
+        for i in 0..abi::NO_PRIORITIES {
+            if self.prio_bitmap & (1 << i) != 0 {
+                return self.pop_from_queue(i);
+            }
+        }
+
+        None
+    }
+}
+
+struct MutexInner {
+    locked: bool,
+    blocked_task: PriorityQueue,
+}
+
+impl MutexInner {
+    pub const fn new() -> MutexInner {
+        MutexInner { locked: false, blocked_task: PriorityQueue::new() }
+    }
+}
+
 pub struct Mutex {
-    inner: *const c_void,
+    inner: Spinlock<MutexInner>,
 }
 
+pub type MovableMutex = Box<Mutex>;
+
 unsafe impl Send for Mutex {}
 unsafe impl Sync for Mutex {}
 
 impl Mutex {
     pub const fn new() -> Mutex {
-        Mutex { inner: ptr::null() }
+        Mutex { inner: Spinlock::new(MutexInner::new()) }
     }
 
     #[inline]
     pub unsafe fn init(&mut self) {
-        let _ = abi::sem_init(&mut self.inner as *mut *const c_void, 1);
+        self.inner = Spinlock::new(MutexInner::new());
     }
 
     #[inline]
     pub unsafe fn lock(&self) {
-        let _ = abi::sem_timedwait(self.inner, 0);
+        loop {
+            let mut guard = self.inner.lock();
+            if guard.locked == false {
+                guard.locked = true;
+                return;
+            } else {
+                let prio = abi::get_priority();
+                let id = abi::getpid();
+
+                guard.blocked_task.push(prio, id);
+                abi::block_current_task();
+                drop(guard);
+                abi::yield_now();
+            }
+        }
     }
 
     #[inline]
     pub unsafe fn unlock(&self) {
-        let _ = abi::sem_post(self.inner);
+        let mut guard = self.inner.lock();
+        guard.locked = false;
+        if let Some(tid) = guard.blocked_task.pop() {
+            abi::wakeup_task(tid);
+        }
     }
 
     #[inline]
     pub unsafe fn try_lock(&self) -> bool {
-        let result = abi::sem_trywait(self.inner);
-        result == 0
+        let mut guard = self.inner.lock();
+        if guard.locked == false {
+            guard.locked = true;
+        }
+        guard.locked
     }
 
     #[inline]
-    pub unsafe fn destroy(&self) {
-        let _ = abi::sem_destroy(self.inner);
-    }
+    pub unsafe fn destroy(&self) {}
 }
 
 pub struct ReentrantMutex {
diff --git a/library/std/src/sys/hermit/process.rs b/library/std/src/sys/hermit/process.rs
deleted file mode 100644
index 4702e5c5492..00000000000
--- a/library/std/src/sys/hermit/process.rs
+++ /dev/null
@@ -1,149 +0,0 @@
-use crate::ffi::OsStr;
-use crate::fmt;
-use crate::io;
-use crate::sys::fs::File;
-use crate::sys::pipe::AnonPipe;
-use crate::sys::{unsupported, Void};
-use crate::sys_common::process::CommandEnv;
-
-pub use crate::ffi::OsString as EnvKey;
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Command {
-    env: CommandEnv,
-}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
-pub enum Stdio {
-    Inherit,
-    Null,
-    MakePipe,
-}
-
-impl Command {
-    pub fn new(_program: &OsStr) -> Command {
-        Command { env: Default::default() }
-    }
-
-    pub fn arg(&mut self, _arg: &OsStr) {}
-
-    pub fn env_mut(&mut self) -> &mut CommandEnv {
-        &mut self.env
-    }
-
-    pub fn cwd(&mut self, _dir: &OsStr) {}
-
-    pub fn stdin(&mut self, _stdin: Stdio) {}
-
-    pub fn stdout(&mut self, _stdout: Stdio) {}
-
-    pub fn stderr(&mut self, _stderr: Stdio) {}
-
-    pub fn spawn(
-        &mut self,
-        _default: Stdio,
-        _needs_stdin: bool,
-    ) -> io::Result<(Process, StdioPipes)> {
-        unsupported()
-    }
-}
-
-impl From<AnonPipe> for Stdio {
-    fn from(pipe: AnonPipe) -> Stdio {
-        pipe.diverge()
-    }
-}
-
-impl From<File> for Stdio {
-    fn from(file: File) -> Stdio {
-        file.diverge()
-    }
-}
-
-impl fmt::Debug for Command {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Ok(())
-    }
-}
-
-pub struct ExitStatus(Void);
-
-impl ExitStatus {
-    pub fn success(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn code(&self) -> Option<i32> {
-        match self.0 {}
-    }
-}
-
-impl Clone for ExitStatus {
-    fn clone(&self) -> ExitStatus {
-        match self.0 {}
-    }
-}
-
-impl Copy for ExitStatus {}
-
-impl PartialEq for ExitStatus {
-    fn eq(&self, _other: &ExitStatus) -> bool {
-        match self.0 {}
-    }
-}
-
-impl Eq for ExitStatus {}
-
-impl fmt::Debug for ExitStatus {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-impl fmt::Display for ExitStatus {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(bool);
-
-impl ExitCode {
-    pub const SUCCESS: ExitCode = ExitCode(false);
-    pub const FAILURE: ExitCode = ExitCode(true);
-
-    pub fn as_i32(&self) -> i32 {
-        self.0 as i32
-    }
-}
-
-pub struct Process(Void);
-
-impl Process {
-    pub fn id(&self) -> u32 {
-        match self.0 {}
-    }
-
-    pub fn kill(&mut self) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn wait(&mut self) -> io::Result<ExitStatus> {
-        match self.0 {}
-    }
-
-    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
-        match self.0 {}
-    }
-}
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 7b5fac922d0..b4628b64911 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -89,6 +89,7 @@ cfg_if::cfg_if! {
         #[stable(feature = "rust1", since = "1.0.0")]
         pub use self::ext as windows_ext;
     } else if #[cfg(any(target_os = "cloudabi",
+                        target_os = "hermit",
                         target_arch = "wasm32",
                         all(target_vendor = "fortanix", target_env = "sgx")))] {
         // On CloudABI and wasm right now the shim below doesn't compile, so
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
index 648cf241cba..d3a29aa5d51 100644
--- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
@@ -10,6 +10,7 @@
       let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10
       let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:35:12: 35:13
       let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:35:15: 35:16
++     let mut _11: i32;                    // in scope 0 at $DIR/matches_reduce_branches.rs:19:9: 19:10
       scope 1 {
           debug a => _2;                   // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
           let _3: bool;                    // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10
@@ -33,10 +34,13 @@
           StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10
           StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
 -         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
-+         _2 = Ne(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
-+         _3 = Eq(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
++         StorageLive(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
++         _11 = _1;                        // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
++         _2 = Ne(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
++         _3 = Eq(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
 +         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22
 +         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21
++         StorageDead(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
 +         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
       }
   
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
index 648cf241cba..d3a29aa5d51 100644
--- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
@@ -10,6 +10,7 @@
       let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10
       let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:35:12: 35:13
       let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:35:15: 35:16
++     let mut _11: i32;                    // in scope 0 at $DIR/matches_reduce_branches.rs:19:9: 19:10
       scope 1 {
           debug a => _2;                   // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
           let _3: bool;                    // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10
@@ -33,10 +34,13 @@
           StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10
           StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
 -         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
-+         _2 = Ne(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
-+         _3 = Eq(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
++         StorageLive(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
++         _11 = _1;                        // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
++         _2 = Ne(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
++         _3 = Eq(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
 +         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22
 +         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21
++         StorageDead(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
 +         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
       }
   
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff
index a52abfb1a72..ba963e3fe92 100644
--- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff
@@ -6,12 +6,16 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25
       let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
++     let mut _4: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
 -         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
-+         _2 = Eq(_3, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++         StorageLive(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
++         _4 = move _3;                    // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
++         _2 = Eq(_4, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++         StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
 +         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
       }
   
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
index a52abfb1a72..ba963e3fe92 100644
--- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
@@ -6,12 +6,16 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25
       let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
++     let mut _4: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
 -         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
-+         _2 = Eq(_3, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++         StorageLive(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
++         _4 = move _3;                    // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
++         _2 = Eq(_4, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++         StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
 +         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
       }
   
diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff
new file mode 100644
index 00000000000..1f46d3777be
--- /dev/null
+++ b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff
@@ -0,0 +1,116 @@
+- // MIR for `match_nested_if` before MatchBranchSimplification
++ // MIR for `match_nested_if` after MatchBranchSimplification
+  
+  fn match_nested_if() -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/matches_reduce_branches.rs:38:25: 38:29
+      let _1: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:39:9: 39:12
+      let mut _2: ();                      // in scope 0 at $DIR/matches_reduce_branches.rs:39:21: 39:23
+      let mut _3: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+      let mut _4: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+      let mut _5: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+      let mut _6: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
++     let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
++     let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
++     let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++     let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+      scope 1 {
+          debug val => _1;                 // in scope 1 at $DIR/matches_reduce_branches.rs:39:9: 39:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:39:9: 39:12
+          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:39:21: 39:23
+          StorageLive(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+          StorageLive(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+          StorageLive(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+          StorageLive(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
+          _6 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
+-         switchInt(_6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
++         StorageLive(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
++         _7 = _6;                         // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
++         _5 = Ne(_7, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
++         StorageDead(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
++         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+      }
+  
+      bb1: {
+          _5 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:30: 40:34
+          goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+      }
+  
+      bb2: {
+          _5 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
+          goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+      }
+  
+      bb3: {
+          StorageDead(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:47: 40:48
+-         switchInt(_5) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
++         StorageLive(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
++         _8 = _5;                         // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
++         _4 = Ne(_8, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
++         StorageDead(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
++         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+      }
+  
+      bb4: {
+          _4 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
+          goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+      }
+  
+      bb5: {
+          _4 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:50: 40:54
+          goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+      }
+  
+      bb6: {
+          StorageDead(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:67: 40:68
+-         switchInt(_4) -> [false: bb7, otherwise: bb8]; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         StorageLive(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         _9 = _4;                         // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         _3 = Ne(_9, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
++         StorageDead(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+      }
+  
+      bb7: {
+          _3 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
+          goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+      }
+  
+      bb8: {
+          _3 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:70: 40:74
+          goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+      }
+  
+      bb9: {
+          StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:87: 40:88
+-         switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         StorageLive(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         _10 = move _3;                   // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
++         _1 = Ne(_10, const false);       // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
++         StorageDead(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+      }
+  
+      bb10: {
+          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
+          _1 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:92: 40:96
+          goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
+      }
+  
+      bb11: {
+          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
+          _1 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
+          goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
+      }
+  
+      bb12: {
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:42:6: 42:7
+          _0 = _1;                         // scope 1 at $DIR/matches_reduce_branches.rs:43:5: 43:8
+          StorageDead(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:44:1: 44:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:44:2: 44:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff
new file mode 100644
index 00000000000..1f46d3777be
--- /dev/null
+++ b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff
@@ -0,0 +1,116 @@
+- // MIR for `match_nested_if` before MatchBranchSimplification
++ // MIR for `match_nested_if` after MatchBranchSimplification
+  
+  fn match_nested_if() -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/matches_reduce_branches.rs:38:25: 38:29
+      let _1: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:39:9: 39:12
+      let mut _2: ();                      // in scope 0 at $DIR/matches_reduce_branches.rs:39:21: 39:23
+      let mut _3: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+      let mut _4: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+      let mut _5: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+      let mut _6: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
++     let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
++     let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
++     let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++     let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+      scope 1 {
+          debug val => _1;                 // in scope 1 at $DIR/matches_reduce_branches.rs:39:9: 39:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:39:9: 39:12
+          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:39:21: 39:23
+          StorageLive(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+          StorageLive(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+          StorageLive(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+          StorageLive(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
+          _6 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:24: 40:28
+-         switchInt(_6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
++         StorageLive(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
++         _7 = _6;                         // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
++         _5 = Ne(_7, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
++         StorageDead(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
++         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+      }
+  
+      bb1: {
+          _5 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:30: 40:34
+          goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+      }
+  
+      bb2: {
+          _5 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:42: 40:47
+          goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:21: 40:48
+      }
+  
+      bb3: {
+          StorageDead(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:47: 40:48
+-         switchInt(_5) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
++         StorageLive(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
++         _8 = _5;                         // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
++         _4 = Ne(_8, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
++         StorageDead(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
++         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+      }
+  
+      bb4: {
+          _4 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:62: 40:67
+          goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+      }
+  
+      bb5: {
+          _4 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:50: 40:54
+          goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:18: 40:68
+      }
+  
+      bb6: {
+          StorageDead(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:67: 40:68
+-         switchInt(_4) -> [false: bb7, otherwise: bb8]; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         StorageLive(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         _9 = _4;                         // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         _3 = Ne(_9, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
++         StorageDead(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+      }
+  
+      bb7: {
+          _3 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:40:82: 40:87
+          goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+      }
+  
+      bb8: {
+          _3 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:70: 40:74
+          goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+      }
+  
+      bb9: {
+          StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:87: 40:88
+-         switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         StorageLive(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         _10 = move _3;                   // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
++         _1 = Ne(_10, const false);       // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
++         StorageDead(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
++         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:40:15: 40:88
+      }
+  
+      bb10: {
+          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
+          _1 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:40:92: 40:96
+          goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
+      }
+  
+      bb11: {
+          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:40:95: 40:96
+          _1 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:41:14: 41:19
+          goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:39:15: 42:6
+      }
+  
+      bb12: {
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:42:6: 42:7
+          _0 = _1;                         // scope 1 at $DIR/matches_reduce_branches.rs:43:5: 43:8
+          StorageDead(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:44:1: 44:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:44:2: 44:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_reduce_branches.rs b/src/test/mir-opt/matches_reduce_branches.rs
index 54b79a84263..e95a62aeeb0 100644
--- a/src/test/mir-opt/matches_reduce_branches.rs
+++ b/src/test/mir-opt/matches_reduce_branches.rs
@@ -1,7 +1,7 @@
-// compile-flags: -Zunsound-mir-opts
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
 // EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
+// EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
 
 fn foo(bar: Option<()>) {
     if matches!(bar, None) {
@@ -35,9 +35,17 @@ fn bar(i: i32) -> (bool, bool, bool, bool) {
     (a, b, c, d)
 }
 
+fn match_nested_if() -> bool {
+    let val = match () {
+        () if if if if true {true} else {false} {true} else {false} {true} else {false} => true,
+        _ => false,
+    };
+    val
+}
 
 fn main() {
   let _ = foo(None);
   let _ = foo(Some(()));
   let _ = bar(0);
+  let _ = match_nested_if();
 }
diff --git a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff
index 39830946aeb..dc3a6a36d9e 100644
--- a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff
+++ b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff
@@ -8,61 +8,52 @@
       let mut _3: isize;                   // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
       let mut _4: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _5: isize;                   // in scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
+      let mut _6: isize;                   // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
+      let mut _7: isize;                   // in scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
+      let mut _8: bool;                    // in scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _3 = discriminant(_1);           // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
-          switchInt(move _3) -> [0_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
+          StorageLive(_6);                 // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
+          _6 = move _3;                    // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
+          _2 = Eq(_6, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_6);                 // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
+          goto -> bb4;                     // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
       }
   
       bb1: {
           _0 = const true;                 // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
-          goto -> bb4;                     // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
+          goto -> bb3;                     // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
       }
   
       bb2: {
-          _0 = const false;                // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
-          goto -> bb4;                     // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
-      }
-  
-      bb3: {
           StorageLive(_4);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _5 = discriminant(_1);           // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
-          switchInt(move _5) -> [1_isize: bb9, otherwise: bb8]; // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
+          StorageLive(_7);                 // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
+          _7 = move _5;                    // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
+          _4 = Eq(_7, const 1_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_7);                 // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
+          goto -> bb5;                     // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
       }
   
-      bb4: {
+      bb3: {
           StorageDead(_4);                 // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46
           StorageDead(_2);                 // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46
           return;                          // scope 0 at $DIR/not_equal_false.rs:5:2: 5:2
       }
   
-      bb5: {
-          _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          goto -> bb7;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb6: {
-          _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          goto -> bb7;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb7: {
-          switchInt(move _2) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
-      }
-  
-      bb8: {
-          _4 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          goto -> bb10;                    // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb9: {
-          _4 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          goto -> bb10;                    // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      bb4: {
+          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
       }
   
-      bb10: {
-          switchInt(move _4) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
+      bb5: {
+          StorageLive(_8);                 // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
+          _8 = move _4;                    // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
+-         _0 = Ne(_8, const false);        // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
++         _0 = _8;                         // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
+          StorageDead(_8);                 // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
+          goto -> bb3;                     // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
       }
   }
   
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/division.rs b/src/test/ui/const-generics/const_evaluatable_checked/division.rs
new file mode 100644
index 00000000000..71a5f2d3472
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/division.rs
@@ -0,0 +1,11 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+fn with_bound<const N: usize>() where [u8; N / 2]: Sized {
+    let _: [u8; N / 2] = [0; N / 2];
+}
+
+fn main() {
+    with_bound::<4>();
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/unused_expr.rs b/src/test/ui/const-generics/const_evaluatable_checked/unused_expr.rs
new file mode 100644
index 00000000000..9c603c57a48
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/unused_expr.rs
@@ -0,0 +1,25 @@
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+fn add<const N: usize>() -> [u8; { N + 1; 5 }] {
+    //~^ ERROR overly complex generic constant
+    todo!()
+}
+
+fn div<const N: usize>() -> [u8; { N / 1; 5 }] {
+    //~^ ERROR overly complex generic constant
+    todo!()
+}
+
+const fn foo(n: usize) {}
+
+fn fn_call<const N: usize>() -> [u8; { foo(N); 5 }] {
+    //~^ ERROR overly complex generic constant
+    todo!()
+}
+
+fn main() {
+    add::<12>();
+    div::<9>();
+    fn_call::<14>();
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/unused_expr.stderr b/src/test/ui/const-generics/const_evaluatable_checked/unused_expr.stderr
new file mode 100644
index 00000000000..1687dbbcbe3
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/unused_expr.stderr
@@ -0,0 +1,32 @@
+error: overly complex generic constant
+  --> $DIR/unused_expr.rs:4:34
+   |
+LL | fn add<const N: usize>() -> [u8; { N + 1; 5 }] {
+   |                                  ^^-----^^^^^
+   |                                    |
+   |                                    dead code
+   |
+   = help: consider moving this anonymous constant into a `const` function
+
+error: overly complex generic constant
+  --> $DIR/unused_expr.rs:9:34
+   |
+LL | fn div<const N: usize>() -> [u8; { N / 1; 5 }] {
+   |                                  ^^-----^^^^^
+   |                                    |
+   |                                    dead code
+   |
+   = help: consider moving this anonymous constant into a `const` function
+
+error: overly complex generic constant
+  --> $DIR/unused_expr.rs:16:38
+   |
+LL | fn fn_call<const N: usize>() -> [u8; { foo(N); 5 }] {
+   |                                      ^^------^^^^^
+   |                                        |
+   |                                        dead code
+   |
+   = help: consider moving this anonymous constant into a `const` function
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/consts/const-eval/const_panic.rs b/src/test/ui/consts/const-eval/const_panic.rs
index ada9feec897..799c185fb8e 100644
--- a/src/test/ui/consts/const-eval/const_panic.rs
+++ b/src/test/ui/consts/const-eval/const_panic.rs
@@ -1,6 +1,8 @@
 #![feature(const_panic)]
 #![crate_type = "lib"]
 
+const MSG: &str = "hello";
+
 const Z: () = std::panic!("cheese");
 //~^ ERROR any use of this value will cause an error
 
@@ -12,6 +14,9 @@ const Y: () = std::unreachable!();
 
 const X: () = std::unimplemented!();
 //~^ ERROR any use of this value will cause an error
+//
+const W: () = std::panic!(MSG);
+//~^ ERROR any use of this value will cause an error
 
 const Z_CORE: () = core::panic!("cheese");
 //~^ ERROR any use of this value will cause an error
@@ -24,3 +29,6 @@ const Y_CORE: () = core::unreachable!();
 
 const X_CORE: () = core::unimplemented!();
 //~^ ERROR any use of this value will cause an error
+
+const W_CORE: () = core::panic!(MSG);
+//~^ ERROR any use of this value will cause an error
diff --git a/src/test/ui/consts/const-eval/const_panic.stderr b/src/test/ui/consts/const-eval/const_panic.stderr
index e4ca1f4fa26..c2711952d58 100644
--- a/src/test/ui/consts/const-eval/const_panic.stderr
+++ b/src/test/ui/consts/const-eval/const_panic.stderr
@@ -1,83 +1,103 @@
 error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:4:15
+  --> $DIR/const_panic.rs:6:15
    |
 LL | const Z: () = std::panic!("cheese");
    | --------------^^^^^^^^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'cheese', $DIR/const_panic.rs:4:15
+   |               the evaluated program panicked at 'cheese', $DIR/const_panic.rs:6:15
    |
    = note: `#[deny(const_err)]` on by default
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:7:16
+  --> $DIR/const_panic.rs:9:16
    |
 LL | const Z2: () = std::panic!();
    | ---------------^^^^^^^^^^^^^-
    |                |
-   |                the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:7:16
+   |                the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:9:16
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:10:15
+  --> $DIR/const_panic.rs:12:15
    |
 LL | const Y: () = std::unreachable!();
    | --------------^^^^^^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:10:15
+   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:12:15
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:13:15
+  --> $DIR/const_panic.rs:15:15
    |
 LL | const X: () = std::unimplemented!();
    | --------------^^^^^^^^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:13:15
+   |               the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:15:15
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:16:20
+  --> $DIR/const_panic.rs:18:15
+   |
+LL | const W: () = std::panic!(MSG);
+   | --------------^^^^^^^^^^^^^^^^-
+   |               |
+   |               the evaluated program panicked at 'hello', $DIR/const_panic.rs:18:15
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: any use of this value will cause an error
+  --> $DIR/const_panic.rs:21:20
    |
 LL | const Z_CORE: () = core::panic!("cheese");
    | -------------------^^^^^^^^^^^^^^^^^^^^^^-
    |                    |
-   |                    the evaluated program panicked at 'cheese', $DIR/const_panic.rs:16:20
+   |                    the evaluated program panicked at 'cheese', $DIR/const_panic.rs:21:20
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:19:21
+  --> $DIR/const_panic.rs:24:21
    |
 LL | const Z2_CORE: () = core::panic!();
    | --------------------^^^^^^^^^^^^^^-
    |                     |
-   |                     the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:19:21
+   |                     the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:24:21
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:22:20
+  --> $DIR/const_panic.rs:27:20
    |
 LL | const Y_CORE: () = core::unreachable!();
    | -------------------^^^^^^^^^^^^^^^^^^^^-
    |                    |
-   |                    the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:22:20
+   |                    the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:27:20
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:25:20
+  --> $DIR/const_panic.rs:30:20
    |
 LL | const X_CORE: () = core::unimplemented!();
    | -------------------^^^^^^^^^^^^^^^^^^^^^^-
    |                    |
-   |                    the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:25:20
+   |                    the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:30:20
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: any use of this value will cause an error
+  --> $DIR/const_panic.rs:33:20
+   |
+LL | const W_CORE: () = core::panic!(MSG);
+   | -------------------^^^^^^^^^^^^^^^^^-
+   |                    |
+   |                    the evaluated program panicked at 'hello', $DIR/const_panic.rs:33:20
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/issues/issue-44333.rs b/src/test/ui/consts/const_in_pattern/issue-44333.rs
index 96e8795e52d..96e8795e52d 100644
--- a/src/test/ui/issues/issue-44333.rs
+++ b/src/test/ui/consts/const_in_pattern/issue-44333.rs
diff --git a/src/test/ui/issues/issue-44333.stderr b/src/test/ui/consts/const_in_pattern/issue-44333.stderr
index 8302b09e533..8302b09e533 100644
--- a/src/test/ui/issues/issue-44333.stderr
+++ b/src/test/ui/consts/const_in_pattern/issue-44333.stderr
diff --git a/src/test/ui/consts/const_in_pattern/issue-53708.rs b/src/test/ui/consts/const_in_pattern/issue-53708.rs
new file mode 100644
index 00000000000..355ba63790f
--- /dev/null
+++ b/src/test/ui/consts/const_in_pattern/issue-53708.rs
@@ -0,0 +1,11 @@
+// check-pass
+// https://github.com/rust-lang/rust/issues/53708
+#[derive(PartialEq, Eq)]
+struct S;
+
+fn main() {
+    const C: &S = &S;
+    match C {
+        C => {}
+    }
+}
diff --git a/src/test/ui/consts/const_in_pattern/issue-78057.rs b/src/test/ui/consts/const_in_pattern/issue-78057.rs
new file mode 100644
index 00000000000..69cf8404da1
--- /dev/null
+++ b/src/test/ui/consts/const_in_pattern/issue-78057.rs
@@ -0,0 +1,17 @@
+#![deny(unreachable_patterns)]
+
+#[derive(PartialEq)]
+struct Opaque(i32);
+
+impl Eq for Opaque {}
+
+const FOO: Opaque = Opaque(42);
+
+fn main() {
+    match FOO {
+        FOO => {},
+        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        _ => {}
+        //~^ ERROR unreachable pattern
+    }
+}
diff --git a/src/test/ui/consts/const_in_pattern/issue-78057.stderr b/src/test/ui/consts/const_in_pattern/issue-78057.stderr
new file mode 100644
index 00000000000..0d49d0e96c8
--- /dev/null
+++ b/src/test/ui/consts/const_in_pattern/issue-78057.stderr
@@ -0,0 +1,20 @@
+error: to use a constant of type `Opaque` in a pattern, `Opaque` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/issue-78057.rs:12:9
+   |
+LL |         FOO => {},
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/issue-78057.rs:14:9
+   |
+LL |         _ => {}
+   |         ^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-78057.rs:1:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
index 24474cabf1e..4a91198ab9f 100644
--- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -53,8 +53,8 @@ enum LR_NonZero {
 fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
     let err = panic::catch_unwind(op).err();
     assert_eq!(
-        err.as_ref().and_then(|a| a.downcast_ref::<String>()).map(|s| &**s),
-        Some(msg)
+        err.as_ref().and_then(|a| a.downcast_ref::<&str>()),
+        Some(&msg)
     );
 }
 
diff --git a/src/test/ui/issues/issue-77919.rs b/src/test/ui/issues/issue-77919.rs
new file mode 100644
index 00000000000..9b04d5ee000
--- /dev/null
+++ b/src/test/ui/issues/issue-77919.rs
@@ -0,0 +1,13 @@
+fn main() {
+    [1; <Multiply<Five, Five>>::VAL]; //~ ERROR evaluation of constant value failed
+}
+trait TypeVal<T> {
+    const VAL: T; //~ ERROR any use of this value will cause an error
+}
+struct Five;
+struct Multiply<N, M> {
+    _n: PhantomData, //~ ERROR cannot find type `PhantomData` in this scope
+}
+impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
+//~^ ERROR cannot find type `VAL` in this scope
+//~| ERROR not all trait items implemented, missing: `VAL`
diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr
new file mode 100644
index 00000000000..129af00644f
--- /dev/null
+++ b/src/test/ui/issues/issue-77919.stderr
@@ -0,0 +1,46 @@
+error[E0412]: cannot find type `PhantomData` in this scope
+  --> $DIR/issue-77919.rs:9:9
+   |
+LL |     _n: PhantomData,
+   |         ^^^^^^^^^^^ not found in this scope
+   |
+help: consider importing this struct
+   |
+LL | use std::marker::PhantomData;
+   |
+
+error[E0412]: cannot find type `VAL` in this scope
+  --> $DIR/issue-77919.rs:11:63
+   |
+LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
+   |          -                                                    ^^^ not found in this scope
+   |          |
+   |          help: you might be missing a type parameter: `, VAL`
+
+error[E0046]: not all trait items implemented, missing: `VAL`
+  --> $DIR/issue-77919.rs:11:1
+   |
+LL |     const VAL: T;
+   |     ------------- `VAL` from trait
+...
+LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
+
+error: any use of this value will cause an error
+  --> $DIR/issue-77919.rs:5:5
+   |
+LL |     const VAL: T;
+   |     ^^^^^^^^^^^^^ no MIR body is available for DefId(0:7 ~ issue_77919[317d]::TypeVal::VAL)
+   |
+   = note: `#[deny(const_err)]` on by default
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/issue-77919.rs:2:9
+   |
+LL |     [1; <Multiply<Five, Five>>::VAL];
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0046, E0080, E0412.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/src/test/ui/macros/issue-78325-inconsistent-resolution.rs b/src/test/ui/macros/issue-78325-inconsistent-resolution.rs
new file mode 100644
index 00000000000..919eca4f9bf
--- /dev/null
+++ b/src/test/ui/macros/issue-78325-inconsistent-resolution.rs
@@ -0,0 +1,12 @@
+macro_rules! define_other_core {
+    ( ) => {
+        extern crate std as core;
+        //~^ ERROR macro-expanded `extern crate` items cannot shadow names passed with `--extern`
+    };
+}
+
+fn main() {
+    core::panic!();
+}
+
+define_other_core!();
diff --git a/src/test/ui/macros/issue-78325-inconsistent-resolution.stderr b/src/test/ui/macros/issue-78325-inconsistent-resolution.stderr
new file mode 100644
index 00000000000..cf3af593141
--- /dev/null
+++ b/src/test/ui/macros/issue-78325-inconsistent-resolution.stderr
@@ -0,0 +1,13 @@
+error: macro-expanded `extern crate` items cannot shadow names passed with `--extern`
+  --> $DIR/issue-78325-inconsistent-resolution.rs:3:9
+   |
+LL |         extern crate std as core;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | define_other_core!();
+   | --------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/pattern/usefulness/consts-opaque.rs b/src/test/ui/pattern/usefulness/consts-opaque.rs
new file mode 100644
index 00000000000..f87f96e34fc
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/consts-opaque.rs
@@ -0,0 +1,114 @@
+// This file tests the exhaustiveness algorithm on opaque constants. Most of the examples give
+// unnecessary warnings because const_to_pat.rs converts a constant pattern to a wildcard when the
+// constant is not allowed as a pattern. This is an edge case so we may not care to fix it.
+// See also https://github.com/rust-lang/rust/issues/78057
+
+#![deny(unreachable_patterns)]
+
+#[derive(PartialEq)]
+struct Foo(i32);
+impl Eq for Foo {}
+const FOO: Foo = Foo(42);
+const FOO_REF: &Foo = &Foo(42);
+const FOO_REF_REF: &&Foo = &&Foo(42);
+
+#[derive(PartialEq)]
+struct Bar;
+impl Eq for Bar {}
+const BAR: Bar = Bar;
+
+#[derive(PartialEq)]
+enum Baz {
+    Baz1,
+    Baz2
+}
+impl Eq for Baz {}
+const BAZ: Baz = Baz::Baz1;
+
+type Quux = fn(usize, usize) -> usize;
+fn quux(a: usize, b: usize) -> usize { a + b }
+const QUUX: Quux = quux;
+
+fn main() {
+    match FOO {
+        FOO => {}
+        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        _ => {} // should not be emitting unreachable warning
+        //~^ ERROR unreachable pattern
+    }
+
+    match FOO_REF {
+        FOO_REF => {}
+        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        Foo(_) => {} // should not be emitting unreachable warning
+        //~^ ERROR unreachable pattern
+    }
+
+    // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071)
+    match FOO_REF_REF {
+        FOO_REF_REF => {}
+        //~^ WARNING must be annotated with `#[derive(PartialEq, Eq)]`
+        //~| WARNING this was previously accepted by the compiler but is being phased out
+        Foo(_) => {}
+    }
+
+    match BAR {
+        Bar => {}
+        BAR => {} // should not be emitting unreachable warning
+        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~| ERROR unreachable pattern
+        _ => {}
+        //~^ ERROR unreachable pattern
+    }
+
+    match BAR {
+        BAR => {}
+        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        Bar => {} // should not be emitting unreachable warning
+        //~^ ERROR unreachable pattern
+        _ => {}
+        //~^ ERROR unreachable pattern
+    }
+
+    match BAR {
+        BAR => {}
+        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        BAR => {} // should not be emitting unreachable warning
+        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~| ERROR unreachable pattern
+        _ => {} // should not be emitting unreachable warning
+        //~^ ERROR unreachable pattern
+    }
+
+    match BAZ {
+        BAZ => {}
+        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        Baz::Baz1 => {} // should not be emitting unreachable warning
+        //~^ ERROR unreachable pattern
+        _ => {}
+        //~^ ERROR unreachable pattern
+    }
+
+    match BAZ {
+        Baz::Baz1 => {}
+        BAZ => {}
+        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        _ => {}
+        //~^ ERROR unreachable pattern
+    }
+
+    match BAZ {
+        BAZ => {}
+        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        Baz::Baz2 => {} // should not be emitting unreachable warning
+        //~^ ERROR unreachable pattern
+        _ => {} // should not be emitting unreachable warning
+        //~^ ERROR unreachable pattern
+    }
+
+    match QUUX {
+        QUUX => {}
+        QUUX => {}
+        _ => {}
+    }
+}
diff --git a/src/test/ui/pattern/usefulness/consts-opaque.stderr b/src/test/ui/pattern/usefulness/consts-opaque.stderr
new file mode 100644
index 00000000000..f10166d5a35
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/consts-opaque.stderr
@@ -0,0 +1,158 @@
+error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:34:9
+   |
+LL |         FOO => {}
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:36:9
+   |
+LL |         _ => {} // should not be emitting unreachable warning
+   |         ^
+   |
+note: the lint level is defined here
+  --> $DIR/consts-opaque.rs:6:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:41:9
+   |
+LL |         FOO_REF => {}
+   |         ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:43:9
+   |
+LL |         Foo(_) => {} // should not be emitting unreachable warning
+   |         ^^^^^^
+
+warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:49:9
+   |
+LL |         FOO_REF_REF => {}
+   |         ^^^^^^^^^^^
+   |
+   = note: `#[warn(indirect_structural_match)]` 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 #62411 <https://github.com/rust-lang/rust/issues/62411>
+
+error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:57:9
+   |
+LL |         BAR => {} // should not be emitting unreachable warning
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:57:9
+   |
+LL |         Bar => {}
+   |         --- matches any value
+LL |         BAR => {} // should not be emitting unreachable warning
+   |         ^^^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:60:9
+   |
+LL |         Bar => {}
+   |         --- matches any value
+...
+LL |         _ => {}
+   |         ^ unreachable pattern
+
+error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:65:9
+   |
+LL |         BAR => {}
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:67:9
+   |
+LL |         Bar => {} // should not be emitting unreachable warning
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:69:9
+   |
+LL |         Bar => {} // should not be emitting unreachable warning
+   |         --- matches any value
+LL |
+LL |         _ => {}
+   |         ^ unreachable pattern
+
+error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:74:9
+   |
+LL |         BAR => {}
+   |         ^^^
+
+error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:76:9
+   |
+LL |         BAR => {} // should not be emitting unreachable warning
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:76:9
+   |
+LL |         BAR => {} // should not be emitting unreachable warning
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:79:9
+   |
+LL |         _ => {} // should not be emitting unreachable warning
+   |         ^
+
+error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:84:9
+   |
+LL |         BAZ => {}
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:86:9
+   |
+LL |         Baz::Baz1 => {} // should not be emitting unreachable warning
+   |         ^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:88:9
+   |
+LL |         _ => {}
+   |         ^
+
+error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:94:9
+   |
+LL |         BAZ => {}
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:96:9
+   |
+LL |         _ => {}
+   |         ^
+
+error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:101:9
+   |
+LL |         BAZ => {}
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:103:9
+   |
+LL |         Baz::Baz2 => {} // should not be emitting unreachable warning
+   |         ^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:105:9
+   |
+LL |         _ => {} // should not be emitting unreachable warning
+   |         ^
+
+error: aborting due to 22 previous errors; 1 warning emitted
+
diff --git a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
index ffc8433403f..7968f9713ff 100644
--- a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
+++ b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
@@ -7,11 +7,11 @@ LL |     match buf {
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8; 4]`
 
-error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
   --> $DIR/match-byte-array-patterns-2.rs:10:11
    |
 LL |     match buf {
-   |           ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
+   |           ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8]`