[clang] [clang][driver][darwin] Use DefaultDeploymentTarget when inferring deployment target from SDK (PR #217983)

Akira Hatanaka via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 21 15:51:46 PDT 2026


https://github.com/ahatanak updated https://github.com/llvm/llvm-project/pull/217983

>From 5945e820e671966cced41f17def609222da89bdd Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Fri, 21 Aug 2026 09:54:18 -0700
Subject: [PATCH 1/4] [clang][driver][darwin] Use DefaultDeploymentTarget when
 inferring deployment target from SDK

Use "DefaultDeploymentTarget" from SDKSettings.json for the inferred
deployment target version, falling back to "Version" if it isn't
present. This only affects the deployment target; other uses of
"Version" (e.g., -target-sdk-version=) are unchanged.

rdar://184842209
---
 clang/include/clang/Basic/DarwinSDKInfo.h     | 14 +++++++++++--
 clang/lib/Basic/DarwinSDKInfo.cpp             |  9 ++++++--
 clang/lib/Driver/ToolChains/Darwin.cpp        |  2 +-
 .../Driver/darwin-default-deployment-target.c | 21 +++++++++++++++++++
 4 files changed, 41 insertions(+), 5 deletions(-)
 create mode 100644 clang/test/Driver/darwin-default-deployment-target.c

diff --git a/clang/include/clang/Basic/DarwinSDKInfo.h b/clang/include/clang/Basic/DarwinSDKInfo.h
index 2d55f4f61cd90..e635e32391b09 100644
--- a/clang/include/clang/Basic/DarwinSDKInfo.h
+++ b/clang/include/clang/Basic/DarwinSDKInfo.h
@@ -170,7 +170,8 @@ class DarwinSDKInfo {
   DarwinSDKInfo(
       std::string FilePath, llvm::Triple::OSType OS,
       llvm::Triple::EnvironmentType Environment, VersionTuple Version,
-      StringRef DisplayName, VersionTuple MaximumDeploymentTarget,
+      VersionTuple DefaultDeploymentTarget, StringRef DisplayName,
+      VersionTuple MaximumDeploymentTarget,
       PlatformInfoStorageType PlatformInfos,
       llvm::DenseMap<OSEnvPair::StorageType,
                      std::optional<RelatedTargetVersionMapping>>
@@ -178,7 +179,8 @@ class DarwinSDKInfo {
               llvm::DenseMap<OSEnvPair::StorageType,
                              std::optional<RelatedTargetVersionMapping>>())
       : FilePath(std::move(FilePath)), OS(OS), Environment(Environment),
-        Version(Version), DisplayName(DisplayName),
+        Version(Version), DefaultDeploymentTarget(DefaultDeploymentTarget),
+        DisplayName(DisplayName),
         MaximumDeploymentTarget(MaximumDeploymentTarget),
         PlatformInfos(std::move(PlatformInfos)),
         VersionMappings(std::move(VersionMappings)) {
@@ -203,6 +205,13 @@ class DarwinSDKInfo {
 
   const llvm::VersionTuple &getVersion() const { return Version; }
 
+  /// Returns the value of the "DefaultDeploymentTarget" key from
+  /// SDKSettings.json, or "Version" when the SDK doesn't specify a
+  /// "DefaultDeploymentTarget".
+  const llvm::VersionTuple &getDefaultDeploymentTarget() const {
+    return DefaultDeploymentTarget;
+  }
+
   const StringRef getDisplayName() const { return DisplayName; }
 
   const llvm::Triple &getCanonicalPlatformTriple() const {
@@ -240,6 +249,7 @@ class DarwinSDKInfo {
   llvm::Triple::OSType OS;
   llvm::Triple::EnvironmentType Environment;
   VersionTuple Version;
+  VersionTuple DefaultDeploymentTarget;
   std::string DisplayName;
   VersionTuple MaximumDeploymentTarget;
   PlatformInfoStorageType PlatformInfos;
diff --git a/clang/lib/Basic/DarwinSDKInfo.cpp b/clang/lib/Basic/DarwinSDKInfo.cpp
index 4e44da8febc3e..4a1590dd001ff 100644
--- a/clang/lib/Basic/DarwinSDKInfo.cpp
+++ b/clang/lib/Basic/DarwinSDKInfo.cpp
@@ -259,6 +259,10 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(std::string FilePath,
   auto Version = getVersionKey(*Obj, "Version");
   if (!Version)
     return std::nullopt;
+  // "DefaultDeploymentTarget" is usually the same as "Version", but the two
+  // can diverge, so prefer "DefaultDeploymentTarget" when it's present.
+  VersionTuple DefaultDeploymentTarget =
+      getVersionKey(*Obj, "DefaultDeploymentTarget").value_or(*Version);
   auto MaximumDeploymentVersion =
       getVersionKey(*Obj, "MaximumDeploymentTarget");
   if (!MaximumDeploymentVersion)
@@ -318,7 +322,8 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(std::string FilePath,
 
   return DarwinSDKInfo(std::move(FilePath), OSAndEnvironment.first,
                        OSAndEnvironment.second, std::move(*Version),
-                       DisplayName, std::move(*MaximumDeploymentVersion),
+                       DefaultDeploymentTarget, DisplayName,
+                       std::move(*MaximumDeploymentVersion),
                        std::move(PlatformInfos), std::move(VersionMappings));
 }
 
@@ -350,7 +355,7 @@ DarwinSDKInfo::DarwinSDKInfo(llvm::Triple::OSType OS,
                              llvm::Triple::EnvironmentType Environment,
                              VersionTuple Version, StringRef DisplayName,
                              VersionTuple MaximumDeploymentTarget)
-    : DarwinSDKInfo("", OS, Environment, Version, DisplayName,
+    : DarwinSDKInfo("", OS, Environment, Version, Version, DisplayName,
                     MaximumDeploymentTarget,
                     legacyPlatformInfos(OS, Environment)) {}
 
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index d3de04fc5155e..98ace0720343f 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -2057,7 +2057,7 @@ struct DarwinPlatform {
                                           const DarwinSDKInfo &SDKInfo) {
     const llvm::Triple &PlatformTriple = SDKInfo.getCanonicalPlatformTriple();
     const llvm::Triple::OSType OS = PlatformTriple.getOS();
-    VersionTuple Version = SDKInfo.getVersion();
+    VersionTuple Version = SDKInfo.getDefaultDeploymentTarget();
     if (OS == llvm::Triple::MacOSX)
       Version = getVersionFromString(
           getSystemOrSDKMacOSVersion(Version.getAsString()));
diff --git a/clang/test/Driver/darwin-default-deployment-target.c b/clang/test/Driver/darwin-default-deployment-target.c
new file mode 100644
index 0000000000000..0fc8f2be94dbe
--- /dev/null
+++ b/clang/test/Driver/darwin-default-deployment-target.c
@@ -0,0 +1,21 @@
+// Ensure that the deployment target inferred from the SDK when none is
+// specified on the command line uses "DefaultDeploymentTarget" rather than
+// "Version" when the SDK specifies both and they differ.
+
+// RUN: rm -rf %t/SDKs/iPhoneOS18.0.sdk
+// RUN: mkdir -p %t/SDKs/iPhoneOS18.0.sdk
+// RUN: echo '{"CanonicalName": "iphoneos18.0", "Version": "18.0", "DefaultDeploymentTarget": "17.0", "MaximumDeploymentTarget": "18.0.99"}' \
+// RUN:   > %t/SDKs/iPhoneOS18.0.sdk/SDKSettings.json
+// RUN: %clang -target arm64-apple-darwin -isysroot %t/SDKs/iPhoneOS18.0.sdk -c -### %s 2>&1 \
+// RUN:   | FileCheck %s
+
+// CHECK: "-triple" "arm64-apple-ios17.0.0"
+// CHECK-SAME: -target-sdk-version=18.0
+
+// An explicit deployment target on the command line overrides the SDK's
+// "DefaultDeploymentTarget".
+// RUN: %clang -target arm64-apple-darwin -isysroot %t/SDKs/iPhoneOS18.0.sdk -miphoneos-version-min=12.0 -c -### %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=OVERRIDE %s
+
+// OVERRIDE: "-triple" "arm64-apple-ios12.0.0"
+// OVERRIDE-SAME: -target-sdk-version=18.0

>From c0cdf9a1618f426144ed10402beb43c876997443 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Fri, 21 Aug 2026 11:51:58 -0700
Subject: [PATCH 2/4] Address review comments

---
 clang/include/clang/Basic/DarwinSDKInfo.h     |  8 ++--
 clang/lib/Basic/DarwinSDKInfo.cpp             |  4 +-
 .../Driver/darwin-default-deployment-target.c | 40 ++++++++++++++++---
 3 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/clang/include/clang/Basic/DarwinSDKInfo.h b/clang/include/clang/Basic/DarwinSDKInfo.h
index e635e32391b09..3de3ccfee13a6 100644
--- a/clang/include/clang/Basic/DarwinSDKInfo.h
+++ b/clang/include/clang/Basic/DarwinSDKInfo.h
@@ -170,7 +170,7 @@ class DarwinSDKInfo {
   DarwinSDKInfo(
       std::string FilePath, llvm::Triple::OSType OS,
       llvm::Triple::EnvironmentType Environment, VersionTuple Version,
-      VersionTuple DefaultDeploymentTarget, StringRef DisplayName,
+      StringRef DisplayName, VersionTuple DefaultDeploymentTarget,
       VersionTuple MaximumDeploymentTarget,
       PlatformInfoStorageType PlatformInfos,
       llvm::DenseMap<OSEnvPair::StorageType,
@@ -179,8 +179,8 @@ class DarwinSDKInfo {
               llvm::DenseMap<OSEnvPair::StorageType,
                              std::optional<RelatedTargetVersionMapping>>())
       : FilePath(std::move(FilePath)), OS(OS), Environment(Environment),
-        Version(Version), DefaultDeploymentTarget(DefaultDeploymentTarget),
-        DisplayName(DisplayName),
+        Version(Version), DisplayName(DisplayName),
+        DefaultDeploymentTarget(DefaultDeploymentTarget),
         MaximumDeploymentTarget(MaximumDeploymentTarget),
         PlatformInfos(std::move(PlatformInfos)),
         VersionMappings(std::move(VersionMappings)) {
@@ -249,8 +249,8 @@ class DarwinSDKInfo {
   llvm::Triple::OSType OS;
   llvm::Triple::EnvironmentType Environment;
   VersionTuple Version;
-  VersionTuple DefaultDeploymentTarget;
   std::string DisplayName;
+  VersionTuple DefaultDeploymentTarget;
   VersionTuple MaximumDeploymentTarget;
   PlatformInfoStorageType PlatformInfos;
   // Need to wrap the value in an optional here as the value has to be default
diff --git a/clang/lib/Basic/DarwinSDKInfo.cpp b/clang/lib/Basic/DarwinSDKInfo.cpp
index 4a1590dd001ff..9a6637ce4a627 100644
--- a/clang/lib/Basic/DarwinSDKInfo.cpp
+++ b/clang/lib/Basic/DarwinSDKInfo.cpp
@@ -322,7 +322,7 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(std::string FilePath,
 
   return DarwinSDKInfo(std::move(FilePath), OSAndEnvironment.first,
                        OSAndEnvironment.second, std::move(*Version),
-                       DefaultDeploymentTarget, DisplayName,
+                       DisplayName, DefaultDeploymentTarget,
                        std::move(*MaximumDeploymentVersion),
                        std::move(PlatformInfos), std::move(VersionMappings));
 }
@@ -355,7 +355,7 @@ DarwinSDKInfo::DarwinSDKInfo(llvm::Triple::OSType OS,
                              llvm::Triple::EnvironmentType Environment,
                              VersionTuple Version, StringRef DisplayName,
                              VersionTuple MaximumDeploymentTarget)
-    : DarwinSDKInfo("", OS, Environment, Version, Version, DisplayName,
+    : DarwinSDKInfo("", OS, Environment, Version, DisplayName, Version,
                     MaximumDeploymentTarget,
                     legacyPlatformInfos(OS, Environment)) {}
 
diff --git a/clang/test/Driver/darwin-default-deployment-target.c b/clang/test/Driver/darwin-default-deployment-target.c
index 0fc8f2be94dbe..5edee3e03c4d2 100644
--- a/clang/test/Driver/darwin-default-deployment-target.c
+++ b/clang/test/Driver/darwin-default-deployment-target.c
@@ -1,12 +1,12 @@
 // Ensure that the deployment target inferred from the SDK when none is
 // specified on the command line uses "DefaultDeploymentTarget" rather than
 // "Version" when the SDK specifies both and they differ.
+// REQUIRES: system-darwin && native
 
-// RUN: rm -rf %t/SDKs/iPhoneOS18.0.sdk
-// RUN: mkdir -p %t/SDKs/iPhoneOS18.0.sdk
-// RUN: echo '{"CanonicalName": "iphoneos18.0", "Version": "18.0", "DefaultDeploymentTarget": "17.0", "MaximumDeploymentTarget": "18.0.99"}' \
-// RUN:   > %t/SDKs/iPhoneOS18.0.sdk/SDKSettings.json
-// RUN: %clang -target arm64-apple-darwin -isysroot %t/SDKs/iPhoneOS18.0.sdk -c -### %s 2>&1 \
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+
+// RUN: %clang -target arm64-apple-darwin -isysroot %t/iPhoneOS18.0.sdk -c -### %s 2>&1 \
 // RUN:   | FileCheck %s
 
 // CHECK: "-triple" "arm64-apple-ios17.0.0"
@@ -14,8 +14,36 @@
 
 // An explicit deployment target on the command line overrides the SDK's
 // "DefaultDeploymentTarget".
-// RUN: %clang -target arm64-apple-darwin -isysroot %t/SDKs/iPhoneOS18.0.sdk -miphoneos-version-min=12.0 -c -### %s 2>&1 \
+// RUN: %clang -target arm64-apple-darwin -isysroot %t/iPhoneOS18.0.sdk -miphoneos-version-min=12.0 -c -### %s 2>&1 \
 // RUN:   | FileCheck --check-prefix=OVERRIDE %s
 
 // OVERRIDE: "-triple" "arm64-apple-ios12.0.0"
 // OVERRIDE-SAME: -target-sdk-version=18.0
+
+//--- iPhoneOS18.0.sdk/SDKSettings.json
+{
+  "CanonicalName": "iphoneos18.0",
+  "Version": "18.0",
+  "IsBaseSDK": "YES",
+  "DisplayName": "iOS 18.0",
+  "MinimalDisplayName": "18.0",
+  "SupportedTargets": {
+    "iphoneos": {
+      "PlatformFamilyName": "iOS",
+      "PlatformFamilyDisplayName": "iOS",
+      "Archs": ["arm64e", "arm64"], "LLVMTargetTripleVendor": "apple", "LLVMTargetTripleSys": "ios", "LLVMTargetTripleEnvironment": "",
+      "BuildVersionPlatformID": "2",
+      "ClangRuntimeLibraryPlatformName": "ios",
+      "SystemPrefix": "",
+      "DefaultDeploymentTarget": "17.0",
+      "RecommendedDeploymentTarget": "15.0",
+      "MinimumDeploymentTarget": "12.0", "MaximumDeploymentTarget": "18.0.99",
+      "ValidDeploymentTargets": ["12.0", "12.1", "12.2", "12.3", "12.4", "13.0", "13.1", "13.2", "13.3", "13.4", "13.5", "13.6", "14.0", "14.1", "14.2", "14.3", "14.4", "14.5", "14.6", "14.7", "15.0", "15.1", "15.2", "15.3", "15.4", "15.5", "15.6", "16.0", "16.1", "16.2", "16.3", "16.4", "16.5", "16.6", "17.0", "17.1", "17.2", "17.3", "17.4", "17.5", "17.6", "18.0"]
+    }
+  },
+  "DefaultDeploymentTarget": "17.0",
+  "MaximumDeploymentTarget": "18.0.99",
+  "Comments": [
+    "Modified version of the iOS SDK from Xcode 18.0 to have \"DefaultDeploymentTarget\" differ from \"Version\"."
+  ]
+}

>From da61a031b3026722c0878d76c2b956607f7944c2 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Fri, 21 Aug 2026 15:20:35 -0700
Subject: [PATCH 3/4] return nullopt if DefaultDeploymentTarget is missing

---
 clang/include/clang/Basic/DarwinSDKInfo.h     |  3 +-
 clang/lib/Basic/DarwinSDKInfo.cpp             |  9 +++--
 .../Driver/darwin-default-deployment-target.c | 36 +++++++++++++++++++
 3 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Basic/DarwinSDKInfo.h b/clang/include/clang/Basic/DarwinSDKInfo.h
index 3de3ccfee13a6..41f4ee4543137 100644
--- a/clang/include/clang/Basic/DarwinSDKInfo.h
+++ b/clang/include/clang/Basic/DarwinSDKInfo.h
@@ -206,8 +206,7 @@ class DarwinSDKInfo {
   const llvm::VersionTuple &getVersion() const { return Version; }
 
   /// Returns the value of the "DefaultDeploymentTarget" key from
-  /// SDKSettings.json, or "Version" when the SDK doesn't specify a
-  /// "DefaultDeploymentTarget".
+  /// SDKSettings.json.
   const llvm::VersionTuple &getDefaultDeploymentTarget() const {
     return DefaultDeploymentTarget;
   }
diff --git a/clang/lib/Basic/DarwinSDKInfo.cpp b/clang/lib/Basic/DarwinSDKInfo.cpp
index 9a6637ce4a627..63608e3e4ad8b 100644
--- a/clang/lib/Basic/DarwinSDKInfo.cpp
+++ b/clang/lib/Basic/DarwinSDKInfo.cpp
@@ -259,10 +259,9 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(std::string FilePath,
   auto Version = getVersionKey(*Obj, "Version");
   if (!Version)
     return std::nullopt;
-  // "DefaultDeploymentTarget" is usually the same as "Version", but the two
-  // can diverge, so prefer "DefaultDeploymentTarget" when it's present.
-  VersionTuple DefaultDeploymentTarget =
-      getVersionKey(*Obj, "DefaultDeploymentTarget").value_or(*Version);
+  auto DefaultDeploymentTarget = getVersionKey(*Obj, "DefaultDeploymentTarget");
+  if (!DefaultDeploymentTarget)
+    return std::nullopt;
   auto MaximumDeploymentVersion =
       getVersionKey(*Obj, "MaximumDeploymentTarget");
   if (!MaximumDeploymentVersion)
@@ -322,7 +321,7 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(std::string FilePath,
 
   return DarwinSDKInfo(std::move(FilePath), OSAndEnvironment.first,
                        OSAndEnvironment.second, std::move(*Version),
-                       DisplayName, DefaultDeploymentTarget,
+                       DisplayName, std::move(*DefaultDeploymentTarget),
                        std::move(*MaximumDeploymentVersion),
                        std::move(PlatformInfos), std::move(VersionMappings));
 }
diff --git a/clang/test/Driver/darwin-default-deployment-target.c b/clang/test/Driver/darwin-default-deployment-target.c
index 5edee3e03c4d2..11edec14d6842 100644
--- a/clang/test/Driver/darwin-default-deployment-target.c
+++ b/clang/test/Driver/darwin-default-deployment-target.c
@@ -20,6 +20,16 @@
 // OVERRIDE: "-triple" "arm64-apple-ios12.0.0"
 // OVERRIDE-SAME: -target-sdk-version=18.0
 
+// When "DefaultDeploymentTarget" is missing, the whole SDKSettings.json is
+// treated as unusable and the version is instead inferred from the SDK
+// path.
+// RUN: %clang -target arm64-apple-darwin -isysroot %t/iPhoneOS18.3.sdk -c -### %s 2>&1 \
+// RUN:   | FileCheck --check-prefix=NO-DEFAULT %s
+
+// NO-DEFAULT: warning: SDK settings were ignored as 'SDKSettings.json' could not be parsed
+// NO-DEFAULT: "-triple" "arm64-apple-ios18.3.0"
+// NO-DEFAULT-SAME: -target-sdk-version=18.3
+
 //--- iPhoneOS18.0.sdk/SDKSettings.json
 {
   "CanonicalName": "iphoneos18.0",
@@ -47,3 +57,29 @@
     "Modified version of the iOS SDK from Xcode 18.0 to have \"DefaultDeploymentTarget\" differ from \"Version\"."
   ]
 }
+
+//--- iPhoneOS18.3.sdk/SDKSettings.json
+{
+  "CanonicalName": "iphoneos18.6",
+  "Version": "18.6",
+  "IsBaseSDK": "YES",
+  "DisplayName": "iOS 18.6",
+  "MinimalDisplayName": "18.6",
+  "SupportedTargets": {
+    "iphoneos": {
+      "PlatformFamilyName": "iOS",
+      "PlatformFamilyDisplayName": "iOS",
+      "Archs": ["arm64e", "arm64"], "LLVMTargetTripleVendor": "apple", "LLVMTargetTripleSys": "ios", "LLVMTargetTripleEnvironment": "",
+      "BuildVersionPlatformID": "2",
+      "ClangRuntimeLibraryPlatformName": "ios",
+      "SystemPrefix": "",
+      "RecommendedDeploymentTarget": "15.0",
+      "MinimumDeploymentTarget": "12.0", "MaximumDeploymentTarget": "18.6.99",
+      "ValidDeploymentTargets": ["12.0", "12.1", "12.2", "12.3", "12.4", "13.0", "13.1", "13.2", "13.3", "13.4", "13.5", "13.6", "14.0", "14.1", "14.2", "14.3", "14.4", "14.5", "14.6", "14.7", "15.0", "15.1", "15.2", "15.3", "15.4", "15.5", "15.6", "16.0", "16.1", "16.2", "16.3", "16.4", "16.5", "16.6", "17.0", "17.1", "17.2", "17.3", "17.4", "17.5", "17.6", "18.0", "18.1", "18.2", "18.3", "18.4", "18.5", "18.6"]
+    }
+  },
+  "MaximumDeploymentTarget": "18.6.99",
+  "Comments": [
+    "Modified version of the iOS SDK from Xcode 18.6 with \"DefaultDeploymentTarget\" removed to test the fallback path used when it's missing. The SDK's folder name deliberately differs from \"Version\" to show the SDK path, not \"Version\", is used for the fallback."
+  ]
+}

>From 1ff4768538af9db6428d786024aaaacbaf2a9c3c Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Fri, 21 Aug 2026 15:45:23 -0700
Subject: [PATCH 4/4] Drop comment

---
 clang/include/clang/Basic/DarwinSDKInfo.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/clang/include/clang/Basic/DarwinSDKInfo.h b/clang/include/clang/Basic/DarwinSDKInfo.h
index 41f4ee4543137..3c8297569180f 100644
--- a/clang/include/clang/Basic/DarwinSDKInfo.h
+++ b/clang/include/clang/Basic/DarwinSDKInfo.h
@@ -205,8 +205,6 @@ class DarwinSDKInfo {
 
   const llvm::VersionTuple &getVersion() const { return Version; }
 
-  /// Returns the value of the "DefaultDeploymentTarget" key from
-  /// SDKSettings.json.
   const llvm::VersionTuple &getDefaultDeploymentTarget() const {
     return DefaultDeploymentTarget;
   }



More information about the cfe-commits mailing list