diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index a1d3453377ab0..05b66f94727ad 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1207,7 +1207,7 @@ impl<'a> Builder<'a> { assert_eq!(target, compiler.host); } - if self.config.rust_optimize { + if self.config.rust_optimize.is_release() { // FIXME: cargo bench/install do not accept `--release` if cmd != "bench" && cmd != "install" { cargo.arg("--release"); @@ -1263,7 +1263,7 @@ impl<'a> Builder<'a> { } let profile_var = |name: &str| { - let profile = if self.config.rust_optimize { "RELEASE" } else { "DEV" }; + let profile = if self.config.rust_optimize.is_release() { "RELEASE" } else { "DEV" }; format!("CARGO_PROFILE_{}_{}", profile, name) }; @@ -1652,6 +1652,9 @@ impl<'a> Builder<'a> { } }; cargo.env(profile_var("DEBUG"), debuginfo_level.to_string()); + if let Some(opt_level) = &self.config.rust_optimize.get_opt_level() { + cargo.env(profile_var("OPT_LEVEL"), opt_level); + } if !self.config.dry_run() && self.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz") { rustflags.arg("-Clink-arg=-gz"); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index b91275e73e9c4..5f5f7ea25fb95 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -202,7 +202,7 @@ pub struct Config { pub llvm_use_libcxx: bool, // rust codegen options - pub rust_optimize: bool, + pub rust_optimize: RustOptimize, pub rust_codegen_units: Option, pub rust_codegen_units_std: Option, pub rust_debug_assertions: bool, @@ -875,17 +875,55 @@ impl Default for StringOrBool { } } +#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] +#[serde(untagged)] +pub enum RustOptimize { + #[serde(deserialize_with = "deserialize_and_validate_opt_level")] + String(String), + Bool(bool), +} + +impl Default for RustOptimize { + fn default() -> RustOptimize { + RustOptimize::Bool(false) + } +} + +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 RustOptimize { + pub(crate) fn is_release(&self) -> bool { + if let RustOptimize::Bool(true) | RustOptimize::String(_) = &self { true } else { false } + } + + pub(crate) fn get_opt_level(&self) -> Option { + match &self { + RustOptimize::String(s) => Some(s.clone()), + RustOptimize::Bool(_) => None, + } + } +} + #[derive(Deserialize)] #[serde(untagged)] enum StringOrInt<'a> { String(&'a str), Int(i64), } - define_config! { /// TOML representation of how the Rust build is configured. struct Rust { - optimize: Option = "optimize", + optimize: Option = "optimize", debug: Option = "debug", codegen_units: Option = "codegen-units", codegen_units_std: Option = "codegen-units-std", @@ -971,7 +1009,7 @@ impl Config { config.ninja_in_file = true; config.llvm_static_stdcpp = false; config.backtrace = true; - config.rust_optimize = true; + config.rust_optimize = RustOptimize::Bool(true); config.rust_optimize_tests = true; config.submodules = None; config.docs = true; @@ -1546,7 +1584,7 @@ impl Config { config.llvm_assertions = llvm_assertions.unwrap_or(false); config.llvm_tests = llvm_tests.unwrap_or(false); config.llvm_plugins = llvm_plugins.unwrap_or(false); - config.rust_optimize = optimize.unwrap_or(true); + config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true)); let default = debug == Some(true); config.rust_debug_assertions = debug_assertions.unwrap_or(default); diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs index 3bee659abd1c5..732df54cdacbd 100644 --- a/src/bootstrap/config/tests.rs +++ b/src/bootstrap/config/tests.rs @@ -178,3 +178,18 @@ fn profile_user_dist() { } Config::parse_inner(&["check".to_owned()], get_toml); } + +#[test] +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 = \"s\"").rust_optimize.get_opt_level(), Some("s".to_string())); +} + +#[test] +#[should_panic] +fn invalid_rust_optimize() { + parse("rust.optimize = \"a\""); +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index c960053d7a0f2..6a51450a777e8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -785,7 +785,7 @@ impl Build { /// Component directory that Cargo will produce output into (e.g. /// release/debug) fn cargo_dir(&self) -> &'static str { - if self.config.rust_optimize { "release" } else { "debug" } + if self.config.rust_optimize.is_release() { "release" } else { "debug" } } fn tools_dir(&self, compiler: Compiler) -> PathBuf { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 2c1f612e39f52..a2938ab4caf37 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -801,7 +801,7 @@ impl Step for Clippy { cargo.arg("-p").arg("clippy_dev"); // clippy_dev gets confused if it can't find `clippy/Cargo.toml` cargo.current_dir(&builder.src.join("src").join("tools").join("clippy")); - if builder.config.rust_optimize { + if builder.config.rust_optimize.is_release() { cargo.env("PROFILE", "release"); } else { cargo.env("PROFILE", "debug");