From 8d8f6995ce063fe812bb668a8b8fe4e5edf213ef Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Sun, 11 Apr 2021 09:35:00 +0100 Subject: [PATCH 01/12] Clarify the guarantees that ThreadId does and doesn't make. The existing documentation does not spell out whether `ThreadId`s are unique during the lifetime of a thread or of a process. I had to examine the source code to realise (pleasingly!) that they're unique for the lifetime of a process. That seems worth documenting clearly, as it's a strong guarantee. Examining the way `ThreadId`s are created also made me realise that the `as_u64` method on `ThreadId` could be a trap for the unwary on those platforms where the platform's notion of a thread identifier is also a 64 bit integer (particularly if they happen to use a similar identifier scheme to `ThreadId`). I therefore think it's worth being even clearer that there's no relationship between the two. --- library/std/src/thread/mod.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index ffdf4be15845..f33e785f96dc 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -965,10 +965,13 @@ pub fn park_timeout(dur: Duration) { /// A unique identifier for a running thread. /// -/// A `ThreadId` is an opaque object that has a unique value for each thread -/// that creates one. `ThreadId`s are not guaranteed to correspond to a thread's -/// system-designated identifier. A `ThreadId` can be retrieved from the [`id`] -/// method on a [`Thread`]. +/// A `ThreadId` is an opaque object that uniquely identifies each thread +/// created during the lifetime of a process. `ThreadId`s are guaranteed not to +/// be reused, even if a thread dies. `ThreadId`s are under the control of +/// Rust's standard library and there may not be any relationship between +/// `ThreadId` and the underlying platform's notion of a thread identifier -- +/// the two concepts cannot, therefore, be used interchangeably. A `ThreadId` +/// can be retrieved from the [`id`] method on a [`Thread`]. /// /// # Examples /// From fb1e03168570852507dd4852af501fec571137e8 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Tue, 7 Dec 2021 01:26:58 +1100 Subject: [PATCH 02/12] Remove unnecessary bounds for some Hash{Map,Set} methods --- library/std/src/collections/hash/map.rs | 154 ++++++++++++------------ library/std/src/collections/hash/set.rs | 44 +++---- 2 files changed, 99 insertions(+), 99 deletions(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 35f17aa781f4..a35fca37f6bd 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -349,6 +349,33 @@ impl HashMap { Keys { inner: self.iter() } } + /// Creates a consuming iterator visiting all the keys in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `K`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// let mut vec: Vec<&str> = map.into_keys().collect(); + /// // The `IntoKeys` iterator produces keys in arbitrary order, so the + /// // keys must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, ["a", "b", "c"]); + /// ``` + #[inline] + #[stable(feature = "map_into_keys_values", since = "1.54.0")] + pub fn into_keys(self) -> IntoKeys { + IntoKeys { inner: self.into_iter() } + } + /// An iterator visiting all values in arbitrary order. /// The iterator element type is `&'a V`. /// @@ -399,6 +426,33 @@ impl HashMap { ValuesMut { inner: self.iter_mut() } } + /// Creates a consuming iterator visiting all the values in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `V`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// let mut vec: Vec = map.into_values().collect(); + /// // The `IntoValues` iterator produces values in arbitrary order, so + /// // the values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + #[inline] + #[stable(feature = "map_into_keys_values", since = "1.54.0")] + pub fn into_values(self) -> IntoValues { + IntoValues { inner: self.into_iter() } + } + /// An iterator visiting all key-value pairs in arbitrary order. /// The iterator element type is `(&'a K, &'a V)`. /// @@ -555,6 +609,29 @@ impl HashMap { DrainFilter { base: self.base.drain_filter(pred) } } + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x*10)).collect(); + /// map.retain(|&k, _| k % 2 == 0); + /// assert_eq!(map.len(), 4); + /// ``` + #[inline] + #[stable(feature = "retain_hash_collection", since = "1.18.0")] + pub fn retain(&mut self, f: F) + where + F: FnMut(&K, &mut V) -> bool, + { + self.base.retain(f) + } + /// Clears the map, removing all key-value pairs. Keeps the allocated memory /// for reuse. /// @@ -937,83 +1014,6 @@ where { self.base.remove_entry(k) } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. - /// The elements are visited in unsorted (and unspecified) order. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map: HashMap = (0..8).map(|x| (x, x*10)).collect(); - /// map.retain(|&k, _| k % 2 == 0); - /// assert_eq!(map.len(), 4); - /// ``` - #[inline] - #[stable(feature = "retain_hash_collection", since = "1.18.0")] - pub fn retain(&mut self, f: F) - where - F: FnMut(&K, &mut V) -> bool, - { - self.base.retain(f) - } - - /// Creates a consuming iterator visiting all the keys in arbitrary order. - /// The map cannot be used after calling this. - /// The iterator element type is `K`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let map = HashMap::from([ - /// ("a", 1), - /// ("b", 2), - /// ("c", 3), - /// ]); - /// - /// let mut vec: Vec<&str> = map.into_keys().collect(); - /// // The `IntoKeys` iterator produces keys in arbitrary order, so the - /// // keys must be sorted to test them against a sorted array. - /// vec.sort_unstable(); - /// assert_eq!(vec, ["a", "b", "c"]); - /// ``` - #[inline] - #[stable(feature = "map_into_keys_values", since = "1.54.0")] - pub fn into_keys(self) -> IntoKeys { - IntoKeys { inner: self.into_iter() } - } - - /// Creates a consuming iterator visiting all the values in arbitrary order. - /// The map cannot be used after calling this. - /// The iterator element type is `V`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let map = HashMap::from([ - /// ("a", 1), - /// ("b", 2), - /// ("c", 3), - /// ]); - /// - /// let mut vec: Vec = map.into_values().collect(); - /// // The `IntoValues` iterator produces values in arbitrary order, so - /// // the values must be sorted to test them against a sorted array. - /// vec.sort_unstable(); - /// assert_eq!(vec, [1, 2, 3]); - /// ``` - #[inline] - #[stable(feature = "map_into_keys_values", since = "1.54.0")] - pub fn into_values(self) -> IntoValues { - IntoValues { inner: self.into_iter() } - } } impl HashMap diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index a1e28c0b0a69..0d087772bf93 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -290,6 +290,28 @@ impl HashSet { DrainFilter { base: self.base.drain_filter(pred) } } + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]); + /// set.retain(|&k| k % 2 == 0); + /// assert_eq!(set.len(), 3); + /// ``` + #[stable(feature = "retain_hash_collection", since = "1.18.0")] + pub fn retain(&mut self, f: F) + where + F: FnMut(&T) -> bool, + { + self.base.retain(f) + } + /// Clears the set, removing all values. /// /// # Examples @@ -906,28 +928,6 @@ where { self.base.take(value) } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all elements `e` such that `f(&e)` returns `false`. - /// The elements are visited in unsorted (and unspecified) order. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]); - /// set.retain(|&k| k % 2 == 0); - /// assert_eq!(set.len(), 3); - /// ``` - #[stable(feature = "retain_hash_collection", since = "1.18.0")] - pub fn retain(&mut self, f: F) - where - F: FnMut(&T) -> bool, - { - self.base.retain(f) - } } #[stable(feature = "rust1", since = "1.0.0")] From d66a9e16bae86863cfdbd033b49b672da34bdde1 Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Sat, 25 Dec 2021 15:18:55 +0000 Subject: [PATCH 03/12] Language tweak. --- library/std/src/thread/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index f33e785f96dc..d1fe9260e529 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -967,8 +967,8 @@ pub fn park_timeout(dur: Duration) { /// /// A `ThreadId` is an opaque object that uniquely identifies each thread /// created during the lifetime of a process. `ThreadId`s are guaranteed not to -/// be reused, even if a thread dies. `ThreadId`s are under the control of -/// Rust's standard library and there may not be any relationship between +/// be reused, even when a thread terminates. `ThreadId`s are under the control +/// of Rust's standard library and there may not be any relationship between /// `ThreadId` and the underlying platform's notion of a thread identifier -- /// the two concepts cannot, therefore, be used interchangeably. A `ThreadId` /// can be retrieved from the [`id`] method on a [`Thread`]. From 51a1681b6950b205575c873b6749682e28c48ad8 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Fri, 31 Dec 2021 16:04:13 -0500 Subject: [PATCH 04/12] Remove pronunciation guide from Vec --- library/alloc/src/vec/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 2863da059329..adf6d22111f3 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -148,7 +148,7 @@ use self::spec_extend::SpecExtend; #[cfg(not(no_global_oom_handling))] mod spec_extend; -/// A contiguous growable array type, written as `Vec` and pronounced 'vector'. +/// A contiguous growable array type, written as `Vec`, short for 'vector'. /// /// # Examples /// From 193342eb8d38afb7327642ced3434730b6f4fa00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20K=C4=85dzio=C5=82ka?= Date: Sat, 1 Jan 2022 05:12:56 +0100 Subject: [PATCH 05/12] Emit an error for `--cfg=)` Fixes #73026 See also: #64467, #89468 The issue stems from a `FatalError` being silently raised in `panictry_buffer`. Normally this is not a problem, because `panictry_buffer` emits the causes of the error, but they are not themselves fatal, so they get filtered out by the silent emitter. To fix this, we use a parser entrypoint which doesn't use `panictry_buffer`, and we handle the error ourselves. --- compiler/rustc_interface/src/interface.rs | 38 +++++++++---------- .../cfg-arg-invalid-8.rs | 3 ++ .../cfg-arg-invalid-8.stderr | 2 + 3 files changed, 24 insertions(+), 19 deletions(-) create mode 100644 src/test/ui/conditional-compilation/cfg-arg-invalid-8.rs create mode 100644 src/test/ui/conditional-compilation/cfg-arg-invalid-8.stderr diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 2904b3f5b707..3804e1003073 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -11,7 +11,7 @@ use rustc_errors::registry::Registry; use rustc_errors::{ErrorReported, Handler}; use rustc_lint::LintStore; use rustc_middle::ty; -use rustc_parse::new_parser_from_source_str; +use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames}; use rustc_session::early_error; @@ -91,7 +91,6 @@ pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option { @@ -102,26 +101,27 @@ pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option { - if meta_item.path.segments.len() != 1 { - error!("argument key must be an identifier"); - } - match &meta_item.kind { - MetaItemKind::List(..) => { - error!(r#"expected `key` or `key="value"`"#); - } - MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { - error!("argument value must be a string"); + match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) { + Ok(mut parser) => match &mut parser.parse_meta_item() { + Ok(meta_item) if parser.token == token::Eof => { + if meta_item.path.segments.len() != 1 { + error!("argument key must be an identifier"); } - MetaItemKind::NameValue(..) | MetaItemKind::Word => { - let ident = meta_item.ident().expect("multi-segment cfg key"); - return (ident.name, meta_item.value_str()); + match &meta_item.kind { + MetaItemKind::List(..) => {} + MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { + error!("argument value must be a string"); + } + MetaItemKind::NameValue(..) | MetaItemKind::Word => { + let ident = meta_item.ident().expect("multi-segment cfg key"); + return (ident.name, meta_item.value_str()); + } } } - } - Ok(..) => {} - Err(err) => err.cancel(), + Ok(..) => {} + Err(err) => err.cancel(), + }, + Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()), } error!(r#"expected `key` or `key="value"`"#); diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-8.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-8.rs new file mode 100644 index 000000000000..1d7fa7885348 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-8.rs @@ -0,0 +1,3 @@ +// compile-flags: --cfg ) +// error-pattern: invalid `--cfg` argument: `)` (expected `key` or `key="value"`) +fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-8.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-8.stderr new file mode 100644 index 000000000000..7bb1814127b2 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-8.stderr @@ -0,0 +1,2 @@ +error: invalid `--cfg` argument: `)` (expected `key` or `key="value"`) + From ec0c83821e590aaadb9446cf7c7a5f9453f0de1b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 1 Jan 2022 10:50:55 +0100 Subject: [PATCH 06/12] Add test for where clause order --- src/test/rustdoc/where-clause-order.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/test/rustdoc/where-clause-order.rs diff --git a/src/test/rustdoc/where-clause-order.rs b/src/test/rustdoc/where-clause-order.rs new file mode 100644 index 000000000000..d0d89cbf126b --- /dev/null +++ b/src/test/rustdoc/where-clause-order.rs @@ -0,0 +1,15 @@ +#![crate_name = "foo"] + +pub trait SomeTrait +where Rhs: ?Sized +{} + +// @has 'foo/trait.SomeTrait.html' +// @has - "//div[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where A: PartialOrd + PartialEq, B: PartialOrd + PartialEq, C: PartialOrd + PartialEq, D: PartialOrd + PartialEq, E: PartialOrd + PartialEq + ?Sized, " +impl SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where + A: PartialOrd + PartialEq, + B: PartialOrd + PartialEq, + C: PartialOrd + PartialEq, + D: PartialOrd + PartialEq, + E: PartialOrd + PartialEq + ?Sized +{} From bffe880cfd2d3e30d6acab6851397cc1527d2ea8 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 30 Dec 2021 15:04:47 +0100 Subject: [PATCH 07/12] Enforce formatting for rustc_codegen_cranelift --- rustfmt.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rustfmt.toml b/rustfmt.toml index 265f2194fef8..aa0d4888f082 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -19,7 +19,6 @@ ignore = [ "library/backtrace", "library/portable-simd", "library/stdarch", - "compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc", "src/doc/book", "src/doc/edition-guide", @@ -36,4 +35,9 @@ ignore = [ "src/tools/rust-analyzer", "src/tools/rustfmt", "src/tools/rust-installer", + + # these are ignored by a standard cargo fmt run + "compiler/rustc_codegen_cranelift/y.rs", # running rustfmt breaks this file + "compiler/rustc_codegen_cranelift/example", + "compiler/rustc_codegen_cranelift/scripts", ] From 2fe2728fa900a708d2c70342d9d6737e5462cf5d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 26 Dec 2021 14:25:39 +0100 Subject: [PATCH 08/12] Remove the lazy_static dependency from rustbuild Rustbuild already depends on once_cell which in the future can be replaced with std::lazy::Lazy. --- Cargo.lock | 1 - src/bootstrap/Cargo.toml | 1 - src/bootstrap/cache.rs | 7 +++---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 959c8161e984..b71488837041 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,7 +175,6 @@ dependencies = [ "filetime", "getopts", "ignore", - "lazy_static", "libc", "merge", "num_cpus", diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 1ce1f0b26db5..9ad453497f69 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -44,7 +44,6 @@ libc = "0.2" serde = { version = "1.0.8", features = ["derive"] } serde_json = "1.0.2" toml = "0.5" -lazy_static = "1.3.0" time = "0.1" ignore = "0.4.10" opener = "0.5" diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs index 0c16fae01bca..fac5d8db5119 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/cache.rs @@ -13,7 +13,8 @@ use std::ops::Deref; use std::path::{Path, PathBuf}; use std::sync::Mutex; -use lazy_static::lazy_static; +// FIXME: replace with std::lazy after it gets stabilized and reaches beta +use once_cell::sync::Lazy; use crate::builder::Step; @@ -222,9 +223,7 @@ impl Interner { } } -lazy_static! { - pub static ref INTERNER: Interner = Interner::default(); -} +pub static INTERNER: Lazy = Lazy::new(Interner::default); /// This is essentially a `HashMap` which allows storing any type in its input and /// any type in its output. It is a write-once cache; values are never evicted, From 043745cb9688fbecd97638b2fa156cb055bbbb14 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 26 Dec 2021 15:05:12 +0100 Subject: [PATCH 09/12] Avoid the merge derive macro in rustbuild The task of the macro is simple enough that a decl macro is almost ten times shorter than the original proc macro. The proc macro is 159 lines while the decl macro is just 18 lines. This reduces the amount of dependencies of rustbuild from 45 to 37. It also slight reduces compilation time from 47s to 44s for debug builds. --- Cargo.lock | 16 -- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/config.rs | 361 +++++++++++++++++++++------------------ 3 files changed, 197 insertions(+), 182 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b71488837041..dd4d48c126fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2225,22 +2225,6 @@ name = "merge" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9" -dependencies = [ - "merge_derive", - "num-traits", -] - -[[package]] -name = "merge_derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] [[package]] name = "minifier" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 9ad453497f69..1f218dd8d67b 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -47,7 +47,7 @@ toml = "0.5" time = "0.1" ignore = "0.4.10" opener = "0.5" -merge = "0.1.0" +merge = { version = "0.1.0", default-features = false, features = ["std"] } once_cell = "1.7.2" [target.'cfg(windows)'.dependencies.winapi] diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 7a4593a75f28..fcca783fbfe3 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -357,105 +357,132 @@ impl Merge for TomlConfig { } } -/// TOML representation of various global build decisions. -#[derive(Deserialize, Default, Clone, Merge)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct Build { - build: Option, - host: Option>, - target: Option>, - // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable - build_dir: Option, - cargo: Option, - rustc: Option, - rustfmt: Option, - docs: Option, - compiler_docs: Option, - docs_minification: Option, - submodules: Option, - fast_submodules: Option, - gdb: Option, - nodejs: Option, - npm: Option, - python: Option, - locked_deps: Option, - vendor: Option, - full_bootstrap: Option, - extended: Option, - tools: Option>, - verbose: Option, - sanitizers: Option, - profiler: Option, - cargo_native_static: Option, - low_priority: Option, - configure_args: Option>, - local_rebuild: Option, - print_step_timings: Option, - print_step_rusage: Option, - check_stage: Option, - doc_stage: Option, - build_stage: Option, - test_stage: Option, - install_stage: Option, - dist_stage: Option, - bench_stage: Option, - patch_binaries_for_nix: Option, +macro_rules! derive_merge { + ($(#[$attr:meta])* struct $name:ident { + $($field:ident: $field_ty:ty,)* + }) => { + $(#[$attr])* + struct $name { + $($field: $field_ty,)* + } + + impl Merge for $name { + fn merge(&mut self, other: Self) { + $( + Merge::merge(&mut self.$field, other.$field); + )* + } + } + } } -/// TOML representation of various global install decisions. -#[derive(Deserialize, Default, Clone, Merge)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct Install { - prefix: Option, - sysconfdir: Option, - docdir: Option, - bindir: Option, - libdir: Option, - mandir: Option, - datadir: Option, +derive_merge! { + /// TOML representation of various global build decisions. + #[derive(Deserialize, Default, Clone)] + #[serde(deny_unknown_fields, rename_all = "kebab-case")] + struct Build { + build: Option, + host: Option>, + target: Option>, + // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable + build_dir: Option, + cargo: Option, + rustc: Option, + rustfmt: Option, + docs: Option, + compiler_docs: Option, + docs_minification: Option, + submodules: Option, + fast_submodules: Option, + gdb: Option, + nodejs: Option, + npm: Option, + python: Option, + locked_deps: Option, + vendor: Option, + full_bootstrap: Option, + extended: Option, + tools: Option>, + verbose: Option, + sanitizers: Option, + profiler: Option, + cargo_native_static: Option, + low_priority: Option, + configure_args: Option>, + local_rebuild: Option, + print_step_timings: Option, + print_step_rusage: Option, + check_stage: Option, + doc_stage: Option, + build_stage: Option, + test_stage: Option, + install_stage: Option, + dist_stage: Option, + bench_stage: Option, + patch_binaries_for_nix: Option, + } } -/// TOML representation of how the LLVM build is configured. -#[derive(Deserialize, Default, Merge)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct Llvm { - skip_rebuild: Option, - optimize: Option, - thin_lto: Option, - release_debuginfo: Option, - assertions: Option, - tests: Option, - plugins: Option, - ccache: Option, - version_check: Option, - static_libstdcpp: Option, - ninja: Option, - targets: Option, - experimental_targets: Option, - link_jobs: Option, - link_shared: Option, - version_suffix: Option, - clang_cl: Option, - cflags: Option, - cxxflags: Option, - ldflags: Option, - use_libcxx: Option, - use_linker: Option, - allow_old_toolchain: Option, - polly: Option, - clang: Option, - download_ci_llvm: Option, +derive_merge! { + /// TOML representation of various global install decisions. + #[derive(Deserialize, Default, Clone)] + #[serde(deny_unknown_fields, rename_all = "kebab-case")] + struct Install { + prefix: Option, + sysconfdir: Option, + docdir: Option, + bindir: Option, + libdir: Option, + mandir: Option, + datadir: Option, + } } -#[derive(Deserialize, Default, Clone, Merge)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct Dist { - sign_folder: Option, - gpg_password_file: Option, - upload_addr: Option, - src_tarball: Option, - missing_tools: Option, - compression_formats: Option>, +derive_merge! { + /// TOML representation of how the LLVM build is configured. + #[derive(Deserialize, Default)] + #[serde(deny_unknown_fields, rename_all = "kebab-case")] + struct Llvm { + skip_rebuild: Option, + optimize: Option, + thin_lto: Option, + release_debuginfo: Option, + assertions: Option, + tests: Option, + plugins: Option, + ccache: Option, + version_check: Option, + static_libstdcpp: Option, + ninja: Option, + targets: Option, + experimental_targets: Option, + link_jobs: Option, + link_shared: Option, + version_suffix: Option, + clang_cl: Option, + cflags: Option, + cxxflags: Option, + ldflags: Option, + use_libcxx: Option, + use_linker: Option, + allow_old_toolchain: Option, + polly: Option, + clang: Option, + download_ci_llvm: Option, + } +} + +derive_merge! { + #[derive(Deserialize, Default, Clone)] + #[serde(deny_unknown_fields, rename_all = "kebab-case")] + struct Dist { + sign_folder: Option, + gpg_password_file: Option, + upload_addr: Option, + src_tarball: Option, + missing_tools: Option, + compression_formats: Option>, + } } #[derive(Deserialize)] @@ -471,80 +498,84 @@ impl Default for StringOrBool { } } -/// TOML representation of how the Rust build is configured. -#[derive(Deserialize, Default, Merge)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct Rust { - optimize: Option, - debug: Option, - codegen_units: Option, - codegen_units_std: Option, - debug_assertions: Option, - debug_assertions_std: Option, - overflow_checks: Option, - overflow_checks_std: Option, - debug_logging: Option, - debuginfo_level: Option, - debuginfo_level_rustc: Option, - debuginfo_level_std: Option, - debuginfo_level_tools: Option, - debuginfo_level_tests: Option, - run_dsymutil: Option, - backtrace: Option, - incremental: Option, - parallel_compiler: Option, - default_linker: Option, - channel: Option, - description: Option, - musl_root: Option, - rpath: Option, - verbose_tests: Option, - optimize_tests: Option, - codegen_tests: Option, - ignore_git: Option, - dist_src: Option, - save_toolstates: Option, - codegen_backends: Option>, - lld: Option, - use_lld: Option, - llvm_tools: Option, - deny_warnings: Option, - backtrace_on_ice: Option, - verify_llvm_ir: Option, - thin_lto_import_instr_limit: Option, - remap_debuginfo: Option, - jemalloc: Option, - test_compare_mode: Option, - llvm_libunwind: Option, - control_flow_guard: Option, - new_symbol_mangling: Option, - profile_generate: Option, - profile_use: Option, - // ignored; this is set from an env var set by bootstrap.py - download_rustc: Option, +derive_merge! { + /// TOML representation of how the Rust build is configured. + #[derive(Deserialize, Default)] + #[serde(deny_unknown_fields, rename_all = "kebab-case")] + struct Rust { + optimize: Option, + debug: Option, + codegen_units: Option, + codegen_units_std: Option, + debug_assertions: Option, + debug_assertions_std: Option, + overflow_checks: Option, + overflow_checks_std: Option, + debug_logging: Option, + debuginfo_level: Option, + debuginfo_level_rustc: Option, + debuginfo_level_std: Option, + debuginfo_level_tools: Option, + debuginfo_level_tests: Option, + run_dsymutil: Option, + backtrace: Option, + incremental: Option, + parallel_compiler: Option, + default_linker: Option, + channel: Option, + description: Option, + musl_root: Option, + rpath: Option, + verbose_tests: Option, + optimize_tests: Option, + codegen_tests: Option, + ignore_git: Option, + dist_src: Option, + save_toolstates: Option, + codegen_backends: Option>, + lld: Option, + use_lld: Option, + llvm_tools: Option, + deny_warnings: Option, + backtrace_on_ice: Option, + verify_llvm_ir: Option, + thin_lto_import_instr_limit: Option, + remap_debuginfo: Option, + jemalloc: Option, + test_compare_mode: Option, + llvm_libunwind: Option, + control_flow_guard: Option, + new_symbol_mangling: Option, + profile_generate: Option, + profile_use: Option, + // ignored; this is set from an env var set by bootstrap.py + download_rustc: Option, + } } -/// TOML representation of how each build target is configured. -#[derive(Deserialize, Default, Merge)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct TomlTarget { - cc: Option, - cxx: Option, - ar: Option, - ranlib: Option, - default_linker: Option, - linker: Option, - llvm_config: Option, - llvm_filecheck: Option, - android_ndk: Option, - sanitizers: Option, - profiler: Option, - crt_static: Option, - musl_root: Option, - musl_libdir: Option, - wasi_root: Option, - qemu_rootfs: Option, - no_std: Option, +derive_merge! { + /// TOML representation of how each build target is configured. + #[derive(Deserialize, Default)] + #[serde(deny_unknown_fields, rename_all = "kebab-case")] + struct TomlTarget { + cc: Option, + cxx: Option, + ar: Option, + ranlib: Option, + default_linker: Option, + linker: Option, + llvm_config: Option, + llvm_filecheck: Option, + android_ndk: Option, + sanitizers: Option, + profiler: Option, + crt_static: Option, + musl_root: Option, + musl_libdir: Option, + wasi_root: Option, + qemu_rootfs: Option, + no_std: Option, + } } impl Config { From 947e9483e9684025faee9eaba56a0fbb200d26b8 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 26 Dec 2021 15:35:50 +0100 Subject: [PATCH 10/12] Make the rustc and rustdoc wrapper not depend on libbootstrap This slightly improves compilation time by reducing linking time (saving about a 1/10 of the the total compilation time after changing rustbuild) and slightly reduces disk usage (from 16MB for the rustc wrapper to 4MB). --- src/bootstrap/bin/rustc.rs | 8 +++++--- src/bootstrap/bin/rustdoc.rs | 8 +++++--- src/bootstrap/dylib_util.rs | 28 ++++++++++++++++++++++++++++ src/bootstrap/util.rs | 24 +----------------------- 4 files changed, 39 insertions(+), 29 deletions(-) create mode 100644 src/bootstrap/dylib_util.rs diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index ed53a98e9a53..7105a2457e28 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -15,6 +15,8 @@ //! switching compilers for the bootstrap and for build scripts will probably //! never get replaced. +include!("../dylib_util.rs"); + use std::env; use std::path::PathBuf; use std::process::{Child, Command}; @@ -50,11 +52,11 @@ fn main() { let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc)); let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir)); - let mut dylib_path = bootstrap::util::dylib_path(); + let mut dylib_path = dylib_path(); dylib_path.insert(0, PathBuf::from(&libdir)); let mut cmd = Command::new(rustc); - cmd.args(&args).env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); // Get the name of the crate we're compiling, if any. let crate_name = @@ -161,7 +163,7 @@ fn main() { eprintln!( "{} command: {:?}={:?} {:?}", prefix, - bootstrap::util::dylib_path_var(), + dylib_path_var(), env::join_paths(&dylib_path).unwrap(), cmd, ); diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index e4396d53016e..ad3800834b07 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -7,6 +7,8 @@ use std::ffi::OsString; use std::path::PathBuf; use std::process::Command; +include!("../dylib_util.rs"); + fn main() { let args = env::args_os().skip(1).collect::>(); let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set"); @@ -20,14 +22,14 @@ fn main() { Err(_) => 0, }; - let mut dylib_path = bootstrap::util::dylib_path(); + let mut dylib_path = dylib_path(); dylib_path.insert(0, PathBuf::from(libdir.clone())); let mut cmd = Command::new(rustdoc); cmd.args(&args) .arg("--sysroot") .arg(&sysroot) - .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + .env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); // Force all crates compiled by this compiler to (a) be unstable and (b) // allow the `rustc_private` feature to link to other unstable crates @@ -59,7 +61,7 @@ fn main() { if verbose > 1 { eprintln!( "rustdoc command: {:?}={:?} {:?}", - bootstrap::util::dylib_path_var(), + dylib_path_var(), env::join_paths(&dylib_path).unwrap(), cmd, ); diff --git a/src/bootstrap/dylib_util.rs b/src/bootstrap/dylib_util.rs new file mode 100644 index 000000000000..6d75272c5013 --- /dev/null +++ b/src/bootstrap/dylib_util.rs @@ -0,0 +1,28 @@ +// Various utilities for working with dylib paths. +// +// This file is meant to be included directly to avoid a dependency on the bootstrap library from +// the rustc and rustdoc wrappers. This improves compilation time by reducing the linking time. + +/// Returns the environment variable which the dynamic library lookup path +/// resides in for this platform. +pub fn dylib_path_var() -> &'static str { + if cfg!(target_os = "windows") { + "PATH" + } else if cfg!(target_os = "macos") { + "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "haiku") { + "LIBRARY_PATH" + } else { + "LD_LIBRARY_PATH" + } +} + +/// Parses the `dylib_path_var()` environment variable, returning a list of +/// paths that are members of this lookup path. +pub fn dylib_path() -> Vec { + let var = match env::var_os(dylib_path_var()) { + Some(v) => v, + None => return vec![], + }; + env::split_paths(&var).collect() +} diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 57178aa382ff..d0a400913856 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -54,29 +54,7 @@ pub fn add_dylib_path(path: Vec, cmd: &mut Command) { cmd.env(dylib_path_var(), t!(env::join_paths(list))); } -/// Returns the environment variable which the dynamic library lookup path -/// resides in for this platform. -pub fn dylib_path_var() -> &'static str { - if cfg!(target_os = "windows") { - "PATH" - } else if cfg!(target_os = "macos") { - "DYLD_LIBRARY_PATH" - } else if cfg!(target_os = "haiku") { - "LIBRARY_PATH" - } else { - "LD_LIBRARY_PATH" - } -} - -/// Parses the `dylib_path_var()` environment variable, returning a list of -/// paths that are members of this lookup path. -pub fn dylib_path() -> Vec { - let var = match env::var_os(dylib_path_var()) { - Some(v) => v, - None => return vec![], - }; - env::split_paths(&var).collect() -} +include!("dylib_util.rs"); /// Adds a list of lookup paths to `cmd`'s link library lookup path. pub fn add_link_lib_path(path: Vec, cmd: &mut Command) { From ad6f98cd28e02d10323c125c8ad2eef44dbfbb20 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 1 Jan 2022 17:03:24 +0100 Subject: [PATCH 11/12] Remove the merge dependency --- Cargo.lock | 7 ------- src/bootstrap/Cargo.toml | 1 - src/bootstrap/config.rs | 11 +++++++++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd4d48c126fd..a912eee97dbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -176,7 +176,6 @@ dependencies = [ "getopts", "ignore", "libc", - "merge", "num_cpus", "once_cell", "opener", @@ -2220,12 +2219,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "merge" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9" - [[package]] name = "minifier" version = "0.0.41" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 1f218dd8d67b..b68b2163f873 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -47,7 +47,6 @@ toml = "0.5" time = "0.1" ignore = "0.4.10" opener = "0.5" -merge = { version = "0.1.0", default-features = false, features = ["std"] } once_cell = "1.7.2" [target.'cfg(windows)'.dependencies.winapi] diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index fcca783fbfe3..c930657c5bd2 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -18,7 +18,6 @@ pub use crate::flags::Subcommand; use crate::flags::{Color, Flags}; use crate::util::exe; use build_helper::t; -use merge::Merge; use serde::Deserialize; macro_rules! check_ci_llvm { @@ -334,6 +333,10 @@ struct TomlConfig { profile: Option, } +trait Merge { + fn merge(&mut self, other: Self); +} + impl Merge for TomlConfig { fn merge( &mut self, @@ -357,6 +360,8 @@ 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 { ($(#[$attr:meta])* struct $name:ident { $($field:ident: $field_ty:ty,)* @@ -369,7 +374,9 @@ macro_rules! derive_merge { impl Merge for $name { fn merge(&mut self, other: Self) { $( - Merge::merge(&mut self.$field, other.$field); + if !self.$field.is_some() { + self.$field = other.$field; + } )* } } From 7ea6e713c21db0fb19e28a9071910776d13ed769 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 1 Jan 2022 18:50:56 +0100 Subject: [PATCH 12/12] Remove some dead code --- src/bootstrap/builder.rs | 3 +-- src/bootstrap/config.rs | 4 ---- src/bootstrap/lib.rs | 5 ----- src/bootstrap/util.rs | 20 -------------------- 4 files changed, 1 insertion(+), 31 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index bbd2c087ccab..917abde9de1c 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -351,7 +351,6 @@ pub enum Kind { Check, Clippy, Fix, - Format, Test, Bench, Dist, @@ -399,7 +398,7 @@ impl<'a> Builder<'a> { native::Lld, native::CrtBeginEnd ), - Kind::Check | Kind::Clippy { .. } | Kind::Fix | Kind::Format => describe!( + Kind::Check | Kind::Clippy { .. } | Kind::Fix => describe!( check::Std, check::Rustc, check::Rustdoc, diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index c930657c5bd2..5af9248583ca 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -1149,10 +1149,6 @@ impl Config { self.verbose > 0 } - pub fn very_verbose(&self) -> bool { - self.verbose > 1 - } - pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool { self.target_config.get(&target).map(|t| t.sanitizers).flatten().unwrap_or(self.sanitizers) } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 82462f9758e5..8569089f7012 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -110,7 +110,6 @@ use std::fs::{self, File, OpenOptions}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; use std::process::{self, Command}; -use std::slice; use std::str; #[cfg(unix)] @@ -472,10 +471,6 @@ impl Build { build } - pub fn build_triple(&self) -> &[Interned] { - slice::from_ref(&self.build.triple) - } - // modified from `check_submodule` and `update_submodule` in bootstrap.py /// Given a path to the directory of a submodule, update it. /// diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index d0a400913856..ee58bedcc873 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -16,11 +16,6 @@ use build_helper::t; use crate::builder::Builder; use crate::config::{Config, TargetSelection}; -/// Returns the `name` as the filename of a static library for `target`. -pub fn staticlib(name: &str, target: TargetSelection) -> String { - if target.contains("windows") { format!("{}.lib", name) } else { format!("lib{}.a", name) } -} - /// Given an executable called `name`, return the filename for the /// executable for a particular target. pub fn exe(name: &str, target: TargetSelection) -> String { @@ -81,21 +76,6 @@ fn link_lib_path() -> Vec { env::split_paths(&var).collect() } -/// `push` all components to `buf`. On windows, append `.exe` to the last component. -pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf { - let (&file, components) = components.split_last().expect("at least one component required"); - let mut file = file.to_owned(); - - if cfg!(windows) { - file.push_str(".exe"); - } - - buf.extend(components); - buf.push(file); - - buf -} - pub struct TimeIt(bool, Instant); /// Returns an RAII structure that prints out how long it took to drop.