about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-10-04 13:49:36 +0000
committerbors <bors@rust-lang.org>2020-10-04 13:49:36 +0000
commita835b483fe0418b48ca44afb65cd0dd6bad4eb9b (patch)
treee5259afd7476af32e8bb7b8f41ea22a4a1f40e07
parent0644cc1242dbeebb69b1b2496562751ba5d23ffb (diff)
parentfa200cec889b2b2308882a897cafe92bf1cf13c7 (diff)
downloadrust-a835b483fe0418b48ca44afb65cd0dd6bad4eb9b.tar.gz
rust-a835b483fe0418b48ca44afb65cd0dd6bad4eb9b.zip
Auto merge of #77527 - jonas-schievink:rollup-szgq5he, r=jonas-schievink
Rollup of 8 pull requests

Successful merges:

 - #77072 (Minor `hash_map` doc adjustments + item attribute orderings)
 - #77368 (Backport LLVM apfloat commit to rustc_apfloat)
 - #77445 (BTreeMap: complete the compile-time test_variance test case)
 - #77504 (Support vectors with fewer than 8 elements for simd_select_bitmask)
 - #77513 (Change DocFragments from enum variant fields to structs with a nested enum)
 - #77518 (Only use Fira Sans for the first `td` in item lists)
 - #77521 (Move target feature whitelist from cg_llvm to cg_ssa)
 - #77525 (Enable RenameReturnPlace MIR optimization on mir-opt-level >= 2)

Failed merges:

r? `@ghost`
-rw-r--r--compiler/rustc_apfloat/src/ieee.rs15
-rw-r--r--compiler/rustc_apfloat/tests/ieee.rs34
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs150
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs150
-rw-r--r--compiler/rustc_mir/src/transform/nrvo.rs6
-rw-r--r--library/alloc/src/collections/btree/map/tests.rs58
-rw-r--r--library/alloc/src/collections/btree/set/tests.rs87
-rw-r--r--library/std/src/collections/hash/map.rs40
-rw-r--r--src/librustdoc/clean/types.rs60
-rw-r--r--src/librustdoc/html/static/rustdoc.css2
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs7
-rw-r--r--src/librustdoc/passes/collapse_docs.rs49
-rw-r--r--src/librustdoc/passes/mod.rs12
-rw-r--r--src/librustdoc/passes/unindent_comments.rs8
-rw-r--r--src/test/ui/issues/issue-69532.rs24
-rw-r--r--src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs4
-rw-r--r--src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr6
-rw-r--r--src/test/ui/simd/simd-intrinsic-generic-select.rs25
21 files changed, 438 insertions, 318 deletions
diff --git a/compiler/rustc_apfloat/src/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs
index e3d941cad7a..71bcb8f090d 100644
--- a/compiler/rustc_apfloat/src/ieee.rs
+++ b/compiler/rustc_apfloat/src/ieee.rs
@@ -1511,11 +1511,16 @@ impl<S: Semantics, T: Semantics> FloatConvert<IeeeFloat<T>> for IeeeFloat<S> {
                 sig::set_bit(&mut r.sig, T::PRECISION - 1);
             }
 
-            // gcc forces the Quiet bit on, which means (float)(double)(float_sNan)
-            // does not give you back the same bits. This is dubious, and we
-            // don't currently do it. You're really supposed to get
-            // an invalid operation signal at runtime, but nobody does that.
-            status = Status::OK;
+            // Convert of sNaN creates qNaN and raises an exception (invalid op).
+            // This also guarantees that a sNaN does not become Inf on a truncation
+            // that loses all payload bits.
+            if self.is_signaling() {
+                // Quiet signaling NaN.
+                sig::set_bit(&mut r.sig, T::QNAN_BIT);
+                status = Status::INVALID_OP;
+            } else {
+                status = Status::OK;
+            }
         } else {
             *loses_info = false;
             status = Status::OK;
diff --git a/compiler/rustc_apfloat/tests/ieee.rs b/compiler/rustc_apfloat/tests/ieee.rs
index 2d8bb7d1e8e..63d925cce9a 100644
--- a/compiler/rustc_apfloat/tests/ieee.rs
+++ b/compiler/rustc_apfloat/tests/ieee.rs
@@ -567,6 +567,17 @@ fn fma() {
 }
 
 #[test]
+fn issue_69532() {
+    let f = Double::from_bits(0x7FF0_0000_0000_0001u64 as u128);
+    let mut loses_info = false;
+    let sta = f.convert(&mut loses_info);
+    let r: Single = sta.value;
+    assert!(loses_info);
+    assert!(r.is_nan());
+    assert_eq!(sta.status, Status::INVALID_OP);
+}
+
+#[test]
 fn min_num() {
     let f1 = Double::from_f64(1.0);
     let f2 = Double::from_f64(2.0);
@@ -1492,27 +1503,32 @@ fn convert() {
     assert_eq!(4294967295.0, test.to_f64());
     assert!(!loses_info);
 
-    let test = Single::snan(None);
-    let x87_snan = X87DoubleExtended::snan(None);
-    let test: X87DoubleExtended = test.convert(&mut loses_info).value;
-    assert!(test.bitwise_eq(x87_snan));
-    assert!(!loses_info);
-
     let test = Single::qnan(None);
     let x87_qnan = X87DoubleExtended::qnan(None);
     let test: X87DoubleExtended = test.convert(&mut loses_info).value;
     assert!(test.bitwise_eq(x87_qnan));
     assert!(!loses_info);
 
-    let test = X87DoubleExtended::snan(None);
-    let test: X87DoubleExtended = test.convert(&mut loses_info).value;
-    assert!(test.bitwise_eq(x87_snan));
+    let test = Single::snan(None);
+    let sta = test.convert(&mut loses_info);
+    let test: X87DoubleExtended = sta.value;
+    assert!(test.is_nan());
+    assert!(!test.is_signaling());
     assert!(!loses_info);
+    assert_eq!(sta.status, Status::INVALID_OP);
 
     let test = X87DoubleExtended::qnan(None);
     let test: X87DoubleExtended = test.convert(&mut loses_info).value;
     assert!(test.bitwise_eq(x87_qnan));
     assert!(!loses_info);
+
+    let test = X87DoubleExtended::snan(None);
+    let sta = test.convert(&mut loses_info);
+    let test: X87DoubleExtended = sta.value;
+    assert!(test.is_nan());
+    assert!(!test.is_signaling());
+    assert!(!loses_info);
+    assert_eq!(sta.status, Status::INVALID_OP);
 }
 
 #[test]
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 73c34818446..a633ea5e5a9 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -349,17 +349,15 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
 }
 
 pub fn provide(providers: &mut Providers) {
+    use rustc_codegen_ssa::target_features::{all_known_features, supported_target_features};
     providers.supported_target_features = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
         if tcx.sess.opts.actually_rustdoc {
             // rustdoc needs to be able to document functions that use all the features, so
             // provide them all.
-            llvm_util::all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
+            all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
         } else {
-            llvm_util::supported_target_features(tcx.sess)
-                .iter()
-                .map(|&(a, b)| (a.to_string(), b))
-                .collect()
+            supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
         }
     };
 
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 7f5b09eac4f..e76e86f5651 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -793,14 +793,18 @@ fn generic_simd_intrinsic(
         require_simd!(arg_tys[1], "argument");
         let v_len = arg_tys[1].simd_size(tcx);
         require!(
-            m_len == v_len,
+            // Allow masks for vectors with fewer than 8 elements to be
+            // represented with a u8 or i8.
+            m_len == v_len || (m_len == 8 && v_len < 8),
             "mismatched lengths: mask length `{}` != other vector length `{}`",
             m_len,
             v_len
         );
         let i1 = bx.type_i1();
-        let i1xn = bx.type_vector(i1, m_len);
-        let m_i1s = bx.bitcast(args[0].immediate(), i1xn);
+        let im = bx.type_ix(v_len);
+        let i1xn = bx.type_vector(i1, v_len);
+        let m_im = bx.trunc(args[0].immediate(), im);
+        let m_i1s = bx.bitcast(m_im, i1xn);
         return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 900f2df383a..d42020047fd 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -1,12 +1,12 @@
 use crate::back::write::create_informational_target_machine;
 use crate::llvm;
 use libc::c_int;
+use rustc_codegen_ssa::target_features::supported_target_features;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_feature::UnstableFeatures;
 use rustc_middle::bug;
 use rustc_session::config::PrintRequest;
 use rustc_session::Session;
-use rustc_span::symbol::sym;
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::{MergeFunctions, PanicStrategy};
 use std::ffi::CString;
@@ -139,140 +139,6 @@ pub fn time_trace_profiler_finish(file_name: &str) {
 // WARNING: the features after applying `to_llvm_feature` must be known
 // to LLVM or the feature detection code will walk past the end of the feature
 // array, leading to crashes.
-
-const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("aclass", Some(sym::arm_target_feature)),
-    ("mclass", Some(sym::arm_target_feature)),
-    ("rclass", Some(sym::arm_target_feature)),
-    ("dsp", Some(sym::arm_target_feature)),
-    ("neon", Some(sym::arm_target_feature)),
-    ("crc", Some(sym::arm_target_feature)),
-    ("crypto", Some(sym::arm_target_feature)),
-    ("v5te", Some(sym::arm_target_feature)),
-    ("v6", Some(sym::arm_target_feature)),
-    ("v6k", Some(sym::arm_target_feature)),
-    ("v6t2", Some(sym::arm_target_feature)),
-    ("v7", Some(sym::arm_target_feature)),
-    ("v8", Some(sym::arm_target_feature)),
-    ("vfp2", Some(sym::arm_target_feature)),
-    ("vfp3", Some(sym::arm_target_feature)),
-    ("vfp4", Some(sym::arm_target_feature)),
-    // This is needed for inline assembly, but shouldn't be stabilized as-is
-    // since it should be enabled per-function using #[instruction_set], not
-    // #[target_feature].
-    ("thumb-mode", Some(sym::arm_target_feature)),
-];
-
-const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("fp", Some(sym::aarch64_target_feature)),
-    ("neon", Some(sym::aarch64_target_feature)),
-    ("sve", Some(sym::aarch64_target_feature)),
-    ("crc", Some(sym::aarch64_target_feature)),
-    ("crypto", Some(sym::aarch64_target_feature)),
-    ("ras", Some(sym::aarch64_target_feature)),
-    ("lse", Some(sym::aarch64_target_feature)),
-    ("rdm", Some(sym::aarch64_target_feature)),
-    ("fp16", Some(sym::aarch64_target_feature)),
-    ("rcpc", Some(sym::aarch64_target_feature)),
-    ("dotprod", Some(sym::aarch64_target_feature)),
-    ("tme", Some(sym::aarch64_target_feature)),
-    ("v8.1a", Some(sym::aarch64_target_feature)),
-    ("v8.2a", Some(sym::aarch64_target_feature)),
-    ("v8.3a", Some(sym::aarch64_target_feature)),
-];
-
-const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("adx", Some(sym::adx_target_feature)),
-    ("aes", None),
-    ("avx", None),
-    ("avx2", None),
-    ("avx512bw", Some(sym::avx512_target_feature)),
-    ("avx512cd", Some(sym::avx512_target_feature)),
-    ("avx512dq", Some(sym::avx512_target_feature)),
-    ("avx512er", Some(sym::avx512_target_feature)),
-    ("avx512f", Some(sym::avx512_target_feature)),
-    ("avx512ifma", Some(sym::avx512_target_feature)),
-    ("avx512pf", Some(sym::avx512_target_feature)),
-    ("avx512vbmi", Some(sym::avx512_target_feature)),
-    ("avx512vl", Some(sym::avx512_target_feature)),
-    ("avx512vpopcntdq", Some(sym::avx512_target_feature)),
-    ("bmi1", None),
-    ("bmi2", None),
-    ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
-    ("f16c", Some(sym::f16c_target_feature)),
-    ("fma", None),
-    ("fxsr", None),
-    ("lzcnt", None),
-    ("movbe", Some(sym::movbe_target_feature)),
-    ("pclmulqdq", None),
-    ("popcnt", None),
-    ("rdrand", None),
-    ("rdseed", None),
-    ("rtm", Some(sym::rtm_target_feature)),
-    ("sha", None),
-    ("sse", None),
-    ("sse2", None),
-    ("sse3", None),
-    ("sse4.1", None),
-    ("sse4.2", None),
-    ("sse4a", Some(sym::sse4a_target_feature)),
-    ("ssse3", None),
-    ("tbm", Some(sym::tbm_target_feature)),
-    ("xsave", None),
-    ("xsavec", None),
-    ("xsaveopt", None),
-    ("xsaves", None),
-];
-
-const HEXAGON_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("hvx", Some(sym::hexagon_target_feature)),
-    ("hvx-length128b", Some(sym::hexagon_target_feature)),
-];
-
-const POWERPC_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("altivec", Some(sym::powerpc_target_feature)),
-    ("power8-altivec", Some(sym::powerpc_target_feature)),
-    ("power9-altivec", Some(sym::powerpc_target_feature)),
-    ("power8-vector", Some(sym::powerpc_target_feature)),
-    ("power9-vector", Some(sym::powerpc_target_feature)),
-    ("vsx", Some(sym::powerpc_target_feature)),
-];
-
-const MIPS_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] =
-    &[("fp64", Some(sym::mips_target_feature)), ("msa", Some(sym::mips_target_feature))];
-
-const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("m", Some(sym::riscv_target_feature)),
-    ("a", Some(sym::riscv_target_feature)),
-    ("c", Some(sym::riscv_target_feature)),
-    ("f", Some(sym::riscv_target_feature)),
-    ("d", Some(sym::riscv_target_feature)),
-    ("e", Some(sym::riscv_target_feature)),
-];
-
-const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("simd128", Some(sym::wasm_target_feature)),
-    ("atomics", Some(sym::wasm_target_feature)),
-    ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
-];
-
-/// When rustdoc is running, provide a list of all known features so that all their respective
-/// primitives may be documented.
-///
-/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
-pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol>)> {
-    std::iter::empty()
-        .chain(ARM_ALLOWED_FEATURES.iter())
-        .chain(AARCH64_ALLOWED_FEATURES.iter())
-        .chain(X86_ALLOWED_FEATURES.iter())
-        .chain(HEXAGON_ALLOWED_FEATURES.iter())
-        .chain(POWERPC_ALLOWED_FEATURES.iter())
-        .chain(MIPS_ALLOWED_FEATURES.iter())
-        .chain(RISCV_ALLOWED_FEATURES.iter())
-        .chain(WASM_ALLOWED_FEATURES.iter())
-        .cloned()
-}
-
 pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
     let arch = if sess.target.target.arch == "x86_64" { "x86" } else { &*sess.target.target.arch };
     match (arch, s) {
@@ -306,20 +172,6 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
         .collect()
 }
 
-pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option<Symbol>)] {
-    match &*sess.target.target.arch {
-        "arm" => ARM_ALLOWED_FEATURES,
-        "aarch64" => AARCH64_ALLOWED_FEATURES,
-        "x86" | "x86_64" => X86_ALLOWED_FEATURES,
-        "hexagon" => HEXAGON_ALLOWED_FEATURES,
-        "mips" | "mips64" => MIPS_ALLOWED_FEATURES,
-        "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
-        "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
-        "wasm32" => WASM_ALLOWED_FEATURES,
-        _ => &[],
-    }
-}
-
 pub fn print_version() {
     // Can be called without initializing LLVM
     unsafe {
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index d4f3bf37797..e34371ef59a 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -42,6 +42,7 @@ pub mod glue;
 pub mod meth;
 pub mod mir;
 pub mod mono_item;
+pub mod target_features;
 pub mod traits;
 
 pub struct ModuleCodegen<M> {
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
new file mode 100644
index 00000000000..4c61e21901b
--- /dev/null
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -0,0 +1,150 @@
+use rustc_session::Session;
+use rustc_span::symbol::sym;
+use rustc_span::symbol::Symbol;
+
+const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("aclass", Some(sym::arm_target_feature)),
+    ("mclass", Some(sym::arm_target_feature)),
+    ("rclass", Some(sym::arm_target_feature)),
+    ("dsp", Some(sym::arm_target_feature)),
+    ("neon", Some(sym::arm_target_feature)),
+    ("crc", Some(sym::arm_target_feature)),
+    ("crypto", Some(sym::arm_target_feature)),
+    ("v5te", Some(sym::arm_target_feature)),
+    ("v6", Some(sym::arm_target_feature)),
+    ("v6k", Some(sym::arm_target_feature)),
+    ("v6t2", Some(sym::arm_target_feature)),
+    ("v7", Some(sym::arm_target_feature)),
+    ("v8", Some(sym::arm_target_feature)),
+    ("vfp2", Some(sym::arm_target_feature)),
+    ("vfp3", Some(sym::arm_target_feature)),
+    ("vfp4", Some(sym::arm_target_feature)),
+    // This is needed for inline assembly, but shouldn't be stabilized as-is
+    // since it should be enabled per-function using #[instruction_set], not
+    // #[target_feature].
+    ("thumb-mode", Some(sym::arm_target_feature)),
+];
+
+const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("fp", Some(sym::aarch64_target_feature)),
+    ("neon", Some(sym::aarch64_target_feature)),
+    ("sve", Some(sym::aarch64_target_feature)),
+    ("crc", Some(sym::aarch64_target_feature)),
+    ("crypto", Some(sym::aarch64_target_feature)),
+    ("ras", Some(sym::aarch64_target_feature)),
+    ("lse", Some(sym::aarch64_target_feature)),
+    ("rdm", Some(sym::aarch64_target_feature)),
+    ("fp16", Some(sym::aarch64_target_feature)),
+    ("rcpc", Some(sym::aarch64_target_feature)),
+    ("dotprod", Some(sym::aarch64_target_feature)),
+    ("tme", Some(sym::aarch64_target_feature)),
+    ("v8.1a", Some(sym::aarch64_target_feature)),
+    ("v8.2a", Some(sym::aarch64_target_feature)),
+    ("v8.3a", Some(sym::aarch64_target_feature)),
+];
+
+const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("adx", Some(sym::adx_target_feature)),
+    ("aes", None),
+    ("avx", None),
+    ("avx2", None),
+    ("avx512bw", Some(sym::avx512_target_feature)),
+    ("avx512cd", Some(sym::avx512_target_feature)),
+    ("avx512dq", Some(sym::avx512_target_feature)),
+    ("avx512er", Some(sym::avx512_target_feature)),
+    ("avx512f", Some(sym::avx512_target_feature)),
+    ("avx512ifma", Some(sym::avx512_target_feature)),
+    ("avx512pf", Some(sym::avx512_target_feature)),
+    ("avx512vbmi", Some(sym::avx512_target_feature)),
+    ("avx512vl", Some(sym::avx512_target_feature)),
+    ("avx512vpopcntdq", Some(sym::avx512_target_feature)),
+    ("bmi1", None),
+    ("bmi2", None),
+    ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
+    ("f16c", Some(sym::f16c_target_feature)),
+    ("fma", None),
+    ("fxsr", None),
+    ("lzcnt", None),
+    ("movbe", Some(sym::movbe_target_feature)),
+    ("pclmulqdq", None),
+    ("popcnt", None),
+    ("rdrand", None),
+    ("rdseed", None),
+    ("rtm", Some(sym::rtm_target_feature)),
+    ("sha", None),
+    ("sse", None),
+    ("sse2", None),
+    ("sse3", None),
+    ("sse4.1", None),
+    ("sse4.2", None),
+    ("sse4a", Some(sym::sse4a_target_feature)),
+    ("ssse3", None),
+    ("tbm", Some(sym::tbm_target_feature)),
+    ("xsave", None),
+    ("xsavec", None),
+    ("xsaveopt", None),
+    ("xsaves", None),
+];
+
+const HEXAGON_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("hvx", Some(sym::hexagon_target_feature)),
+    ("hvx-length128b", Some(sym::hexagon_target_feature)),
+];
+
+const POWERPC_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("altivec", Some(sym::powerpc_target_feature)),
+    ("power8-altivec", Some(sym::powerpc_target_feature)),
+    ("power9-altivec", Some(sym::powerpc_target_feature)),
+    ("power8-vector", Some(sym::powerpc_target_feature)),
+    ("power9-vector", Some(sym::powerpc_target_feature)),
+    ("vsx", Some(sym::powerpc_target_feature)),
+];
+
+const MIPS_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] =
+    &[("fp64", Some(sym::mips_target_feature)), ("msa", Some(sym::mips_target_feature))];
+
+const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("m", Some(sym::riscv_target_feature)),
+    ("a", Some(sym::riscv_target_feature)),
+    ("c", Some(sym::riscv_target_feature)),
+    ("f", Some(sym::riscv_target_feature)),
+    ("d", Some(sym::riscv_target_feature)),
+    ("e", Some(sym::riscv_target_feature)),
+];
+
+const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("simd128", Some(sym::wasm_target_feature)),
+    ("atomics", Some(sym::wasm_target_feature)),
+    ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
+];
+
+/// When rustdoc is running, provide a list of all known features so that all their respective
+/// primitives may be documented.
+///
+/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
+pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol>)> {
+    std::iter::empty()
+        .chain(ARM_ALLOWED_FEATURES.iter())
+        .chain(AARCH64_ALLOWED_FEATURES.iter())
+        .chain(X86_ALLOWED_FEATURES.iter())
+        .chain(HEXAGON_ALLOWED_FEATURES.iter())
+        .chain(POWERPC_ALLOWED_FEATURES.iter())
+        .chain(MIPS_ALLOWED_FEATURES.iter())
+        .chain(RISCV_ALLOWED_FEATURES.iter())
+        .chain(WASM_ALLOWED_FEATURES.iter())
+        .cloned()
+}
+
+pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option<Symbol>)] {
+    match &*sess.target.target.arch {
+        "arm" => ARM_ALLOWED_FEATURES,
+        "aarch64" => AARCH64_ALLOWED_FEATURES,
+        "x86" | "x86_64" => X86_ALLOWED_FEATURES,
+        "hexagon" => HEXAGON_ALLOWED_FEATURES,
+        "mips" | "mips64" => MIPS_ALLOWED_FEATURES,
+        "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
+        "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
+        "wasm32" => WASM_ALLOWED_FEATURES,
+        _ => &[],
+    }
+}
diff --git a/compiler/rustc_mir/src/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs
index 1ffb5a87c47..3673b6a4aa2 100644
--- a/compiler/rustc_mir/src/transform/nrvo.rs
+++ b/compiler/rustc_mir/src/transform/nrvo.rs
@@ -36,12 +36,6 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
             return;
         }
 
-        if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
-            // The `DestinationPropagation` pass runs at level 2, so this pass is redundant (and
-            // fails some asserts).
-            return;
-        }
-
         let returned_local = match local_eligible_for_nrvo(body) {
             Some(l) => l,
             None => {
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index 8018514fa17..118e173bb16 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -1,12 +1,10 @@
+use super::super::{navigate::Position, node, DeterministicRng};
+use super::Entry::{Occupied, Vacant};
+use super::*;
 use crate::boxed::Box;
-use crate::collections::btree::navigate::Position;
-use crate::collections::btree::node;
-use crate::collections::btree_map::Entry::{Occupied, Vacant};
-use crate::collections::BTreeMap;
 use crate::fmt::Debug;
 use crate::rc::Rc;
-use crate::string::String;
-use crate::string::ToString;
+use crate::string::{String, ToString};
 use crate::vec::Vec;
 use std::convert::TryFrom;
 use std::iter::FromIterator;
@@ -16,19 +14,17 @@ use std::ops::RangeBounds;
 use std::panic::{catch_unwind, AssertUnwindSafe};
 use std::sync::atomic::{AtomicUsize, Ordering};
 
-use super::super::DeterministicRng;
-
 // Capacity of a tree with a single level,
-// i.e. a tree who's root is a leaf node at height 0.
+// i.e., a tree who's root is a leaf node at height 0.
 const NODE_CAPACITY: usize = node::CAPACITY;
 
 // Minimum number of elements to insert, to guarantee a tree with 2 levels,
-// i.e. a tree who's root is an internal node at height 1, with edges to leaf nodes.
+// i.e., a tree who's root is an internal node at height 1, with edges to leaf nodes.
 // It's not the minimum size: removing an element from such a tree does not always reduce height.
 const MIN_INSERTS_HEIGHT_1: usize = NODE_CAPACITY + 1;
 
 // Minimum number of elements to insert in ascending order, to guarantee a tree with 3 levels,
-// i.e. a tree who's root is an internal node at height 2, with edges to more internal nodes.
+// i.e., a tree who's root is an internal node at height 2, with edges to more internal nodes.
 // It's not the minimum size: removing an element from such a tree does not always reduce height.
 const MIN_INSERTS_HEIGHT_2: usize = 89;
 
@@ -1386,44 +1382,65 @@ fn test_clone_from() {
     }
 }
 
-#[test]
 #[allow(dead_code)]
 fn test_variance() {
-    use std::collections::btree_map::{IntoIter, Iter, Keys, Range, Values};
-
     fn map_key<'new>(v: BTreeMap<&'static str, ()>) -> BTreeMap<&'new str, ()> {
         v
     }
     fn map_val<'new>(v: BTreeMap<(), &'static str>) -> BTreeMap<(), &'new str> {
         v
     }
+
     fn iter_key<'a, 'new>(v: Iter<'a, &'static str, ()>) -> Iter<'a, &'new str, ()> {
         v
     }
     fn iter_val<'a, 'new>(v: Iter<'a, (), &'static str>) -> Iter<'a, (), &'new str> {
         v
     }
+
     fn into_iter_key<'new>(v: IntoIter<&'static str, ()>) -> IntoIter<&'new str, ()> {
         v
     }
     fn into_iter_val<'new>(v: IntoIter<(), &'static str>) -> IntoIter<(), &'new str> {
         v
     }
+
+    fn into_keys_key<'new>(v: IntoKeys<&'static str, ()>) -> IntoKeys<&'new str, ()> {
+        v
+    }
+    fn into_keys_val<'new>(v: IntoKeys<(), &'static str>) -> IntoKeys<(), &'new str> {
+        v
+    }
+
+    fn into_values_key<'new>(v: IntoValues<&'static str, ()>) -> IntoValues<&'new str, ()> {
+        v
+    }
+    fn into_values_val<'new>(v: IntoValues<(), &'static str>) -> IntoValues<(), &'new str> {
+        v
+    }
+
     fn range_key<'a, 'new>(v: Range<'a, &'static str, ()>) -> Range<'a, &'new str, ()> {
         v
     }
     fn range_val<'a, 'new>(v: Range<'a, (), &'static str>) -> Range<'a, (), &'new str> {
         v
     }
-    fn keys<'a, 'new>(v: Keys<'a, &'static str, ()>) -> Keys<'a, &'new str, ()> {
+
+    fn keys_key<'a, 'new>(v: Keys<'a, &'static str, ()>) -> Keys<'a, &'new str, ()> {
+        v
+    }
+    fn keys_val<'a, 'new>(v: Keys<'a, (), &'static str>) -> Keys<'a, (), &'new str> {
+        v
+    }
+
+    fn values_key<'a, 'new>(v: Values<'a, &'static str, ()>) -> Values<'a, &'new str, ()> {
         v
     }
-    fn vals<'a, 'new>(v: Values<'a, (), &'static str>) -> Values<'a, (), &'new str> {
+    fn values_val<'a, 'new>(v: Values<'a, (), &'static str>) -> Values<'a, (), &'new str> {
         v
     }
 }
 
-#[test]
 #[allow(dead_code)]
 fn test_sync() {
     fn map<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
@@ -1493,7 +1510,6 @@ fn test_sync() {
     }
 }
 
-#[test]
 #[allow(dead_code)]
 fn test_send() {
     fn map<T: Send>(v: BTreeMap<T, T>) -> impl Send {
@@ -1520,7 +1536,7 @@ fn test_send() {
         v.iter()
     }
 
-    fn iter_mut<T: Send + Sync>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+    fn iter_mut<T: Send>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
         v.iter_mut()
     }
 
@@ -1532,7 +1548,7 @@ fn test_send() {
         v.values()
     }
 
-    fn values_mut<T: Send + Sync>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+    fn values_mut<T: Send>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
         v.values_mut()
     }
 
@@ -1540,7 +1556,7 @@ fn test_send() {
         v.range(..)
     }
 
-    fn range_mut<T: Send + Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+    fn range_mut<T: Send + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
         v.range_mut(..)
     }
 
diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs
index f4e957e22fe..92674357282 100644
--- a/library/alloc/src/collections/btree/set/tests.rs
+++ b/library/alloc/src/collections/btree/set/tests.rs
@@ -1,11 +1,10 @@
-use crate::collections::BTreeSet;
+use super::super::DeterministicRng;
+use super::*;
 use crate::vec::Vec;
 use std::iter::FromIterator;
 use std::panic::{catch_unwind, AssertUnwindSafe};
 use std::sync::atomic::{AtomicU32, Ordering};
 
-use super::super::DeterministicRng;
-
 #[test]
 fn test_clone_eq() {
     let mut m = BTreeSet::new();
@@ -528,11 +527,8 @@ fn test_recovery() {
     assert_eq!(s.iter().next(), None);
 }
 
-#[test]
 #[allow(dead_code)]
 fn test_variance() {
-    use std::collections::btree_set::{IntoIter, Iter, Range};
-
     fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> {
         v
     }
@@ -545,6 +541,85 @@ fn test_variance() {
     fn range<'a, 'new>(v: Range<'a, &'static str>) -> Range<'a, &'new str> {
         v
     }
+    // not applied to Difference, Intersection, SymmetricDifference, Union
+}
+
+#[allow(dead_code)]
+fn test_sync() {
+    fn set<T: Sync>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v
+    }
+
+    fn iter<T: Sync>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v.iter()
+    }
+
+    fn into_iter<T: Sync>(v: BTreeSet<T>) -> impl Sync {
+        v.into_iter()
+    }
+
+    fn range<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v.range(..)
+    }
+
+    fn drain_filter<T: Sync + Ord>(v: &mut BTreeSet<T>) -> impl Sync + '_ {
+        v.drain_filter(|_| false)
+    }
+
+    fn difference<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v.difference(&v)
+    }
+
+    fn intersection<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v.intersection(&v)
+    }
+
+    fn symmetric_difference<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v.symmetric_difference(&v)
+    }
+
+    fn union<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v.union(&v)
+    }
+}
+
+#[allow(dead_code)]
+fn test_send() {
+    fn set<T: Send>(v: BTreeSet<T>) -> impl Send {
+        v
+    }
+
+    fn iter<T: Send + Sync>(v: &BTreeSet<T>) -> impl Send + '_ {
+        v.iter()
+    }
+
+    fn into_iter<T: Send>(v: BTreeSet<T>) -> impl Send {
+        v.into_iter()
+    }
+
+    fn range<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
+        v.range(..)
+    }
+
+    fn drain_filter<T: Send + Ord>(v: &mut BTreeSet<T>) -> impl Send + '_ {
+        v.drain_filter(|_| false)
+    }
+
+    fn difference<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
+        v.difference(&v)
+    }
+
+    fn intersection<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
+        v.intersection(&v)
+    }
+
+    fn symmetric_difference<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
+        v.symmetric_difference(&v)
+    }
+
+    fn union<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
+        v.union(&v)
+    }
 }
 
 #[test]
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index f12cefffbf6..114707b639b 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -554,8 +554,8 @@ impl<K, V, S> HashMap<K, V, S> {
     /// a.clear();
     /// assert!(a.is_empty());
     /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn clear(&mut self) {
         self.base.clear();
     }
@@ -746,8 +746,8 @@ where
     /// assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
     /// assert_eq!(map.get_key_value(&2), None);
     /// ```
-    #[stable(feature = "map_get_key_value", since = "1.40.0")]
     #[inline]
+    #[stable(feature = "map_get_key_value", since = "1.40.0")]
     pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
     where
         K: Borrow<Q>,
@@ -772,8 +772,8 @@ where
     /// assert_eq!(map.contains_key(&1), true);
     /// assert_eq!(map.contains_key(&2), false);
     /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
     where
         K: Borrow<Q>,
@@ -800,8 +800,8 @@ where
     /// }
     /// assert_eq!(map[&1], "b");
     /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
     where
         K: Borrow<Q>,
@@ -834,8 +834,8 @@ where
     /// assert_eq!(map.insert(37, "c"), Some("b"));
     /// assert_eq!(map[&37], "c");
     /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, k: K, v: V) -> Option<V> {
         self.base.insert(k, v)
     }
@@ -857,8 +857,8 @@ where
     /// assert_eq!(map.remove(&1), Some("a"));
     /// assert_eq!(map.remove(&1), None);
     /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
     where
         K: Borrow<Q>,
@@ -886,8 +886,8 @@ where
     /// assert_eq!(map.remove(&1), None);
     /// # }
     /// ```
-    #[stable(feature = "hash_map_remove_entry", since = "1.27.0")]
     #[inline]
+    #[stable(feature = "hash_map_remove_entry", since = "1.27.0")]
     pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)>
     where
         K: Borrow<Q>,
@@ -909,8 +909,8 @@ where
     /// map.retain(|&k, _| k % 2 == 0);
     /// assert_eq!(map.len(), 4);
     /// ```
-    #[stable(feature = "retain_hash_collection", since = "1.18.0")]
     #[inline]
+    #[stable(feature = "retain_hash_collection", since = "1.18.0")]
     pub fn retain<F>(&mut self, f: F)
     where
         F: FnMut(&K, &mut V) -> bool,
@@ -1647,7 +1647,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> {
         self.base.get()
     }
 
-    /// Converts the OccupiedEntry into a mutable reference to the value in the entry
+    /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry
     /// with a lifetime bound to the map itself.
     #[inline]
     #[unstable(feature = "hash_raw_entry", issue = "56167")]
@@ -1676,7 +1676,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> {
         self.base.get_key_value_mut()
     }
 
-    /// Converts the OccupiedEntry into a mutable reference to the key and value in the entry
+    /// Converts the `OccupiedEntry` into a mutable reference to the key and value in the entry
     /// with a lifetime bound to the map itself.
     #[inline]
     #[unstable(feature = "hash_raw_entry", issue = "56167")]
@@ -1714,7 +1714,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> {
 }
 
 impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
-    /// Sets the value of the entry with the VacantEntry's key,
+    /// Sets the value of the entry with the `VacantEntry`'s key,
     /// and returns a mutable reference to it.
     #[inline]
     #[unstable(feature = "hash_raw_entry", issue = "56167")]
@@ -2173,7 +2173,6 @@ where
 }
 
 impl<'a, K, V> Entry<'a, K, V> {
-    #[stable(feature = "rust1", since = "1.0.0")]
     /// Ensures a value is in the entry by inserting the default if empty, and returns
     /// a mutable reference to the value in the entry.
     ///
@@ -2191,6 +2190,7 @@ impl<'a, K, V> Entry<'a, K, V> {
     /// assert_eq!(map["poneyland"], 6);
     /// ```
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn or_insert(self, default: V) -> &'a mut V {
         match self {
             Occupied(entry) => entry.into_mut(),
@@ -2198,7 +2198,6 @@ impl<'a, K, V> Entry<'a, K, V> {
         }
     }
 
-    #[stable(feature = "rust1", since = "1.0.0")]
     /// Ensures a value is in the entry by inserting the result of the default function if empty,
     /// and returns a mutable reference to the value in the entry.
     ///
@@ -2215,6 +2214,7 @@ impl<'a, K, V> Entry<'a, K, V> {
     /// assert_eq!(map["poneyland"], "hoho".to_string());
     /// ```
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
         match self {
             Occupied(entry) => entry.into_mut(),
@@ -2222,7 +2222,6 @@ impl<'a, K, V> Entry<'a, K, V> {
         }
     }
 
-    #[unstable(feature = "or_insert_with_key", issue = "71024")]
     /// Ensures a value is in the entry by inserting, if empty, the result of the default function,
     /// which takes the key as its argument, and returns a mutable reference to the value in the
     /// entry.
@@ -2240,6 +2239,7 @@ impl<'a, K, V> Entry<'a, K, V> {
     /// assert_eq!(map["poneyland"], 9);
     /// ```
     #[inline]
+    #[unstable(feature = "or_insert_with_key", issue = "71024")]
     pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V {
         match self {
             Occupied(entry) => entry.into_mut(),
@@ -2304,7 +2304,7 @@ impl<'a, K, V> Entry<'a, K, V> {
         }
     }
 
-    /// Sets the value of the entry, and returns an OccupiedEntry.
+    /// Sets the value of the entry, and returns an `OccupiedEntry`.
     ///
     /// # Examples
     ///
@@ -2331,7 +2331,6 @@ impl<'a, K, V> Entry<'a, K, V> {
 }
 
 impl<'a, K, V: Default> Entry<'a, K, V> {
-    #[stable(feature = "entry_or_default", since = "1.28.0")]
     /// Ensures a value is in the entry by inserting the default value if empty,
     /// and returns a mutable reference to the value in the entry.
     ///
@@ -2348,6 +2347,7 @@ impl<'a, K, V: Default> Entry<'a, K, V> {
     /// # }
     /// ```
     #[inline]
+    #[stable(feature = "entry_or_default", since = "1.28.0")]
     pub fn or_default(self) -> &'a mut V {
         match self {
             Occupied(entry) => entry.into_mut(),
@@ -2452,7 +2452,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
         self.base.get_mut()
     }
 
-    /// Converts the OccupiedEntry into a mutable reference to the value in the entry
+    /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry
     /// with a lifetime bound to the map itself.
     ///
     /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
@@ -2624,7 +2624,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
         self.base.into_key()
     }
 
-    /// Sets the value of the entry with the VacantEntry's key,
+    /// Sets the value of the entry with the `VacantEntry`'s key,
     /// and returns a mutable reference to it.
     ///
     /// # Examples
@@ -2646,8 +2646,8 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
         self.base.insert(value)
     }
 
-    /// Sets the value of the entry with the VacantEntry's key,
-    /// and returns an OccupiedEntry.
+    /// Sets the value of the entry with the `VacantEntry`'s key,
+    /// and returns an `OccupiedEntry`.
     ///
     /// # Examples
     ///
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 8fbfb04bac3..d70446d2574 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -370,32 +370,22 @@ impl<I: IntoIterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I {
 /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
 /// kept separate because of issue #42760.
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum DocFragment {
+pub struct DocFragment {
+    pub line: usize,
+    pub span: rustc_span::Span,
+    pub doc: String,
+    pub kind: DocFragmentKind,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum DocFragmentKind {
     /// A doc fragment created from a `///` or `//!` doc comment.
-    SugaredDoc(usize, rustc_span::Span, String),
+    SugaredDoc,
     /// A doc fragment created from a "raw" `#[doc=""]` attribute.
-    RawDoc(usize, rustc_span::Span, String),
+    RawDoc,
     /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
     /// given filename and the file contents.
-    Include(usize, rustc_span::Span, String, String),
-}
-
-impl DocFragment {
-    pub fn as_str(&self) -> &str {
-        match *self {
-            DocFragment::SugaredDoc(_, _, ref s) => &s[..],
-            DocFragment::RawDoc(_, _, ref s) => &s[..],
-            DocFragment::Include(_, _, _, ref s) => &s[..],
-        }
-    }
-
-    pub fn span(&self) -> rustc_span::Span {
-        match *self {
-            DocFragment::SugaredDoc(_, span, _)
-            | DocFragment::RawDoc(_, span, _)
-            | DocFragment::Include(_, span, _, _) => span,
-        }
-    }
+    Include { filename: String },
 }
 
 impl<'a> FromIterator<&'a DocFragment> for String {
@@ -407,12 +397,7 @@ impl<'a> FromIterator<&'a DocFragment> for String {
             if !acc.is_empty() {
                 acc.push('\n');
             }
-            match *frag {
-                DocFragment::SugaredDoc(_, _, ref docs)
-                | DocFragment::RawDoc(_, _, ref docs)
-                | DocFragment::Include(_, _, _, ref docs) => acc.push_str(docs),
-            }
-
+            acc.push_str(&frag.doc);
             acc
         })
     }
@@ -547,15 +532,15 @@ impl Attributes {
             .filter_map(|attr| {
                 if let Some(value) = attr.doc_str() {
                     let value = beautify_doc_string(value);
-                    let mk_fragment: fn(_, _, _) -> _ = if attr.is_doc_comment() {
-                        DocFragment::SugaredDoc
+                    let kind = if attr.is_doc_comment() {
+                        DocFragmentKind::SugaredDoc
                     } else {
-                        DocFragment::RawDoc
+                        DocFragmentKind::RawDoc
                     };
 
                     let line = doc_line;
                     doc_line += value.lines().count();
-                    doc_strings.push(mk_fragment(line, attr.span, value));
+                    doc_strings.push(DocFragment { line, span: attr.span, doc: value, kind });
 
                     if sp.is_none() {
                         sp = Some(attr.span);
@@ -575,9 +560,12 @@ impl Attributes {
                             {
                                 let line = doc_line;
                                 doc_line += contents.lines().count();
-                                doc_strings.push(DocFragment::Include(
-                                    line, attr.span, filename, contents,
-                                ));
+                                doc_strings.push(DocFragment {
+                                    line,
+                                    span: attr.span,
+                                    doc: contents,
+                                    kind: DocFragmentKind::Include { filename },
+                                });
                             }
                         }
                     }
@@ -621,7 +609,7 @@ impl Attributes {
     /// Finds the `doc` attribute as a NameValue and returns the corresponding
     /// value found.
     pub fn doc_value(&self) -> Option<&str> {
-        self.doc_strings.first().map(|s| s.as_str())
+        self.doc_strings.first().map(|s| s.doc.as_str())
     }
 
     /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 935b96e51fc..3f4bd2886b1 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -120,7 +120,7 @@ h3.impl, h3.method, h3.type {
 }
 
 h1, h2, h3, h4,
-.sidebar, a.source, .search-input, .content table :not(code)>a,
+.sidebar, a.source, .search-input, .content table td:first-child > a,
 .collapse-toggle, div.item-list .out-of-band,
 #source-sidebar, #sidebar-toggle {
 	font-family: "Fira Sans", sans-serif;
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 671e0825567..4bca3996eb4 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -232,7 +232,12 @@ impl fold::DocFolder for CoverageCalculator {
                 let mut tests = Tests { found_tests: 0 };
 
                 find_testable_code(
-                    &i.attrs.doc_strings.iter().map(|d| d.as_str()).collect::<Vec<_>>().join("\n"),
+                    &i.attrs
+                        .doc_strings
+                        .iter()
+                        .map(|d| d.doc.as_str())
+                        .collect::<Vec<_>>()
+                        .join("\n"),
                     &mut tests,
                     ErrorCodes::No,
                     false,
diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs
index c2185592d14..be7250f833f 100644
--- a/src/librustdoc/passes/collapse_docs.rs
+++ b/src/librustdoc/passes/collapse_docs.rs
@@ -1,4 +1,4 @@
-use crate::clean::{self, DocFragment, Item};
+use crate::clean::{self, DocFragment, DocFragmentKind, Item};
 use crate::core::DocContext;
 use crate::fold;
 use crate::fold::DocFolder;
@@ -12,23 +12,6 @@ pub const COLLAPSE_DOCS: Pass = Pass {
     description: "concatenates all document attributes into one document attribute",
 };
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum DocFragmentKind {
-    Sugared,
-    Raw,
-    Include,
-}
-
-impl DocFragment {
-    fn kind(&self) -> DocFragmentKind {
-        match *self {
-            DocFragment::SugaredDoc(..) => DocFragmentKind::Sugared,
-            DocFragment::RawDoc(..) => DocFragmentKind::Raw,
-            DocFragment::Include(..) => DocFragmentKind::Include,
-        }
-    }
-}
-
 pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
     let mut krate = Collapser.fold_crate(krate);
     krate.collapsed = true;
@@ -50,30 +33,22 @@ fn collapse(doc_strings: &mut Vec<DocFragment>) {
 
     for frag in take(doc_strings) {
         if let Some(mut curr_frag) = last_frag.take() {
-            let curr_kind = curr_frag.kind();
-            let new_kind = frag.kind();
+            let curr_kind = &curr_frag.kind;
+            let new_kind = &frag.kind;
 
-            if curr_kind == DocFragmentKind::Include || curr_kind != new_kind {
-                match curr_frag {
-                    DocFragment::SugaredDoc(_, _, ref mut doc_string)
-                    | DocFragment::RawDoc(_, _, ref mut doc_string) => {
-                        // add a newline for extra padding between segments
-                        doc_string.push('\n');
-                    }
-                    _ => {}
+            if matches!(*curr_kind, DocFragmentKind::Include { .. }) || curr_kind != new_kind {
+                if *curr_kind == DocFragmentKind::SugaredDoc
+                    || *curr_kind == DocFragmentKind::RawDoc
+                {
+                    // add a newline for extra padding between segments
+                    curr_frag.doc.push('\n');
                 }
                 docs.push(curr_frag);
                 last_frag = Some(frag);
             } else {
-                match curr_frag {
-                    DocFragment::SugaredDoc(_, ref mut span, ref mut doc_string)
-                    | DocFragment::RawDoc(_, ref mut span, ref mut doc_string) => {
-                        doc_string.push('\n');
-                        doc_string.push_str(frag.as_str());
-                        *span = span.to(frag.span());
-                    }
-                    _ => unreachable!(),
-                }
+                curr_frag.doc.push('\n');
+                curr_frag.doc.push_str(&frag.doc);
+                curr_frag.span = curr_frag.span.to(frag.span);
                 last_frag = Some(curr_frag);
             }
         } else {
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 75a65966667..f8e395bfb41 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -8,7 +8,7 @@ use std::mem;
 use std::ops::Range;
 
 use self::Condition::*;
-use crate::clean::{self, GetDefId, Item};
+use crate::clean::{self, DocFragmentKind, GetDefId, Item};
 use crate::core::DocContext;
 use crate::fold::{DocFolder, StripItem};
 
@@ -314,11 +314,11 @@ crate fn span_of_attrs(attrs: &clean::Attributes) -> Option<Span> {
     if attrs.doc_strings.is_empty() {
         return None;
     }
-    let start = attrs.doc_strings[0].span();
+    let start = attrs.doc_strings[0].span;
     if start == DUMMY_SP {
         return None;
     }
-    let end = attrs.doc_strings.last().expect("no doc strings provided").span();
+    let end = attrs.doc_strings.last().expect("no doc strings provided").span;
     Some(start.to(end))
 }
 
@@ -333,10 +333,8 @@ crate fn source_span_for_markdown_range(
     md_range: &Range<usize>,
     attrs: &clean::Attributes,
 ) -> Option<Span> {
-    let is_all_sugared_doc = attrs.doc_strings.iter().all(|frag| match frag {
-        clean::DocFragment::SugaredDoc(..) => true,
-        _ => false,
-    });
+    let is_all_sugared_doc =
+        attrs.doc_strings.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
 
     if !is_all_sugared_doc {
         return None;
diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs
index 5604a9c2dc1..a9cf5a87f54 100644
--- a/src/librustdoc/passes/unindent_comments.rs
+++ b/src/librustdoc/passes/unindent_comments.rs
@@ -36,13 +36,7 @@ impl clean::Attributes {
 
 fn unindent_fragments(docs: &mut Vec<DocFragment>) {
     for fragment in docs {
-        match *fragment {
-            DocFragment::SugaredDoc(_, _, ref mut doc_string)
-            | DocFragment::RawDoc(_, _, ref mut doc_string)
-            | DocFragment::Include(_, _, _, ref mut doc_string) => {
-                *doc_string = unindent(doc_string)
-            }
-        }
+        fragment.doc = unindent(&fragment.doc);
     }
 }
 
diff --git a/src/test/ui/issues/issue-69532.rs b/src/test/ui/issues/issue-69532.rs
new file mode 100644
index 00000000000..81007b15074
--- /dev/null
+++ b/src/test/ui/issues/issue-69532.rs
@@ -0,0 +1,24 @@
+// run-pass
+#![feature(const_fn_transmute)]
+
+const fn make_nans() -> (f64, f64, f32, f32) {
+    let nan1: f64 = unsafe { std::mem::transmute(0x7FF0_0001_0000_0001u64) };
+    let nan2: f64 = unsafe { std::mem::transmute(0x7FF0_0000_0000_0001u64) };
+
+    let nan1_32 = nan1 as f32;
+    let nan2_32 = nan2 as f32;
+
+    (nan1, nan2, nan1_32, nan2_32)
+}
+
+static NANS: (f64, f64, f32, f32) = make_nans();
+
+fn main() {
+    let (nan1, nan2, nan1_32, nan2_32) = NANS;
+
+    assert!(nan1.is_nan());
+    assert!(nan2.is_nan());
+
+    assert!(nan1_32.is_nan());
+    assert!(nan2_32.is_nan());
+}
diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs
index a719b314150..7d68af49e28 100644
--- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs
+++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs
@@ -49,8 +49,8 @@ fn main() {
         simd_select(m4, 0u32, 1u32);
         //~^ ERROR found non-SIMD `u32`
 
-        simd_select_bitmask(0u8, x, x);
-        //~^ ERROR mask length `8` != other vector length `4`
+        simd_select_bitmask(0u16, x, x);
+        //~^ ERROR mask length `16` != other vector length `4`
         //
         simd_select_bitmask(0u8, 1u32, 2u32);
         //~^ ERROR found non-SIMD `u32`
diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr
index f68c969d13e..a1ef0bb8ee0 100644
--- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr
+++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr
@@ -22,11 +22,11 @@ error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD
 LL |         simd_select(m4, 0u32, 1u32);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `8` != other vector length `4`
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `16` != other vector length `4`
   --> $DIR/simd-intrinsic-generic-select.rs:52:9
    |
-LL |         simd_select_bitmask(0u8, x, x);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_select_bitmask(0u16, x, x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32`
   --> $DIR/simd-intrinsic-generic-select.rs:55:9
diff --git a/src/test/ui/simd/simd-intrinsic-generic-select.rs b/src/test/ui/simd/simd-intrinsic-generic-select.rs
index dc9ec5d2760..b850cf9750a 100644
--- a/src/test/ui/simd/simd-intrinsic-generic-select.rs
+++ b/src/test/ui/simd/simd-intrinsic-generic-select.rs
@@ -167,4 +167,29 @@ fn main() {
         let e = u32x8(8, 9, 10, 11, 4, 5, 6, 7);
         assert_eq!(r, e);
     }
+
+    unsafe {
+        let a = u32x4(0, 1, 2, 3);
+        let b = u32x4(4, 5, 6, 7);
+
+        let r: u32x4 = simd_select_bitmask(0u8, a, b);
+        let e = b;
+        assert_eq!(r, e);
+
+        let r: u32x4 = simd_select_bitmask(0xfu8, a, b);
+        let e = a;
+        assert_eq!(r, e);
+
+        let r: u32x4 = simd_select_bitmask(0b0101u8, a, b);
+        let e = u32x4(0, 5, 2, 7);
+        assert_eq!(r, e);
+
+        let r: u32x4 = simd_select_bitmask(0b1010u8, a, b);
+        let e = u32x4(4, 1, 6, 3);
+        assert_eq!(r, e);
+
+        let r: u32x4 = simd_select_bitmask(0b1100u8, a, b);
+        let e = u32x4(4, 5, 2, 3);
+        assert_eq!(r, e);
+    }
 }