about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-07-17 00:09:49 +0000
committerbors <bors@rust-lang.org>2020-07-17 00:09:49 +0000
commit8534be72fc3b9c5f2f2dc4e4ee7b651a008e9a3e (patch)
tree9b6f6432be9c4a78fd4677f7a3125f3eb93e1a0a /src
parent5c9e5df3a097e094641f16dab501ab1c4da10e9f (diff)
parent5bb9bef79577b9629b12800dcdae1d8fd52998c0 (diff)
downloadrust-8534be72fc3b9c5f2f2dc4e4ee7b651a008e9a3e.tar.gz
rust-8534be72fc3b9c5f2f2dc4e4ee7b651a008e9a3e.zip
Auto merge of #74422 - Manishearth:rollup-7mfrf6g, r=Manishearth
Rollup of 8 pull requests

Successful merges:

 - #73101 (Resolve items for cross-crate imports relative to the original module)
 - #73269 (Enable some timeouts in SGX platform)
 - #74033 (Add build support for Cargo's build-std feature.)
 - #74351 (Do not render unstable items for rustc doc)
 - #74357 (Some `Symbol` related improvements)
 - #74371 (Improve ayu rustdoc theme)
 - #74386 (Add RISC-V GNU/Linux to src/tools/build-manifest as a host platform)
 - #74398 (Clean up E0723 explanation)

Failed merges:

r? @ghost
Diffstat (limited to 'src')
-rw-r--r--src/libpanic_abort/Cargo.toml1
-rw-r--r--src/libpanic_abort/lib.rs35
-rw-r--r--src/libpanic_unwind/lib.rs20
-rw-r--r--src/libproc_macro/lib.rs1
-rw-r--r--src/librustc_builtin_macros/deriving/bounds.rs4
-rw-r--r--src/librustc_builtin_macros/deriving/clone.rs8
-rw-r--r--src/librustc_builtin_macros/deriving/cmp/eq.rs14
-rw-r--r--src/librustc_builtin_macros/deriving/cmp/ord.rs10
-rw-r--r--src/librustc_builtin_macros/deriving/cmp/partial_eq.rs10
-rw-r--r--src/librustc_builtin_macros/deriving/cmp/partial_ord.rs16
-rw-r--r--src/librustc_builtin_macros/deriving/debug.rs21
-rw-r--r--src/librustc_builtin_macros/deriving/decodable.rs43
-rw-r--r--src/librustc_builtin_macros/deriving/default.rs7
-rw-r--r--src/librustc_builtin_macros/deriving/encodable.rs46
-rw-r--r--src/librustc_builtin_macros/deriving/generic/mod.rs28
-rw-r--r--src/librustc_builtin_macros/deriving/generic/ty.rs71
-rw-r--r--src/librustc_builtin_macros/deriving/hash.rs13
-rw-r--r--src/librustc_builtin_macros/deriving/mod.rs8
-rw-r--r--src/librustc_builtin_macros/format.rs46
-rw-r--r--src/librustc_builtin_macros/global_allocator.rs4
-rw-r--r--src/librustc_builtin_macros/proc_macro_harness.rs14
-rw-r--r--src/librustc_builtin_macros/test.rs30
-rw-r--r--src/librustc_builtin_macros/test_harness.rs2
-rw-r--r--src/librustc_error_codes/error_codes/E0723.md2
-rw-r--r--src/librustc_expand/base.rs3
-rw-r--r--src/librustc_expand/build.rs2
-rw-r--r--src/librustc_middle/mir/query.rs92
-rw-r--r--src/librustc_middle/ty/print/pretty.rs6
-rw-r--r--src/librustc_middle/ty/query/profiling_support.rs7
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs112
-rw-r--r--src/librustc_passes/stability.rs3
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs17
-rw-r--r--src/librustc_resolve/lib.rs4
-rw-r--r--src/librustc_span/symbol.rs57
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs4
-rw-r--r--src/librustc_typeck/check/demand.rs4
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/librustdoc/html/render.rs45
-rw-r--r--src/librustdoc/html/static/themes/ayu.css21
-rw-r--r--src/librustdoc/html/static/themes/dark.css5
-rw-r--r--src/librustdoc/html/static/themes/light.css5
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs83
-rw-r--r--src/libstd/build.rs24
-rw-r--r--src/libstd/env.rs77
-rw-r--r--src/libstd/lib.rs9
-rw-r--r--src/libstd/sync/condvar.rs4
-rw-r--r--src/libstd/sync/mpsc/mod.rs9
-rw-r--r--src/libstd/sys/mod.rs3
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/mod.rs92
-rw-r--r--src/libstd/sys/sgx/condvar.rs6
-rw-r--r--src/libstd/sys/sgx/mod.rs9
-rw-r--r--src/libstd/sys/sgx/thread.rs4
-rw-r--r--src/libstd/sys/sgx/waitqueue.rs129
-rw-r--r--src/libstd/sys/unsupported/alloc.rs22
-rw-r--r--src/libstd/sys/unsupported/args.rs38
-rw-r--r--src/libstd/sys/unsupported/cmath.rs (renamed from src/libstd/sys/wasm/cmath.rs)0
-rw-r--r--src/libstd/sys/unsupported/common.rs48
-rw-r--r--src/libstd/sys/unsupported/condvar.rs (renamed from src/libstd/sys/wasm/condvar.rs)4
-rw-r--r--src/libstd/sys/unsupported/env.rs9
-rw-r--r--src/libstd/sys/unsupported/fs.rs (renamed from src/libstd/sys/wasm/fs.rs)0
-rw-r--r--src/libstd/sys/unsupported/io.rs (renamed from src/libstd/sys/wasm/io.rs)0
-rw-r--r--src/libstd/sys/unsupported/mod.rs24
-rw-r--r--src/libstd/sys/unsupported/mutex.rs (renamed from src/libstd/sys/wasm/mutex.rs)7
-rw-r--r--src/libstd/sys/unsupported/net.rs (renamed from src/libstd/sys/wasm/net.rs)0
-rw-r--r--src/libstd/sys/unsupported/os.rs (renamed from src/libstd/sys/wasm/os.rs)21
-rw-r--r--src/libstd/sys/unsupported/path.rs (renamed from src/libstd/sys/wasm/path.rs)0
-rw-r--r--src/libstd/sys/unsupported/pipe.rs (renamed from src/libstd/sys/wasm/pipe.rs)0
-rw-r--r--src/libstd/sys/unsupported/process.rs (renamed from src/libstd/sys/wasm/process.rs)0
-rw-r--r--src/libstd/sys/unsupported/rwlock.rs (renamed from src/libstd/sys/wasm/rwlock.rs)2
-rw-r--r--src/libstd/sys/unsupported/stack_overflow.rs (renamed from src/libstd/sys/wasm/stack_overflow.rs)0
-rw-r--r--src/libstd/sys/unsupported/stdio.rs (renamed from src/libstd/sys/wasm/stdio.rs)0
-rw-r--r--src/libstd/sys/unsupported/thread.rs41
-rw-r--r--src/libstd/sys/unsupported/thread_local_dtor.rs (renamed from src/libstd/sys/wasm/thread_local_dtor.rs)0
-rw-r--r--src/libstd/sys/unsupported/thread_local_key.rs (renamed from src/libstd/sys/wasm/thread_local_key.rs)10
-rw-r--r--src/libstd/sys/unsupported/time.rs (renamed from src/libstd/sys/wasm/time.rs)4
-rw-r--r--src/libstd/sys/wasi/mod.rs45
-rw-r--r--src/libstd/sys/wasm/memchr.rs1
-rw-r--r--src/libstd/sys/wasm/mod.rs63
-rw-r--r--src/libstd/sys_common/mod.rs11
-rw-r--r--src/libstd/sys_common/mutex.rs1
-rw-r--r--src/libstd/thread/mod.rs3
-rw-r--r--src/libtest/Cargo.toml1
-rw-r--r--src/libtest/helpers/concurrency.rs171
-rw-r--r--src/libtest/helpers/isatty.rs56
-rw-r--r--src/libunwind/lib.rs27
-rw-r--r--src/test/rustdoc-ui/intra-links-private.rs2
-rw-r--r--src/test/rustdoc/internal.rs10
-rw-r--r--src/test/rustdoc/intra-doc-crate/additional_doc.rs10
-rw-r--r--src/test/rustdoc/intra-doc-crate/auxiliary/additional_doc.rs6
-rw-r--r--src/test/rustdoc/intra-doc-crate/auxiliary/intra-doc-basic.rs7
-rw-r--r--src/test/rustdoc/intra-doc-crate/auxiliary/macro_inner.rs10
-rw-r--r--src/test/rustdoc/intra-doc-crate/auxiliary/module.rs7
-rw-r--r--src/test/rustdoc/intra-doc-crate/auxiliary/proc_macro.rs20
-rw-r--r--src/test/rustdoc/intra-doc-crate/auxiliary/submodule-inner.rs12
-rw-r--r--src/test/rustdoc/intra-doc-crate/auxiliary/submodule-outer.rs13
-rw-r--r--src/test/rustdoc/intra-doc-crate/auxiliary/traits.rs16
-rw-r--r--src/test/rustdoc/intra-doc-crate/basic.rs9
-rw-r--r--src/test/rustdoc/intra-doc-crate/macro.rs12
-rw-r--r--src/test/rustdoc/intra-doc-crate/module.rs8
-rw-r--r--src/test/rustdoc/intra-doc-crate/submodule-inner.rs8
-rw-r--r--src/test/rustdoc/intra-doc-crate/submodule-outer.rs16
-rw-r--r--src/test/rustdoc/intra-doc-crate/traits.rs17
-rw-r--r--src/test/rustdoc/intra-link-prim-precedence.rs2
-rw-r--r--src/test/ui/issues/issue-59020.rs1
-rw-r--r--src/test/ui/issues/issue-9396.rs1
-rw-r--r--src/test/ui/mpsc_stress.rs3
-rw-r--r--src/test/ui/sleep.rs1
-rw-r--r--src/test/ui/tcp-stress.rs1
-rw-r--r--src/tools/build-manifest/src/main.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs4
-rw-r--r--src/tools/rustc-std-workspace-std/lib.rs1
112 files changed, 1310 insertions, 802 deletions
diff --git a/src/libpanic_abort/Cargo.toml b/src/libpanic_abort/Cargo.toml
index 2bee0b716c7..dc385022440 100644
--- a/src/libpanic_abort/Cargo.toml
+++ b/src/libpanic_abort/Cargo.toml
@@ -11,6 +11,7 @@ bench = false
 doc = false
 
 [dependencies]
+cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
 core = { path = "../libcore" }
 libc = { version = "0.2", default-features = false }
 compiler_builtins = "0.1.0"
diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs
index 27056d5f934..95f3966228a 100644
--- a/src/libpanic_abort/lib.rs
+++ b/src/libpanic_abort/lib.rs
@@ -40,23 +40,26 @@ pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Sen
 pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 {
     abort();
 
-    #[cfg(any(unix, target_os = "cloudabi"))]
-    unsafe fn abort() -> ! {
-        libc::abort();
-    }
-
-    #[cfg(any(windows, all(target_arch = "wasm32", not(target_os = "emscripten"))))]
-    unsafe fn abort() -> ! {
-        core::intrinsics::abort();
-    }
-
-    #[cfg(any(target_os = "hermit", all(target_vendor = "fortanix", target_env = "sgx")))]
-    unsafe fn abort() -> ! {
-        // call std::sys::abort_internal
-        extern "C" {
-            pub fn __rust_abort() -> !;
+    cfg_if::cfg_if! {
+        if #[cfg(any(unix, target_os = "cloudabi"))] {
+            unsafe fn abort() -> ! {
+                libc::abort();
+            }
+        } else if #[cfg(any(target_os = "hermit",
+                            all(target_vendor = "fortanix", target_env = "sgx")
+        ))] {
+            unsafe fn abort() -> ! {
+                // call std::sys::abort_internal
+                extern "C" {
+                    pub fn __rust_abort() -> !;
+                }
+                __rust_abort();
+            }
+        } else {
+            unsafe fn abort() -> ! {
+                core::intrinsics::abort();
+            }
         }
-        __rust_abort();
     }
 }
 
diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs
index f361354da2a..430062d4ac4 100644
--- a/src/libpanic_unwind/lib.rs
+++ b/src/libpanic_unwind/lib.rs
@@ -41,21 +41,33 @@ cfg_if::cfg_if! {
     if #[cfg(target_os = "emscripten")] {
         #[path = "emcc.rs"]
         mod real_imp;
-    } else if #[cfg(target_arch = "wasm32")] {
-        #[path = "dummy.rs"]
-        mod real_imp;
     } else if #[cfg(target_os = "hermit")] {
         #[path = "hermit.rs"]
         mod real_imp;
     } else if #[cfg(target_env = "msvc")] {
         #[path = "seh.rs"]
         mod real_imp;
-    } else {
+    } else if #[cfg(any(
+        all(target_family = "windows", target_env = "gnu"),
+        target_os = "cloudabi",
+        target_family = "unix",
+        all(target_vendor = "fortanix", target_env = "sgx"),
+    ))] {
         // Rust runtime's startup objects depend on these symbols, so make them public.
         #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
         pub use real_imp::eh_frame_registry::*;
         #[path = "gcc.rs"]
         mod real_imp;
+    } else {
+        // Targets that don't support unwinding.
+        // - arch=wasm32
+        // - os=none ("bare metal" targets)
+        // - os=uefi
+        // - nvptx64-nvidia-cuda
+        // - avr-unknown-unknown
+        // - mipsel-sony-psp
+        #[path = "dummy.rs"]
+        mod real_imp;
     }
 }
 
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 2d5bd7e872b..f960bdecc57 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -26,6 +26,7 @@
 #![feature(in_band_lifetimes)]
 #![feature(negative_impls)]
 #![feature(optin_builtin_traits)]
+#![feature(restricted_std)]
 #![feature(rustc_attrs)]
 #![feature(min_specialization)]
 #![recursion_limit = "256"]
diff --git a/src/librustc_builtin_macros/deriving/bounds.rs b/src/librustc_builtin_macros/deriving/bounds.rs
index a1c818caff3..cef0da60a61 100644
--- a/src/librustc_builtin_macros/deriving/bounds.rs
+++ b/src/librustc_builtin_macros/deriving/bounds.rs
@@ -16,9 +16,9 @@ pub fn expand_deriving_copy(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, marker::Copy),
+        path: path_std!(marker::Copy),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: true,
         methods: Vec::new(),
diff --git a/src/librustc_builtin_macros/deriving/clone.rs b/src/librustc_builtin_macros/deriving/clone.rs
index 5a8648f2aaa..b307ee26c91 100644
--- a/src/librustc_builtin_macros/deriving/clone.rs
+++ b/src/librustc_builtin_macros/deriving/clone.rs
@@ -56,7 +56,7 @@ pub fn expand_deriving_clone(
                 }
             }
             ItemKind::Union(..) => {
-                bounds = vec![Literal(path_std!(cx, marker::Copy))];
+                bounds = vec![Literal(path_std!(marker::Copy))];
                 is_shallow = true;
                 substructure = combine_substructure(Box::new(|c, s, sub| {
                     cs_clone_shallow("Clone", c, s, sub, true)
@@ -78,14 +78,14 @@ pub fn expand_deriving_clone(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, clone::Clone),
+        path: path_std!(clone::Clone),
         additional_bounds: bounds,
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: true,
         methods: vec![MethodDef {
             name: sym::clone,
-            generics: LifetimeBounds::empty(),
+            generics: Bounds::empty(),
             explicit_self: borrowed_explicit_self(),
             args: Vec::new(),
             ret_ty: Self_,
diff --git a/src/librustc_builtin_macros/deriving/cmp/eq.rs b/src/librustc_builtin_macros/deriving/cmp/eq.rs
index e1677ae70cc..d1b799cd6a1 100644
--- a/src/librustc_builtin_macros/deriving/cmp/eq.rs
+++ b/src/librustc_builtin_macros/deriving/cmp/eq.rs
@@ -22,14 +22,14 @@ pub fn expand_deriving_eq(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, cmp::Eq),
+        path: path_std!(cmp::Eq),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: true,
         methods: vec![MethodDef {
             name: sym::assert_receiver_is_total_eq,
-            generics: LifetimeBounds::empty(),
+            generics: Bounds::empty(),
             explicit_self: borrowed_explicit_self(),
             args: vec![],
             ret_ty: nil_ty(),
@@ -43,13 +43,7 @@ pub fn expand_deriving_eq(
         associated_types: Vec::new(),
     };
 
-    super::inject_impl_of_structural_trait(
-        cx,
-        span,
-        item,
-        path_std!(cx, marker::StructuralEq),
-        push,
-    );
+    super::inject_impl_of_structural_trait(cx, span, item, path_std!(marker::StructuralEq), push);
 
     trait_def.expand_ext(cx, mitem, item, push, true)
 }
diff --git a/src/librustc_builtin_macros/deriving/cmp/ord.rs b/src/librustc_builtin_macros/deriving/cmp/ord.rs
index a9bc03db8b7..3bf3860d323 100644
--- a/src/librustc_builtin_macros/deriving/cmp/ord.rs
+++ b/src/librustc_builtin_macros/deriving/cmp/ord.rs
@@ -20,17 +20,17 @@ pub fn expand_deriving_ord(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, cmp::Ord),
+        path: path_std!(cmp::Ord),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
             name: sym::cmp,
-            generics: LifetimeBounds::empty(),
+            generics: Bounds::empty(),
             explicit_self: borrowed_explicit_self(),
-            args: vec![(borrowed_self(), "other")],
-            ret_ty: Literal(path_std!(cx, cmp::Ordering)),
+            args: vec![(borrowed_self(), sym::other)],
+            ret_ty: Literal(path_std!(cmp::Ordering)),
             attributes: attrs,
             is_unsafe: false,
             unify_fieldless_variants: true,
diff --git a/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs b/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs
index e7d8f781180..d8edd641acd 100644
--- a/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs
+++ b/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs
@@ -69,9 +69,9 @@ pub fn expand_deriving_partial_eq(
             let attrs = vec![cx.attribute(inline)];
             MethodDef {
                 name: $name,
-                generics: LifetimeBounds::empty(),
+                generics: Bounds::empty(),
                 explicit_self: borrowed_explicit_self(),
-                args: vec![(borrowed_self(), "other")],
+                args: vec![(borrowed_self(), sym::other)],
                 ret_ty: Literal(path_local!(bool)),
                 attributes: attrs,
                 is_unsafe: false,
@@ -85,7 +85,7 @@ pub fn expand_deriving_partial_eq(
         cx,
         span,
         item,
-        path_std!(cx, marker::StructuralPartialEq),
+        path_std!(marker::StructuralPartialEq),
         push,
     );
 
@@ -100,9 +100,9 @@ pub fn expand_deriving_partial_eq(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, cmp::PartialEq),
+        path: path_std!(cmp::PartialEq),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods,
diff --git a/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs b/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs
index a3eb96fb782..39a747c8568 100644
--- a/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs
+++ b/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs
@@ -23,9 +23,9 @@ pub fn expand_deriving_partial_ord(
             let attrs = vec![cx.attribute(inline)];
             MethodDef {
                 name: $name,
-                generics: LifetimeBounds::empty(),
+                generics: Bounds::empty(),
                 explicit_self: borrowed_explicit_self(),
-                args: vec![(borrowed_self(), "other")],
+                args: vec![(borrowed_self(), sym::other)],
                 ret_ty: Literal(path_local!(bool)),
                 attributes: attrs,
                 is_unsafe: false,
@@ -37,9 +37,9 @@ pub fn expand_deriving_partial_ord(
         }};
     }
 
-    let ordering_ty = Literal(path_std!(cx, cmp::Ordering));
+    let ordering_ty = Literal(path_std!(cmp::Ordering));
     let ret_ty = Literal(Path::new_(
-        pathvec_std!(cx, option::Option),
+        pathvec_std!(option::Option),
         None,
         vec![Box::new(ordering_ty)],
         PathKind::Std,
@@ -50,9 +50,9 @@ pub fn expand_deriving_partial_ord(
 
     let partial_cmp_def = MethodDef {
         name: sym::partial_cmp,
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         explicit_self: borrowed_explicit_self(),
-        args: vec![(borrowed_self(), "other")],
+        args: vec![(borrowed_self(), sym::other)],
         ret_ty,
         attributes: attrs,
         is_unsafe: false,
@@ -80,9 +80,9 @@ pub fn expand_deriving_partial_ord(
     let trait_def = TraitDef {
         span,
         attributes: vec![],
-        path: path_std!(cx, cmp::PartialOrd),
+        path: path_std!(cmp::PartialOrd),
         additional_bounds: vec![],
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods,
diff --git a/src/librustc_builtin_macros/deriving/debug.rs b/src/librustc_builtin_macros/deriving/debug.rs
index 6befeb746bd..76e21bc43c5 100644
--- a/src/librustc_builtin_macros/deriving/debug.rs
+++ b/src/librustc_builtin_macros/deriving/debug.rs
@@ -18,22 +18,22 @@ pub fn expand_deriving_debug(
 ) {
     // &mut ::std::fmt::Formatter
     let fmtr =
-        Ptr(Box::new(Literal(path_std!(cx, fmt::Formatter))), Borrowed(None, ast::Mutability::Mut));
+        Ptr(Box::new(Literal(path_std!(fmt::Formatter))), Borrowed(None, ast::Mutability::Mut));
 
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, fmt::Debug),
+        path: path_std!(fmt::Debug),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
             name: sym::fmt,
-            generics: LifetimeBounds::empty(),
+            generics: Bounds::empty(),
             explicit_self: borrowed_explicit_self(),
-            args: vec![(fmtr, "f")],
-            ret_ty: Literal(path_std!(cx, fmt::Result)),
+            args: vec![(fmtr, sym::f)],
+            ret_ty: Literal(path_std!(fmt::Result)),
             attributes: Vec::new(),
             is_unsafe: false,
             unify_fieldless_variants: false,
@@ -62,7 +62,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
     // We want to make sure we have the ctxt set so that we can use unstable methods
     let span = cx.with_def_site_ctxt(span);
     let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
-    let builder = cx.ident_of("debug_trait_builder", span);
+    let builder = Ident::new(sym::debug_trait_builder, span);
     let builder_expr = cx.expr_ident(span, builder);
 
     let fmt = substr.nonself_args[0].clone();
@@ -71,7 +71,8 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
     match vdata {
         ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
             // tuple struct/"normal" variant
-            let expr = cx.expr_method_call(span, fmt, cx.ident_of("debug_tuple", span), vec![name]);
+            let expr =
+                cx.expr_method_call(span, fmt, Ident::new(sym::debug_tuple, span), vec![name]);
             stmts.push(cx.stmt_let(span, true, builder, expr));
 
             for field in fields {
@@ -94,7 +95,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         ast::VariantData::Struct(..) => {
             // normal struct/struct variant
             let expr =
-                cx.expr_method_call(span, fmt, cx.ident_of("debug_struct", span), vec![name]);
+                cx.expr_method_call(span, fmt, Ident::new(sym::debug_struct, span), vec![name]);
             stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
 
             for field in fields {
@@ -117,7 +118,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         }
     }
 
-    let expr = cx.expr_method_call(span, builder_expr, cx.ident_of("finish", span), vec![]);
+    let expr = cx.expr_method_call(span, builder_expr, Ident::new(sym::finish, span), vec![]);
 
     stmts.push(cx.stmt_expr(expr));
     let block = cx.block(span, stmts);
diff --git a/src/librustc_builtin_macros/deriving/decodable.rs b/src/librustc_builtin_macros/deriving/decodable.rs
index 0792be73263..ce8c2dfe4d5 100644
--- a/src/librustc_builtin_macros/deriving/decodable.rs
+++ b/src/librustc_builtin_macros/deriving/decodable.rs
@@ -8,7 +8,7 @@ use rustc_ast::ast;
 use rustc_ast::ast::{Expr, MetaItem, Mutability};
 use rustc_ast::ptr::P;
 use rustc_expand::base::{Annotatable, ExtCtxt};
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 
 pub fn expand_deriving_rustc_decodable(
@@ -18,38 +18,37 @@ pub fn expand_deriving_rustc_decodable(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
-    let krate = "rustc_serialize";
-    let typaram = "__D";
+    let krate = sym::rustc_serialize;
+    let typaram = sym::__D;
 
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: Path::new_(vec![krate, "Decodable"], None, vec![], PathKind::Global),
+        path: Path::new_(vec![krate, sym::Decodable], None, vec![], PathKind::Global),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
             name: sym::decode,
-            generics: LifetimeBounds {
-                lifetimes: Vec::new(),
+            generics: Bounds {
                 bounds: vec![(
                     typaram,
-                    vec![Path::new_(vec![krate, "Decoder"], None, vec![], PathKind::Global)],
+                    vec![Path::new_(vec![krate, sym::Decoder], None, vec![], PathKind::Global)],
                 )],
             },
             explicit_self: None,
             args: vec![(
                 Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
-                "d",
+                sym::d,
             )],
             ret_ty: Literal(Path::new_(
-                pathvec_std!(cx, result::Result),
+                pathvec_std!(result::Result),
                 None,
                 vec![
                     Box::new(Self_),
                     Box::new(Literal(Path::new_(
-                        vec![typaram, "Error"],
+                        vec![typaram, sym::Error],
                         None,
                         vec![],
                         PathKind::Local,
@@ -74,17 +73,17 @@ fn decodable_substructure(
     cx: &mut ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
-    krate: &str,
+    krate: Symbol,
 ) -> P<Expr> {
     let decoder = substr.nonself_args[0].clone();
     let recurse = vec![
-        cx.ident_of(krate, trait_span),
-        cx.ident_of("Decodable", trait_span),
-        cx.ident_of("decode", trait_span),
+        Ident::new(krate, trait_span),
+        Ident::new(sym::Decodable, trait_span),
+        Ident::new(sym::decode, trait_span),
     ];
     let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse));
     // throw an underscore in front to suppress unused variable warnings
-    let blkarg = cx.ident_of("_d", trait_span);
+    let blkarg = Ident::new(sym::_d, trait_span);
     let blkdecoder = cx.expr_ident(trait_span, blkarg);
 
     match *substr.fields {
@@ -93,7 +92,7 @@ fn decodable_substructure(
                 Unnamed(ref fields, _) => fields.len(),
                 Named(ref fields) => fields.len(),
             };
-            let read_struct_field = cx.ident_of("read_struct_field", trait_span);
+            let read_struct_field = Ident::new(sym::read_struct_field, trait_span);
 
             let path = cx.path_ident(trait_span, substr.type_ident);
             let result =
@@ -116,7 +115,7 @@ fn decodable_substructure(
             cx.expr_method_call(
                 trait_span,
                 decoder,
-                cx.ident_of("read_struct", trait_span),
+                Ident::new(sym::read_struct, trait_span),
                 vec![
                     cx.expr_str(trait_span, substr.type_ident.name),
                     cx.expr_usize(trait_span, nfields),
@@ -125,11 +124,11 @@ fn decodable_substructure(
             )
         }
         StaticEnum(_, ref fields) => {
-            let variant = cx.ident_of("i", trait_span);
+            let variant = Ident::new(sym::i, trait_span);
 
             let mut arms = Vec::with_capacity(fields.len() + 1);
             let mut variants = Vec::with_capacity(fields.len());
-            let rvariant_arg = cx.ident_of("read_enum_variant_arg", trait_span);
+            let rvariant_arg = Ident::new(sym::read_enum_variant_arg, trait_span);
 
             for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() {
                 variants.push(cx.expr_str(v_span, ident.name));
@@ -164,13 +163,13 @@ fn decodable_substructure(
             let result = cx.expr_method_call(
                 trait_span,
                 blkdecoder,
-                cx.ident_of("read_enum_variant", trait_span),
+                Ident::new(sym::read_enum_variant, trait_span),
                 vec![variant_vec, lambda],
             );
             cx.expr_method_call(
                 trait_span,
                 decoder,
-                cx.ident_of("read_enum", trait_span),
+                Ident::new(sym::read_enum, trait_span),
                 vec![
                     cx.expr_str(trait_span, substr.type_ident.name),
                     cx.lambda1(trait_span, result, blkarg),
diff --git a/src/librustc_builtin_macros/deriving/default.rs b/src/librustc_builtin_macros/deriving/default.rs
index 5dfb0e8f37c..8ca1be1efb6 100644
--- a/src/librustc_builtin_macros/deriving/default.rs
+++ b/src/librustc_builtin_macros/deriving/default.rs
@@ -1,6 +1,5 @@
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
-use crate::deriving::path_std;
 
 use rustc_ast::ast::{Expr, MetaItem};
 use rustc_ast::ptr::P;
@@ -21,14 +20,14 @@ pub fn expand_deriving_default(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, default::Default),
+        path: Path::new(vec![kw::Default, sym::Default]),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
             name: kw::Default,
-            generics: LifetimeBounds::empty(),
+            generics: Bounds::empty(),
             explicit_self: None,
             args: Vec::new(),
             ret_ty: Self_,
diff --git a/src/librustc_builtin_macros/deriving/encodable.rs b/src/librustc_builtin_macros/deriving/encodable.rs
index 4a90b7a1938..7a880357a59 100644
--- a/src/librustc_builtin_macros/deriving/encodable.rs
+++ b/src/librustc_builtin_macros/deriving/encodable.rs
@@ -92,7 +92,7 @@ use crate::deriving::pathvec_std;
 use rustc_ast::ast::{Expr, ExprKind, MetaItem, Mutability};
 use rustc_ast::ptr::P;
 use rustc_expand::base::{Annotatable, ExtCtxt};
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 
 pub fn expand_deriving_rustc_encodable(
@@ -102,38 +102,42 @@ pub fn expand_deriving_rustc_encodable(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
-    let krate = "rustc_serialize";
-    let typaram = "__S";
+    let krate = sym::rustc_serialize;
+    let typaram = sym::__S;
 
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: Path::new_(vec![krate, "Encodable"], None, vec![], PathKind::Global),
+        path: Path::new_(vec![krate, sym::Encodable], None, vec![], PathKind::Global),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
             name: sym::encode,
-            generics: LifetimeBounds {
-                lifetimes: Vec::new(),
+            generics: Bounds {
                 bounds: vec![(
                     typaram,
-                    vec![Path::new_(vec![krate, "Encoder"], None, vec![], PathKind::Global)],
+                    vec![Path::new_(vec![krate, sym::Encoder], None, vec![], PathKind::Global)],
                 )],
             },
             explicit_self: borrowed_explicit_self(),
             args: vec![(
                 Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
-                "s",
+                // FIXME: we could use `sym::s` here, but making `s` a static
+                // symbol changes the symbol index ordering in a way that makes
+                // ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
+                // fail. The linting code should be fixed so that its output
+                // does not depend on the symbol index ordering.
+                Symbol::intern("s"),
             )],
             ret_ty: Literal(Path::new_(
-                pathvec_std!(cx, result::Result),
+                pathvec_std!(result::Result),
                 None,
                 vec![
                     Box::new(Tuple(Vec::new())),
                     Box::new(Literal(Path::new_(
-                        vec![typaram, "Error"],
+                        vec![typaram, sym::Error],
                         None,
                         vec![],
                         PathKind::Local,
@@ -158,24 +162,24 @@ fn encodable_substructure(
     cx: &mut ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
-    krate: &'static str,
+    krate: Symbol,
 ) -> P<Expr> {
     let encoder = substr.nonself_args[0].clone();
     // throw an underscore in front to suppress unused variable warnings
-    let blkarg = cx.ident_of("_e", trait_span);
+    let blkarg = Ident::new(sym::_e, trait_span);
     let blkencoder = cx.expr_ident(trait_span, blkarg);
     let fn_path = cx.expr_path(cx.path_global(
         trait_span,
         vec![
-            cx.ident_of(krate, trait_span),
-            cx.ident_of("Encodable", trait_span),
-            cx.ident_of("encode", trait_span),
+            Ident::new(krate, trait_span),
+            Ident::new(sym::Encodable, trait_span),
+            Ident::new(sym::encode, trait_span),
         ],
     ));
 
     match *substr.fields {
         Struct(_, ref fields) => {
-            let emit_struct_field = cx.ident_of("emit_struct_field", trait_span);
+            let emit_struct_field = Ident::new(sym::emit_struct_field, trait_span);
             let mut stmts = Vec::new();
             for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
                 let name = match name {
@@ -215,7 +219,7 @@ fn encodable_substructure(
             cx.expr_method_call(
                 trait_span,
                 encoder,
-                cx.ident_of("emit_struct", trait_span),
+                Ident::new(sym::emit_struct, trait_span),
                 vec![
                     cx.expr_str(trait_span, substr.type_ident.name),
                     cx.expr_usize(trait_span, fields.len()),
@@ -231,7 +235,7 @@ fn encodable_substructure(
             // actually exist.
             let me = cx.stmt_let(trait_span, false, blkarg, encoder);
             let encoder = cx.expr_ident(trait_span, blkarg);
-            let emit_variant_arg = cx.ident_of("emit_enum_variant_arg", trait_span);
+            let emit_variant_arg = Ident::new(sym::emit_enum_variant_arg, trait_span);
             let mut stmts = Vec::new();
             if !fields.is_empty() {
                 let last = fields.len() - 1;
@@ -264,7 +268,7 @@ fn encodable_substructure(
             let call = cx.expr_method_call(
                 trait_span,
                 blkencoder,
-                cx.ident_of("emit_enum_variant", trait_span),
+                Ident::new(sym::emit_enum_variant, trait_span),
                 vec![
                     name,
                     cx.expr_usize(trait_span, idx),
@@ -276,7 +280,7 @@ fn encodable_substructure(
             let ret = cx.expr_method_call(
                 trait_span,
                 encoder,
-                cx.ident_of("emit_enum", trait_span),
+                Ident::new(sym::emit_enum, trait_span),
                 vec![cx.expr_str(trait_span, substr.type_ident.name), blk],
             );
             cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)]))
diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs
index 050774aa24c..c43d1cf1888 100644
--- a/src/librustc_builtin_macros/deriving/generic/mod.rs
+++ b/src/librustc_builtin_macros/deriving/generic/mod.rs
@@ -191,7 +191,7 @@ use rustc_span::source_map::respan;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 
-use ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty};
+use ty::{Bounds, Path, Ptr, PtrTy, Self_, Ty};
 
 use crate::deriving;
 
@@ -204,14 +204,14 @@ pub struct TraitDef<'a> {
     pub attributes: Vec<ast::Attribute>,
 
     /// Path of the trait, including any type parameters
-    pub path: Path<'a>,
+    pub path: Path,
 
     /// Additional bounds required of any type parameters of the type,
     /// other than the current trait
-    pub additional_bounds: Vec<Ty<'a>>,
+    pub additional_bounds: Vec<Ty>,
 
     /// Any extra lifetimes and/or bounds, e.g., `D: serialize::Decoder`
-    pub generics: LifetimeBounds<'a>,
+    pub generics: Bounds,
 
     /// Is it an `unsafe` trait?
     pub is_unsafe: bool,
@@ -221,14 +221,14 @@ pub struct TraitDef<'a> {
 
     pub methods: Vec<MethodDef<'a>>,
 
-    pub associated_types: Vec<(Ident, Ty<'a>)>,
+    pub associated_types: Vec<(Ident, Ty)>,
 }
 
 pub struct MethodDef<'a> {
     /// name of the method
     pub name: Symbol,
     /// List of generics, e.g., `R: rand::Rng`
-    pub generics: LifetimeBounds<'a>,
+    pub generics: Bounds,
 
     /// Whether there is a self argument (outer Option) i.e., whether
     /// this is a static function, and whether it is a pointer (inner
@@ -236,10 +236,10 @@ pub struct MethodDef<'a> {
     pub explicit_self: Option<Option<PtrTy>>,
 
     /// Arguments other than the self argument
-    pub args: Vec<(Ty<'a>, &'a str)>,
+    pub args: Vec<(Ty, Symbol)>,
 
     /// Returns type
-    pub ret_ty: Ty<'a>,
+    pub ret_ty: Ty,
 
     pub attributes: Vec<ast::Attribute>,
 
@@ -865,7 +865,7 @@ impl<'a> MethodDef<'a> {
 
         for (ty, name) in self.args.iter() {
             let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
-            let ident = cx.ident_of(name, trait_.span);
+            let ident = Ident::new(*name, trait_.span);
             arg_tys.push((ident, ast_ty));
 
             let arg_expr = cx.expr_ident(trait_.span, ident);
@@ -1170,8 +1170,10 @@ impl<'a> MethodDef<'a> {
             )
             .collect::<Vec<String>>();
 
-        let self_arg_idents =
-            self_arg_names.iter().map(|name| cx.ident_of(name, sp)).collect::<Vec<Ident>>();
+        let self_arg_idents = self_arg_names
+            .iter()
+            .map(|name| Ident::from_str_and_span(name, sp))
+            .collect::<Vec<Ident>>();
 
         // The `vi_idents` will be bound, solely in the catch-all, to
         // a series of let statements mapping each self_arg to an int
@@ -1180,7 +1182,7 @@ impl<'a> MethodDef<'a> {
             .iter()
             .map(|name| {
                 let vi_suffix = format!("{}_vi", &name[..]);
-                cx.ident_of(&vi_suffix[..], trait_.span)
+                Ident::from_str_and_span(&vi_suffix, trait_.span)
             })
             .collect::<Vec<Ident>>();
 
@@ -1568,7 +1570,7 @@ impl<'a> TraitDef<'a> {
         let mut ident_exprs = Vec::new();
         for (i, struct_field) in struct_def.fields().iter().enumerate() {
             let sp = struct_field.span.with_ctxt(self.span.ctxt());
-            let ident = cx.ident_of(&format!("{}_{}", prefix, i), self.span);
+            let ident = Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span);
             paths.push(ident.with_span_pos(sp));
             let val = cx.expr_path(cx.path_ident(sp, ident));
             let val = if use_temporaries { val } else { cx.expr_deref(sp, val) };
diff --git a/src/librustc_builtin_macros/deriving/generic/ty.rs b/src/librustc_builtin_macros/deriving/generic/ty.rs
index 609feb6f259..51314dbcffc 100644
--- a/src/librustc_builtin_macros/deriving/generic/ty.rs
+++ b/src/librustc_builtin_macros/deriving/generic/ty.rs
@@ -8,7 +8,7 @@ use rustc_ast::ast::{self, Expr, GenericArg, GenericParamKind, Generics, SelfKin
 use rustc_ast::ptr::P;
 use rustc_expand::base::ExtCtxt;
 use rustc_span::source_map::{respan, DUMMY_SP};
-use rustc_span::symbol::{kw, Ident};
+use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::Span;
 
 /// The types of pointers
@@ -24,10 +24,10 @@ pub enum PtrTy {
 /// A path, e.g., `::std::option::Option::<i32>` (global). Has support
 /// for type parameters and a lifetime.
 #[derive(Clone)]
-pub struct Path<'a> {
-    path: Vec<&'a str>,
+pub struct Path {
+    path: Vec<Symbol>,
     lifetime: Option<Ident>,
-    params: Vec<Box<Ty<'a>>>,
+    params: Vec<Box<Ty>>,
     kind: PathKind,
 }
 
@@ -38,19 +38,19 @@ pub enum PathKind {
     Std,
 }
 
-impl<'a> Path<'a> {
-    pub fn new(path: Vec<&str>) -> Path<'_> {
+impl Path {
+    pub fn new(path: Vec<Symbol>) -> Path {
         Path::new_(path, None, Vec::new(), PathKind::Std)
     }
-    pub fn new_local(path: &str) -> Path<'_> {
+    pub fn new_local(path: Symbol) -> Path {
         Path::new_(vec![path], None, Vec::new(), PathKind::Local)
     }
-    pub fn new_<'r>(
-        path: Vec<&'r str>,
+    pub fn new_(
+        path: Vec<Symbol>,
         lifetime: Option<Ident>,
-        params: Vec<Box<Ty<'r>>>,
+        params: Vec<Box<Ty>>,
         kind: PathKind,
-    ) -> Path<'r> {
+    ) -> Path {
         Path { path, lifetime, params, kind }
     }
 
@@ -70,7 +70,7 @@ impl<'a> Path<'a> {
         self_ty: Ident,
         self_generics: &Generics,
     ) -> ast::Path {
-        let mut idents = self.path.iter().map(|s| cx.ident_of(*s, span)).collect();
+        let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect();
         let lt = mk_lifetimes(cx, span, &self.lifetime);
         let tys: Vec<P<ast::Ty>> =
             self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
@@ -94,21 +94,21 @@ impl<'a> Path<'a> {
 
 /// A type. Supports pointers, Self, and literals.
 #[derive(Clone)]
-pub enum Ty<'a> {
+pub enum Ty {
     Self_,
     /// &/Box/ Ty
-    Ptr(Box<Ty<'a>>, PtrTy),
+    Ptr(Box<Ty>, PtrTy),
     /// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type
     /// parameter, and things like `i32`
-    Literal(Path<'a>),
+    Literal(Path),
     /// includes unit
-    Tuple(Vec<Ty<'a>>),
+    Tuple(Vec<Ty>),
 }
 
 pub fn borrowed_ptrty() -> PtrTy {
     Borrowed(None, ast::Mutability::Not)
 }
-pub fn borrowed(ty: Box<Ty<'_>>) -> Ty<'_> {
+pub fn borrowed(ty: Box<Ty>) -> Ty {
     Ptr(ty, borrowed_ptrty())
 }
 
@@ -116,11 +116,11 @@ pub fn borrowed_explicit_self() -> Option<Option<PtrTy>> {
     Some(Some(borrowed_ptrty()))
 }
 
-pub fn borrowed_self<'r>() -> Ty<'r> {
+pub fn borrowed_self() -> Ty {
     borrowed(Box::new(Self_))
 }
 
-pub fn nil_ty<'r>() -> Ty<'r> {
+pub fn nil_ty() -> Ty {
     Tuple(Vec::new())
 }
 
@@ -132,7 +132,7 @@ fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Vec<ast::Li
     mk_lifetime(cx, span, lt).into_iter().collect()
 }
 
-impl<'a> Ty<'a> {
+impl Ty {
     pub fn to_ty(
         &self,
         cx: &ExtCtxt<'_>,
@@ -199,9 +199,9 @@ impl<'a> Ty<'a> {
 fn mk_ty_param(
     cx: &ExtCtxt<'_>,
     span: Span,
-    name: &str,
+    name: Symbol,
     attrs: &[ast::Attribute],
-    bounds: &[Path<'_>],
+    bounds: &[Path],
     self_ident: Ident,
     self_generics: &Generics,
 ) -> ast::GenericParam {
@@ -212,7 +212,7 @@ fn mk_ty_param(
             cx.trait_bound(path)
         })
         .collect();
-    cx.typaram(span, cx.ident_of(name, span), attrs.to_owned(), bounds, None)
+    cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None)
 }
 
 fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
@@ -223,16 +223,15 @@ fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
     }
 }
 
-/// Lifetimes and bounds on type parameters
+/// Bounds on type parameters.
 #[derive(Clone)]
-pub struct LifetimeBounds<'a> {
-    pub lifetimes: Vec<(&'a str, Vec<&'a str>)>,
-    pub bounds: Vec<(&'a str, Vec<Path<'a>>)>,
+pub struct Bounds {
+    pub bounds: Vec<(Symbol, Vec<Path>)>,
 }
 
-impl<'a> LifetimeBounds<'a> {
-    pub fn empty() -> LifetimeBounds<'a> {
-        LifetimeBounds { lifetimes: Vec::new(), bounds: Vec::new() }
+impl Bounds {
+    pub fn empty() -> Bounds {
+        Bounds { bounds: Vec::new() }
     }
     pub fn to_generics(
         &self,
@@ -242,18 +241,12 @@ impl<'a> LifetimeBounds<'a> {
         self_generics: &Generics,
     ) -> Generics {
         let generic_params = self
-            .lifetimes
+            .bounds
             .iter()
-            .map(|&(lt, ref bounds)| {
-                let bounds = bounds
-                    .iter()
-                    .map(|b| ast::GenericBound::Outlives(cx.lifetime(span, Ident::from_str(b))));
-                cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds.collect())
-            })
-            .chain(self.bounds.iter().map(|t| {
+            .map(|t| {
                 let (name, ref bounds) = *t;
                 mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics)
-            }))
+            })
             .collect();
 
         mk_generics(generic_params, span)
diff --git a/src/librustc_builtin_macros/deriving/hash.rs b/src/librustc_builtin_macros/deriving/hash.rs
index f975b75f0be..d7195188085 100644
--- a/src/librustc_builtin_macros/deriving/hash.rs
+++ b/src/librustc_builtin_macros/deriving/hash.rs
@@ -15,9 +15,9 @@ pub fn expand_deriving_hash(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
-    let path = Path::new_(pathvec_std!(cx, hash::Hash), None, vec![], PathKind::Std);
+    let path = Path::new_(pathvec_std!(hash::Hash), None, vec![], PathKind::Std);
 
-    let typaram = "__H";
+    let typaram = sym::__H;
 
     let arg = Path::new_local(typaram);
     let hash_trait_def = TraitDef {
@@ -25,17 +25,14 @@ pub fn expand_deriving_hash(
         attributes: Vec::new(),
         path,
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
             name: sym::hash,
-            generics: LifetimeBounds {
-                lifetimes: Vec::new(),
-                bounds: vec![(typaram, vec![path_std!(cx, hash::Hasher)])],
-            },
+            generics: Bounds { bounds: vec![(typaram, vec![path_std!(hash::Hasher)])] },
             explicit_self: borrowed_explicit_self(),
-            args: vec![(Ptr(Box::new(Literal(arg)), Borrowed(None, Mutability::Mut)), "state")],
+            args: vec![(Ptr(Box::new(Literal(arg)), Borrowed(None, Mutability::Mut)), sym::state)],
             ret_ty: nil_ty(),
             attributes: vec![],
             is_unsafe: false,
diff --git a/src/librustc_builtin_macros/deriving/mod.rs b/src/librustc_builtin_macros/deriving/mod.rs
index 6cee21fc6e6..33c0edde98f 100644
--- a/src/librustc_builtin_macros/deriving/mod.rs
+++ b/src/librustc_builtin_macros/deriving/mod.rs
@@ -7,11 +7,11 @@ use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 
 macro path_local($x:ident) {
-    generic::ty::Path::new_local(stringify!($x))
+    generic::ty::Path::new_local(sym::$x)
 }
 
-macro pathvec_std($cx:expr, $($rest:ident)::+) {{
-    vec![ $( stringify!($rest) ),+ ]
+macro pathvec_std($($rest:ident)::+) {{
+    vec![ $( sym::$rest ),+ ]
 }}
 
 macro path_std($($x:tt)*) {
@@ -84,7 +84,7 @@ fn inject_impl_of_structural_trait(
     cx: &mut ExtCtxt<'_>,
     span: Span,
     item: &Annotatable,
-    structural_path: generic::ty::Path<'_>,
+    structural_path: generic::ty::Path,
     push: &mut dyn FnMut(Annotatable),
 ) {
     let item = match *item {
diff --git a/src/librustc_builtin_macros/format.rs b/src/librustc_builtin_macros/format.rs
index 2becbe2f675..55eab24b8a5 100644
--- a/src/librustc_builtin_macros/format.rs
+++ b/src/librustc_builtin_macros/format.rs
@@ -578,31 +578,31 @@ impl<'a, 'b> Context<'a, 'b> {
         self.count_args_index_offset = sofar;
     }
 
-    fn rtpath(ecx: &ExtCtxt<'_>, s: &str) -> Vec<Ident> {
-        ecx.std_path(&[sym::fmt, sym::rt, sym::v1, Symbol::intern(s)])
+    fn rtpath(ecx: &ExtCtxt<'_>, s: Symbol) -> Vec<Ident> {
+        ecx.std_path(&[sym::fmt, sym::rt, sym::v1, s])
     }
 
     fn build_count(&self, c: parse::Count) -> P<ast::Expr> {
         let sp = self.macsp;
         let count = |c, arg| {
-            let mut path = Context::rtpath(self.ecx, "Count");
-            path.push(self.ecx.ident_of(c, sp));
+            let mut path = Context::rtpath(self.ecx, sym::Count);
+            path.push(Ident::new(c, sp));
             match arg {
                 Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]),
                 None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
             }
         };
         match c {
-            parse::CountIs(i) => count("Is", Some(self.ecx.expr_usize(sp, i))),
+            parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))),
             parse::CountIsParam(i) => {
                 // This needs mapping too, as `i` is referring to a macro
                 // argument. If `i` is not found in `count_positions` then
                 // the error had already been emitted elsewhere.
                 let i = self.count_positions.get(&i).cloned().unwrap_or(0)
                     + self.count_args_index_offset;
-                count("Param", Some(self.ecx.expr_usize(sp, i)))
+                count(sym::Param, Some(self.ecx.expr_usize(sp, i)))
             }
-            parse::CountImplied => count("Implied", None),
+            parse::CountImplied => count(sym::Implied, None),
             // should never be the case, names are already resolved
             parse::CountIsName(_) => panic!("should never happen"),
         }
@@ -690,40 +690,40 @@ impl<'a, 'b> Context<'a, 'b> {
                 // Build the format
                 let fill = self.ecx.expr_lit(sp, ast::LitKind::Char(fill));
                 let align = |name| {
-                    let mut p = Context::rtpath(self.ecx, "Alignment");
-                    p.push(self.ecx.ident_of(name, sp));
+                    let mut p = Context::rtpath(self.ecx, sym::Alignment);
+                    p.push(Ident::new(name, sp));
                     self.ecx.path_global(sp, p)
                 };
                 let align = match arg.format.align {
-                    parse::AlignLeft => align("Left"),
-                    parse::AlignRight => align("Right"),
-                    parse::AlignCenter => align("Center"),
-                    parse::AlignUnknown => align("Unknown"),
+                    parse::AlignLeft => align(sym::Left),
+                    parse::AlignRight => align(sym::Right),
+                    parse::AlignCenter => align(sym::Center),
+                    parse::AlignUnknown => align(sym::Unknown),
                 };
                 let align = self.ecx.expr_path(align);
                 let flags = self.ecx.expr_u32(sp, arg.format.flags);
                 let prec = self.build_count(arg.format.precision);
                 let width = self.build_count(arg.format.width);
-                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "FormatSpec"));
+                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, sym::FormatSpec));
                 let fmt = self.ecx.expr_struct(
                     sp,
                     path,
                     vec![
-                        self.ecx.field_imm(sp, self.ecx.ident_of("fill", sp), fill),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("align", sp), align),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("flags", sp), flags),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("precision", sp), prec),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("width", sp), width),
+                        self.ecx.field_imm(sp, Ident::new(sym::fill, sp), fill),
+                        self.ecx.field_imm(sp, Ident::new(sym::align, sp), align),
+                        self.ecx.field_imm(sp, Ident::new(sym::flags, sp), flags),
+                        self.ecx.field_imm(sp, Ident::new(sym::precision, sp), prec),
+                        self.ecx.field_imm(sp, Ident::new(sym::width, sp), width),
                     ],
                 );
 
-                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "Argument"));
+                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, sym::Argument));
                 Some(self.ecx.expr_struct(
                     sp,
                     path,
                     vec![
-                        self.ecx.field_imm(sp, self.ecx.ident_of("position", sp), pos),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("format", sp), fmt),
+                        self.ecx.field_imm(sp, Ident::new(sym::position, sp), pos),
+                        self.ecx.field_imm(sp, Ident::new(sym::format, sp), fmt),
                     ],
                 ))
             }
@@ -740,7 +740,7 @@ impl<'a, 'b> Context<'a, 'b> {
         let mut heads = Vec::with_capacity(self.args.len());
 
         let names_pos: Vec<_> = (0..self.args.len())
-            .map(|i| self.ecx.ident_of(&format!("arg{}", i), self.macsp))
+            .map(|i| Ident::from_str_and_span(&format!("arg{}", i), self.macsp))
             .collect();
 
         // First, build up the static array which will become our precompiled
diff --git a/src/librustc_builtin_macros/global_allocator.rs b/src/librustc_builtin_macros/global_allocator.rs
index f8a9a97b2a5..89446a1aa96 100644
--- a/src/librustc_builtin_macros/global_allocator.rs
+++ b/src/librustc_builtin_macros/global_allocator.rs
@@ -58,7 +58,7 @@ impl AllocFnFactory<'_, '_> {
         let mut abi_args = Vec::new();
         let mut i = 0;
         let mut mk = || {
-            let name = self.cx.ident_of(&format!("arg{}", i), self.span);
+            let name = Ident::from_str_and_span(&format!("arg{}", i), self.span);
             i += 1;
             name
         };
@@ -72,7 +72,7 @@ impl AllocFnFactory<'_, '_> {
         let kind = ItemKind::Fn(ast::Defaultness::Final, sig, Generics::default(), block);
         let item = self.cx.item(
             self.span,
-            self.cx.ident_of(&self.kind.fn_name(method.name), self.span),
+            Ident::from_str_and_span(&self.kind.fn_name(method.name), self.span),
             self.attrs(),
             kind,
         );
diff --git a/src/librustc_builtin_macros/proc_macro_harness.rs b/src/librustc_builtin_macros/proc_macro_harness.rs
index 7cc9c1f7663..f044ce41e87 100644
--- a/src/librustc_builtin_macros/proc_macro_harness.rs
+++ b/src/librustc_builtin_macros/proc_macro_harness.rs
@@ -384,12 +384,12 @@ fn mk_decls(
     let proc_macro = Ident::new(sym::proc_macro, span);
     let krate = cx.item(span, proc_macro, Vec::new(), ast::ItemKind::ExternCrate(None));
 
-    let bridge = cx.ident_of("bridge", span);
-    let client = cx.ident_of("client", span);
-    let proc_macro_ty = cx.ident_of("ProcMacro", span);
-    let custom_derive = cx.ident_of("custom_derive", span);
-    let attr = cx.ident_of("attr", span);
-    let bang = cx.ident_of("bang", span);
+    let bridge = Ident::new(sym::bridge, span);
+    let client = Ident::new(sym::client, span);
+    let proc_macro_ty = Ident::new(sym::ProcMacro, span);
+    let custom_derive = Ident::new(sym::custom_derive, span);
+    let attr = Ident::new(sym::attr, span);
+    let bang = Ident::new(sym::bang, span);
 
     let krate_ref = RefCell::new(ast_krate);
 
@@ -447,7 +447,7 @@ fn mk_decls(
     let decls_static = cx
         .item_static(
             span,
-            cx.ident_of("_DECLS", span),
+            Ident::new(sym::_DECLS, span),
             cx.ty_rptr(
                 span,
                 cx.ty(
diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs
index d62f34bab1a..460f947a792 100644
--- a/src/librustc_builtin_macros/test.rs
+++ b/src/librustc_builtin_macros/test.rs
@@ -108,22 +108,38 @@ pub fn expand_test_or_bench(
     let test_id = Ident::new(sym::test, attr_sp);
 
     // creates test::$name
-    let test_path = |name| cx.path(sp, vec![test_id, cx.ident_of(name, sp)]);
+    let test_path = |name| cx.path(sp, vec![test_id, Ident::from_str_and_span(name, sp)]);
 
     // creates test::ShouldPanic::$name
-    let should_panic_path =
-        |name| cx.path(sp, vec![test_id, cx.ident_of("ShouldPanic", sp), cx.ident_of(name, sp)]);
+    let should_panic_path = |name| {
+        cx.path(
+            sp,
+            vec![
+                test_id,
+                Ident::from_str_and_span("ShouldPanic", sp),
+                Ident::from_str_and_span(name, sp),
+            ],
+        )
+    };
 
     // creates test::TestType::$name
-    let test_type_path =
-        |name| cx.path(sp, vec![test_id, cx.ident_of("TestType", sp), cx.ident_of(name, sp)]);
+    let test_type_path = |name| {
+        cx.path(
+            sp,
+            vec![
+                test_id,
+                Ident::from_str_and_span("TestType", sp),
+                Ident::from_str_and_span(name, sp),
+            ],
+        )
+    };
 
     // creates $name: $expr
-    let field = |name, expr| cx.field_imm(sp, cx.ident_of(name, sp), expr);
+    let field = |name, expr| cx.field_imm(sp, Ident::from_str_and_span(name, sp), expr);
 
     let test_fn = if is_bench {
         // A simple ident for a lambda
-        let b = cx.ident_of("b", attr_sp);
+        let b = Ident::from_str_and_span("b", attr_sp);
 
         cx.expr_call(
             sp,
diff --git a/src/librustc_builtin_macros/test_harness.rs b/src/librustc_builtin_macros/test_harness.rs
index 98e42ebf46f..98c5c6936d7 100644
--- a/src/librustc_builtin_macros/test_harness.rs
+++ b/src/librustc_builtin_macros/test_harness.rs
@@ -270,7 +270,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
     let mut test_runner = cx
         .test_runner
         .clone()
-        .unwrap_or(ecx.path(sp, vec![test_id, ecx.ident_of(runner_name, sp)]));
+        .unwrap_or(ecx.path(sp, vec![test_id, Ident::from_str_and_span(runner_name, sp)]));
 
     test_runner.span = sp;
 
diff --git a/src/librustc_error_codes/error_codes/E0723.md b/src/librustc_error_codes/error_codes/E0723.md
index 394ee057b0b..95d47ab21cb 100644
--- a/src/librustc_error_codes/error_codes/E0723.md
+++ b/src/librustc_error_codes/error_codes/E0723.md
@@ -1,4 +1,4 @@
-An feature unstable in `const` contexts was used.
+An unstable feature in `const` contexts was used.
 
 Erroneous code example:
 
diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs
index 3e48224ef9f..64e2d5b3a46 100644
--- a/src/librustc_expand/base.rs
+++ b/src/librustc_expand/base.rs
@@ -1061,9 +1061,6 @@ impl<'a> ExtCtxt<'a> {
     pub fn set_trace_macros(&mut self, x: bool) {
         self.ecfg.trace_mac = x
     }
-    pub fn ident_of(&self, st: &str, sp: Span) -> Ident {
-        Ident::from_str_and_span(st, sp)
-    }
     pub fn std_path(&self, components: &[Symbol]) -> Vec<Ident> {
         let def_site = self.with_def_site_ctxt(DUMMY_SP);
         iter::once(Ident::new(kw::DollarCrate, def_site))
diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs
index 20d2ea0a215..81ff4b31578 100644
--- a/src/librustc_expand/build.rs
+++ b/src/librustc_expand/build.rs
@@ -368,7 +368,7 @@ impl<'a> ExtCtxt<'a> {
         let err = self.std_path(&[sym::result, sym::Result, sym::Err]);
         let err_path = self.path_global(sp, err);
 
-        let binding_variable = self.ident_of("__try_var", sp);
+        let binding_variable = Ident::new(sym::__try_var, sp);
         let binding_pat = self.pat_ident(sp, binding_variable);
         let binding_expr = self.expr_ident(sp, binding_variable);
 
diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs
index 560a8421c17..b311f8344bb 100644
--- a/src/librustc_middle/mir/query.rs
+++ b/src/librustc_middle/mir/query.rs
@@ -8,7 +8,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::bit_set::BitMatrix;
 use rustc_index::vec::IndexVec;
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
 use smallvec::SmallVec;
 use std::cell::Cell;
@@ -18,7 +18,7 @@ use super::{Field, SourceInfo};
 
 #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
 pub enum UnsafetyViolationKind {
-    /// Only permitted in regular `fn`s, prohibitted in `const fn`s.
+    /// Only permitted in regular `fn`s, prohibited in `const fn`s.
     General,
     /// Permitted both in `const fn`s and regular `fn`s.
     GeneralAndConstFn,
@@ -36,12 +36,96 @@ pub enum UnsafetyViolationKind {
 }
 
 #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
+pub enum UnsafetyViolationDetails {
+    CallToUnsafeFunction,
+    UseOfInlineAssembly,
+    InitializingTypeWith,
+    CastOfPointerToInt,
+    BorrowOfPackedField,
+    UseOfMutableStatic,
+    UseOfExternStatic,
+    DerefOfRawPointer,
+    AssignToNonCopyUnionField,
+    AccessToUnionField,
+    MutationOfLayoutConstrainedField,
+    BorrowOfLayoutConstrainedField,
+    CallToFunctionWith,
+}
+
+impl UnsafetyViolationDetails {
+    pub fn description_and_note(&self) -> (&'static str, &'static str) {
+        use UnsafetyViolationDetails::*;
+        match self {
+            CallToUnsafeFunction => (
+                "call to unsafe function",
+                "consult the function's documentation for information on how to avoid undefined \
+                 behavior",
+            ),
+            UseOfInlineAssembly => (
+                "use of inline assembly",
+                "inline assembly is entirely unchecked and can cause undefined behavior",
+            ),
+            InitializingTypeWith => (
+                "initializing type with `rustc_layout_scalar_valid_range` attr",
+                "initializing a layout restricted type's field with a value outside the valid \
+                 range is undefined behavior",
+            ),
+            CastOfPointerToInt => {
+                ("cast of pointer to int", "casting pointers to integers in constants")
+            }
+            BorrowOfPackedField => (
+                "borrow of packed field",
+                "fields of packed structs might be misaligned: dereferencing a misaligned pointer \
+                 or even just creating a misaligned reference is undefined behavior",
+            ),
+            UseOfMutableStatic => (
+                "use of mutable static",
+                "mutable statics can be mutated by multiple threads: aliasing violations or data \
+                 races will cause undefined behavior",
+            ),
+            UseOfExternStatic => (
+                "use of extern static",
+                "extern statics are not controlled by the Rust type system: invalid data, \
+                 aliasing violations or data races will cause undefined behavior",
+            ),
+            DerefOfRawPointer => (
+                "dereference of raw pointer",
+                "raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules \
+                 and cause data races: all of these are undefined behavior",
+            ),
+            AssignToNonCopyUnionField => (
+                "assignment to non-`Copy` union field",
+                "the previous content of the field will be dropped, which causes undefined \
+                 behavior if the field was not properly initialized",
+            ),
+            AccessToUnionField => (
+                "access to union field",
+                "the field may not be properly initialized: using uninitialized data will cause \
+                 undefined behavior",
+            ),
+            MutationOfLayoutConstrainedField => (
+                "mutation of layout constrained field",
+                "mutating layout constrained fields cannot statically be checked for valid values",
+            ),
+            BorrowOfLayoutConstrainedField => (
+                "borrow of layout constrained field with interior mutability",
+                "references to fields of layout constrained fields lose the constraints. Coupled \
+                 with interior mutability, the field can be changed to invalid values",
+            ),
+            CallToFunctionWith => (
+                "call to function with `#[target_feature]`",
+                "can only be called if the required target features are available",
+            ),
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
 pub struct UnsafetyViolation {
     pub source_info: SourceInfo,
     pub lint_root: hir::HirId,
-    pub description: Symbol,
-    pub details: Symbol,
     pub kind: UnsafetyViolationKind,
+    pub details: UnsafetyViolationDetails,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs
index b50d2852c1c..043d85cb6ef 100644
--- a/src/librustc_middle/ty/print/pretty.rs
+++ b/src/librustc_middle/ty/print/pretty.rs
@@ -1440,12 +1440,12 @@ impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> {
 
         // FIXME(eddyb) `name` should never be empty, but it
         // currently is for `extern { ... }` "foreign modules".
-        let name = disambiguated_data.data.as_symbol().as_str();
-        if !name.is_empty() {
+        let name = disambiguated_data.data.as_symbol();
+        if name != kw::Invalid {
             if !self.empty_path {
                 write!(self, "::")?;
             }
-            if Ident::from_str(&name).is_raw_guess() {
+            if Ident::with_dummy_span(name).is_raw_guess() {
                 write!(self, "r#")?;
             }
             write!(self, "{}", name)?;
diff --git a/src/librustc_middle/ty/query/profiling_support.rs b/src/librustc_middle/ty/query/profiling_support.rs
index 3c446624418..0683dc02011 100644
--- a/src/librustc_middle/ty/query/profiling_support.rs
+++ b/src/librustc_middle/ty/query/profiling_support.rs
@@ -60,12 +60,12 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> {
 
         match def_key.disambiguated_data.data {
             DefPathData::CrateRoot => {
-                name = self.tcx.original_crate_name(def_id.krate).as_str();
+                name = self.tcx.original_crate_name(def_id.krate);
                 dis = "";
                 end_index = 3;
             }
             other => {
-                name = other.as_symbol().as_str();
+                name = other.as_symbol();
                 if def_key.disambiguated_data.disambiguator == 0 {
                     dis = "";
                     end_index = 3;
@@ -79,10 +79,11 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> {
             }
         }
 
+        let name = &*name.as_str();
         let components = [
             StringComponent::Ref(parent_string_id),
             StringComponent::Value("::"),
-            StringComponent::Value(&name[..]),
+            StringComponent::Value(name),
             StringComponent::Value(dis),
         ];
 
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 2605d45f810..81d7ac08926 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -12,7 +12,7 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
 use rustc_session::lint::Level;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::sym;
 
 use std::ops::Bound;
 
@@ -86,10 +86,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                 let sig = func_ty.fn_sig(self.tcx);
                 if let hir::Unsafety::Unsafe = sig.unsafety() {
                     self.require_unsafe(
-                        "call to unsafe function",
-                        "consult the function's documentation for information on how to avoid \
-                         undefined behavior",
                         UnsafetyViolationKind::GeneralAndConstFn,
+                        UnsafetyViolationDetails::CallToUnsafeFunction,
                     )
                 }
 
@@ -99,9 +97,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             }
 
             TerminatorKind::InlineAsm { .. } => self.require_unsafe(
-                "use of inline assembly",
-                "inline assembly is entirely unchecked and can cause undefined behavior",
                 UnsafetyViolationKind::General,
+                UnsafetyViolationDetails::UseOfInlineAssembly,
             ),
         }
         self.super_terminator(terminator, location);
@@ -122,9 +119,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             }
 
             StatementKind::LlvmInlineAsm { .. } => self.require_unsafe(
-                "use of inline assembly",
-                "inline assembly is entirely unchecked and can cause undefined behavior",
                 UnsafetyViolationKind::General,
+                UnsafetyViolationDetails::UseOfInlineAssembly,
             ),
         }
         self.super_statement(statement, location);
@@ -138,10 +134,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                     match self.tcx.layout_scalar_valid_range(def.did) {
                         (Bound::Unbounded, Bound::Unbounded) => {}
                         _ => self.require_unsafe(
-                            "initializing type with `rustc_layout_scalar_valid_range` attr",
-                            "initializing a layout restricted type's field with a value \
-                                outside the valid range is undefined behavior",
                             UnsafetyViolationKind::GeneralAndConstFn,
+                            UnsafetyViolationDetails::InitializingTypeWith,
                         ),
                     }
                 }
@@ -163,9 +157,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                 match (cast_in, cast_out) {
                     (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
                         self.require_unsafe(
-                            "cast of pointer to int",
-                            "casting pointers to integers in constants",
                             UnsafetyViolationKind::General,
+                            UnsafetyViolationDetails::CastOfPointerToInt,
                         );
                     }
                     _ => {}
@@ -190,11 +183,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
         if context.is_borrow() {
             if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
                 self.require_unsafe(
-                    "borrow of packed field",
-                    "fields of packed structs might be misaligned: dereferencing a \
-                    misaligned pointer or even just creating a misaligned reference \
-                    is undefined behavior",
                     UnsafetyViolationKind::BorrowPacked,
+                    UnsafetyViolationDetails::BorrowOfPackedField,
                 );
             }
         }
@@ -204,11 +194,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             if context.is_borrow() {
                 if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
                     self.require_unsafe(
-                        "borrow of packed field",
-                        "fields of packed structs might be misaligned: dereferencing a \
-                        misaligned pointer or even just creating a misaligned reference \
-                        is undefined behavior",
                         UnsafetyViolationKind::BorrowPacked,
+                        UnsafetyViolationDetails::BorrowOfPackedField,
                     );
                 }
             }
@@ -219,19 +206,14 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                     if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
                         if self.tcx.is_mutable_static(def_id) {
                             self.require_unsafe(
-                                "use of mutable static",
-                                "mutable statics can be mutated by multiple threads: aliasing \
-                            violations or data races will cause undefined behavior",
                                 UnsafetyViolationKind::General,
+                                UnsafetyViolationDetails::UseOfMutableStatic,
                             );
                             return;
                         } else if self.tcx.is_foreign_item(def_id) {
                             self.require_unsafe(
-                                "use of extern static",
-                                "extern statics are not controlled by the Rust type system: \
-                            invalid data, aliasing violations or data races will cause \
-                            undefined behavior",
                                 UnsafetyViolationKind::General,
+                                UnsafetyViolationDetails::UseOfExternStatic,
                             );
                             return;
                         }
@@ -246,11 +228,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
             match base_ty.kind {
                 ty::RawPtr(..) => self.require_unsafe(
-                    "dereference of raw pointer",
-                    "raw pointers may be NULL, dangling or unaligned; they can violate \
-                         aliasing rules and cause data races: all of these are undefined \
-                         behavior",
                     UnsafetyViolationKind::General,
+                    UnsafetyViolationDetails::DerefOfRawPointer,
                 ),
                 ty::Adt(adt, _) => {
                     if adt.is_union() {
@@ -271,21 +250,16 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                                 self.param_env,
                             ) {
                                 self.require_unsafe(
-                                    "assignment to non-`Copy` union field",
-                                    "the previous content of the field will be dropped, which \
-                                     causes undefined behavior if the field was not properly \
-                                     initialized",
                                     UnsafetyViolationKind::GeneralAndConstFn,
+                                    UnsafetyViolationDetails::AssignToNonCopyUnionField,
                                 )
                             } else {
                                 // write to non-move union, safe
                             }
                         } else {
                             self.require_unsafe(
-                                "access to union field",
-                                "the field may not be properly initialized: using \
-                                 uninitialized data will cause undefined behavior",
                                 UnsafetyViolationKind::GeneralAndConstFn,
+                                UnsafetyViolationDetails::AccessToUnionField,
                             )
                         }
                     }
@@ -298,12 +272,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
-    fn require_unsafe(
-        &mut self,
-        description: &'static str,
-        details: &'static str,
-        kind: UnsafetyViolationKind,
-    ) {
+    fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) {
         let source_info = self.source_info;
         let lint_root = self.body.source_scopes[self.source_info.scope]
             .local_data
@@ -311,13 +280,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
             .assert_crate_local()
             .lint_root;
         self.register_violations(
-            &[UnsafetyViolation {
-                source_info,
-                lint_root,
-                description: Symbol::intern(description),
-                details: Symbol::intern(details),
-                kind,
-            }],
+            &[UnsafetyViolation { source_info, lint_root, kind, details }],
             &[],
         );
     }
@@ -434,12 +397,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                         if self.tcx.layout_scalar_valid_range(def.did)
                             != (Bound::Unbounded, Bound::Unbounded)
                         {
-                            let (description, details) = if is_mut_use {
-                                (
-                                    "mutation of layout constrained field",
-                                    "mutating layout constrained fields cannot statically be \
-                                        checked for valid values",
-                                )
+                            let details = if is_mut_use {
+                                UnsafetyViolationDetails::MutationOfLayoutConstrainedField
 
                             // Check `is_freeze` as late as possible to avoid cycle errors
                             // with opaque types.
@@ -448,21 +407,11 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                                 .ty
                                 .is_freeze(self.tcx.at(self.source_info.span), self.param_env)
                             {
-                                (
-                                    "borrow of layout constrained field with interior \
-                                        mutability",
-                                    "references to fields of layout constrained fields \
-                                        lose the constraints. Coupled with interior mutability, \
-                                        the field can be changed to invalid values",
-                                )
+                                UnsafetyViolationDetails::BorrowOfLayoutConstrainedField
                             } else {
                                 continue;
                             };
-                            self.require_unsafe(
-                                description,
-                                details,
-                                UnsafetyViolationKind::GeneralAndConstFn,
-                            );
+                            self.require_unsafe(UnsafetyViolationKind::GeneralAndConstFn, details);
                         }
                     }
                 }
@@ -480,9 +429,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
         // Is `callee_features` a subset of `calling_features`?
         if !callee_features.iter().all(|feature| self_features.contains(feature)) {
             self.require_unsafe(
-                "call to function with `#[target_feature]`",
-                "can only be called if the required target features are available",
                 UnsafetyViolationKind::GeneralAndConstFn,
+                UnsafetyViolationDetails::CallToFunctionWith,
             )
         }
     }
@@ -675,9 +623,9 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 
     let UnsafetyCheckResult { violations, unsafe_blocks } = tcx.unsafety_check_result(def_id);
 
-    for &UnsafetyViolation { source_info, lint_root, description, details, kind } in
-        violations.iter()
-    {
+    for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
+        let (description, note) = details.description_and_note();
+
         // Report an error.
         let unsafe_fn_msg =
             if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" };
@@ -693,8 +641,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                     description,
                     unsafe_fn_msg,
                 )
-                .span_label(source_info.span, &*description.as_str())
-                .note(&details.as_str())
+                .span_label(source_info.span, description)
+                .note(note)
                 .emit();
             }
             UnsafetyViolationKind::BorrowPacked => {
@@ -712,7 +660,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                                 "{} is unsafe and requires unsafe{} block (error E0133)",
                                 description, unsafe_fn_msg,
                             ))
-                            .note(&details.as_str())
+                            .note(note)
                             .emit()
                         },
                     )
@@ -727,8 +675,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                         "{} is unsafe and requires unsafe block (error E0133)",
                         description,
                     ))
-                    .span_label(source_info.span, &*description.as_str())
-                    .note(&details.as_str())
+                    .span_label(source_info.span, description)
+                    .note(note)
                     .emit();
                 },
             ),
@@ -756,8 +704,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                         "{} is unsafe and requires unsafe block (error E0133)",
                         description,
                     ))
-                    .span_label(source_info.span, &*description.as_str())
-                    .note(&details.as_str())
+                    .span_label(source_info.span, description)
+                    .note(note)
                     .emit();
                 })
             }
diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs
index 76bc6b6c85f..5d972c70d13 100644
--- a/src/librustc_passes/stability.rs
+++ b/src/librustc_passes/stability.rs
@@ -502,7 +502,8 @@ impl Visitor<'tcx> for Checker<'tcx> {
         match item.kind {
             hir::ItemKind::ExternCrate(_) => {
                 // compiler-generated `extern crate` items have a dummy span.
-                if item.span.is_dummy() {
+                // `std` is still checked for the `restricted-std` feature.
+                if item.span.is_dummy() && item.ident.as_str() != "std" {
                     return;
                 }
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 8db27babd05..45253fc8782 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -111,12 +111,17 @@ impl<'a> Resolver<'a> {
             (self.cstore().crate_name_untracked(def_id.krate), None)
         } else {
             let def_key = self.cstore().def_key(def_id);
-            (
-                // This unwrap is safe: crates must always have a name
-                def_key.disambiguated_data.data.get_opt_name().unwrap(),
-                // This unwrap is safe since we know this isn't the root
-                Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id })),
-            )
+            let name = def_key
+                .disambiguated_data
+                .data
+                .get_opt_name()
+                .expect("given a DefId that wasn't a module");
+            // This unwrap is safe since we know this isn't the root
+            let parent = Some(self.get_module(DefId {
+                index: def_key.parent.expect("failed to get parent for module"),
+                ..def_id
+            }));
+            (name, parent)
         };
 
         // Allocate and return a new module with the information we found
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index c3686ca4899..686385e24ec 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -2978,7 +2978,7 @@ impl<'a> Resolver<'a> {
         span: Span,
         path_str: &str,
         ns: Namespace,
-        module_id: LocalDefId,
+        module_id: DefId,
     ) -> Result<(ast::Path, Res), ()> {
         let path = if path_str.starts_with("::") {
             ast::Path {
@@ -2998,7 +2998,7 @@ impl<'a> Resolver<'a> {
                     .collect(),
             }
         };
-        let module = self.module_map.get(&module_id).copied().unwrap_or(self.graph_root);
+        let module = self.get_module(module_id);
         let parent_scope = &ParentScope::module(module);
         let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?;
         Ok((path, res))
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index ccb6ccb57fa..5d332ddf5f3 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -122,19 +122,28 @@ symbols! {
     // There is currently no checking that all symbols are used; that would be
     // nice to have.
     Symbols {
+        Alignment,
         Arc,
+        Argument,
         ArgumentV1,
         Arguments,
         C,
+        Center,
         Clone,
         Copy,
+        Count,
         Debug,
         Decodable,
+        Decoder,
         Default,
         Encodable,
+        Encoder,
         Eq,
         Equal,
         Err,
+        Error,
+        FormatSpec,
+        Formatter,
         From,
         Future,
         FxHashMap,
@@ -143,11 +152,15 @@ symbols! {
         Hash,
         HashMap,
         HashSet,
+        Hasher,
+        Implied,
         Input,
         IntoIterator,
+        Is,
         ItemContext,
         Iterator,
         Layout,
+        Left,
         LintPass,
         None,
         Ok,
@@ -155,11 +168,13 @@ symbols! {
         Ord,
         Ordering,
         Output,
+        Param,
         PartialEq,
         PartialOrd,
         Pending,
         Pin,
         Poll,
+        ProcMacro,
         ProcMacroHack,
         ProceduralMasqueradeDummyType,
         Range,
@@ -172,20 +187,31 @@ symbols! {
         Ready,
         Result,
         Return,
+        Right,
         RustcDecodable,
         RustcEncodable,
         Send,
         Some,
+        StructuralEq,
+        StructuralPartialEq,
         Sync,
         Target,
         Try,
         Ty,
         TyCtxt,
         TyKind,
+        Unknown,
         Vec,
         Yield,
+        _DECLS,
         _Self,
+        __D,
+        __H,
+        __S,
         __next,
+        __try_var,
+        _d,
+        _e,
         _task_context,
         aarch64_target_feature,
         abi,
@@ -226,6 +252,7 @@ symbols! {
         allowed,
         always,
         and,
+        and_then,
         any,
         arbitrary_enum_discriminant,
         arbitrary_self_types,
@@ -256,6 +283,7 @@ symbols! {
         automatically_derived,
         avx512_target_feature,
         await_macro,
+        bang,
         begin_panic,
         bench,
         bin,
@@ -278,6 +306,7 @@ symbols! {
         box_syntax,
         braced_empty_structs,
         breakpoint,
+        bridge,
         bswap,
         c_variadic,
         call,
@@ -299,6 +328,7 @@ symbols! {
         cfg_target_vendor,
         cfg_version,
         char,
+        client,
         clippy,
         clone,
         clone_closures,
@@ -370,11 +400,15 @@ symbols! {
         custom_derive,
         custom_inner_attributes,
         custom_test_frameworks,
+        d,
         dead_code,
         dealloc,
         debug,
         debug_assertions,
+        debug_struct,
         debug_trait,
+        debug_trait_builder,
+        debug_tuple,
         decl_macro,
         declare_lint_pass,
         decode,
@@ -421,6 +455,11 @@ symbols! {
         dyn_trait,
         eh_catch_typeinfo,
         eh_personality,
+        emit_enum,
+        emit_enum_variant,
+        emit_enum_variant_arg,
+        emit_struct,
+        emit_struct_field,
         enable,
         enclosing_scope,
         encode,
@@ -448,6 +487,7 @@ symbols! {
         extern_prelude,
         extern_types,
         external_doc,
+        f,
         f16c_target_feature,
         f32,
         f32_runtime,
@@ -464,6 +504,9 @@ symbols! {
         field,
         field_init_shorthand,
         file,
+        fill,
+        finish,
+        flags,
         float_to_int_unchecked,
         floorf32,
         floorf64,
@@ -478,6 +521,7 @@ symbols! {
         fn_once_output,
         forbid,
         forget,
+        format,
         format_args,
         format_args_capture,
         format_args_nl,
@@ -519,6 +563,7 @@ symbols! {
         html_no_source,
         html_playground_url,
         html_root_url,
+        i,
         i128,
         i128_type,
         i16,
@@ -606,6 +651,7 @@ symbols! {
         main,
         managed_boxes,
         manually_drop,
+        map,
         marker,
         marker_trait_attr,
         masked,
@@ -708,6 +754,7 @@ symbols! {
         options,
         or,
         or_patterns,
+        other,
         out,
         overlapping_marker_traits,
         owned_box,
@@ -739,6 +786,7 @@ symbols! {
         plugins,
         pointer,
         poll,
+        position,
         post_dash_lto: "post-lto",
         powerpc_target_feature,
         powf32,
@@ -747,6 +795,7 @@ symbols! {
         powif64,
         pre_dash_lto: "pre-lto",
         precise_pointer_size_matching,
+        precision,
         pref_align_of,
         prefetch_read_data,
         prefetch_read_instruction,
@@ -783,6 +832,11 @@ symbols! {
         raw_identifiers,
         raw_ref_op,
         re_rebalance_coherence,
+        read_enum,
+        read_enum_variant,
+        read_enum_variant_arg,
+        read_struct,
+        read_struct_field,
         readonly,
         realloc,
         reason,
@@ -872,6 +926,7 @@ symbols! {
         rustc_promotable,
         rustc_regions,
         rustc_reservation_impl,
+        rustc_serialize,
         rustc_specialization_trait,
         rustc_stable,
         rustc_std_internal_symbol,
@@ -976,6 +1031,7 @@ symbols! {
         stable,
         staged_api,
         start,
+        state,
         static_in_const,
         static_nobundle,
         static_recursion,
@@ -1123,6 +1179,7 @@ symbols! {
         wasm_import_module,
         wasm_target_feature,
         while_let,
+        width,
         windows,
         windows_subsystem,
         wrapping_add,
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index 79d5c148ce4..a9b045cee60 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -26,7 +26,7 @@ use rustc_middle::ty::{
     TypeFoldable, WithConstness,
 };
 use rustc_session::DiagnosticMessageId;
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{kw, sym};
 use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
 use std::fmt;
 
@@ -1524,7 +1524,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                     (self.tcx.sess.source_map().span_to_snippet(span), &obligation.cause.code)
                 {
                     let generics = self.tcx.generics_of(*def_id);
-                    if generics.params.iter().any(|p| p.name.as_str() != "Self")
+                    if generics.params.iter().any(|p| p.name != kw::SelfUpper)
                         && !snippet.ends_with('>')
                     {
                         // FIXME: To avoid spurious suggestions in functions where type arguments
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 9a9630f0958..f575548ddd6 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -322,12 +322,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let self_ty = self.tables.borrow().node_type(method_expr[0].hir_id);
         let self_ty = format!("{:?}", self_ty);
-        let name = method_path.ident.as_str();
+        let name = method_path.ident.name;
         let is_as_ref_able = (self_ty.starts_with("&std::option::Option")
             || self_ty.starts_with("&std::result::Result")
             || self_ty.starts_with("std::option::Option")
             || self_ty.starts_with("std::result::Result"))
-            && (name == "map" || name == "and_then");
+            && (name == sym::map || name == sym::and_then);
         match (is_as_ref_able, self.sess().source_map().span_to_snippet(*method_span)) {
             (true, Ok(src)) => {
                 let suggestion = format!("as_ref().{}", src);
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 00315675faf..6a52974534f 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -430,7 +430,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
                                 DUMMY_SP,
                                 extern_name,
                                 TypeNS,
-                                LocalDefId { local_def_index: CRATE_DEF_INDEX },
+                                LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(),
                             )
                             .unwrap_or_else(|()| {
                                 panic!("Unable to resolve external crate {}", extern_name)
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 31e35125dac..f872ed7010c 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2230,12 +2230,15 @@ fn stability_tags(item: &clean::Item) -> String {
         tags += &tag_html("deprecated", message);
     }
 
-    if let Some(stab) = item.stability.as_ref().filter(|s| s.level == stability::Unstable) {
-        if stab.feature.as_deref() == Some("rustc_private") {
-            tags += &tag_html("internal", "Internal");
-        } else {
-            tags += &tag_html("unstable", "Experimental");
-        }
+    // The "rustc_private" crates are permanently unstable so it makes no sense
+    // to render "unstable" everywhere.
+    if item
+        .stability
+        .as_ref()
+        .map(|s| s.level == stability::Unstable && s.feature.as_deref() != Some("rustc_private"))
+        == Some(true)
+    {
+        tags += &tag_html("unstable", "Experimental");
     }
 
     if let Some(ref cfg) = item.attrs.cfg {
@@ -2286,15 +2289,13 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
         ));
     }
 
-    if let Some(stab) = item.stability.as_ref().filter(|stab| stab.level == stability::Unstable) {
-        let is_rustc_private = stab.feature.as_deref() == Some("rustc_private");
-
-        let mut message = if is_rustc_private {
-            "<span class='emoji'>⚙️</span> This is an internal compiler API."
-        } else {
-            "<span class='emoji'>🔬</span> This is a nightly-only experimental API."
-        }
-        .to_owned();
+    // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
+    // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
+    if let Some(stab) = item.stability.as_ref().filter(|stab| {
+        stab.level == stability::Unstable && stab.feature.as_deref() != Some("rustc_private")
+    }) {
+        let mut message =
+            "<span class='emoji'>🔬</span> This is a nightly-only experimental API.".to_owned();
 
         if let Some(feature) = stab.feature.as_deref() {
             let mut feature = format!("<code>{}</code>", Escape(&feature));
@@ -2310,17 +2311,6 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
         }
 
         if let Some(unstable_reason) = &stab.unstable_reason {
-            // Provide a more informative message than the compiler help.
-            let unstable_reason = if is_rustc_private {
-                "This crate is being loaded from the sysroot, a permanently unstable location \
-                for private compiler dependencies. It is not intended for general use. Prefer \
-                using a public version of this crate from \
-                [crates.io](https://crates.io) via [`Cargo.toml`]\
-                (https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html)."
-            } else {
-                unstable_reason
-            };
-
             let mut ids = cx.id_map.borrow_mut();
             message = format!(
                 "<details><summary>{}</summary>{}</details>",
@@ -2336,8 +2326,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
             );
         }
 
-        let class = if is_rustc_private { "internal" } else { "unstable" };
-        stability.push(format!("<div class='stab {}'>{}</div>", class, message));
+        stability.push(format!("<div class='stab unstable'>{}</div>", message));
     }
 
     if let Some(ref cfg) = item.attrs.cfg {
diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css
index b436997da58..1326acec51c 100644
--- a/src/librustdoc/html/static/themes/ayu.css
+++ b/src/librustdoc/html/static/themes/ayu.css
@@ -108,7 +108,7 @@ pre {
 }
 
 .sidebar .version {
-	border-bottom-color: #DDD;
+	border-bottom-color: #424c57;
 }
 
 .sidebar-title {
@@ -198,7 +198,7 @@ pre.rust .comment, pre.rust .doccomment {
 }
 
 nav:not(.sidebar) {
-	border-bottom-color: #e0e0e0;
+	border-bottom-color: #424c57;
 }
 nav.main .current {
 	border-top-color: #5c6773;
@@ -216,10 +216,6 @@ a {
 	color: #39AFD7;
 }
 
-.stab.internal a {
-	color: #304FFE;
-}
-
 .collapse-toggle {
 	color: #999;
 }
@@ -227,22 +223,19 @@ a {
 #crate-search {
 	color: #c5c5c5;
 	background-color: #141920;
-	border-radius: 4px;
-	box-shadow: none;
-	border-color: #5c6773;
+	box-shadow: 0 0 0 1px #424c57,0 0 0 2px transparent;
+	border-color: #424c57;
 }
 
 .search-input {
     color: #ffffff;
     background-color: #141920;
-    box-shadow: none;
+    box-shadow: 0 0 0 1px #424c57,0 0 0 2px transparent;
     transition: box-shadow 150ms ease-in-out;
-    border-radius: 4px;
-    margin-left: 8px;
 }
 
 #crate-search+.search-input:focus {
-    box-shadow: 0px 6px 20px 0px black;
+    box-shadow: 0 0 0 1px #148099,0 0 0 2px transparent;
 }
 
 .search-focus:disabled {
@@ -254,7 +247,6 @@ a {
 }
 
 .stab.unstable,
-.stab.internal,
 .stab.deprecated,
 .stab.portability {
     color: #c5c5c5;
@@ -462,7 +454,6 @@ pre.rust .doccomment {}
 .content .highlighted.type {}
 pre.rust .kw-2,pre.rust .prelude-ty {}
 .content span.trait,.content a.trait,.block a.current.trait {}
-.stab.internal {}
 
 @media (max-width: 700px) {
 	.sidebar-menu {
diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css
index f4ca67f8540..dc15220aa06 100644
--- a/src/librustdoc/html/static/themes/dark.css
+++ b/src/librustdoc/html/static/themes/dark.css
@@ -172,10 +172,6 @@ a {
 	color: #D2991D;
 }
 
-.stab.internal a {
-	color: #304FFE;
-}
-
 a.test-arrow {
 	color: #dedede;
 }
@@ -214,7 +210,6 @@ a.test-arrow {
 }
 
 .stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
-.stab.internal { background: #FFB9B3; border-color: #B71C1C; color: #2f2f2f; }
 .stab.deprecated { background: #F3DFFF; border-color: #7F0087; color: #2f2f2f; }
 .stab.portability { background: #C4ECFF; border-color: #7BA5DB; color: #2f2f2f; }
 
diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css
index b5a0ba4775c..64d59ca411a 100644
--- a/src/librustdoc/html/static/themes/light.css
+++ b/src/librustdoc/html/static/themes/light.css
@@ -173,10 +173,6 @@ a {
 	color: #3873AD;
 }
 
-.stab.internal a {
-	color: #304FFE;
-}
-
 a.test-arrow {
 	color: #f5f5f5;
 }
@@ -215,7 +211,6 @@ a.test-arrow {
 }
 
 .stab.unstable { background: #FFF5D6; border-color: #FFC600; }
-.stab.internal { background: #FFB9B3; border-color: #B71C1C; }
 .stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
 .stab.portability { background: #C4ECFF; border-color: #7BA5DB; }
 
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index f707c1a3e1a..b1db1328392 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -8,7 +8,7 @@ use rustc_hir::def::{
     Namespace::{self, *},
     PerNS, Res,
 };
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty;
 use rustc_resolve::ParentScope;
 use rustc_session::lint;
@@ -50,7 +50,8 @@ enum ErrorKind {
 
 struct LinkCollector<'a, 'tcx> {
     cx: &'a DocContext<'tcx>,
-    mod_ids: Vec<hir::HirId>,
+    // NOTE: this may not necessarily be a module in the current crate
+    mod_ids: Vec<DefId>,
 }
 
 impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
@@ -62,7 +63,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         &self,
         path_str: &str,
         current_item: &Option<String>,
-        module_id: LocalDefId,
+        module_id: DefId,
     ) -> Result<(Res, Option<String>), ErrorKind> {
         let cx = self.cx;
 
@@ -124,7 +125,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     }
 
     /// Resolves a string as a macro.
-    fn macro_resolve(&self, path_str: &str, parent_id: Option<hir::HirId>) -> Option<Res> {
+    fn macro_resolve(&self, path_str: &str, parent_id: Option<DefId>) -> Option<Res> {
         let cx = self.cx;
         let path = ast::Path::from_ident(Ident::from_str(path_str));
         cx.enter_resolver(|resolver| {
@@ -142,8 +143,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
                 return Some(res.map_id(|_| panic!("unexpected id")));
             }
-            if let Some(module_id) = parent_id.or(self.mod_ids.last().cloned()) {
-                let module_id = cx.tcx.hir().local_def_id(module_id);
+            if let Some(module_id) = parent_id {
                 if let Ok((_, res)) =
                     resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id)
                 {
@@ -167,15 +167,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         disambiguator: Option<&str>,
         ns: Namespace,
         current_item: &Option<String>,
-        parent_id: Option<hir::HirId>,
+        parent_id: Option<DefId>,
         extra_fragment: &Option<String>,
         item_opt: Option<&Item>,
     ) -> Result<(Res, Option<String>), ErrorKind> {
         let cx = self.cx;
 
         // In case we're in a module, try to resolve the relative path.
-        if let Some(module_id) = parent_id.or(self.mod_ids.last().cloned()) {
-            let module_id = cx.tcx.hir().local_def_id(module_id);
+        if let Some(module_id) = parent_id {
             let result = cx.enter_resolver(|resolver| {
                 resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
             });
@@ -445,40 +444,40 @@ fn is_derive_trait_collision<T>(ns: &PerNS<Option<(Res, T)>>) -> bool {
 
 impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
     fn fold_item(&mut self, mut item: Item) -> Option<Item> {
-        let item_hir_id = if item.is_mod() {
-            if let Some(def_id) = item.def_id.as_local() {
-                Some(self.cx.tcx.hir().as_local_hir_id(def_id))
-            } else {
-                debug!("attempting to fold on a non-local item: {:?}", item);
-                return self.fold_item_recur(item);
-            }
-        } else {
-            None
-        };
+        use rustc_middle::ty::DefIdTree;
 
-        // FIXME: get the resolver to work with non-local resolve scopes.
-        let parent_node = self.cx.as_local_hir_id(item.def_id).and_then(|hir_id| {
-            // FIXME: this fails hard for impls in non-module scope, but is necessary for the
-            // current `resolve()` implementation.
-            match self.cx.as_local_hir_id(self.cx.tcx.parent_module(hir_id).to_def_id()).unwrap() {
-                id if id != hir_id => Some(id),
-                _ => None,
+        let parent_node = if item.is_fake() {
+            // FIXME: is this correct?
+            None
+        } else {
+            let mut current = item.def_id;
+            // The immediate parent might not always be a module.
+            // Find the first parent which is.
+            loop {
+                if let Some(parent) = self.cx.tcx.parent(current) {
+                    if self.cx.tcx.def_kind(parent) == DefKind::Mod {
+                        break Some(parent);
+                    }
+                    current = parent;
+                } else {
+                    break None;
+                }
             }
-        });
+        };
 
         if parent_node.is_some() {
-            debug!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id);
+            trace!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id);
         }
 
         let current_item = match item.inner {
             ModuleItem(..) => {
                 if item.attrs.inner_docs {
-                    if item_hir_id.unwrap() != hir::CRATE_HIR_ID { item.name.clone() } else { None }
+                    if item.def_id.is_top_level_module() { item.name.clone() } else { None }
                 } else {
-                    match parent_node.or(self.mod_ids.last().cloned()) {
-                        Some(parent) if parent != hir::CRATE_HIR_ID => {
+                    match parent_node.or(self.mod_ids.last().copied()) {
+                        Some(parent) if !parent.is_top_level_module() => {
                             // FIXME: can we pull the parent module's name from elsewhere?
-                            Some(self.cx.tcx.hir().name(parent).to_string())
+                            Some(self.cx.tcx.item_name(parent).to_string())
                         }
                         _ => None,
                     }
@@ -488,18 +487,22 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                 for_.def_id().map(|did| self.cx.tcx.item_name(did).to_string())
             }
             // we don't display docs on `extern crate` items anyway, so don't process them.
-            ExternCrateItem(..) => return self.fold_item_recur(item),
+            ExternCrateItem(..) => {
+                debug!("ignoring extern crate item {:?}", item.def_id);
+                return self.fold_item_recur(item);
+            }
             ImportItem(Import::Simple(ref name, ..)) => Some(name.clone()),
             MacroItem(..) => None,
             _ => item.name.clone(),
         };
 
         if item.is_mod() && item.attrs.inner_docs {
-            self.mod_ids.push(item_hir_id.unwrap());
+            self.mod_ids.push(item.def_id);
         }
 
         let cx = self.cx;
         let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
+        trace!("got documentation '{}'", dox);
 
         look_for_tests(&cx, &dox, &item, true);
 
@@ -541,6 +544,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
         });
 
         for (ori_link, link_range) in markdown_links(&dox) {
+            trace!("considering link '{}'", ori_link);
+
             // Bail early for real links.
             if ori_link.contains('/') {
                 continue;
@@ -641,8 +646,11 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                 // we've already pushed this node onto the resolution stack but
                 // for outer comments we explicitly try and resolve against the
                 // parent_node first.
-                let base_node =
-                    if item.is_mod() && item.attrs.inner_docs { None } else { parent_node };
+                let base_node = if item.is_mod() && item.attrs.inner_docs {
+                    self.mod_ids.last().copied()
+                } else {
+                    parent_node
+                };
 
                 // replace `Self` with suitable item's parent name
                 if path_str.starts_with("Self::") {
@@ -826,7 +834,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
         }
 
         if item.is_mod() && !item.attrs.inner_docs {
-            self.mod_ids.push(item_hir_id.unwrap());
+            self.mod_ids.push(item.def_id);
         }
 
         if item.is_mod() {
@@ -864,6 +872,7 @@ fn build_diagnostic(
         Some(hir_id) => hir_id,
         None => {
             // If non-local, no need to check anything.
+            info!("ignoring warning from parent crate: {}", err_msg);
             return;
         }
     };
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 743a1778fbd..eb2753d6245 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -62,5 +62,29 @@ fn main() {
         }
         println!("cargo:rustc-link-lib=c");
         println!("cargo:rustc-link-lib=compiler_rt");
+    } else if (target.contains("sgx") && target.contains("fortanix"))
+        || target.contains("hermit")
+        || target.contains("l4re")
+        || target.contains("redox")
+        || target.contains("haiku")
+        || target.contains("vxworks")
+        || target.contains("wasm32")
+        || target.contains("asmjs")
+    {
+        // These platforms don't have any special requirements.
+    } else {
+        // This is for Cargo's build-std support, to mark std as unstable for
+        // typically no_std platforms.
+        // This covers:
+        // - os=none ("bare metal" targets)
+        // - mipsel-sony-psp
+        // - nvptx64-nvidia-cuda
+        // - avr-unknown-unknown
+        // - tvos (aarch64-apple-tvos, x86_64-apple-tvos)
+        // - uefi (x86_64-unknown-uefi, i686-unknown-uefi)
+        // - JSON targets
+        // - Any new targets that have not been explicitly added above.
+        println!("cargo:rustc-cfg=feature=\"restricted-std\"");
     }
+    println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap());
 }
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
index 97c20ca9459..6489e0709cb 100644
--- a/src/libstd/env.rs
+++ b/src/libstd/env.rs
@@ -882,7 +882,7 @@ pub mod consts {
     /// - s390x
     /// - sparc64
     #[stable(feature = "env", since = "1.0.0")]
-    pub const ARCH: &str = super::arch::ARCH;
+    pub const ARCH: &str = env!("STD_ENV_ARCH");
 
     /// The family of the operating system. Example value is `unix`.
     ///
@@ -966,81 +966,6 @@ pub mod consts {
     pub const EXE_EXTENSION: &str = os::EXE_EXTENSION;
 }
 
-#[cfg(target_arch = "x86")]
-mod arch {
-    pub const ARCH: &str = "x86";
-}
-
-#[cfg(target_arch = "x86_64")]
-mod arch {
-    pub const ARCH: &str = "x86_64";
-}
-
-#[cfg(target_arch = "arm")]
-mod arch {
-    pub const ARCH: &str = "arm";
-}
-
-#[cfg(target_arch = "aarch64")]
-mod arch {
-    pub const ARCH: &str = "aarch64";
-}
-
-#[cfg(target_arch = "mips")]
-mod arch {
-    pub const ARCH: &str = "mips";
-}
-
-#[cfg(target_arch = "mips64")]
-mod arch {
-    pub const ARCH: &str = "mips64";
-}
-
-#[cfg(target_arch = "powerpc")]
-mod arch {
-    pub const ARCH: &str = "powerpc";
-}
-
-#[cfg(target_arch = "powerpc64")]
-mod arch {
-    pub const ARCH: &str = "powerpc64";
-}
-
-#[cfg(target_arch = "s390x")]
-mod arch {
-    pub const ARCH: &str = "s390x";
-}
-
-#[cfg(target_arch = "sparc64")]
-mod arch {
-    pub const ARCH: &str = "sparc64";
-}
-
-#[cfg(target_arch = "le32")]
-mod arch {
-    pub const ARCH: &str = "le32";
-}
-
-#[cfg(target_arch = "asmjs")]
-mod arch {
-    pub const ARCH: &str = "asmjs";
-}
-
-#[cfg(target_arch = "wasm32")]
-mod arch {
-    pub const ARCH: &str = "wasm32";
-}
-
-#[cfg(target_arch = "hexagon")]
-mod arch {
-    pub const ARCH: &'static str = "hexagon";
-}
-
-#[cfg(target_arch = "riscv64")]
-mod arch {
-    pub const ARCH: &'static str = "riscv64";
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index cbc24009a94..b5ba0da7ae5 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -198,7 +198,8 @@
 //! [primitive types]: ../book/ch03-02-data-types.html
 //! [rust-discord]: https://discord.gg/rust-lang
 
-#![stable(feature = "rust1", since = "1.0.0")]
+#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
+#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
 #![doc(
     html_root_url = "https://doc.rust-lang.org/nightly/",
     html_playground_url = "https://play.rust-lang.org/",
@@ -554,3 +555,9 @@ include!("primitive_docs.rs");
 // the rustdoc documentation for the existing keywords. Using `include!`
 // because rustdoc only looks for these modules at the crate level.
 include!("keyword_docs.rs");
+
+// This is required to avoid an unstable error when `restricted-std` is not
+// enabled. The use of #![feature(restricted_std)] in rustc-std-workspace-std
+// is unconditional, so the unstable feature needs to be defined somewhere.
+#[cfg_attr(not(feature = "restricted-std"), unstable(feature = "restricted_std", issue = "none"))]
+mod __restricted_std_workaround {}
diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index 2250c0d4203..9b90bfd68b5 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -694,7 +694,6 @@ mod tests {
 
     #[test]
     #[cfg_attr(target_os = "emscripten", ignore)]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn wait_timeout_wait() {
         let m = Arc::new(Mutex::new(()));
         let c = Arc::new(Condvar::new());
@@ -714,7 +713,6 @@ mod tests {
 
     #[test]
     #[cfg_attr(target_os = "emscripten", ignore)]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn wait_timeout_while_wait() {
         let m = Arc::new(Mutex::new(()));
         let c = Arc::new(Condvar::new());
@@ -739,7 +737,6 @@ mod tests {
 
     #[test]
     #[cfg_attr(target_os = "emscripten", ignore)]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn wait_timeout_while_wake() {
         let pair = Arc::new((Mutex::new(false), Condvar::new()));
         let pair_copy = pair.clone();
@@ -763,7 +760,6 @@ mod tests {
 
     #[test]
     #[cfg_attr(target_os = "emscripten", ignore)]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn wait_timeout_wake() {
         let m = Arc::new(Mutex::new(()));
         let c = Arc::new(Condvar::new());
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
index d6cc811154f..3ff50e9f213 100644
--- a/src/libstd/sync/mpsc/mod.rs
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -2088,7 +2088,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn oneshot_single_thread_recv_timeout() {
         let (tx, rx) = channel();
         tx.send(()).unwrap();
@@ -2099,7 +2098,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn stress_recv_timeout_two_threads() {
         let (tx, rx) = channel();
         let stress = stress_factor() + 100;
@@ -2130,7 +2128,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn recv_timeout_upgrade() {
         let (tx, rx) = channel::<()>();
         let timeout = Duration::from_millis(1);
@@ -2142,7 +2139,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn stress_recv_timeout_shared() {
         let (tx, rx) = channel();
         let stress = stress_factor() + 100;
@@ -2173,7 +2169,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn very_long_recv_timeout_wont_panic() {
         let (tx, rx) = channel::<()>();
         let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX)));
@@ -2195,7 +2190,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn shared_recv_timeout() {
         let (tx, rx) = channel();
         let total = 5;
@@ -2425,7 +2419,6 @@ mod sync_tests {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn recv_timeout() {
         let (tx, rx) = sync_channel::<i32>(1);
         assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
@@ -2517,7 +2510,6 @@ mod sync_tests {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn stress_recv_timeout_two_threads() {
         let (tx, rx) = sync_channel::<i32>(0);
 
@@ -2543,7 +2535,6 @@ mod sync_tests {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn stress_recv_timeout_shared() {
         const AMT: u32 = 1000;
         const NTHREADS: u32 = 8;
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs
index 875ff1af920..7b5fac922d0 100644
--- a/src/libstd/sys/mod.rs
+++ b/src/libstd/sys/mod.rs
@@ -48,7 +48,8 @@ cfg_if::cfg_if! {
         mod sgx;
         pub use self::sgx::*;
     } else {
-        compile_error!("libstd doesn't compile for this platform yet");
+        mod unsupported;
+        pub use self::unsupported::*;
     }
 }
 
diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs
index ae803ee47a6..73f1b951e74 100644
--- a/src/libstd/sys/sgx/abi/usercalls/mod.rs
+++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs
@@ -1,6 +1,8 @@
 use crate::cmp;
-use crate::io::{Error as IoError, IoSlice, IoSliceMut, Result as IoResult};
-use crate::time::Duration;
+use crate::convert::TryFrom;
+use crate::io::{Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult};
+use crate::sys::rand::rdrand64;
+use crate::time::{Duration, Instant};
 
 pub(crate) mod alloc;
 #[macro_use]
@@ -149,10 +151,94 @@ pub fn exit(panic: bool) -> ! {
 
 /// Usercall `wait`. See the ABI documentation for more information.
 #[unstable(feature = "sgx_platform", issue = "56975")]
-pub fn wait(event_mask: u64, timeout: u64) -> IoResult<u64> {
+pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult<u64> {
+    if timeout != WAIT_NO && timeout != WAIT_INDEFINITE {
+        // We don't want people to rely on accuracy of timeouts to make
+        // security decisions in an SGX enclave. That's why we add a random
+        // amount not exceeding +/- 10% to the timeout value to discourage
+        // people from relying on accuracy of timeouts while providing a way
+        // to make things work in other cases. Note that in the SGX threat
+        // model the enclave runner which is serving the wait usercall is not
+        // trusted to ensure accurate timeouts.
+        if let Ok(timeout_signed) = i64::try_from(timeout) {
+            let tenth = timeout_signed / 10;
+            let deviation = (rdrand64() as i64).checked_rem(tenth).unwrap_or(0);
+            timeout = timeout_signed.saturating_add(deviation) as _;
+        }
+    }
     unsafe { raw::wait(event_mask, timeout).from_sgx_result() }
 }
 
+/// This function makes an effort to wait for a non-spurious event at least as
+/// long as `duration`. Note that in general there is no guarantee about accuracy
+/// of time and timeouts in SGX model. The enclave runner serving usercalls may
+/// lie about current time and/or ignore timeout values.
+///
+/// Once the event is observed, `should_wake_up` will be used to determine
+/// whether or not the event was spurious.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn wait_timeout<F>(event_mask: u64, duration: Duration, should_wake_up: F)
+where
+    F: Fn() -> bool,
+{
+    // Calls the wait usercall and checks the result. Returns true if event was
+    // returned, and false if WouldBlock/TimedOut was returned.
+    // If duration is None, it will use WAIT_NO.
+    fn wait_checked(event_mask: u64, duration: Option<Duration>) -> bool {
+        let timeout = duration.map_or(raw::WAIT_NO, |duration| {
+            cmp::min((u64::MAX - 1) as u128, duration.as_nanos()) as u64
+        });
+        match wait(event_mask, timeout) {
+            Ok(eventset) => {
+                if event_mask == 0 {
+                    rtabort!("expected wait() to return Err, found Ok.");
+                }
+                rtassert!(eventset != 0 && eventset & !event_mask == 0);
+                true
+            }
+            Err(e) => {
+                rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock);
+                false
+            }
+        }
+    }
+
+    match wait_checked(event_mask, Some(duration)) {
+        false => return,                    // timed out
+        true if should_wake_up() => return, // woken up
+        true => {}                          // spurious event
+    }
+
+    // Drain all cached events.
+    // Note that `event_mask != 0` is implied if we get here.
+    loop {
+        match wait_checked(event_mask, None) {
+            false => break,                     // no more cached events
+            true if should_wake_up() => return, // woken up
+            true => {}                          // spurious event
+        }
+    }
+
+    // Continue waiting, but take note of time spent waiting so we don't wait
+    // forever. We intentionally don't call `Instant::now()` before this point
+    // to avoid the cost of the `insecure_time` usercall in case there are no
+    // spurious wakeups.
+
+    let start = Instant::now();
+    let mut remaining = duration;
+    loop {
+        match wait_checked(event_mask, Some(remaining)) {
+            false => return,                    // timed out
+            true if should_wake_up() => return, // woken up
+            true => {}                          // spurious event
+        }
+        remaining = match duration.checked_sub(start.elapsed()) {
+            Some(remaining) => remaining,
+            None => break,
+        }
+    }
+}
+
 /// Usercall `send`. See the ABI documentation for more information.
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {
diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs
index 9c5c086184d..ed6dbcf4971 100644
--- a/src/libstd/sys/sgx/condvar.rs
+++ b/src/libstd/sys/sgx/condvar.rs
@@ -31,8 +31,10 @@ impl Condvar {
         mutex.lock()
     }
 
-    pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
-        rtabort!("timeout not supported in SGX");
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        let success = WaitQueue::wait_timeout(&self.inner, dur, || mutex.unlock());
+        mutex.lock();
+        success
     }
 
     #[inline]
diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs
index a4968ff7d4f..1d32eb25424 100644
--- a/src/libstd/sys/sgx/mod.rs
+++ b/src/libstd/sys/sgx/mod.rs
@@ -137,8 +137,8 @@ pub extern "C" fn __rust_abort() {
     abort_internal();
 }
 
-pub fn hashmap_random_keys() -> (u64, u64) {
-    fn rdrand64() -> u64 {
+pub mod rand {
+    pub fn rdrand64() -> u64 {
         unsafe {
             let mut ret: u64 = 0;
             for _ in 0..10 {
@@ -149,7 +149,10 @@ pub fn hashmap_random_keys() -> (u64, u64) {
             rtabort!("Failed to obtain random data");
         }
     }
-    (rdrand64(), rdrand64())
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    (self::rand::rdrand64(), self::rand::rdrand64())
 }
 
 pub use crate::sys_common::{AsInner, FromInner, IntoInner};
diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs
index 9b515eb82de..5895f70436e 100644
--- a/src/libstd/sys/sgx/thread.rs
+++ b/src/libstd/sys/sgx/thread.rs
@@ -73,8 +73,8 @@ impl Thread {
         // FIXME: could store this pointer in TLS somewhere
     }
 
-    pub fn sleep(_dur: Duration) {
-        rtabort!("can't sleep"); // FIXME
+    pub fn sleep(dur: Duration) {
+        usercalls::wait_timeout(0, dur, || true);
     }
 
     pub fn join(self) {
diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs
index 6e50f161b3b..070afa55f30 100644
--- a/src/libstd/sys/sgx/waitqueue.rs
+++ b/src/libstd/sys/sgx/waitqueue.rs
@@ -1,16 +1,17 @@
+//! A simple queue implementation for synchronization primitives.
+//!
+//! This queue is used to implement condition variable and mutexes.
+//!
+//! Users of this API are expected to use the `WaitVariable<T>` type. Since
+//! that type is not `Sync`, it needs to be protected by e.g., a `SpinMutex` to
+//! allow shared access.
+//!
+//! Since userspace may send spurious wake-ups, the wakeup event state is
+//! recorded in the enclave. The wakeup event state is protected by a spinlock.
+//! The queue and associated wait state are stored in a `WaitVariable`.
 use crate::num::NonZeroUsize;
-/// A simple queue implementation for synchronization primitives.
-///
-/// This queue is used to implement condition variable and mutexes.
-///
-/// Users of this API are expected to use the `WaitVariable<T>` type. Since
-/// that type is not `Sync`, it needs to be protected by e.g., a `SpinMutex` to
-/// allow shared access.
-///
-/// Since userspace may send spurious wake-ups, the wakeup event state is
-/// recorded in the enclave. The wakeup event state is protected by a spinlock.
-/// The queue and associated wait state are stored in a `WaitVariable`.
 use crate::ops::{Deref, DerefMut};
+use crate::time::Duration;
 
 use super::abi::thread;
 use super::abi::usercalls;
@@ -158,6 +159,34 @@ impl WaitQueue {
         }
     }
 
+    /// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
+    /// until a wakeup event or timeout. If event was observed, returns true.
+    /// If not, it will remove the calling thread from the wait queue.
+    pub fn wait_timeout<T, F: FnOnce()>(
+        lock: &SpinMutex<WaitVariable<T>>,
+        timeout: Duration,
+        before_wait: F,
+    ) -> bool {
+        // very unsafe: check requirements of UnsafeList::push
+        unsafe {
+            let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry {
+                tcs: thread::current(),
+                wake: false,
+            }));
+            let entry_lock = lock.lock().queue.inner.push(&mut entry);
+            before_wait();
+            usercalls::wait_timeout(EV_UNPARK, timeout, || entry_lock.lock().wake);
+            // acquire the wait queue's lock first to avoid deadlock.
+            let mut guard = lock.lock();
+            let success = entry_lock.lock().wake;
+            if !success {
+                // nobody is waking us up, so remove our entry from the wait queue.
+                guard.queue.inner.remove(&mut entry);
+            }
+            success
+        }
+    }
+
     /// Either find the next waiter on the wait queue, or return the mutex
     /// guard unchanged.
     ///
@@ -325,6 +354,31 @@ mod unsafe_list {
                 Some((*first.as_ptr()).value.as_ref().unwrap())
             }
         }
+
+        /// Removes an entry from the list.
+        ///
+        /// # Safety
+        ///
+        /// The caller must ensure that `entry` has been pushed onto `self`
+        /// prior to this call and has not moved since then.
+        pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry<T>) {
+            rtassert!(!self.is_empty());
+            // BEFORE:
+            //     /----\ next ---> /-----\ next ---> /----\
+            // ... |prev|           |entry|           |next| ...
+            //     \----/ <--- prev \-----/ <--- prev \----/
+            //
+            // AFTER:
+            //     /----\ next ---> /----\
+            // ... |prev|           |next| ...
+            //     \----/ <--- prev \----/
+            let mut prev = entry.prev;
+            let mut next = entry.next;
+            prev.as_mut().next = next;
+            next.as_mut().prev = prev;
+            entry.next = NonNull::dangling();
+            entry.prev = NonNull::dangling();
+        }
     }
 
     #[cfg(test)]
@@ -355,6 +409,51 @@ mod unsafe_list {
         }
 
         #[test]
+        fn push_remove() {
+            unsafe {
+                let mut node = UnsafeListEntry::new(1234);
+                let mut list = UnsafeList::new();
+                assert_eq!(list.push(&mut node), &1234);
+                list.remove(&mut node);
+                assert_empty(&mut list);
+            }
+        }
+
+        #[test]
+        fn push_remove_pop() {
+            unsafe {
+                let mut node1 = UnsafeListEntry::new(11);
+                let mut node2 = UnsafeListEntry::new(12);
+                let mut node3 = UnsafeListEntry::new(13);
+                let mut node4 = UnsafeListEntry::new(14);
+                let mut node5 = UnsafeListEntry::new(15);
+                let mut list = UnsafeList::new();
+                assert_eq!(list.push(&mut node1), &11);
+                assert_eq!(list.push(&mut node2), &12);
+                assert_eq!(list.push(&mut node3), &13);
+                assert_eq!(list.push(&mut node4), &14);
+                assert_eq!(list.push(&mut node5), &15);
+
+                list.remove(&mut node1);
+                assert_eq!(list.pop().unwrap(), &12);
+                list.remove(&mut node3);
+                assert_eq!(list.pop().unwrap(), &14);
+                list.remove(&mut node5);
+                assert_empty(&mut list);
+
+                assert_eq!(list.push(&mut node1), &11);
+                assert_eq!(list.pop().unwrap(), &11);
+                assert_empty(&mut list);
+
+                assert_eq!(list.push(&mut node3), &13);
+                assert_eq!(list.push(&mut node4), &14);
+                list.remove(&mut node3);
+                list.remove(&mut node4);
+                assert_empty(&mut list);
+            }
+        }
+
+        #[test]
         fn complex_pushes_pops() {
             unsafe {
                 let mut node1 = UnsafeListEntry::new(1234);
@@ -474,7 +573,7 @@ mod spin_mutex {
         use super::*;
         use crate::sync::Arc;
         use crate::thread;
-        use crate::time::{Duration, SystemTime};
+        use crate::time::Duration;
 
         #[test]
         fn sleep() {
@@ -485,11 +584,7 @@ mod spin_mutex {
                 *mutex2.lock() = 1;
             });
 
-            // "sleep" for 50ms
-            // FIXME: https://github.com/fortanix/rust-sgx/issues/31
-            let start = SystemTime::now();
-            let max = Duration::from_millis(50);
-            while start.elapsed().unwrap() < max {}
+            thread::sleep(Duration::from_millis(50));
 
             assert_eq!(*guard, 0);
             drop(guard);
diff --git a/src/libstd/sys/unsupported/alloc.rs b/src/libstd/sys/unsupported/alloc.rs
new file mode 100644
index 00000000000..8d5d0a2f5cc
--- /dev/null
+++ b/src/libstd/sys/unsupported/alloc.rs
@@ -0,0 +1,22 @@
+use crate::alloc::{GlobalAlloc, Layout, System};
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+    #[inline]
+    unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
+        0 as *mut u8
+    }
+
+    #[inline]
+    unsafe fn alloc_zeroed(&self, _layout: Layout) -> *mut u8 {
+        0 as *mut u8
+    }
+
+    #[inline]
+    unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
+
+    #[inline]
+    unsafe fn realloc(&self, _ptr: *mut u8, _layout: Layout, _new_size: usize) -> *mut u8 {
+        0 as *mut u8
+    }
+}
diff --git a/src/libstd/sys/unsupported/args.rs b/src/libstd/sys/unsupported/args.rs
new file mode 100644
index 00000000000..71d0c5fa13e
--- /dev/null
+++ b/src/libstd/sys/unsupported/args.rs
@@ -0,0 +1,38 @@
+use crate::ffi::OsString;
+
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
+pub unsafe fn cleanup() {}
+
+pub struct Args {}
+
+pub fn args() -> Args {
+    Args {}
+}
+
+impl Args {
+    pub fn inner_debug(&self) -> &[OsString] {
+        &[]
+    }
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> {
+        None
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (0, Some(0))
+    }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize {
+        0
+    }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> {
+        None
+    }
+}
diff --git a/src/libstd/sys/wasm/cmath.rs b/src/libstd/sys/unsupported/cmath.rs
index 304cf906b2a..304cf906b2a 100644
--- a/src/libstd/sys/wasm/cmath.rs
+++ b/src/libstd/sys/unsupported/cmath.rs
diff --git a/src/libstd/sys/unsupported/common.rs b/src/libstd/sys/unsupported/common.rs
new file mode 100644
index 00000000000..80311d26819
--- /dev/null
+++ b/src/libstd/sys/unsupported/common.rs
@@ -0,0 +1,48 @@
+use crate::io as std_io;
+
+pub mod memchr {
+    pub use core::slice::memchr::{memchr, memrchr};
+}
+
+pub use crate::sys_common::os_str_bytes as os_str;
+
+// This is not necessarily correct. May want to consider making it part of the
+// spec definition?
+use crate::os::raw::c_char;
+
+#[cfg(not(test))]
+pub fn init() {}
+
+pub fn unsupported<T>() -> std_io::Result<T> {
+    Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> std_io::Error {
+    std_io::Error::new(std_io::ErrorKind::Other, "operation not supported on this platform")
+}
+
+pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
+    crate::io::ErrorKind::Other
+}
+
+pub fn abort_internal() -> ! {
+    core::intrinsics::abort();
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    (1, 2)
+}
+
+// This enum is used as the storage for a bunch of types which can't actually
+// exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
+pub unsafe fn strlen(mut s: *const c_char) -> usize {
+    let mut n = 0;
+    while *s != 0 {
+        n += 1;
+        s = s.offset(1);
+    }
+    return n;
+}
diff --git a/src/libstd/sys/wasm/condvar.rs b/src/libstd/sys/unsupported/condvar.rs
index 9fd781c7282..a578eee8ccc 100644
--- a/src/libstd/sys/wasm/condvar.rs
+++ b/src/libstd/sys/unsupported/condvar.rs
@@ -18,11 +18,11 @@ impl Condvar {
     pub unsafe fn notify_all(&self) {}
 
     pub unsafe fn wait(&self, _mutex: &Mutex) {
-        panic!("can't block with web assembly")
+        panic!("condvar wait not supported")
     }
 
     pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
-        panic!("can't block with web assembly");
+        panic!("condvar wait not supported");
     }
 
     #[inline]
diff --git a/src/libstd/sys/unsupported/env.rs b/src/libstd/sys/unsupported/env.rs
new file mode 100644
index 00000000000..d2efec506c5
--- /dev/null
+++ b/src/libstd/sys/unsupported/env.rs
@@ -0,0 +1,9 @@
+pub mod os {
+    pub const FAMILY: &str = "";
+    pub const OS: &str = "";
+    pub const DLL_PREFIX: &str = "";
+    pub const DLL_SUFFIX: &str = "";
+    pub const DLL_EXTENSION: &str = "";
+    pub const EXE_SUFFIX: &str = "";
+    pub const EXE_EXTENSION: &str = "";
+}
diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/unsupported/fs.rs
index ecb5b51cccd..ecb5b51cccd 100644
--- a/src/libstd/sys/wasm/fs.rs
+++ b/src/libstd/sys/unsupported/fs.rs
diff --git a/src/libstd/sys/wasm/io.rs b/src/libstd/sys/unsupported/io.rs
index d5f475b4310..d5f475b4310 100644
--- a/src/libstd/sys/wasm/io.rs
+++ b/src/libstd/sys/unsupported/io.rs
diff --git a/src/libstd/sys/unsupported/mod.rs b/src/libstd/sys/unsupported/mod.rs
new file mode 100644
index 00000000000..87f655eecd5
--- /dev/null
+++ b/src/libstd/sys/unsupported/mod.rs
@@ -0,0 +1,24 @@
+pub mod alloc;
+pub mod args;
+pub mod cmath;
+pub mod condvar;
+pub mod env;
+pub mod fs;
+pub mod io;
+pub mod mutex;
+pub mod net;
+pub mod os;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod stdio;
+pub mod thread;
+#[cfg(target_thread_local)]
+pub mod thread_local_dtor;
+pub mod thread_local_key;
+pub mod time;
+
+mod common;
+pub use common::*;
diff --git a/src/libstd/sys/wasm/mutex.rs b/src/libstd/sys/unsupported/mutex.rs
index 7aaf1b3a343..9ef8af52eb5 100644
--- a/src/libstd/sys/wasm/mutex.rs
+++ b/src/libstd/sys/unsupported/mutex.rs
@@ -5,9 +5,10 @@ pub struct Mutex {
 }
 
 unsafe impl Send for Mutex {}
-unsafe impl Sync for Mutex {} // no threads on wasm
+unsafe impl Sync for Mutex {} // no threads on this platform
 
 impl Mutex {
+    #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
     pub const fn new() -> Mutex {
         Mutex { locked: UnsafeCell::new(false) }
     }
@@ -42,8 +43,8 @@ impl Mutex {
     pub unsafe fn destroy(&self) {}
 }
 
-// All empty stubs because wasm has no threads yet, so lock acquisition always
-// succeeds.
+// All empty stubs because this platform does not yet support threads, so lock
+// acquisition always succeeds.
 pub struct ReentrantMutex {}
 
 impl ReentrantMutex {
diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/unsupported/net.rs
index 5c9f1098f9b..5c9f1098f9b 100644
--- a/src/libstd/sys/wasm/net.rs
+++ b/src/libstd/sys/unsupported/net.rs
diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/unsupported/os.rs
index 91afdc8a5a0..0615780c242 100644
--- a/src/libstd/sys/wasm/os.rs
+++ b/src/libstd/sys/unsupported/os.rs
@@ -1,10 +1,9 @@
+use super::{unsupported, Void};
 use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::fmt;
 use crate::io;
 use crate::path::{self, PathBuf};
-use crate::str;
-use crate::sys::{unsupported, Void};
 
 pub fn errno() -> i32 {
     0
@@ -48,14 +47,14 @@ where
 
 impl fmt::Display for JoinPathsError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        "not supported on wasm yet".fmt(f)
+        "not supported on this platform yet".fmt(f)
     }
 }
 
 impl StdError for JoinPathsError {
     #[allow(deprecated)]
     fn description(&self) -> &str {
-        "not supported on wasm yet"
+        "not supported on this platform yet"
     }
 }
 
@@ -73,7 +72,7 @@ impl Iterator for Env {
 }
 
 pub fn env() -> Env {
-    panic!("not supported on web assembly")
+    panic!("not supported on this platform")
 }
 
 pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
@@ -81,15 +80,15 @@ pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
 }
 
 pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
-    Err(io::Error::new(io::ErrorKind::Other, "cannot set env vars on wasm32-unknown-unknown"))
+    Err(io::Error::new(io::ErrorKind::Other, "cannot set env vars on this platform"))
 }
 
 pub fn unsetenv(_: &OsStr) -> io::Result<()> {
-    Err(io::Error::new(io::ErrorKind::Other, "cannot unset env vars on wasm32-unknown-unknown"))
+    Err(io::Error::new(io::ErrorKind::Other, "cannot unset env vars on this platform"))
 }
 
 pub fn temp_dir() -> PathBuf {
-    panic!("no filesystem on wasm")
+    panic!("no filesystem on this platform")
 }
 
 pub fn home_dir() -> Option<PathBuf> {
@@ -97,11 +96,9 @@ pub fn home_dir() -> Option<PathBuf> {
 }
 
 pub fn exit(_code: i32) -> ! {
-    unsafe {
-        crate::arch::wasm32::unreachable();
-    }
+    crate::intrinsics::abort()
 }
 
 pub fn getpid() -> u32 {
-    panic!("no pids on wasm")
+    panic!("no pids on this platform")
 }
diff --git a/src/libstd/sys/wasm/path.rs b/src/libstd/sys/unsupported/path.rs
index 840a7ae0426..840a7ae0426 100644
--- a/src/libstd/sys/wasm/path.rs
+++ b/src/libstd/sys/unsupported/path.rs
diff --git a/src/libstd/sys/wasm/pipe.rs b/src/libstd/sys/unsupported/pipe.rs
index 10d0925823e..10d0925823e 100644
--- a/src/libstd/sys/wasm/pipe.rs
+++ b/src/libstd/sys/unsupported/pipe.rs
diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/unsupported/process.rs
index 4702e5c5492..4702e5c5492 100644
--- a/src/libstd/sys/wasm/process.rs
+++ b/src/libstd/sys/unsupported/process.rs
diff --git a/src/libstd/sys/wasm/rwlock.rs b/src/libstd/sys/unsupported/rwlock.rs
index a59944482e9..d37f34ac935 100644
--- a/src/libstd/sys/wasm/rwlock.rs
+++ b/src/libstd/sys/unsupported/rwlock.rs
@@ -5,7 +5,7 @@ pub struct RWLock {
 }
 
 unsafe impl Send for RWLock {}
-unsafe impl Sync for RWLock {} // no threads on wasm
+unsafe impl Sync for RWLock {} // no threads on this platform
 
 impl RWLock {
     pub const fn new() -> RWLock {
diff --git a/src/libstd/sys/wasm/stack_overflow.rs b/src/libstd/sys/unsupported/stack_overflow.rs
index 32555394cd5..32555394cd5 100644
--- a/src/libstd/sys/wasm/stack_overflow.rs
+++ b/src/libstd/sys/unsupported/stack_overflow.rs
diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/unsupported/stdio.rs
index 5a4e4505e93..5a4e4505e93 100644
--- a/src/libstd/sys/wasm/stdio.rs
+++ b/src/libstd/sys/unsupported/stdio.rs
diff --git a/src/libstd/sys/unsupported/thread.rs b/src/libstd/sys/unsupported/thread.rs
new file mode 100644
index 00000000000..20ae309db30
--- /dev/null
+++ b/src/libstd/sys/unsupported/thread.rs
@@ -0,0 +1,41 @@
+use super::{unsupported, Void};
+use crate::ffi::CStr;
+use crate::io;
+use crate::time::Duration;
+
+pub struct Thread(Void);
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
+
+impl Thread {
+    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+    pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+        unsupported()
+    }
+
+    pub fn yield_now() {
+        // do nothing
+    }
+
+    pub fn set_name(_name: &CStr) {
+        // nope
+    }
+
+    pub fn sleep(_dur: Duration) {
+        panic!("can't sleep");
+    }
+
+    pub fn join(self) {
+        match self.0 {}
+    }
+}
+
+pub mod guard {
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> {
+        None
+    }
+    pub unsafe fn init() -> Option<Guard> {
+        None
+    }
+}
diff --git a/src/libstd/sys/wasm/thread_local_dtor.rs b/src/libstd/sys/unsupported/thread_local_dtor.rs
index 85d66098302..85d66098302 100644
--- a/src/libstd/sys/wasm/thread_local_dtor.rs
+++ b/src/libstd/sys/unsupported/thread_local_dtor.rs
diff --git a/src/libstd/sys/wasm/thread_local_key.rs b/src/libstd/sys/unsupported/thread_local_key.rs
index f8be9863ed5..c31b61cbf56 100644
--- a/src/libstd/sys/wasm/thread_local_key.rs
+++ b/src/libstd/sys/unsupported/thread_local_key.rs
@@ -2,25 +2,25 @@ pub type Key = usize;
 
 #[inline]
 pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on this target");
 }
 
 #[inline]
 pub unsafe fn set(_key: Key, _value: *mut u8) {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on this target");
 }
 
 #[inline]
 pub unsafe fn get(_key: Key) -> *mut u8 {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on this target");
 }
 
 #[inline]
 pub unsafe fn destroy(_key: Key) {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on this target");
 }
 
 #[inline]
 pub fn requires_synchronized_create() -> bool {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on this target");
 }
diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/unsupported/time.rs
index d9edc7fdc44..8aaf1777f24 100644
--- a/src/libstd/sys/wasm/time.rs
+++ b/src/libstd/sys/unsupported/time.rs
@@ -10,7 +10,7 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
 
 impl Instant {
     pub fn now() -> Instant {
-        panic!("time not implemented on wasm32-unknown-unknown")
+        panic!("time not implemented on this platform")
     }
 
     pub const fn zero() -> Instant {
@@ -36,7 +36,7 @@ impl Instant {
 
 impl SystemTime {
     pub fn now() -> SystemTime {
-        panic!("time not implemented on wasm32-unknown-unknown")
+        panic!("time not implemented on this platform")
     }
 
     pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs
index 85f5282034f..2704ff484f9 100644
--- a/src/libstd/sys/wasi/mod.rs
+++ b/src/libstd/sys/wasi/mod.rs
@@ -16,21 +16,18 @@
 
 use crate::io as std_io;
 use crate::mem;
-use crate::os::raw::c_char;
 
 pub mod alloc;
 pub mod args;
-#[path = "../wasm/cmath.rs"]
+#[path = "../unsupported/cmath.rs"]
 pub mod cmath;
-#[path = "../wasm/condvar.rs"]
+#[path = "../unsupported/condvar.rs"]
 pub mod condvar;
 pub mod env;
 pub mod fd;
 pub mod fs;
 pub mod io;
-#[path = "../wasm/memchr.rs"]
-pub mod memchr;
-#[path = "../wasm/mutex.rs"]
+#[path = "../unsupported/mutex.rs"]
 pub mod mutex;
 pub mod net;
 pub mod os;
@@ -39,28 +36,22 @@ pub mod ext;
 pub mod path;
 pub mod pipe;
 pub mod process;
-#[path = "../wasm/rwlock.rs"]
+#[path = "../unsupported/rwlock.rs"]
 pub mod rwlock;
-#[path = "../wasm/stack_overflow.rs"]
+#[path = "../unsupported/stack_overflow.rs"]
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-#[path = "../wasm/thread_local_dtor.rs"]
+#[path = "../unsupported/thread_local_dtor.rs"]
 pub mod thread_local_dtor;
-#[path = "../wasm/thread_local_key.rs"]
+#[path = "../unsupported/thread_local_key.rs"]
 pub mod thread_local_key;
 pub mod time;
 
-#[cfg(not(test))]
-pub fn init() {}
-
-pub fn unsupported<T>() -> std_io::Result<T> {
-    Err(unsupported_err())
-}
-
-pub fn unsupported_err() -> std_io::Error {
-    std_io::Error::new(std_io::ErrorKind::Other, "operation not supported on wasm yet")
-}
+#[path = "../unsupported/common.rs"]
+#[allow(unused)]
+mod common;
+pub use common::*;
 
 pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
     use std_io::ErrorKind::*;
@@ -86,20 +77,6 @@ pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
     }
 }
 
-// This enum is used as the storage for a bunch of types which can't actually
-// exist.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub enum Void {}
-
-pub unsafe fn strlen(mut s: *const c_char) -> usize {
-    let mut n = 0;
-    while *s != 0 {
-        n += 1;
-        s = s.offset(1);
-    }
-    return n;
-}
-
 pub fn abort_internal() -> ! {
     unsafe { libc::abort() }
 }
diff --git a/src/libstd/sys/wasm/memchr.rs b/src/libstd/sys/wasm/memchr.rs
deleted file mode 100644
index 9967482197e..00000000000
--- a/src/libstd/sys/wasm/memchr.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub use core::slice::memchr::{memchr, memrchr};
diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs
index 6939596e52d..3de58904043 100644
--- a/src/libstd/sys/wasm/mod.rs
+++ b/src/libstd/sys/wasm/mod.rs
@@ -14,25 +14,35 @@
 //! compiling for wasm. That way it's a compile time error for something that's
 //! guaranteed to be a runtime error!
 
-use crate::os::raw::c_char;
-
 pub mod alloc;
 pub mod args;
+#[path = "../unsupported/cmath.rs"]
 pub mod cmath;
 pub mod env;
+#[path = "../unsupported/fs.rs"]
 pub mod fs;
+#[path = "../unsupported/io.rs"]
 pub mod io;
-pub mod memchr;
+#[path = "../unsupported/net.rs"]
 pub mod net;
+#[path = "../unsupported/os.rs"]
 pub mod os;
+#[path = "../unsupported/path.rs"]
 pub mod path;
+#[path = "../unsupported/pipe.rs"]
 pub mod pipe;
+#[path = "../unsupported/process.rs"]
 pub mod process;
+#[path = "../unsupported/stack_overflow.rs"]
 pub mod stack_overflow;
+#[path = "../unsupported/stdio.rs"]
 pub mod stdio;
 pub mod thread;
+#[path = "../unsupported/thread_local_dtor.rs"]
 pub mod thread_local_dtor;
+#[path = "../unsupported/thread_local_key.rs"]
 pub mod thread_local_key;
+#[path = "../unsupported/time.rs"]
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
@@ -46,50 +56,15 @@ cfg_if::cfg_if! {
         #[path = "rwlock_atomics.rs"]
         pub mod rwlock;
     } else {
+        #[path = "../unsupported/condvar.rs"]
         pub mod condvar;
+        #[path = "../unsupported/mutex.rs"]
         pub mod mutex;
+        #[path = "../unsupported/rwlock.rs"]
         pub mod rwlock;
     }
 }
 
-#[cfg(not(test))]
-pub fn init() {}
-
-pub fn unsupported<T>() -> crate::io::Result<T> {
-    Err(unsupported_err())
-}
-
-pub fn unsupported_err() -> crate::io::Error {
-    crate::io::Error::new(crate::io::ErrorKind::Other, "operation not supported on wasm yet")
-}
-
-pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
-    crate::io::ErrorKind::Other
-}
-
-// This enum is used as the storage for a bunch of types which can't actually
-// exist.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub enum Void {}
-
-pub unsafe fn strlen(mut s: *const c_char) -> usize {
-    let mut n = 0;
-    while *s != 0 {
-        n += 1;
-        s = s.offset(1);
-    }
-    return n;
-}
-
-pub fn abort_internal() -> ! {
-    unsafe { crate::arch::wasm32::unreachable() }
-}
-
-// We don't have randomness yet, but I totally used a random number generator to
-// generate these numbers.
-//
-// More seriously though this is just for DOS protection in hash maps. It's ok
-// if we don't do that on wasm just yet.
-pub fn hashmap_random_keys() -> (u64, u64) {
-    (1, 2)
-}
+#[path = "../unsupported/common.rs"]
+mod common;
+pub use common::*;
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
index e57bb267cbd..840f9093e00 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -51,13 +51,9 @@ pub mod condvar;
 pub mod fs;
 pub mod io;
 pub mod mutex;
-#[cfg(any(doc, // see `mod os`, docs are generated for multiple platforms
-          unix,
-          target_os = "redox",
-          target_os = "cloudabi",
-          target_os = "hermit",
-          target_arch = "wasm32",
-          all(target_vendor = "fortanix", target_env = "sgx")))]
+// `doc` is required because `sys/mod.rs` imports `unix/ext/mod.rs` on Windows
+// when generating documentation.
+#[cfg(any(doc, not(windows)))]
 pub mod os_str_bytes;
 pub mod poison;
 pub mod process;
@@ -74,6 +70,7 @@ cfg_if::cfg_if! {
     if #[cfg(any(target_os = "cloudabi",
                  target_os = "l4re",
                  target_os = "hermit",
+                 feature = "restricted-std",
                  all(target_arch = "wasm32", not(target_os = "emscripten")),
                  all(target_vendor = "fortanix", target_env = "sgx")))] {
         pub use crate::sys::net;
diff --git a/src/libstd/sys_common/mutex.rs b/src/libstd/sys_common/mutex.rs
index 899fc6a7235..e66d8994147 100644
--- a/src/libstd/sys_common/mutex.rs
+++ b/src/libstd/sys_common/mutex.rs
@@ -17,6 +17,7 @@ impl Mutex {
     /// Also, until `init` is called, behavior is undefined if this
     /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock`
     /// are called by the thread currently holding the lock.
+    #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
     pub const fn new() -> Mutex {
         Mutex(imp::Mutex::new())
     }
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index d354a9b1842..202867258f1 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -1741,7 +1741,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn test_park_timeout_unpark_not_called() {
         for _ in 0..10 {
             thread::park_timeout(Duration::from_millis(10));
@@ -1749,7 +1748,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn test_park_timeout_unpark_called_other_thread() {
         for _ in 0..10 {
             let th = thread::current();
@@ -1764,7 +1762,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn sleep_ms_smoke() {
         thread::sleep(Duration::from_millis(2));
     }
diff --git a/src/libtest/Cargo.toml b/src/libtest/Cargo.toml
index 1667334871d..a4748c5a466 100644
--- a/src/libtest/Cargo.toml
+++ b/src/libtest/Cargo.toml
@@ -10,6 +10,7 @@ path = "lib.rs"
 crate-type = ["dylib", "rlib"]
 
 [dependencies]
+cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
 getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] }
 term = { path = "../libterm" }
 std = { path = "../libstd" }
diff --git a/src/libtest/helpers/concurrency.rs b/src/libtest/helpers/concurrency.rs
index e8f3820558a..2fe87247e3a 100644
--- a/src/libtest/helpers/concurrency.rs
+++ b/src/libtest/helpers/concurrency.rs
@@ -14,61 +14,36 @@ pub fn get_concurrency() -> usize {
         }
         Err(..) => num_cpus(),
     };
+}
 
-    #[cfg(windows)]
-    #[allow(nonstandard_style)]
-    fn num_cpus() -> usize {
-        #[repr(C)]
-        struct SYSTEM_INFO {
-            wProcessorArchitecture: u16,
-            wReserved: u16,
-            dwPageSize: u32,
-            lpMinimumApplicationAddress: *mut u8,
-            lpMaximumApplicationAddress: *mut u8,
-            dwActiveProcessorMask: *mut u8,
-            dwNumberOfProcessors: u32,
-            dwProcessorType: u32,
-            dwAllocationGranularity: u32,
-            wProcessorLevel: u16,
-            wProcessorRevision: u16,
-        }
-        extern "system" {
-            fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
-        }
-        unsafe {
-            let mut sysinfo = std::mem::zeroed();
-            GetSystemInfo(&mut sysinfo);
-            sysinfo.dwNumberOfProcessors as usize
+cfg_if::cfg_if! {
+    if #[cfg(windows)] {
+        #[allow(nonstandard_style)]
+        fn num_cpus() -> usize {
+            #[repr(C)]
+            struct SYSTEM_INFO {
+                wProcessorArchitecture: u16,
+                wReserved: u16,
+                dwPageSize: u32,
+                lpMinimumApplicationAddress: *mut u8,
+                lpMaximumApplicationAddress: *mut u8,
+                dwActiveProcessorMask: *mut u8,
+                dwNumberOfProcessors: u32,
+                dwProcessorType: u32,
+                dwAllocationGranularity: u32,
+                wProcessorLevel: u16,
+                wProcessorRevision: u16,
+            }
+            extern "system" {
+                fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
+            }
+            unsafe {
+                let mut sysinfo = std::mem::zeroed();
+                GetSystemInfo(&mut sysinfo);
+                sysinfo.dwNumberOfProcessors as usize
+            }
         }
-    }
-
-    #[cfg(target_os = "vxworks")]
-    fn num_cpus() -> usize {
-        // FIXME: Implement num_cpus on vxWorks
-        1
-    }
-
-    #[cfg(target_os = "redox")]
-    fn num_cpus() -> usize {
-        // FIXME: Implement num_cpus on Redox
-        1
-    }
-
-    #[cfg(target_os = "hermit")]
-    fn num_cpus() -> usize {
-        // FIXME: Implement num_cpus on HermitCore
-        1
-    }
-
-    #[cfg(any(
-        all(target_arch = "wasm32", not(target_os = "emscripten")),
-        all(target_vendor = "fortanix", target_env = "sgx")
-    ))]
-    fn num_cpus() -> usize {
-        1
-    }
-
-    #[cfg(any(
+    } else if #[cfg(any(
         target_os = "android",
         target_os = "cloudabi",
         target_os = "emscripten",
@@ -78,23 +53,46 @@ pub fn get_concurrency() -> usize {
         target_os = "macos",
         target_os = "solaris",
         target_os = "illumos",
-    ))]
-    fn num_cpus() -> usize {
-        unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
-    }
-
-    #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))]
-    fn num_cpus() -> usize {
-        use std::ptr;
+    ))] {
+        fn num_cpus() -> usize {
+            unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
+        }
+    } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
+        fn num_cpus() -> usize {
+            use std::ptr;
 
-        let mut cpus: libc::c_uint = 0;
-        let mut cpus_size = std::mem::size_of_val(&cpus);
+            let mut cpus: libc::c_uint = 0;
+            let mut cpus_size = std::mem::size_of_val(&cpus);
 
-        unsafe {
-            cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
+            unsafe {
+                cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
+            }
+            if cpus < 1 {
+                let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+                unsafe {
+                    libc::sysctl(
+                        mib.as_mut_ptr(),
+                        2,
+                        &mut cpus as *mut _ as *mut _,
+                        &mut cpus_size as *mut _ as *mut _,
+                        ptr::null_mut(),
+                        0,
+                    );
+                }
+                if cpus < 1 {
+                    cpus = 1;
+                }
+            }
+            cpus as usize
         }
-        if cpus < 1 {
+    } else if #[cfg(target_os = "openbsd")] {
+        fn num_cpus() -> usize {
+            use std::ptr;
+
+            let mut cpus: libc::c_uint = 0;
+            let mut cpus_size = std::mem::size_of_val(&cpus);
             let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+
             unsafe {
                 libc::sysctl(
                     mib.as_mut_ptr(),
@@ -108,43 +106,12 @@ pub fn get_concurrency() -> usize {
             if cpus < 1 {
                 cpus = 1;
             }
+            cpus as usize
         }
-        cpus as usize
-    }
-
-    #[cfg(target_os = "openbsd")]
-    fn num_cpus() -> usize {
-        use std::ptr;
-
-        let mut cpus: libc::c_uint = 0;
-        let mut cpus_size = std::mem::size_of_val(&cpus);
-        let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
-
-        unsafe {
-            libc::sysctl(
-                mib.as_mut_ptr(),
-                2,
-                &mut cpus as *mut _ as *mut _,
-                &mut cpus_size as *mut _ as *mut _,
-                ptr::null_mut(),
-                0,
-            );
-        }
-        if cpus < 1 {
-            cpus = 1;
+    } else {
+        // FIXME: implement on vxWorks, Redox, HermitCore, Haiku, l4re
+        fn num_cpus() -> usize {
+            1
         }
-        cpus as usize
-    }
-
-    #[cfg(target_os = "haiku")]
-    fn num_cpus() -> usize {
-        // FIXME: implement
-        1
-    }
-
-    #[cfg(target_os = "l4re")]
-    fn num_cpus() -> usize {
-        // FIXME: implement
-        1
     }
 }
diff --git a/src/libtest/helpers/isatty.rs b/src/libtest/helpers/isatty.rs
index 831094f7545..874ecc37645 100644
--- a/src/libtest/helpers/isatty.rs
+++ b/src/libtest/helpers/isatty.rs
@@ -1,34 +1,32 @@
 //! Helper module which provides a function to test
 //! if stdout is a tty.
 
-#[cfg(any(
-    target_os = "cloudabi",
-    target_os = "hermit",
-    all(target_arch = "wasm32", not(target_os = "emscripten")),
-    all(target_vendor = "fortanix", target_env = "sgx")
-))]
-pub fn stdout_isatty() -> bool {
-    // FIXME: Implement isatty on SGX
-    false
-}
-#[cfg(unix)]
-pub fn stdout_isatty() -> bool {
-    unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
-}
-#[cfg(windows)]
-pub fn stdout_isatty() -> bool {
-    type DWORD = u32;
-    type BOOL = i32;
-    type HANDLE = *mut u8;
-    type LPDWORD = *mut u32;
-    const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
-    extern "system" {
-        fn GetStdHandle(which: DWORD) -> HANDLE;
-        fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
-    }
-    unsafe {
-        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
-        let mut out = 0;
-        GetConsoleMode(handle, &mut out) != 0
+cfg_if::cfg_if! {
+    if #[cfg(unix)] {
+        pub fn stdout_isatty() -> bool {
+            unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
+        }
+    } else if #[cfg(windows)] {
+        pub fn stdout_isatty() -> bool {
+            type DWORD = u32;
+            type BOOL = i32;
+            type HANDLE = *mut u8;
+            type LPDWORD = *mut u32;
+            const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
+            extern "system" {
+                fn GetStdHandle(which: DWORD) -> HANDLE;
+                fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
+            }
+            unsafe {
+                let handle = GetStdHandle(STD_OUTPUT_HANDLE);
+                let mut out = 0;
+                GetConsoleMode(handle, &mut out) != 0
+            }
+        }
+    } else {
+        // FIXME: Implement isatty on SGX
+        pub fn stdout_isatty() -> bool {
+            false
+        }
     }
 }
diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs
index cc025da1af5..c4d10ab177b 100644
--- a/src/libunwind/lib.rs
+++ b/src/libunwind/lib.rs
@@ -9,12 +9,31 @@
 
 cfg_if::cfg_if! {
     if #[cfg(target_env = "msvc")] {
-        // no extra unwinder support needed
-    } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] {
-        // no unwinder on the system!
-    } else {
+        // Windows MSVC no extra unwinder support needed
+    } else if #[cfg(any(
+        target_os = "l4re",
+        target_os = "none",
+    ))] {
+        // These "unix" family members do not have unwinder.
+        // Note this also matches x86_64-linux-kernel.
+    } else if #[cfg(any(
+        unix,
+        windows,
+        target_os = "cloudabi",
+        all(target_vendor = "fortanix", target_env = "sgx"),
+    ))] {
         mod libunwind;
         pub use libunwind::*;
+    } else {
+        // no unwinder on the system!
+        // - wasm32 (not emscripten, which is "unix" family)
+        // - os=none ("bare metal" targets)
+        // - os=hermit
+        // - os=uefi
+        // - os=cuda
+        // - nvptx64-nvidia-cuda
+        // - mipsel-sony-psp
+        // - Any new targets not listed above.
     }
 }
 
diff --git a/src/test/rustdoc-ui/intra-links-private.rs b/src/test/rustdoc-ui/intra-links-private.rs
index b7906aba5b1..86cf9fed3da 100644
--- a/src/test/rustdoc-ui/intra-links-private.rs
+++ b/src/test/rustdoc-ui/intra-links-private.rs
@@ -1,7 +1,7 @@
 // check-pass
 // revisions: public private
 // [private]compile-flags: --document-private-items
-#![cfg_attr(private, deny(intra_doc_resolution_failure))]
+#![cfg_attr(private, deny(intra_doc_link_resolution_failure))]
 
 /// docs [DontDocMe]
 //[public]~^ WARNING `[DontDocMe]` public documentation for `DocMe` links to a private item
diff --git a/src/test/rustdoc/internal.rs b/src/test/rustdoc/internal.rs
index 2cb7c472cc8..a1e322fb9a3 100644
--- a/src/test/rustdoc/internal.rs
+++ b/src/test/rustdoc/internal.rs
@@ -1,11 +1,13 @@
 // compile-flags: -Z force-unstable-if-unmarked
 
-// @matches internal/index.html '//*[@class="docblock-short"]/span[@class="stab internal"]' \
-//      'Internal'
+// Check that the unstable marker is not added for "rustc_private".
+
+// @!matches internal/index.html '//*[@class="docblock-short"]/span[@class="stab unstable"]'
+// @!matches internal/index.html '//*[@class="docblock-short"]/span[@class="stab internal"]'
 // @matches - '//*[@class="docblock-short"]' 'Docs'
 
-// @has internal/struct.S.html '//*[@class="stab internal"]' \
-//      'This is an internal compiler API. (rustc_private)'
+// @!has internal/struct.S.html '//*[@class="stab unstable"]'
+// @!has internal/struct.S.html '//*[@class="stab internal"]'
 /// Docs
 pub struct S;
 
diff --git a/src/test/rustdoc/intra-doc-crate/additional_doc.rs b/src/test/rustdoc/intra-doc-crate/additional_doc.rs
new file mode 100644
index 00000000000..adfa7f5754e
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/additional_doc.rs
@@ -0,0 +1,10 @@
+// aux-build:additional_doc.rs
+// build-aux-docs
+#![deny(intra_doc_link_resolution_failure)]
+
+extern crate my_rand;
+
+// @has 'additional_doc/trait.Rng.html' '//a[@href="../additional_doc/trait.Rng.html"]' 'Rng'
+// @has 'additional_doc/trait.Rng.html' '//a[@href="../my_rand/trait.RngCore.html"]' 'RngCore'
+/// This is an [`Rng`].
+pub use my_rand::Rng;
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/additional_doc.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/additional_doc.rs
new file mode 100644
index 00000000000..8b8793e75ed
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/auxiliary/additional_doc.rs
@@ -0,0 +1,6 @@
+#![crate_name = "my_rand"]
+#![deny(intra_doc_link_resolution_failure)]
+
+pub trait RngCore {}
+/// Rng extends [`RngCore`].
+pub trait Rng: RngCore {}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/intra-doc-basic.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/intra-doc-basic.rs
new file mode 100644
index 00000000000..2ee5835a7df
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/auxiliary/intra-doc-basic.rs
@@ -0,0 +1,7 @@
+#![crate_name = "a"]
+#![deny(intra_doc_link_resolution_failure)]
+
+pub struct Foo;
+
+/// Link to [Foo]
+pub struct Bar;
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/macro_inner.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/macro_inner.rs
new file mode 100644
index 00000000000..abd41fec130
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/auxiliary/macro_inner.rs
@@ -0,0 +1,10 @@
+#![crate_name = "macro_inner"]
+#![deny(intra_doc_link_resolution_failure)]
+
+pub struct Foo;
+
+/// See also [`Foo`]
+#[macro_export]
+macro_rules! my_macro {
+    () => {}
+}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/module.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/module.rs
new file mode 100644
index 00000000000..5d63d7e37b6
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/auxiliary/module.rs
@@ -0,0 +1,7 @@
+#![crate_name = "module_inner"]
+#![deny(intra_doc_link_resolution_failure)]
+/// [SomeType] links to [bar]
+pub struct SomeType;
+pub trait SomeTrait {}
+/// [bar] links to [SomeTrait] and also [SomeType]
+pub mod bar {}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/proc_macro.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/proc_macro.rs
new file mode 100644
index 00000000000..0d5a954075d
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/auxiliary/proc_macro.rs
@@ -0,0 +1,20 @@
+// force-host
+// no-prefer-dynamic
+// compile-flags: --crate-type proc-macro
+#![crate_type="proc-macro"]
+#![crate_name="proc_macro_inner"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+/// Links to [`OtherDerive`]
+#[proc_macro_derive(DeriveA)]
+pub fn a_derive(input: TokenStream) -> TokenStream {
+    input
+}
+
+#[proc_macro_derive(OtherDerive)]
+pub fn other_derive(input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-inner.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-inner.rs
new file mode 100644
index 00000000000..3a22d13e673
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-inner.rs
@@ -0,0 +1,12 @@
+#![crate_name = "a"]
+#![deny(intra_doc_link_resolution_failure)]
+
+pub mod bar {
+   pub struct Bar;
+}
+
+pub mod foo {
+  use crate::bar;
+  /// link to [bar::Bar]
+  pub struct Foo;
+}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-outer.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-outer.rs
new file mode 100644
index 00000000000..b8ca4e44e1f
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-outer.rs
@@ -0,0 +1,13 @@
+#![crate_name = "bar"]
+#![deny(intra_doc_link_resolution_failure)]
+
+pub trait Foo {
+    /// [`Bar`] [`Baz`]
+    fn foo();
+}
+
+pub trait Bar {
+}
+
+pub trait Baz {
+}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/traits.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/traits.rs
new file mode 100644
index 00000000000..c16e39d56f3
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/auxiliary/traits.rs
@@ -0,0 +1,16 @@
+#![crate_name = "inner"]
+/// this is a trait
+pub trait SomeTrait {
+    /// this is a method for [a trait][SomeTrait]
+    fn foo();
+}
+
+pub mod bar {
+    use super::SomeTrait;
+
+    pub struct BarStruct;
+
+    impl SomeTrait for BarStruct {
+        fn foo() {}
+    }
+}
diff --git a/src/test/rustdoc/intra-doc-crate/basic.rs b/src/test/rustdoc/intra-doc-crate/basic.rs
new file mode 100644
index 00000000000..a245a0f8453
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/basic.rs
@@ -0,0 +1,9 @@
+// aux-build:intra-doc-basic.rs
+// build-aux-docs
+#![deny(intra_doc_link_resolution_failure)]
+
+// from https://github.com/rust-lang/rust/issues/65983
+extern crate a;
+
+// @has 'basic/struct.Bar.html' '//a[@href="../a/struct.Foo.html"]' 'Foo'
+pub use a::Bar;
diff --git a/src/test/rustdoc/intra-doc-crate/macro.rs b/src/test/rustdoc/intra-doc-crate/macro.rs
new file mode 100644
index 00000000000..72fd57b6b0c
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/macro.rs
@@ -0,0 +1,12 @@
+// ignore-tidy-linelength
+// aux-build:macro_inner.rs
+// aux-build:proc_macro.rs
+// build-aux-docs
+#![deny(intra_doc_link_resolution_failure)]
+extern crate macro_inner;
+extern crate proc_macro_inner;
+
+// @has 'macro/macro.my_macro.html' '//a[@href="../macro_inner/struct.Foo.html"]' 'Foo'
+pub use macro_inner::my_macro;
+// @has 'macro/derive.DeriveA.html' '//a[@href="../proc_macro_inner/derive.OtherDerive.html"]' 'OtherDerive'
+pub use proc_macro_inner::DeriveA;
diff --git a/src/test/rustdoc/intra-doc-crate/module.rs b/src/test/rustdoc/intra-doc-crate/module.rs
new file mode 100644
index 00000000000..67fa7293f37
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/module.rs
@@ -0,0 +1,8 @@
+// outer.rs
+// aux-build: module.rs
+// build-aux-docs
+#![deny(intra_doc_link_resolution_failure)]
+extern crate module_inner;
+// @has 'module/bar/index.html' '//a[@href="../../module_inner/trait.SomeTrait.html"]' 'SomeTrait'
+// @has 'module/bar/index.html' '//a[@href="../../module_inner/struct.SomeType.html"]' 'SomeType'
+pub use module_inner::bar;
diff --git a/src/test/rustdoc/intra-doc-crate/submodule-inner.rs b/src/test/rustdoc/intra-doc-crate/submodule-inner.rs
new file mode 100644
index 00000000000..b4b615bf9ed
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/submodule-inner.rs
@@ -0,0 +1,8 @@
+// aux-build:submodule-inner.rs
+// build-aux-docs
+#![deny(intra_doc_link_resolution_failure)]
+
+extern crate a;
+
+// @has 'submodule_inner/struct.Foo.html' '//a[@href="../a/bar/struct.Bar.html"]' 'Bar'
+pub use a::foo::Foo;
diff --git a/src/test/rustdoc/intra-doc-crate/submodule-outer.rs b/src/test/rustdoc/intra-doc-crate/submodule-outer.rs
new file mode 100644
index 00000000000..6b30ef8b3de
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/submodule-outer.rs
@@ -0,0 +1,16 @@
+// aux-build:submodule-outer.rs
+// edition:2018
+#![deny(intra_doc_link_resolution_failure)]
+
+extern crate bar as bar_;
+
+// from https://github.com/rust-lang/rust/issues/60883
+pub mod bar {
+    pub use ::bar_::Bar;
+}
+
+// NOTE: we re-exported both `Foo` and `Bar` here,
+// NOTE: so they are inlined and therefore we link to the current module.
+// @has 'submodule_outer/trait.Foo.html' '//a[@href="../submodule_outer/bar/trait.Bar.html"]' 'Bar'
+// @has 'submodule_outer/trait.Foo.html' '//a[@href="../submodule_outer/trait.Baz.html"]' 'Baz'
+pub use ::bar_::{Foo, Baz};
diff --git a/src/test/rustdoc/intra-doc-crate/traits.rs b/src/test/rustdoc/intra-doc-crate/traits.rs
new file mode 100644
index 00000000000..61733123690
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-crate/traits.rs
@@ -0,0 +1,17 @@
+// ignore-test
+// ^ this is https://github.com/rust-lang/rust/issues/73829
+// aux-build:traits.rs
+// build-aux-docs
+// ignore-tidy-line-length
+#![deny(intra_doc_link_resolution_failure)]
+
+extern crate inner;
+use inner::SomeTrait;
+
+pub struct SomeStruct;
+
+ // @has 'traits/struct.SomeStruct.html' '//a[@href="../inner/trait.SomeTrait.html"]' 'SomeTrait'
+impl SomeTrait for SomeStruct {
+    // @has 'traits/struct.SomeStruct.html' '//a[@href="../inner/trait.SomeTrait.html"]' 'a trait'
+    fn foo() {}
+}
diff --git a/src/test/rustdoc/intra-link-prim-precedence.rs b/src/test/rustdoc/intra-link-prim-precedence.rs
index ca83d5e2281..d7ebb73b3be 100644
--- a/src/test/rustdoc/intra-link-prim-precedence.rs
+++ b/src/test/rustdoc/intra-link-prim-precedence.rs
@@ -1,5 +1,5 @@
 // ignore-tidy-linelength
-#![deny(intra_doc_resolution_failure)]
+#![deny(intra_doc_link_resolution_failure)]
 
 pub mod char {}
 
diff --git a/src/test/ui/issues/issue-59020.rs b/src/test/ui/issues/issue-59020.rs
index e7544934da0..a2b11764a2f 100644
--- a/src/test/ui/issues/issue-59020.rs
+++ b/src/test/ui/issues/issue-59020.rs
@@ -1,7 +1,6 @@
 // edition:2018
 // run-pass
 // ignore-emscripten no threads support
-// ignore-sgx no thread sleep support
 
 use std::thread;
 use std::time::Duration;
diff --git a/src/test/ui/issues/issue-9396.rs b/src/test/ui/issues/issue-9396.rs
index 27b5185377d..3e7e9a51cdd 100644
--- a/src/test/ui/issues/issue-9396.rs
+++ b/src/test/ui/issues/issue-9396.rs
@@ -2,7 +2,6 @@
 #![allow(unused_must_use)]
 #![allow(deprecated)]
 // ignore-emscripten no threads support
-// ignore-sgx no thread sleep support
 
 use std::sync::mpsc::{TryRecvError, channel};
 use std::thread;
diff --git a/src/test/ui/mpsc_stress.rs b/src/test/ui/mpsc_stress.rs
index bce5fdcd119..a889542fec0 100644
--- a/src/test/ui/mpsc_stress.rs
+++ b/src/test/ui/mpsc_stress.rs
@@ -1,7 +1,6 @@
 // run-pass
 // compile-flags:--test
 // ignore-emscripten
-// ignore-sgx no thread sleep support
 
 use std::sync::mpsc::channel;
 use std::sync::mpsc::TryRecvError;
@@ -37,6 +36,8 @@ impl Barrier {
     fn wait(self) {
         self.shared.fetch_add(1, Ordering::SeqCst);
         while self.shared.load(Ordering::SeqCst) != self.count {
+            #[cfg(target_env = "sgx")]
+            thread::yield_now();
         }
     }
 }
diff --git a/src/test/ui/sleep.rs b/src/test/ui/sleep.rs
index 757578b8475..3b3a4a4f325 100644
--- a/src/test/ui/sleep.rs
+++ b/src/test/ui/sleep.rs
@@ -1,6 +1,5 @@
 // run-pass
 // ignore-emscripten no threads support
-// ignore-sgx no thread sleep support
 
 use std::thread::{self, sleep};
 use std::time::Duration;
diff --git a/src/test/ui/tcp-stress.rs b/src/test/ui/tcp-stress.rs
index 1f1948fa8fa..08b47dc5318 100644
--- a/src/test/ui/tcp-stress.rs
+++ b/src/test/ui/tcp-stress.rs
@@ -4,7 +4,6 @@
 // ignore-emscripten no threads or sockets support
 // ignore-netbsd system ulimit (Too many open files)
 // ignore-openbsd system ulimit (Too many open files)
-// ignore-sgx no thread sleep support
 
 use std::io::prelude::*;
 use std::net::{TcpListener, TcpStream};
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 2c64abb4be6..6ac89f2b1b8 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -34,6 +34,7 @@ static HOSTS: &[&str] = &[
     "powerpc-unknown-linux-gnu",
     "powerpc64-unknown-linux-gnu",
     "powerpc64le-unknown-linux-gnu",
+    "riscv64gc-unknown-linux-gnu",
     "s390x-unknown-linux-gnu",
     "x86_64-apple-darwin",
     "x86_64-pc-windows-gnu",
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index 7128fee9bcf..1d4772bb3d6 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -8,7 +8,7 @@ use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::{Ident, SymbolStr};
+use rustc_span::symbol::{Ident, Symbol};
 use std::cmp::Ordering;
 
 declare_clippy_lint! {
@@ -75,7 +75,7 @@ pub struct NonExpressiveNames {
 impl_lint_pass!(NonExpressiveNames => [SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES, JUST_UNDERSCORES_AND_DIGITS]);
 
 struct ExistingName {
-    interned: SymbolStr,
+    interned: Symbol,
     span: Span,
     len: usize,
     exemptions: &'static [&'static str],
@@ -218,18 +218,19 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
             let mut split_at = None;
             match existing_name.len.cmp(&count) {
                 Ordering::Greater => {
-                    if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) {
+                    if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned.as_str()) {
                         continue;
                     }
                 },
                 Ordering::Less => {
-                    if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) {
+                    if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned.as_str(), &interned_name) {
                         continue;
                     }
                 },
                 Ordering::Equal => {
                     let mut interned_chars = interned_name.chars();
-                    let mut existing_chars = existing_name.interned.chars();
+                    let interned_str = existing_name.interned.as_str();
+                    let mut existing_chars = interned_str.chars();
                     let first_i = interned_chars.next().expect("we know we have at least one char");
                     let first_e = existing_chars.next().expect("we know we have at least one char");
                     let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric();
@@ -302,7 +303,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
         }
         self.0.names.push(ExistingName {
             exemptions: get_exemptions(&interned_name).unwrap_or(&[]),
-            interned: interned_name,
+            interned: ident.name,
             span: ident.span,
             len: count,
         });
diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
index 735800e7e74..154082a0fdb 100644
--- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
+++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
@@ -3,7 +3,7 @@ use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::{Ident, SymbolStr};
+use rustc_span::symbol::Ident;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for imports that remove "unsafe" from an item's
@@ -73,6 +73,6 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>,
 }
 
 #[must_use]
-fn contains_unsafe(name: &SymbolStr) -> bool {
+fn contains_unsafe(name: &str) -> bool {
     name.contains("Unsafe") || name.contains("unsafe")
 }
diff --git a/src/tools/rustc-std-workspace-std/lib.rs b/src/tools/rustc-std-workspace-std/lib.rs
index f40d09cafbb..1e955c61ac8 100644
--- a/src/tools/rustc-std-workspace-std/lib.rs
+++ b/src/tools/rustc-std-workspace-std/lib.rs
@@ -1 +1,2 @@
+#![feature(restricted_std)]
 pub use std::*;