From 92b5d0c4cb1f369442beb79f87aa6114987e7956 Mon Sep 17 00:00:00 2001 From: hi-rustin Date: Mon, 3 Jul 2023 09:16:44 +0800 Subject: [PATCH] Use String or Int to set the opt level Signed-off-by: hi-rustin --- config.example.toml | 14 ++++++- src/bootstrap/config.rs | 73 ++++++++++++++++++++++++++++------- src/bootstrap/config/tests.rs | 5 ++- 3 files changed, 76 insertions(+), 16 deletions(-) diff --git a/config.example.toml b/config.example.toml index 0c65b25fe13..367f95b156f 100644 --- a/config.example.toml +++ b/config.example.toml @@ -400,10 +400,20 @@ changelog-seen = 2 # ============================================================================= [rust] -# Whether or not to optimize the compiler and standard library. +# Whether or not to optimize when compiling the compiler and standard library, +# and what level of optimization to use. # WARNING: Building with optimize = false is NOT SUPPORTED. Due to bootstrapping, # building without optimizations takes much longer than optimizing. Further, some platforms # fail to build without this optimization (c.f. #65352). +# The valid options are: +# true - Enable optimizations. +# false - Disable optimizations. +# 0 - Disable optimizations. +# 1 - Basic optimizations. +# 2 - Some optimizations. +# 3 - All optimizations. +# "s" - Optimize for binary size. +# "z" - Optimize for binary size, but also turn off loop vectorization. #optimize = true # Indicates that the build should be configured for debugging Rust. A @@ -757,7 +767,7 @@ changelog-seen = 2 # This option will override the same option under [build] section. #profiler = build.profiler (bool) -# This option supports enable `rpath` in each target independently, +# This option supports enable `rpath` in each target independently, # and will override the same option under [rust] section. It only works on Unix platforms #rpath = rust.rpath (bool) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5f5f7ea25fb..28ae46efefe 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -875,11 +875,10 @@ fn default() -> StringOrBool { } } -#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] -#[serde(untagged)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum RustOptimize { - #[serde(deserialize_with = "deserialize_and_validate_opt_level")] String(String), + Int(u8), Bool(bool), } @@ -889,26 +888,74 @@ fn default() -> RustOptimize { } } -fn deserialize_and_validate_opt_level<'de, D>(d: D) -> Result -where - D: serde::de::Deserializer<'de>, -{ - let v = String::deserialize(d)?; - if ["0", "1", "2", "3", "s", "z"].iter().find(|x| **x == v).is_some() { - Ok(v) - } else { - Err(format!(r#"unrecognized option for rust optimize: "{}", expected one of "0", "1", "2", "3", "s", "z""#, v)).map_err(serde::de::Error::custom) +impl<'de> Deserialize<'de> for RustOptimize { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(OptimizeVisitor) } } +struct OptimizeVisitor; + +impl<'de> serde::de::Visitor<'de> for OptimizeVisitor { + type Value = RustOptimize; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str(r#"one of: 0, 1, 2, 3, "s", "z", true, false"#) + } + + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + if ["s", "z"].iter().find(|x| **x == value).is_some() { + Ok(RustOptimize::String(value.to_string())) + } else { + Err(format_optimize_error_msg(value)).map_err(serde::de::Error::custom) + } + } + + fn visit_i64(self, value: i64) -> Result + where + E: serde::de::Error, + { + if matches!(value, 0..=3) { + Ok(RustOptimize::Int(value as u8)) + } else { + Err(format_optimize_error_msg(value)).map_err(serde::de::Error::custom) + } + } + + fn visit_bool(self, value: bool) -> Result + where + E: serde::de::Error, + { + Ok(RustOptimize::Bool(value)) + } +} + +fn format_optimize_error_msg(v: impl std::fmt::Display) -> String { + format!( + r#"unrecognized option for rust optimize: "{}", expected one of 0, 1, 2, 3, "s", "z", true, false"#, + v + ) +} + impl RustOptimize { pub(crate) fn is_release(&self) -> bool { - if let RustOptimize::Bool(true) | RustOptimize::String(_) = &self { true } else { false } + match &self { + RustOptimize::Bool(true) | RustOptimize::String(_) => true, + RustOptimize::Int(i) => *i > 0, + RustOptimize::Bool(false) => false, + } } pub(crate) fn get_opt_level(&self) -> Option { match &self { RustOptimize::String(s) => Some(s.clone()), + RustOptimize::Int(i) => Some(i.to_string()), RustOptimize::Bool(_) => None, } } diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs index 732df54cdac..c340bb2982a 100644 --- a/src/bootstrap/config/tests.rs +++ b/src/bootstrap/config/tests.rs @@ -184,7 +184,10 @@ fn rust_optimize() { assert_eq!(parse("").rust_optimize.is_release(), true); assert_eq!(parse("rust.optimize = false").rust_optimize.is_release(), false); assert_eq!(parse("rust.optimize = true").rust_optimize.is_release(), true); - assert_eq!(parse("rust.optimize = \"1\"").rust_optimize.get_opt_level(), Some("1".to_string())); + assert_eq!(parse("rust.optimize = 0").rust_optimize.is_release(), false); + assert_eq!(parse("rust.optimize = 1").rust_optimize.is_release(), true); + assert_eq!(parse("rust.optimize = 1").rust_optimize.get_opt_level(), Some("1".to_string())); + assert_eq!(parse("rust.optimize = \"s\"").rust_optimize.is_release(), true); assert_eq!(parse("rust.optimize = \"s\"").rust_optimize.get_opt_level(), Some("s".to_string())); }