about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-03-13 20:59:29 +0000
committerbors <bors@rust-lang.org>2022-03-13 20:59:29 +0000
commite95b10ba4ac4564ed25f7eef143e3182c33b3902 (patch)
tree15d3fac2d0464ef9f8f6f9963eb9e13bebddc502
parent21b0325c68421b00c6c91055ac330bd5ffe1ea6b (diff)
parentc7030d3eb36ffe024e795eb9e6eeba0ebcbb1cd4 (diff)
downloadrust-e95b10ba4ac4564ed25f7eef143e3182c33b3902.tar.gz
rust-e95b10ba4ac4564ed25f7eef143e3182c33b3902.zip
Auto merge of #94916 - matthiaskrgr:rollup-s6zedfl, r=matthiaskrgr
Rollup of 5 pull requests

Successful merges:

 - #93292 (Implement `BITS` constant for non-zero integers)
 - #94777 (Update armv7-unknown-linux-uclibceabi platform support page.)
 - #94816 (Add `Atomic*::get_mut_slice`)
 - #94844 (Reduce rustbuild bloat caused by serde_derive)
 - #94907 (Omit stdarch test crates from the rust-src component)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--library/core/src/num/nonzero.rs40
-rw-r--r--library/core/src/sync/atomic.rs110
-rw-r--r--src/bootstrap/config.rs386
-rw-r--r--src/bootstrap/dist.rs5
-rw-r--r--src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md32
5 files changed, 397 insertions, 176 deletions
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 5bdd78aa2de..c3652931478 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -465,7 +465,7 @@ macro_rules! nonzero_unsigned_operations {
                               without modifying the original"]
                 #[inline]
                 pub const fn log2(self) -> u32 {
-                    <$Int>::BITS - 1 - self.leading_zeros()
+                    Self::BITS - 1 - self.leading_zeros()
                 }
 
                 /// Returns the base 10 logarithm of the number, rounded down.
@@ -1090,3 +1090,41 @@ nonzero_min_max_signed! {
     NonZeroI128(i128);
     NonZeroIsize(isize);
 }
+
+macro_rules! nonzero_bits {
+    ( $( $Ty: ident($Int: ty); )+ ) => {
+        $(
+            impl $Ty {
+                /// The size of this non-zero integer type in bits.
+                ///
+                #[doc = concat!("This value is equal to [`", stringify!($Int), "::BITS`].")]
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_bits)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::BITS, ", stringify!($Int), "::BITS);")]
+                /// ```
+                #[unstable(feature = "nonzero_bits", issue = "94881")]
+                pub const BITS: u32 = <$Int>::BITS;
+            }
+        )+
+    }
+}
+
+nonzero_bits! {
+    NonZeroU8(u8);
+    NonZeroI8(i8);
+    NonZeroU16(u16);
+    NonZeroI16(i16);
+    NonZeroU32(u32);
+    NonZeroI32(i32);
+    NonZeroU64(u64);
+    NonZeroI64(i64);
+    NonZeroU128(u128);
+    NonZeroI128(i128);
+    NonZeroUsize(usize);
+    NonZeroIsize(isize);
+}
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 62103f5b075..a9edec80540 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -340,6 +340,40 @@ impl AtomicBool {
         unsafe { &mut *(v as *mut bool as *mut Self) }
     }
 
+    /// Get non-atomic access to a `&mut [AtomicBool]` slice.
+    ///
+    /// This is safe because the mutable reference guarantees that no other threads are
+    /// concurrently accessing the atomic data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(atomic_from_mut, inline_const, scoped_threads)]
+    /// use std::sync::atomic::{AtomicBool, Ordering};
+    ///
+    /// let mut some_bools = [const { AtomicBool::new(false) }; 10];
+    ///
+    /// let view: &mut [bool] = AtomicBool::get_mut_slice(&mut some_bools);
+    /// assert_eq!(view, [false; 10]);
+    /// view[..5].copy_from_slice(&[true; 5]);
+    ///
+    /// std::thread::scope(|s| {
+    ///     for t in &some_bools[..5] {
+    ///         s.spawn(move || assert_eq!(t.load(Ordering::Relaxed), true));
+    ///     }
+    ///
+    ///     for f in &some_bools[5..] {
+    ///         s.spawn(move || assert_eq!(f.load(Ordering::Relaxed), false));
+    ///     }
+    /// });
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_from_mut", issue = "76314")]
+    pub fn get_mut_slice(this: &mut [Self]) -> &mut [bool] {
+        // SAFETY: the mutable reference guarantees unique ownership.
+        unsafe { &mut *(this as *mut [Self] as *mut [bool]) }
+    }
+
     /// Get atomic access to a `&mut [bool]` slice.
     ///
     /// # Examples
@@ -971,6 +1005,46 @@ impl<T> AtomicPtr<T> {
         unsafe { &mut *(v as *mut *mut T as *mut Self) }
     }
 
+    /// Get non-atomic access to a `&mut [AtomicPtr]` slice.
+    ///
+    /// This is safe because the mutable reference guarantees that no other threads are
+    /// concurrently accessing the atomic data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(atomic_from_mut, inline_const, scoped_threads)]
+    /// use std::ptr::null_mut;
+    /// use std::sync::atomic::{AtomicPtr, Ordering};
+    ///
+    /// let mut some_ptrs = [const { AtomicPtr::new(null_mut::<String>()) }; 10];
+    ///
+    /// let view: &mut [*mut String] = AtomicPtr::get_mut_slice(&mut some_ptrs);
+    /// assert_eq!(view, [null_mut::<String>(); 10]);
+    /// view
+    ///     .iter_mut()
+    ///     .enumerate()
+    ///     .for_each(|(i, ptr)| *ptr = Box::into_raw(Box::new(format!("iteration#{i}"))));
+    ///
+    /// std::thread::scope(|s| {
+    ///     for ptr in &some_ptrs {
+    ///         s.spawn(move || {
+    ///             let ptr = ptr.load(Ordering::Relaxed);
+    ///             assert!(!ptr.is_null());
+    ///
+    ///             let name = unsafe { Box::from_raw(ptr) };
+    ///             println!("Hello, {name}!");
+    ///         });
+    ///     }
+    /// });
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_from_mut", issue = "76314")]
+    pub fn get_mut_slice(this: &mut [Self]) -> &mut [*mut T] {
+        // SAFETY: the mutable reference guarantees unique ownership.
+        unsafe { &mut *(this as *mut [Self] as *mut [*mut T]) }
+    }
+
     /// Get atomic access to a slice of pointers.
     ///
     /// # Examples
@@ -1521,6 +1595,42 @@ macro_rules! atomic_int {
                 unsafe { &mut *(v as *mut $int_type as *mut Self) }
             }
 
+            #[doc = concat!("Get non-atomic access to a `&mut [", stringify!($atomic_type), "]` slice")]
+            ///
+            /// This is safe because the mutable reference guarantees that no other threads are
+            /// concurrently accessing the atomic data.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// #![feature(atomic_from_mut, inline_const, scoped_threads)]
+            #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
+            ///
+            #[doc = concat!("let mut some_ints = [const { ", stringify!($atomic_type), "::new(0) }; 10];")]
+            ///
+            #[doc = concat!("let view: &mut [", stringify!($int_type), "] = ", stringify!($atomic_type), "::get_mut_slice(&mut some_ints);")]
+            /// assert_eq!(view, [0; 10]);
+            /// view
+            ///     .iter_mut()
+            ///     .enumerate()
+            ///     .for_each(|(idx, int)| *int = idx as _);
+            ///
+            /// std::thread::scope(|s| {
+            ///     some_ints
+            ///         .iter()
+            ///         .enumerate()
+            ///         .for_each(|(idx, int)| {
+            ///             s.spawn(move || assert_eq!(int.load(Ordering::Relaxed), idx as _));
+            ///         })
+            /// });
+            /// ```
+            #[inline]
+            #[unstable(feature = "atomic_from_mut", issue = "76314")]
+            pub fn get_mut_slice(this: &mut [Self]) -> &mut [$int_type] {
+                // SAFETY: the mutable reference guarantees unique ownership.
+                unsafe { &mut *(this as *mut [Self] as *mut [$int_type]) }
+            }
+
             #[doc = concat!("Get atomic access to a `&mut [", stringify!($int_type), "]` slice.")]
             ///
             /// # Examples
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 0c0a4733231..e744810295d 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -17,7 +17,7 @@ use crate::channel::GitInfo;
 pub use crate::flags::Subcommand;
 use crate::flags::{Color, Flags};
 use crate::util::{exe, t};
-use serde::Deserialize;
+use serde::{Deserialize, Deserializer};
 
 macro_rules! check_ci_llvm {
     ($name:expr) => {
@@ -362,13 +362,13 @@ impl Merge for TomlConfig {
 
 // We are using a decl macro instead of a derive proc macro here to reduce the compile time of
 // rustbuild.
-macro_rules! derive_merge {
+macro_rules! define_config {
     ($(#[$attr:meta])* struct $name:ident {
-        $($field:ident: $field_ty:ty,)*
+        $($field:ident: Option<$field_ty:ty> = $field_key:literal,)*
     }) => {
         $(#[$attr])*
         struct $name {
-            $($field: $field_ty,)*
+            $($field: Option<$field_ty>,)*
         }
 
         impl Merge for $name {
@@ -380,115 +380,173 @@ macro_rules! derive_merge {
                 )*
             }
         }
+
+        // The following is a trimmed version of what serde_derive generates. All parts not relevant
+        // for toml deserialization have been removed. This reduces the binary size and improves
+        // compile time of rustbuild.
+        impl<'de> Deserialize<'de> for $name {
+            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+            where
+                D: Deserializer<'de>,
+            {
+                struct Field;
+                impl<'de> serde::de::Visitor<'de> for Field {
+                    type Value = $name;
+                    fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                        f.write_str(concat!("struct ", stringify!($name)))
+                    }
+
+                    #[inline]
+                    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
+                    where
+                        A: serde::de::MapAccess<'de>,
+                    {
+                        $(let mut $field: Option<$field_ty> = None;)*
+                        while let Some(key) =
+                            match serde::de::MapAccess::next_key::<String>(&mut map) {
+                                Ok(val) => val,
+                                Err(err) => {
+                                    return Err(err);
+                                }
+                            }
+                        {
+                            match &*key {
+                                $($field_key => {
+                                    if $field.is_some() {
+                                        return Err(<A::Error as serde::de::Error>::duplicate_field(
+                                            $field_key,
+                                        ));
+                                    }
+                                    $field = match serde::de::MapAccess::next_value::<$field_ty>(
+                                        &mut map,
+                                    ) {
+                                        Ok(val) => Some(val),
+                                        Err(err) => {
+                                            return Err(err);
+                                        }
+                                    };
+                                })*
+                                key => {
+                                    return Err(serde::de::Error::unknown_field(key, FIELDS));
+                                }
+                            }
+                        }
+                        Ok($name { $($field),* })
+                    }
+                }
+                const FIELDS: &'static [&'static str] = &[
+                    $($field_key,)*
+                ];
+                Deserializer::deserialize_struct(
+                    deserializer,
+                    stringify!($name),
+                    FIELDS,
+                    Field,
+                )
+            }
+        }
     }
 }
 
-derive_merge! {
+define_config! {
     /// TOML representation of various global build decisions.
-    #[derive(Deserialize, Default)]
-    #[serde(deny_unknown_fields, rename_all = "kebab-case")]
+    #[derive(Default)]
     struct Build {
-        build: Option<String>,
-        host: Option<Vec<String>>,
-        target: Option<Vec<String>>,
-        build_dir: Option<String>,
-        cargo: Option<String>,
-        rustc: Option<String>,
-        rustfmt: Option<PathBuf>,
-        docs: Option<bool>,
-        compiler_docs: Option<bool>,
-        docs_minification: Option<bool>,
-        submodules: Option<bool>,
-        fast_submodules: Option<bool>,
-        gdb: Option<String>,
-        nodejs: Option<String>,
-        npm: Option<String>,
-        python: Option<String>,
-        locked_deps: Option<bool>,
-        vendor: Option<bool>,
-        full_bootstrap: Option<bool>,
-        extended: Option<bool>,
-        tools: Option<HashSet<String>>,
-        verbose: Option<usize>,
-        sanitizers: Option<bool>,
-        profiler: Option<bool>,
-        cargo_native_static: Option<bool>,
-        low_priority: Option<bool>,
-        configure_args: Option<Vec<String>>,
-        local_rebuild: Option<bool>,
-        print_step_timings: Option<bool>,
-        print_step_rusage: Option<bool>,
-        check_stage: Option<u32>,
-        doc_stage: Option<u32>,
-        build_stage: Option<u32>,
-        test_stage: Option<u32>,
-        install_stage: Option<u32>,
-        dist_stage: Option<u32>,
-        bench_stage: Option<u32>,
-        patch_binaries_for_nix: Option<bool>,
+        build: Option<String> = "build",
+        host: Option<Vec<String>> = "host",
+        target: Option<Vec<String>> = "target",
+        build_dir: Option<String> = "build-dir",
+        cargo: Option<String> = "cargo",
+        rustc: Option<String> = "rustc",
+        rustfmt: Option<PathBuf> = "rustfmt",
+        docs: Option<bool> = "docs",
+        compiler_docs: Option<bool> = "compiler-docs",
+        docs_minification: Option<bool> = "docs-minification",
+        submodules: Option<bool> = "submodules",
+        fast_submodules: Option<bool> = "fast-submodules",
+        gdb: Option<String> = "gdb",
+        nodejs: Option<String> = "nodejs",
+        npm: Option<String> = "npm",
+        python: Option<String> = "python",
+        locked_deps: Option<bool> = "locked-deps",
+        vendor: Option<bool> = "vendor",
+        full_bootstrap: Option<bool> = "full-bootstrap",
+        extended: Option<bool> = "extended",
+        tools: Option<HashSet<String>> = "tools",
+        verbose: Option<usize> = "verbose",
+        sanitizers: Option<bool> = "sanitizers",
+        profiler: Option<bool> = "profiler",
+        cargo_native_static: Option<bool> = "cargo-native-static",
+        low_priority: Option<bool> = "low-priority",
+        configure_args: Option<Vec<String>> = "configure-args",
+        local_rebuild: Option<bool> = "local-rebuild",
+        print_step_timings: Option<bool> = "print-step-timings",
+        print_step_rusage: Option<bool> = "print-step-rusage",
+        check_stage: Option<u32> = "check-stage",
+        doc_stage: Option<u32> = "doc-stage",
+        build_stage: Option<u32> = "build-stage",
+        test_stage: Option<u32> = "test-stage",
+        install_stage: Option<u32> = "install-stage",
+        dist_stage: Option<u32> = "dist-stage",
+        bench_stage: Option<u32> = "bench-stage",
+        patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
     }
 }
 
-derive_merge! {
+define_config! {
     /// TOML representation of various global install decisions.
-    #[derive(Deserialize)]
-    #[serde(deny_unknown_fields, rename_all = "kebab-case")]
     struct Install {
-        prefix: Option<String>,
-        sysconfdir: Option<String>,
-        docdir: Option<String>,
-        bindir: Option<String>,
-        libdir: Option<String>,
-        mandir: Option<String>,
-        datadir: Option<String>,
+        prefix: Option<String> = "prefix",
+        sysconfdir: Option<String> = "sysconfdir",
+        docdir: Option<String> = "docdir",
+        bindir: Option<String> = "bindir",
+        libdir: Option<String> = "libdir",
+        mandir: Option<String> = "mandir",
+        datadir: Option<String> = "datadir",
     }
 }
 
-derive_merge! {
+define_config! {
     /// TOML representation of how the LLVM build is configured.
-    #[derive(Deserialize)]
-    #[serde(deny_unknown_fields, rename_all = "kebab-case")]
     struct Llvm {
-        skip_rebuild: Option<bool>,
-        optimize: Option<bool>,
-        thin_lto: Option<bool>,
-        release_debuginfo: Option<bool>,
-        assertions: Option<bool>,
-        tests: Option<bool>,
-        plugins: Option<bool>,
-        ccache: Option<StringOrBool>,
-        version_check: Option<bool>,
-        static_libstdcpp: Option<bool>,
-        ninja: Option<bool>,
-        targets: Option<String>,
-        experimental_targets: Option<String>,
-        link_jobs: Option<u32>,
-        link_shared: Option<bool>,
-        version_suffix: Option<String>,
-        clang_cl: Option<String>,
-        cflags: Option<String>,
-        cxxflags: Option<String>,
-        ldflags: Option<String>,
-        use_libcxx: Option<bool>,
-        use_linker: Option<String>,
-        allow_old_toolchain: Option<bool>,
-        polly: Option<bool>,
-        clang: Option<bool>,
-        download_ci_llvm: Option<StringOrBool>,
-        build_config: Option<HashMap<String, String>>,
+        skip_rebuild: Option<bool> = "skip-rebuild",
+        optimize: Option<bool> = "optimize",
+        thin_lto: Option<bool> = "thin-lto",
+        release_debuginfo: Option<bool> = "release-debuginfo",
+        assertions: Option<bool> = "assertions",
+        tests: Option<bool> = "tests",
+        plugins: Option<bool> = "plugins",
+        ccache: Option<StringOrBool> = "ccache",
+        version_check: Option<bool> = "version-check",
+        static_libstdcpp: Option<bool> = "static-libstdcpp",
+        ninja: Option<bool> = "ninja",
+        targets: Option<String> = "targets",
+        experimental_targets: Option<String> = "experimental-targets",
+        link_jobs: Option<u32> = "link-jobs",
+        link_shared: Option<bool> = "link-shared",
+        version_suffix: Option<String> = "version-suffix",
+        clang_cl: Option<String> = "clang-cl",
+        cflags: Option<String> = "cflags",
+        cxxflags: Option<String> = "cxxflags",
+        ldflags: Option<String> = "ldflags",
+        use_libcxx: Option<bool> = "use-libcxx",
+        use_linker: Option<String> = "use-linker",
+        allow_old_toolchain: Option<bool> = "allow-old-toolchain",
+        polly: Option<bool> = "polly",
+        clang: Option<bool> = "clang",
+        download_ci_llvm: Option<StringOrBool> = "download-ci-llvm",
+        build_config: Option<HashMap<String, String>> = "build-config",
     }
 }
 
-derive_merge! {
-    #[derive(Deserialize)]
-    #[serde(deny_unknown_fields, rename_all = "kebab-case")]
+define_config! {
     struct Dist {
-        sign_folder: Option<String>,
-        gpg_password_file: Option<String>,
-        upload_addr: Option<String>,
-        src_tarball: Option<bool>,
-        missing_tools: Option<bool>,
-        compression_formats: Option<Vec<String>>,
+        sign_folder: Option<String> = "sign-folder",
+        gpg_password_file: Option<String> = "gpg-password-file",
+        upload_addr: Option<String> = "upload-addr",
+        src_tarball: Option<bool> = "src-tarball",
+        missing_tools: Option<bool> = "missing-tools",
+        compression_formats: Option<Vec<String>> = "compression-formats",
     }
 }
 
@@ -505,83 +563,79 @@ impl Default for StringOrBool {
     }
 }
 
-derive_merge! {
+define_config! {
     /// TOML representation of how the Rust build is configured.
-    #[derive(Deserialize)]
-    #[serde(deny_unknown_fields, rename_all = "kebab-case")]
     struct Rust {
-        optimize: Option<bool>,
-        debug: Option<bool>,
-        codegen_units: Option<u32>,
-        codegen_units_std: Option<u32>,
-        debug_assertions: Option<bool>,
-        debug_assertions_std: Option<bool>,
-        overflow_checks: Option<bool>,
-        overflow_checks_std: Option<bool>,
-        debug_logging: Option<bool>,
-        debuginfo_level: Option<u32>,
-        debuginfo_level_rustc: Option<u32>,
-        debuginfo_level_std: Option<u32>,
-        debuginfo_level_tools: Option<u32>,
-        debuginfo_level_tests: Option<u32>,
-        run_dsymutil: Option<bool>,
-        backtrace: Option<bool>,
-        incremental: Option<bool>,
-        parallel_compiler: Option<bool>,
-        default_linker: Option<String>,
-        channel: Option<String>,
-        description: Option<String>,
-        musl_root: Option<String>,
-        rpath: Option<bool>,
-        verbose_tests: Option<bool>,
-        optimize_tests: Option<bool>,
-        codegen_tests: Option<bool>,
-        ignore_git: Option<bool>,
-        dist_src: Option<bool>,
-        save_toolstates: Option<String>,
-        codegen_backends: Option<Vec<String>>,
-        lld: Option<bool>,
-        use_lld: Option<bool>,
-        llvm_tools: Option<bool>,
-        deny_warnings: Option<bool>,
-        backtrace_on_ice: Option<bool>,
-        verify_llvm_ir: Option<bool>,
-        thin_lto_import_instr_limit: Option<u32>,
-        remap_debuginfo: Option<bool>,
-        jemalloc: Option<bool>,
-        test_compare_mode: Option<bool>,
-        llvm_libunwind: Option<String>,
-        control_flow_guard: Option<bool>,
-        new_symbol_mangling: Option<bool>,
-        profile_generate: Option<String>,
-        profile_use: Option<String>,
+        optimize: Option<bool> = "optimize",
+        debug: Option<bool> = "debug",
+        codegen_units: Option<u32> = "codegen-units",
+        codegen_units_std: Option<u32> = "codegen-units-std",
+        debug_assertions: Option<bool> = "debug-assertions",
+        debug_assertions_std: Option<bool> = "debug-assertions-std",
+        overflow_checks: Option<bool> = "overflow-checks",
+        overflow_checks_std: Option<bool> = "overflow-checks-std",
+        debug_logging: Option<bool> = "debug-logging",
+        debuginfo_level: Option<u32> = "debuginfo-level",
+        debuginfo_level_rustc: Option<u32> = "debuginfo-level-rustc",
+        debuginfo_level_std: Option<u32> = "debuginfo-level-std",
+        debuginfo_level_tools: Option<u32> = "debuginfo-level-tools",
+        debuginfo_level_tests: Option<u32> = "debuginfo-level-tests",
+        run_dsymutil: Option<bool> = "run-dsymutil",
+        backtrace: Option<bool> = "backtrace",
+        incremental: Option<bool> = "incremental",
+        parallel_compiler: Option<bool> = "parallel-compiler",
+        default_linker: Option<String> = "default-linker",
+        channel: Option<String> = "channel",
+        description: Option<String> = "description",
+        musl_root: Option<String> = "musl-root",
+        rpath: Option<bool> = "rpath",
+        verbose_tests: Option<bool> = "verbose-tests",
+        optimize_tests: Option<bool> = "optimize-tests",
+        codegen_tests: Option<bool> = "codegen-tests",
+        ignore_git: Option<bool> = "ignore-git",
+        dist_src: Option<bool> = "dist-src",
+        save_toolstates: Option<String> = "save-toolstates",
+        codegen_backends: Option<Vec<String>> = "codegen-backends",
+        lld: Option<bool> = "lld",
+        use_lld: Option<bool> = "use-lld",
+        llvm_tools: Option<bool> = "llvm-tools",
+        deny_warnings: Option<bool> = "deny-warnings",
+        backtrace_on_ice: Option<bool> = "backtrace-on-ice",
+        verify_llvm_ir: Option<bool> = "verify-llvm-ir",
+        thin_lto_import_instr_limit: Option<u32> = "thin-lto-import-instr-limit",
+        remap_debuginfo: Option<bool> = "remap-debuginfo",
+        jemalloc: Option<bool> = "jemalloc",
+        test_compare_mode: Option<bool> = "test-compare-mode",
+        llvm_libunwind: Option<String> = "llvm-libunwind",
+        control_flow_guard: Option<bool> = "control-flow-guard",
+        new_symbol_mangling: Option<bool> = "new-symbol-mangling",
+        profile_generate: Option<String> = "profile-generate",
+        profile_use: Option<String> = "profile-use",
         // ignored; this is set from an env var set by bootstrap.py
-        download_rustc: Option<StringOrBool>,
+        download_rustc: Option<StringOrBool> = "download-rustc",
     }
 }
 
-derive_merge! {
+define_config! {
     /// TOML representation of how each build target is configured.
-    #[derive(Deserialize)]
-    #[serde(deny_unknown_fields, rename_all = "kebab-case")]
     struct TomlTarget {
-        cc: Option<String>,
-        cxx: Option<String>,
-        ar: Option<String>,
-        ranlib: Option<String>,
-        default_linker: Option<PathBuf>,
-        linker: Option<String>,
-        llvm_config: Option<String>,
-        llvm_filecheck: Option<String>,
-        android_ndk: Option<String>,
-        sanitizers: Option<bool>,
-        profiler: Option<bool>,
-        crt_static: Option<bool>,
-        musl_root: Option<String>,
-        musl_libdir: Option<String>,
-        wasi_root: Option<String>,
-        qemu_rootfs: Option<String>,
-        no_std: Option<bool>,
+        cc: Option<String> = "cc",
+        cxx: Option<String> = "cxx",
+        ar: Option<String> = "ar",
+        ranlib: Option<String> = "ranlib",
+        default_linker: Option<PathBuf> = "default-linker",
+        linker: Option<String> = "linker",
+        llvm_config: Option<String> = "llvm-config",
+        llvm_filecheck: Option<String> = "llvm-filecheck",
+        android_ndk: Option<String> = "android-ndk",
+        sanitizers: Option<bool> = "sanitizers",
+        profiler: Option<bool> = "profiler",
+        crt_static: Option<bool> = "crt-static",
+        musl_root: Option<String> = "musl-root",
+        musl_libdir: Option<String> = "musl-libdir",
+        wasi_root: Option<String> = "wasi-root",
+        qemu_rootfs: Option<String> = "qemu-rootfs",
+        no_std: Option<bool> = "no-std",
     }
 }
 
@@ -649,7 +703,11 @@ impl Config {
 
             let contents =
                 t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
-            match toml::from_str(&contents) {
+            // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
+            // TomlConfig and sub types to be monomorphized 5x by toml.
+            match toml::from_str(&contents)
+                .and_then(|table: toml::Value| TomlConfig::deserialize(table))
+            {
                 Ok(table) => table,
                 Err(err) => {
                     println!("failed to parse TOML configuration '{}': {}", file.display(), err);
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 5f92cc2ca6f..76054122d00 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -821,6 +821,11 @@ impl Step for Src {
                 // not needed and contains symlinks which rustup currently
                 // chokes on when unpacking.
                 "library/backtrace/crates",
+                // these are 30MB combined and aren't necessary for building
+                // the standard library.
+                "library/stdarch/crates/Cargo.toml",
+                "library/stdarch/crates/stdarch-verify",
+                "library/stdarch/crates/intrinsic-test",
             ],
             &dst_src,
         );
diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
index d58b8570595..71afca527d1 100644
--- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
+++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
@@ -36,8 +36,8 @@ target = ["armv7-unknown-linux-uclibceabi"]
 cc = "/path/to/arm-unknown-linux-uclibcgnueabi-gcc"
 cxx = "/path/to/arm-unknown-linux-uclibcgnueabi-g++"
 ar = "path/to/arm-unknown-linux-uclibcgnueabi-ar"
-ranlib = "path/to/arm-unknown-linux-uclibcgnueabi-"
-linker = "/path/to/arm-unknown-linux-uclibcgnueabi-"
+ranlib = "path/to/arm-unknown-linux-uclibcgnueabi-ranlib"
+linker = "/path/to/arm-unknown-linux-uclibcgnueabi-gcc"
 ```
 
 ## Building Rust programs
@@ -75,27 +75,37 @@ To cross compile, you'll need to:
     ```
 * Build with:
     ```text
-    CC=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
-    CXX=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-g++ \
-    AR=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-ar \
+    CC_armv7_unknown_linux_uclibceabi=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
+    CXX_armv7_unknown_linux_uclibceabi=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-g++ \
+    AR_armv7_unknown_linux_uclibceabi=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-ar \
+    CFLAGS_armv7_unknown_linux_uclibceabi="-march=armv7-a -mtune=cortex-a9" \
+    CXXFLAGS_armv7_unknown_linux_uclibceabi="-march=armv7-a -mtune=cortex-a9" \
     CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABI_LINKER=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
     CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABI_RUSTFLAGS='-Clink-arg=-s -Clink-arg=-Wl,--dynamic-linker=/mmc/lib/ld-uClibc.so.1 -Clink-arg=-Wl,-rpath,/mmc/lib' \
-    cargo +stage2 build --target armv7-unknown-linux-uclibceabi --release
+    cargo +stage2 \
+    build \
+    --target armv7-unknown-linux-uclibceabi \
+    --release
     ```
 * Copy the binary to your target device and run.
 
-We specify `CC`, `CXX`, and `AR` because somtimes a project or a subproject requires the use of your `'C'` cross toolchain. Since Tomatoware has a modified sysroot we also pass via RUSTFLAGS the location of the dynamic-linker and rpath.
+We specify `CC`, `CXX`, `AR`, `CFLAGS`, and `CXXFLAGS` environment variables because somtimes a project or a subproject requires the use of your `'C'` cross toolchain. Since Tomatoware has a modified sysroot we also pass via RUSTFLAGS the location of the dynamic-linker and rpath.
 
 ### Test with QEMU
 
 To test a cross-compiled binary on your build system follow the instructions for `Cross Compilation`, install `qemu-arm-static`, and run with the following.
 ```text
-CC=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
-CXX=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-g++ \
-AR=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-ar \
+CC_armv7_unknown_linux_uclibceabi=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
+CXX_armv7_unknown_linux_uclibceabi=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-g++ \
+AR_armv7_unknown_linux_uclibceabi=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-ar \
+CFLAGS_armv7_unknown_linux_uclibceabi="-march=armv7-a -mtune=cortex-a9" \
+CXXFLAGS_armv7_unknown_linux_uclibceabi="-march=armv7-a -mtune=cortex-a9" \
 CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABI_LINKER=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
 CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABI_RUNNER="qemu-arm-static -L /opt/tomatoware/arm-soft-mmc/arm-tomatoware-linux-uclibcgnueabi/sysroot/" \
-cargo +stage2 run --target armv7-unknown-linux-uclibceabi --release
+cargo +stage2 \
+run \
+--target armv7-unknown-linux-uclibceabi \
+--release
 ```
 ### Run in a chroot