Skip to content

Commit efaa2d4

Browse files
committed
Convert OSVersion to a struct that implements traits
Instead of being a type-alias to a tuple. This allows us to implement Deserialize for OSVersion, which will be useful when parsing SDK settings.
1 parent c70b075 commit efaa2d4

File tree

12 files changed

+113
-54
lines changed

12 files changed

+113
-54
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4450,6 +4450,7 @@ dependencies = [
44504450
"rustc_macros",
44514451
"rustc_serialize",
44524452
"rustc_span",
4453+
"serde",
44534454
"serde_json",
44544455
"tracing",
44554456
]

compiler/rustc_codegen_ssa/src/apple.rs

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,19 @@
11
use std::borrow::Cow;
2-
use std::env;
3-
use std::fs;
42
use std::io::ErrorKind;
5-
use std::fmt::{Display, from_fn};
63
use std::path::{Path, PathBuf};
4+
use std::{env, fs};
75

86
use rustc_session::Session;
97
use rustc_target::spec::{
108
AppleOSVersion, apple_deployment_target_env_var, apple_minimum_deployment_target,
11-
apple_os_minimum_deployment_target, apple_parse_version,
9+
apple_os_minimum_deployment_target,
1210
};
1311

1412
use crate::errors::{AppleDeploymentTarget, AppleSdkError};
1513

1614
#[cfg(test)]
1715
mod tests;
1816

19-
pub fn pretty_version(version: AppleOSVersion) -> impl Display {
20-
let (major, minor, patch) = version;
21-
from_fn(move |f| {
22-
write!(f, "{major}.{minor}")?;
23-
if patch != 0 {
24-
write!(f, ".{patch}")?;
25-
}
26-
Ok(())
27-
})
28-
}
29-
3017
/// Get the deployment target based on the standard environment variables, or fall back to the
3118
/// minimum version supported by `rustc`.
3219
pub fn deployment_target(sess: &Session) -> AppleOSVersion {
@@ -35,7 +22,7 @@ pub fn deployment_target(sess: &Session) -> AppleOSVersion {
3522
let env_var = apple_deployment_target_env_var(&sess.target.os);
3623

3724
if let Ok(deployment_target) = env::var(env_var) {
38-
match apple_parse_version(&deployment_target) {
25+
match deployment_target.parse::<AppleOSVersion>() {
3926
Ok(version) => {
4027
// It is common that the deployment target is set a bit too low, for example on
4128
// macOS Aarch64 to also target older x86_64. So we only want to warn when variable
@@ -44,8 +31,8 @@ pub fn deployment_target(sess: &Session) -> AppleOSVersion {
4431
if version < os_min {
4532
sess.dcx().emit_warn(AppleDeploymentTarget::TooLow {
4633
env_var,
47-
version: pretty_version(version).to_string(),
48-
os_min: pretty_version(os_min).to_string(),
34+
version: version.pretty().to_string(),
35+
os_min: os_min.pretty().to_string(),
4936
});
5037
}
5138

@@ -71,7 +58,7 @@ fn add_version_to_llvm_target(llvm_target: &str, deployment_target: AppleOSVersi
7158
let environment = components.next();
7259
assert_eq!(components.next(), None, "too many LLVM triple components");
7360

74-
let (major, minor, patch) = deployment_target;
61+
let AppleOSVersion { major, minor, patch } = deployment_target;
7562

7663
assert!(
7764
!os.contains(|c: char| c.is_ascii_digit()),

compiler/rustc_codegen_ssa/src/apple/tests.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,21 @@ use std::io;
22
use std::path::PathBuf;
33
use std::process::Command;
44

5+
use rustc_target::spec::AppleOSVersion;
6+
57
use super::{add_version_to_llvm_target, find_sdk_root};
68

79
#[test]
810
fn test_add_version_to_llvm_target() {
11+
let version = AppleOSVersion { major: 10, minor: 14, patch: 1 };
912
assert_eq!(
10-
add_version_to_llvm_target("aarch64-apple-macosx", (10, 14, 1)),
13+
add_version_to_llvm_target("aarch64-apple-macosx", version),
1114
"aarch64-apple-macosx10.14.1"
1215
);
16+
17+
let version = AppleOSVersion { major: 16, minor: 1, patch: 0 };
1318
assert_eq!(
14-
add_version_to_llvm_target("aarch64-apple-ios-simulator", (16, 1, 0)),
19+
add_version_to_llvm_target("aarch64-apple-ios-simulator", version),
1520
"aarch64-apple-ios16.1.0-simulator"
1621
);
1722
}

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ use rustc_session::{Session, filesearch};
3838
use rustc_span::symbol::Symbol;
3939
use rustc_target::spec::crt_objects::CrtObjects;
4040
use rustc_target::spec::{
41-
Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures,
42-
LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
43-
SplitDebuginfo,
41+
AppleOSVersion, Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault,
42+
LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel,
43+
SanitizerSet, SplitDebuginfo,
4444
};
4545
use tempfile::Builder as TempFileBuilder;
4646
use tracing::{debug, info, warn};
@@ -3038,7 +3038,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
30383038
_ => bug!("invalid OS/ABI combination for Apple target: {target_os}, {target_abi}"),
30393039
};
30403040

3041-
let (major, minor, patch) = deployment_target(sess);
3041+
let AppleOSVersion { major, minor, patch } = deployment_target(sess);
30423042
let min_version = format!("{major}.{minor}.{patch}");
30433043

30443044
// The SDK version is used at runtime when compiling with a newer SDK / version of Xcode:
@@ -3108,7 +3108,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
31083108

31093109
// The presence of `-mmacosx-version-min` makes CC default to
31103110
// macOS, and it sets the deployment target.
3111-
let (major, minor, patch) = deployment_target(sess);
3111+
let AppleOSVersion { major, minor, patch } = deployment_target(sess);
31123112
// Intentionally pass this as a single argument, Clang doesn't
31133113
// seem to like it otherwise.
31143114
cmd.cc_arg(&format!("-mmacosx-version-min={major}.{minor}.{patch}"));

compiler/rustc_codegen_ssa/src/back/metadata.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,9 +392,12 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
392392
/// Since Xcode 15, Apple's LD apparently requires object files to use this load command, so this
393393
/// returns the `MachOBuildVersion` for the target to do so.
394394
fn macho_object_build_version_for_target(sess: &Session) -> object::write::MachOBuildVersion {
395+
use rustc_target::spec::AppleOSVersion;
396+
395397
/// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz"
396398
/// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200
397-
fn pack_version((major, minor, patch): (u16, u8, u8)) -> u32 {
399+
fn pack_version(version: AppleOSVersion) -> u32 {
400+
let AppleOSVersion { major, minor, patch } = version;
398401
let (major, minor, patch) = (major as u32, minor as u32, patch as u32);
399402
(major << 16) | (minor << 8) | patch
400403
}

compiler/rustc_codegen_ssa/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#![doc(rust_logo)]
77
#![feature(assert_matches)]
88
#![feature(box_patterns)]
9-
#![feature(debug_closure_helpers)]
109
#![feature(file_buffered)]
1110
#![feature(if_let_guard)]
1211
#![feature(let_chains)]

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -855,10 +855,10 @@ fn print_crate_info(
855855
}
856856
}
857857
DeploymentTarget => {
858-
use rustc_codegen_ssa::apple::{deployment_target, pretty_version};
858+
use rustc_codegen_ssa::apple::deployment_target;
859859

860860
if sess.target.is_like_osx {
861-
println_info!("deployment_target={}", pretty_version(deployment_target(sess)))
861+
println_info!("deployment_target={}", deployment_target(sess).pretty())
862862
} else {
863863
#[allow(rustc::diagnostic_outside_of_impl)]
864864
sess.dcx().fatal("only Apple targets currently support deployment version info")

compiler/rustc_target/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ rustc_index = { path = "../rustc_index" }
1414
rustc_macros = { path = "../rustc_macros" }
1515
rustc_serialize = { path = "../rustc_serialize" }
1616
rustc_span = { path = "../rustc_span" }
17+
serde = "1"
1718
serde_json = "1.0.59"
1819
tracing = "0.1"
1920
# tidy-alphabetical-end

compiler/rustc_target/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
1313
#![doc(rust_logo)]
1414
#![feature(assert_matches)]
15+
#![feature(debug_closure_helpers)]
1516
#![feature(iter_intersperse)]
1617
#![feature(let_chains)]
1718
#![feature(rustc_attrs)]

compiler/rustc_target/src/spec/base/apple/mod.rs

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use std::borrow::Cow;
2-
use std::env;
32
use std::num::ParseIntError;
3+
use std::str::FromStr;
4+
use std::{env, fmt};
5+
6+
use serde::de;
47

58
use crate::spec::{
69
Cc, DebuginfoKind, FramePointer, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType, StaticCow,
@@ -201,14 +204,15 @@ pub fn os_minimum_deployment_target(os: &str) -> OSVersion {
201204
// ```
202205
// $ rustc --print deployment-target
203206
// ```
204-
match os {
207+
let (major, minor, patch) = match os {
205208
"macos" => (10, 12, 0),
206209
"ios" => (10, 0, 0),
207210
"tvos" => (10, 0, 0),
208211
"watchos" => (5, 0, 0),
209212
"visionos" => (1, 0, 0),
210213
_ => unreachable!("tried to get deployment target for non-Apple platform"),
211-
}
214+
};
215+
OSVersion { major, minor, patch }
212216
}
213217

214218
/// The deployment target for the given target.
@@ -219,7 +223,7 @@ pub fn os_minimum_deployment_target(os: &str) -> OSVersion {
219223
/// This matches what LLVM does, see in part:
220224
/// <https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L1900-L1932>
221225
pub fn minimum_deployment_target(target: &Target) -> OSVersion {
222-
match (&*target.os, &*target.arch, &*target.abi) {
226+
let (major, minor, patch) = match (&*target.os, &*target.arch, &*target.abi) {
223227
("macos", "aarch64", _) => (11, 0, 0),
224228
("ios", "aarch64", "macabi") => (14, 0, 0),
225229
("ios", "aarch64", "sim") => (14, 0, 0),
@@ -228,8 +232,9 @@ pub fn minimum_deployment_target(target: &Target) -> OSVersion {
228232
("ios", _, "macabi") => (13, 1, 0),
229233
("tvos", "aarch64", "sim") => (14, 0, 0),
230234
("watchos", "aarch64", "sim") => (7, 0, 0),
231-
(os, _, _) => os_minimum_deployment_target(os),
232-
}
235+
(os, _, _) => return os_minimum_deployment_target(os),
236+
};
237+
OSVersion { major, minor, patch }
233238
}
234239

235240
/// Name of the environment variable used to fetch the deployment target on the given OS.
@@ -307,18 +312,68 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> {
307312
/// Deployment target or SDK version.
308313
///
309314
/// The size of the numbers in here are limited by Mach-O's `LC_BUILD_VERSION`.
310-
pub type OSVersion = (u16, u8, u8);
311-
312-
/// Parse an OS version triple (SDK version or deployment target).
313-
pub fn parse_version(version: &str) -> Result<OSVersion, ParseIntError> {
314-
if let Some((major, minor)) = version.split_once('.') {
315-
let major = major.parse()?;
316-
if let Some((minor, patch)) = minor.split_once('.') {
317-
Ok((major, minor.parse()?, patch.parse()?))
315+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
316+
pub struct OSVersion {
317+
pub major: u16,
318+
pub minor: u8,
319+
pub patch: u8,
320+
}
321+
322+
impl OSVersion {
323+
pub const MIN: Self = Self { major: u16::MIN, minor: u8::MIN, patch: u8::MIN };
324+
325+
pub const MAX: Self = Self { major: u16::MAX, minor: u8::MAX, patch: u8::MAX };
326+
327+
pub fn pretty(self) -> impl fmt::Display {
328+
let OSVersion { major, minor, patch } = self;
329+
fmt::from_fn(move |f| {
330+
write!(f, "{major}.{minor}")?;
331+
if patch != 0 {
332+
write!(f, ".{patch}")?;
333+
}
334+
Ok(())
335+
})
336+
}
337+
}
338+
339+
impl<'de> de::Deserialize<'de> for OSVersion {
340+
fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<OSVersion, D::Error> {
341+
struct OSVersionVisitor;
342+
343+
impl<'de> de::Visitor<'de> for OSVersionVisitor {
344+
type Value = OSVersion;
345+
346+
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347+
f.write_str("a valid `major.minor.patch` version")
348+
}
349+
350+
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
351+
OSVersion::from_str(value).map_err(E::custom)
352+
}
353+
}
354+
355+
deserializer.deserialize_str(OSVersionVisitor)
356+
}
357+
}
358+
359+
impl FromStr for OSVersion {
360+
type Err = ParseIntError;
361+
362+
/// Parse an OS version triple (SDK version or deployment target).
363+
fn from_str(version: &str) -> Result<Self, Self::Err> {
364+
if let Some((major, minor)) = version.split_once('.') {
365+
let major = major.parse()?;
366+
if let Some((minor, patch)) = minor.split_once('.') {
367+
let minor = minor.parse()?;
368+
let patch = patch.parse()?;
369+
Ok(Self { major, minor, patch })
370+
} else {
371+
let minor = minor.parse()?;
372+
Ok(Self { major, minor, patch: 0 })
373+
}
318374
} else {
319-
Ok((major, minor.parse()?, 0))
375+
let major = version.parse()?;
376+
Ok(Self { major, minor: 0, patch: 0 })
320377
}
321-
} else {
322-
Ok((version.parse()?, 0, 0))
323378
}
324379
}

compiler/rustc_target/src/spec/base/apple/tests.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use super::parse_version;
1+
use std::str::FromStr;
2+
3+
use super::OSVersion;
24
use crate::spec::targets::{
35
aarch64_apple_darwin, aarch64_apple_ios_sim, aarch64_apple_visionos_sim,
46
aarch64_apple_watchos_sim, i686_apple_darwin, x86_64_apple_darwin, x86_64_apple_ios,
@@ -43,8 +45,14 @@ fn macos_link_environment_unmodified() {
4345

4446
#[test]
4547
fn test_parse_version() {
46-
assert_eq!(parse_version("10"), Ok((10, 0, 0)));
47-
assert_eq!(parse_version("10.12"), Ok((10, 12, 0)));
48-
assert_eq!(parse_version("10.12.6"), Ok((10, 12, 6)));
49-
assert_eq!(parse_version("9999.99.99"), Ok((9999, 99, 99)));
48+
let cases = [
49+
("10", 10, 0, 0),
50+
("10.12", 10, 12, 0),
51+
("10.12.6", 10, 12, 6),
52+
("9999.99.99", 9999, 99, 99),
53+
];
54+
for (str, major, minor, patch) in cases {
55+
let expected = OSVersion { major, minor, patch };
56+
assert_eq!(Ok(expected), OSVersion::from_str(str));
57+
}
5058
}

compiler/rustc_target/src/spec/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,7 @@ pub use base::apple::{
6363
OSVersion as AppleOSVersion, deployment_target_env_var as apple_deployment_target_env_var,
6464
minimum_deployment_target as apple_minimum_deployment_target,
6565
os_minimum_deployment_target as apple_os_minimum_deployment_target,
66-
parse_version as apple_parse_version, platform as current_apple_platform,
67-
sdk_name as apple_sdk_name,
66+
platform as current_apple_platform, sdk_name as apple_sdk_name,
6867
};
6968
pub use base::avr_gnu::ef_avr_arch;
7069

0 commit comments

Comments
 (0)