Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use String or Int to set the opt level #113273

Merged
merged 1 commit into from
Jul 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down
73 changes: 60 additions & 13 deletions src/bootstrap/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -875,11 +875,10 @@ impl Default for 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),
}

Expand All @@ -889,26 +888,74 @@ impl Default for RustOptimize {
}
}

fn deserialize_and_validate_opt_level<'de, D>(d: D) -> Result<String, D::Error>
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<D>(deserializer: D) -> Result<Self, D::Error>
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<E>(self, value: &str) -> Result<Self::Value, E>
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<E>(self, value: i64) -> Result<Self::Value, E>
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<E>(self, value: bool) -> Result<Self::Value, E>
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<String> {
match &self {
RustOptimize::String(s) => Some(s.clone()),
RustOptimize::Int(i) => Some(i.to_string()),
RustOptimize::Bool(_) => None,
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/bootstrap/config/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}

Expand Down