Author: Cyndy Ishida
Date: 2025-06-10T09:50:46-07:00
New Revision: 88f041f3e05e26617856cc096d2e2864dfaa1c7b

URL: 
https://github.com/llvm/llvm-project/commit/88f041f3e05e26617856cc096d2e2864dfaa1c7b
DIFF: 
https://github.com/llvm/llvm-project/commit/88f041f3e05e26617856cc096d2e2864dfaa1c7b.diff

LOG: [clang][Darwin] Align all OS Versions for 26 (#143548)

* Translate the following versions to 26.
  * watchOS 12 -> 26
  * visionOS 3 -> 26
  * macos 16 -> 26
  * iOS 19 -> 26
  * tvOS 19 -> 26

* Emit diagnostics, but allow conversion when clients attempt to use
invalid gaps in OS versioning in availability.

* For target-triples, only allow "valid" versions for implicit
conversions.

Added: 
    clang/test/CodeGen/attr-availability-aligned-versions.c
    clang/test/Driver/darwin-invalid-os-versions.c
    clang/test/Sema/Inputs/XROS.sdk/SDKSettings.json
    clang/test/Sema/attr-availability-invalid-os-versions.c
    clang/test/Sema/attr-availability-ios-aligned-versions.c
    clang/test/Sema/attr-availability-ios-fallback-aligned-versions.c

Modified: 
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Driver/ToolChains/Darwin.cpp
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/lib/Sema/SemaExprObjC.cpp
    clang/test/Driver/darwin-infer-simulator-sdkroot.c
    clang/test/Driver/darwin-ld-platform-version-macos.c
    clang/test/Driver/darwin-ld-platform-version-watchos.c
    clang/test/ExtractAPI/availability.c
    clang/test/ExtractAPI/inherited_availability.m
    clang/test/Sema/attr-availability-iosmac-infer-from-macos.c
    llvm/include/llvm/TargetParser/Triple.h
    llvm/lib/TargetParser/Triple.cpp
    llvm/lib/TextAPI/Platform.cpp
    llvm/unittests/TargetParser/TripleTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index f889e41c8699f..bd07bb1361a85 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1111,6 +1111,8 @@ static llvm::StringRef 
canonicalizePlatformName(llvm::StringRef Platform) {
     return llvm::StringSwitch<llvm::StringRef>(Platform)
              .Case("iOS", "ios")
              .Case("macOS", "macos")
+             .Case("macOSX", "macos")
+             .Case("macosx", "macos")
              .Case("tvOS", "tvos")
              .Case("watchOS", "watchos")
              .Case("iOSApplicationExtension", "ios_app_extension")
@@ -1175,6 +1177,26 @@ static llvm::Triple::EnvironmentType 
getEnvironmentType(llvm::StringRef Environm
              .Case("library", llvm::Triple::Library)
              .Default(llvm::Triple::UnknownEnvironment);
 }
+
+static llvm::Triple::OSType getOSType(llvm::StringRef Platform) {
+    using OSType = llvm::Triple::OSType;
+    return llvm::StringSwitch<OSType>(Platform)
+             .Case("ios", OSType::IOS)
+             .Case("macos", OSType::MacOSX)
+             .Case("maccatalyst", OSType::IOS)
+             .Case("tvos", OSType::TvOS)
+             .Case("watchos", OSType::WatchOS)
+             .Case("bridgeos", OSType::BridgeOS)
+             .Case("ios_app_extension", OSType::IOS)
+             .Case("maccatalyst_app_extension", OSType::IOS)
+             .Case("macos_app_extension", OSType::MacOSX)
+             .Case("tvos_app_extension", OSType::TvOS)
+             .Case("watchos_app_extension", OSType::WatchOS)
+             .Case("xros", OSType::XROS)
+             .Case("xros_app_extension", OSType::XROS)
+             .Default(OSType::UnknownOS);
+}
+
 }];
   let HasCustomParsing = 1;
   let InheritEvenIfAlreadyPresent = 1;

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1f283b776a02c..0f77083dac9df 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4063,6 +4063,9 @@ def warn_at_available_unchecked_use : Warning<
   "%select{@available|__builtin_available}0 does not guard availability here; "
   "use if (%select{@available|__builtin_available}0) instead">,
   InGroup<DiagGroup<"unsupported-availability-guard">>;
+def warn_availability_invalid_os_version
+    : Warning<"invalid %1 version '%0' in availability attribute">, 
InGroup<DiagGroup<"invalid-version-availability">>;
+def note_availability_invalid_os_version_adjusted: Note<"implicitly treating 
version as '%0'">;
 
 def warn_missing_sdksettings_for_availability_checking : Warning<
   "%0 availability is ignored without a valid 'SDKSettings.json' in the SDK">,

diff  --git a/clang/lib/Driver/ToolChains/Darwin.cpp 
b/clang/lib/Driver/ToolChains/Darwin.cpp
index 59f423b633464..e987ef78920e8 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1721,10 +1721,14 @@ struct DarwinPlatform {
     UnderlyingOSVersion.reset();
     return Result;
   }
+  bool isValidOSVersion() const {
+    return llvm::Triple::isValidVersionForOS(getOSFromPlatform(Platform),
+                                             getOSVersion());
+  }
 
   VersionTuple getCanonicalOSVersion() const {
-    return llvm::Triple::getCanonicalVersionForOS(getOSFromPlatform(Platform),
-                                                  getOSVersion());
+    return llvm::Triple::getCanonicalVersionForOS(
+        getOSFromPlatform(Platform), getOSVersion(), /*IsInValidRange=*/true);
   }
 
   void setOSVersion(const VersionTuple &Version) {
@@ -2451,6 +2455,9 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) 
const {
   }
 
   assert(PlatformAndVersion && "Unable to infer Darwin variant");
+  if (!PlatformAndVersion->isValidOSVersion())
+    getDriver().Diag(diag::err_drv_invalid_version_number)
+        << PlatformAndVersion->getAsString(Args, Opts);
   // After the deployment OS version has been resolved, set it to the canonical
   // version before further error detection and converting to a proper target
   // triple.
@@ -2552,6 +2559,12 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) 
const {
     ZipperedOSVersion = PlatformAndVersion->getZipperedOSVersion();
   setTarget(Platform, Environment, Major, Minor, Micro, ZipperedOSVersion);
   TargetVariantTriple = PlatformAndVersion->getTargetVariantTriple();
+  if (TargetVariantTriple &&
+      !llvm::Triple::isValidVersionForOS(TargetVariantTriple->getOS(),
+                                         TargetVariantTriple->getOSVersion())) 
{
+    getDriver().Diag(diag::err_drv_invalid_version_number)
+        << TargetVariantTriple->str();
+  }
 
   if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
     StringRef SDK = getSDKName(A->getValue());

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index da0e3265767d8..6360827f415b8 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -2374,7 +2374,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
   IdentifierLoc *Platform = AL.getArgAsIdent(0);
 
   IdentifierInfo *II = Platform->getIdentifierInfo();
-  if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty())
+  StringRef PrettyName = 
AvailabilityAttr::getPrettyPlatformName(II->getName());
+  if (PrettyName.empty())
     S.Diag(Platform->getLoc(), diag::warn_availability_unknown_platform)
         << Platform->getIdentifierInfo();
 
@@ -2385,6 +2386,32 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
   AvailabilityChange Introduced = AL.getAvailabilityIntroduced();
   AvailabilityChange Deprecated = AL.getAvailabilityDeprecated();
   AvailabilityChange Obsoleted = AL.getAvailabilityObsoleted();
+
+  const llvm::Triple::OSType PlatformOS = AvailabilityAttr::getOSType(
+      AvailabilityAttr::canonicalizePlatformName(II->getName()));
+
+  auto reportAndUpdateIfInvalidOS = [&](auto &InputVersion) -> void {
+    const bool IsInValidRange =
+        llvm::Triple::isValidVersionForOS(PlatformOS, InputVersion);
+    // Canonicalize availability versions.
+    auto CanonicalVersion = llvm::Triple::getCanonicalVersionForOS(
+        PlatformOS, InputVersion, IsInValidRange);
+    if (!IsInValidRange) {
+      S.Diag(Platform->getLoc(), diag::warn_availability_invalid_os_version)
+          << InputVersion.getAsString() << PrettyName;
+      S.Diag(Platform->getLoc(),
+             diag::note_availability_invalid_os_version_adjusted)
+          << CanonicalVersion.getAsString();
+    }
+    InputVersion = CanonicalVersion;
+  };
+
+  if (PlatformOS != llvm::Triple::OSType::UnknownOS) {
+    reportAndUpdateIfInvalidOS(Introduced.Version);
+    reportAndUpdateIfInvalidOS(Deprecated.Version);
+    reportAndUpdateIfInvalidOS(Obsoleted.Version);
+  }
+
   bool IsUnavailable = AL.getUnavailableLoc().isValid();
   bool IsStrict = AL.getStrictLoc().isValid();
   StringRef Str;
@@ -2476,7 +2503,11 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
         }
 
         auto Major = Version.getMajor();
-        auto NewMajor = Major >= 9 ? Major - 7 : 0;
+        auto NewMajor = Major;
+        if (Major < 9)
+          NewMajor = 0;
+        else if (Major < 12)
+          NewMajor = Major - 7;
         if (NewMajor >= 2) {
           if (Version.getMinor()) {
             if (Version.getSubminor())

diff  --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index b248ea380a526..3505d9f38d23c 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -5151,7 +5151,8 @@ ExprResult SemaObjC::ActOnObjCAvailabilityCheckExpr(
     SourceLocation RParen) {
   ASTContext &Context = getASTContext();
   auto FindSpecVersion =
-      [&](StringRef Platform) -> std::optional<VersionTuple> {
+      [&](StringRef Platform,
+          const llvm::Triple::OSType &OS) -> std::optional<VersionTuple> {
     auto Spec = llvm::find_if(AvailSpecs, [&](const AvailabilitySpec &Spec) {
       return Spec.getPlatform() == Platform;
     });
@@ -5164,12 +5165,16 @@ ExprResult SemaObjC::ActOnObjCAvailabilityCheckExpr(
     }
     if (Spec == AvailSpecs.end())
       return std::nullopt;
-    return Spec->getVersion();
+
+    return llvm::Triple::getCanonicalVersionForOS(
+        OS, Spec->getVersion(),
+        llvm::Triple::isValidVersionForOS(OS, Spec->getVersion()));
   };
 
   VersionTuple Version;
   if (auto MaybeVersion =
-          FindSpecVersion(Context.getTargetInfo().getPlatformName()))
+          FindSpecVersion(Context.getTargetInfo().getPlatformName(),
+                          Context.getTargetInfo().getTriple().getOS()))
     Version = *MaybeVersion;
 
   // The use of `@available` in the enclosing context should be analyzed to

diff  --git a/clang/test/CodeGen/attr-availability-aligned-versions.c 
b/clang/test/CodeGen/attr-availability-aligned-versions.c
new file mode 100644
index 0000000000000..5555fa8e7f690
--- /dev/null
+++ b/clang/test/CodeGen/attr-availability-aligned-versions.c
@@ -0,0 +1,28 @@
+/// This test verifies IR generated for APIs protected with availability 
annotations with a common versions.
+// RUN: %clang_cc1 -fvisibility=hidden "-triple" "arm64-apple-ios26.0" 
-emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fvisibility=hidden "-triple" "arm64-apple-tvos26" 
-emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fvisibility=hidden "-triple" "arm64-apple-watchos26" 
-emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fvisibility=hidden "-triple" "arm64-apple-ios18" 
-emit-llvm -o - %s | FileCheck -check-prefix=OLD %s
+
+__attribute__((availability(ios,introduced=19)))
+void f0(void);
+
+__attribute__((availability(ios,introduced=26)))
+void f1(void);
+
+__attribute__((availability(ios,introduced=27)))
+void f2(void);
+
+// OLD: declare extern_weak void @f0
+// OLD: declare extern_weak void @f1
+// OLD: declare extern_weak void @f2
+
+// CHECK:  declare void @f0
+// CHECK:  declare void @f1
+// CHECK:  declare extern_weak void @f2
+
+void test() {
+  f0();
+  f1();
+  f2();
+}

diff  --git a/clang/test/Driver/darwin-infer-simulator-sdkroot.c 
b/clang/test/Driver/darwin-infer-simulator-sdkroot.c
index 519e6d27540e3..a946015028aa3 100644
--- a/clang/test/Driver/darwin-infer-simulator-sdkroot.c
+++ b/clang/test/Driver/darwin-infer-simulator-sdkroot.c
@@ -41,9 +41,9 @@
 //
 // RUN: rm -rf %t/SDKs/WatchOS3.0.sdk
 // RUN: mkdir -p %t/SDKs/WatchOS3.0.sdk
-// RUN: env SDKROOT=%t/SDKs/WatchOS3.0.sdk %clang %s -fuse-ld= 
-mlinker-version=400 -### 2>&1 \
+// RUN: env SDKROOT=%t/SDKs/WatchOS3.0.sdk %clang %s -fuse-ld= -arch arm64_32 
-mlinker-version=400 -### 2>&1 \
 // RUN:   | FileCheck --check-prefix=CHECK-WATCH %s
-// RUN: env WATCHOS_DEPLOYMENT_TARGET=3.0 %clang %s -fuse-ld= -isysroot 
%t/SDKs/WatchOS3.0.sdk -mlinker-version=400 -### 2>&1 \
+// RUN: env WATCHOS_DEPLOYMENT_TARGET=3.0 %clang %s -fuse-ld= -arch arm64_32 
-isysroot %t/SDKs/WatchOS3.0.sdk -mlinker-version=400 -### 2>&1 \
 // RUN:   | FileCheck --check-prefix=CHECK-WATCH %s
 //
 // CHECK-WATCH: clang

diff  --git a/clang/test/Driver/darwin-invalid-os-versions.c 
b/clang/test/Driver/darwin-invalid-os-versions.c
new file mode 100644
index 0000000000000..d9424c1e67280
--- /dev/null
+++ b/clang/test/Driver/darwin-invalid-os-versions.c
@@ -0,0 +1,22 @@
+/// Verify invalid OSVersions are diagnosed.
+
+// RUN: not %clang -target arm64-apple-ios20 -c %s 2>&1 | FileCheck %s 
--check-prefix=IOS
+// IOS: error: invalid version number in '-target arm64-apple-ios20'
+
+// RUN: not %clang -target arm64-apple-watchos20 -c %s 2>&1 | FileCheck %s 
--check-prefix=WATCHOS
+// WATCHOS: error: invalid version number in '-target arm64-apple-watchos20'
+
+// RUN: not %clang -target arm64-apple-macosx19 -c %s 2>&1 | FileCheck %s 
--check-prefix=MAC
+// MAC: error: invalid version number in '-target arm64-apple-macosx19'
+
+// RUN: not %clang -target arm64-apple-ios22-macabi -c %s 2>&1 | FileCheck %s 
--check-prefix=IOSMAC
+// IOSMAC: error: invalid version number in '-target arm64-apple-ios22-macabi'
+
+// RUN: not %clang -target arm64-apple-macosx16 -darwin-target-variant 
arm64-apple-ios22-macabi  -c %s 2>&1 | FileCheck %s --check-prefix=ZIPPERED
+// ZIPPERED: error: invalid version number in 'arm64-apple-ios22-macabi'
+
+// RUN: not %clang -target arm64-apple-visionos5 -c %s 2>&1 | FileCheck %s 
--check-prefix=VISION
+// VISION: error: invalid version number in '-target arm64-apple-visionos5'
+
+// RUN: not %clang -target arm64-apple-tvos21 -c %s 2>&1 | FileCheck %s 
--check-prefix=TV
+// TV: error: invalid version number in '-target arm64-apple-tvos21'

diff  --git a/clang/test/Driver/darwin-ld-platform-version-macos.c 
b/clang/test/Driver/darwin-ld-platform-version-macos.c
index 355df8dfc1bc2..b16ca8a853745 100644
--- a/clang/test/Driver/darwin-ld-platform-version-macos.c
+++ b/clang/test/Driver/darwin-ld-platform-version-macos.c
@@ -48,3 +48,8 @@
 // RUN:   -### %t.o 2>&1 \
 // RUN:   | FileCheck --check-prefix=NOSDK %s
 // NOSDK: "-platform_version" "macos" "10.13.0" "10.13.0"
+
+// RUN: %clang -target arm64-apple-macos26 -mlinker-version=520 \
+// RUN:   -### %t.o 2>&1 \
+// RUN:   | FileCheck --check-prefix=VERSION_BUMP %s
+// VERSION_BUMP: "-platform_version" "macos" "26.0.0" "26.0.0"

diff  --git a/clang/test/Driver/darwin-ld-platform-version-watchos.c 
b/clang/test/Driver/darwin-ld-platform-version-watchos.c
index fc8e859f30efa..afbc3194963fb 100644
--- a/clang/test/Driver/darwin-ld-platform-version-watchos.c
+++ b/clang/test/Driver/darwin-ld-platform-version-watchos.c
@@ -17,6 +17,54 @@
 // RUN:   -### %t.o 2>&1 \
 // RUN:   | FileCheck --check-prefix=SIMUL %s
 
+// RUN: %clang -target arm64-apple-watchos6.3 -fuse-ld= \
+// RUN:   -isysroot %S/Inputs/WatchOS6.0.sdk -mlinker-version=400 \
+// RUN:   -### %t.o 2>&1 \
+// RUN:   | FileCheck --check-prefix=ARM64-LINKER-OLD %s
+
+// RUN: %clang -target arm64e-apple-watchos6.3 -fuse-ld= \
+// RUN:   -isysroot %S/Inputs/WatchOS6.0.sdk -mlinker-version=400 \
+// RUN:   -### %t.o 2>&1 \
+// RUN:   | FileCheck --check-prefix=ARM64-LINKER-OLD %s
+
+// RUN: %clang -target arm64-apple-watchos26.1 -fuse-ld= \
+// RUN:   -isysroot %S/Inputs/WatchOS6.0.sdk -mlinker-version=400 \
+// RUN:   -### %t.o 2>&1 \
+// RUN:   | FileCheck --check-prefix=ARM64-LINKER-OLD-261 %s
+
+// RUN: %clang -target arm64-apple-watchos6.3 -fuse-ld=lld \
+// RUN:   -isysroot %S/Inputs/WatchOS6.0.sdk -mlinker-version=0 \
+// RUN:   -### %t.o -B%S/Inputs/lld 2>&1 \
+// RUN:   | FileCheck --check-prefix=ARM64-LINKER-NEW %s
+
+// RUN: %clang -target arm64e-apple-watchos6.3 -fuse-ld=lld \
+// RUN:   -isysroot %S/Inputs/WatchOS6.0.sdk -mlinker-version=0 \
+// RUN:   -### %t.o -B%S/Inputs/lld 2>&1 \
+// RUN:   | FileCheck --check-prefix=ARM64-LINKER-NEW %s
+
+// RUN: %clang -target arm64-apple-watchos6.3 -fuse-ld= \
+// RUN:   -isysroot %S/Inputs/WatchOS6.0.sdk -mlinker-version=520 \
+// RUN:   -### %t.o 2>&1 \
+// RUN:   | FileCheck --check-prefix=ARM64-LINKER-NEW %s
+
+// RUN: %clang -target arm64-apple-watchos26.1 -fuse-ld= \
+// RUN:   -isysroot %S/Inputs/WatchOS6.0.sdk -mlinker-version=520 \
+// RUN:   -### %t.o 2>&1 \
+// RUN:   | FileCheck --check-prefix=ARM64-LINKER-NEW-261 %s
+
+// RUN: %clang -target arm64-apple-watchos6-simulator -fuse-ld= \
+// RUN:   -isysroot %S/Inputs/WatchOS6.0.sdk -mlinker-version=520 \
+// RUN:   -### %t.o 2>&1 \
+// RUN:   | FileCheck --check-prefix=ARM64-SIMUL %s
+
 // LINKER-OLD: "-watchos_version_min" "5.2.0"
 // LINKER-NEW: "-platform_version" "watchos" "5.2.0" "6.0"
 // SIMUL: "-platform_version" "watchos-simulator" "6.0.0" "6.0"
+
+// ARM64-LINKER-OLD: "-watchos_version_min" "26.0.0"
+// ARM64-LINKER-OLD-261: "-watchos_version_min" "26.1.0"
+
+// ARM64-LINKER-NEW: "-platform_version" "watchos" "26.0.0" "6.0"
+// ARM64-LINKER-NEW-261: "-platform_version" "watchos" "26.1.0" "6.0"
+
+// ARM64-SIMUL: "-platform_version" "watchos-simulator" "7.0.0" "6.0"

diff  --git a/clang/test/ExtractAPI/availability.c 
b/clang/test/ExtractAPI/availability.c
index 237b2ffa55d7d..4f7e21a5c3765 100644
--- a/clang/test/ExtractAPI/availability.c
+++ b/clang/test/ExtractAPI/availability.c
@@ -17,7 +17,7 @@ void a(void) __attribute__((availability(macos, 
introduced=12.0)));
 // A-NEXT: ]
 
 // RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix B
-void b(void) __attribute__((availability(macos, introduced=11.0, 
deprecated=12.0, obsoleted=20.0)));
+void b(void) __attribute__((availability(macos, introduced=11.0, 
deprecated=12.0, obsoleted=30.0)));
 // B-LABEL: "!testLabel": "c:@F@b"
 // B:      "availability": [
 // B-NEXT:   {
@@ -33,7 +33,7 @@ void b(void) __attribute__((availability(macos, 
introduced=11.0, deprecated=12.0
 // B-NEXT:       "patch": 0
 // B-NEXT:     },
 // B-NEXT:     "obsoleted": {
-// B-NEXT:       "major": 20,
+// B-NEXT:       "major": 30,
 // B-NEXT:       "minor": 0,
 // B-NEXT:       "patch": 0
 // B-NEXT:     }
@@ -41,7 +41,7 @@ void b(void) __attribute__((availability(macos, 
introduced=11.0, deprecated=12.0
 // B-NEXT: ]
 
 // RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix E
-void c(void) __attribute__((availability(macos, introduced=11.0, 
deprecated=12.0, obsoleted=20.0))) __attribute__((availability(ios, 
introduced=13.0)));
+void c(void) __attribute__((availability(macos, introduced=11.0, 
deprecated=12.0, obsoleted=30.0))) __attribute__((availability(ios, 
introduced=13.0)));
 // C-LABEL: "!testLabel": "c:@F@c"
 // C:       "availability": [
 // C-NEXT:    {
@@ -57,7 +57,7 @@ void c(void) __attribute__((availability(macos, 
introduced=11.0, deprecated=12.0
 // C-NEXT:        "patch": 0
 // C-NEXT:      },
 // C-NEXT:      "obsoleted": {
-// C-NEXT:        "major": 20,
+// C-NEXT:        "major": 30,
 // C-NEXT:        "minor": 0,
 // C-NEXT:        "patch": 0
 // C-NEXT:      }

diff  --git a/clang/test/ExtractAPI/inherited_availability.m 
b/clang/test/ExtractAPI/inherited_availability.m
index c24e7fa8e208f..3d9f953bbda1f 100644
--- a/clang/test/ExtractAPI/inherited_availability.m
+++ b/clang/test/ExtractAPI/inherited_availability.m
@@ -4,7 +4,7 @@
 
 
 // RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix A
-__attribute__((availability(macos, introduced=9.0, deprecated=12.0, 
obsoleted=20.0)))
+__attribute__((availability(macos, introduced=9.0, deprecated=12.0, 
obsoleted=30.0)))
 @interface A
 // A-LABEL: "!testLabel": "c:objc(cs)A"
 // A:      "availability": [
@@ -21,7 +21,7 @@ @interface A
 // A-NEXT:       "patch": 0
 // A-NEXT:     }
 // A-NEXT:     "obsoleted": {
-// A-NEXT:       "major": 20,
+// A-NEXT:       "major": 30,
 // A-NEXT:       "minor": 0,
 // A-NEXT:       "patch": 0
 // A-NEXT:     }
@@ -45,7 +45,7 @@ @interface A
 // CP-NEXT:       "patch": 0
 // CP-NEXT:     }
 // CP-NEXT:     "obsoleted": {
-// CP-NEXT:       "major": 20,
+// CP-NEXT:       "major": 30,
 // CP-NEXT:       "minor": 0,
 // CP-NEXT:       "patch": 0
 // CP-NEXT:     }
@@ -69,7 +69,7 @@ @interface A
 // IP-NEXT:       "patch": 0
 // IP-NEXT:     }
 // IP-NEXT:     "obsoleted": {
-// IP-NEXT:       "major": 20,
+// IP-NEXT:       "major": 30,
 // IP-NEXT:       "minor": 0,
 // IP-NEXT:       "patch": 0
 // IP-NEXT:     }
@@ -77,7 +77,7 @@ @interface A
 // IP-NEXT: ]
 
 // RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix MR
-@property int moreRestrictive __attribute__((availability(macos, 
introduced=10.0, deprecated=11.0, obsoleted=19.0)));
+@property int moreRestrictive __attribute__((availability(macos, 
introduced=10.0, deprecated=11.0, obsoleted=29.0)));
 // MR-LABEL: "!testLabel": "c:objc(cs)A(py)moreRestrictive"
 // MR:      "availability": [
 // MR-NEXT:   {
@@ -93,7 +93,7 @@ @interface A
 // MR-NEXT:       "patch": 0
 // MR-NEXT:     }
 // MR-NEXT:     "obsoleted": {
-// MR-NEXT:       "major": 19,
+// MR-NEXT:       "major": 29,
 // MR-NEXT:       "minor": 0,
 // MR-NEXT:       "patch": 0
 // MR-NEXT:     }
@@ -148,7 +148,7 @@ @interface C
 
 @interface D
 // RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix DIP
-@property int DIP __attribute__((availability(macos, introduced=10.0, 
deprecated=11.0, obsoleted=19.0)));
+@property int DIP __attribute__((availability(macos, introduced=10.0, 
deprecated=11.0, obsoleted=29.0)));
 // DIP-LABEL: "!testLabel": "c:objc(cs)D(py)DIP"
 // DIP:      "availability": [
 // DIP-NEXT:   {
@@ -164,7 +164,7 @@ @interface D
 // DIP-NEXT:       "patch": 0
 // DIP-NEXT:     }
 // DIP-NEXT:     "obsoleted": {
-// DIP-NEXT:       "major": 19,
+// DIP-NEXT:       "major": 29,
 // DIP-NEXT:       "minor": 0,
 // DIP-NEXT:       "patch": 0
 // DIP-NEXT:     }

diff  --git a/clang/test/Sema/Inputs/XROS.sdk/SDKSettings.json 
b/clang/test/Sema/Inputs/XROS.sdk/SDKSettings.json
new file mode 100644
index 0000000000000..a56a7d61431b9
--- /dev/null
+++ b/clang/test/Sema/Inputs/XROS.sdk/SDKSettings.json
@@ -0,0 +1,9 @@
+{
+  "DefaultVariant": "xrOS", "DisplayName": "xrOS",
+  "Version": "26.0",
+  "CanonicalName": "xros26.0",
+  "MaximumDeploymentTarget": "26.0.99",
+  "VersionMap": {
+    "iOS_xrOS":{"15.0":"1.0", "16.0":"2.0", "19.0":"26.0", "26.0":"26.0"}
+  }
+}

diff  --git a/clang/test/Sema/attr-availability-invalid-os-versions.c 
b/clang/test/Sema/attr-availability-invalid-os-versions.c
new file mode 100644
index 0000000000000..871263fc62cb0
--- /dev/null
+++ b/clang/test/Sema/attr-availability-invalid-os-versions.c
@@ -0,0 +1,35 @@
+/// This test verifies diagnostic reporting for OS versions within an invalid 
range.
+// RUN: %clang_cc1 -triple x86_64-apple-darwin25 -fsyntax-only -verify %s
+
+ __attribute__((availability(macosx,introduced=16, deprecated=20))) 
+void invalid_dep(void); // expected-warning@-1 {{invalid macOS version '20' in 
availability attribute}}
+                        // expected-note@-2 {{implicitly treating version as 
'30'}}
+ 
+__attribute__((availability(macosx,introduced=15,  obsoleted=19)))
+void invalid_obsolete(void); // expected-warning@-1 {{invalid macOS version 
'19' in availability attribute}}
+                             // expected-note@-2 {{implicitly treating version 
as '29'}}
+
+__attribute__((availability(macosx,introduced=24)))
+void invalid_intro(void); // expected-warning@-1 {{invalid macOS version '24' 
in availability attribute}}
+                          // expected-note@-2 {{implicitly treating version as 
'34'}}
+
+__attribute__((availability(watchos,introduced=24)))
+void invalid_watch_intro(void); // expected-warning@-1 {{invalid watchOS 
version '24' in availability attribute}}
+                                // expected-note@-2 {{implicitly treating 
version as '38'}}
+
+__attribute__((availability(maccatalyst, introduced=18.1, deprecated=21.1)))
+void invalid_catalyst_intro(void); // expected-warning@-1 {{invalid 
macCatalyst version '21.1' in availability attribute}}
+                                   // expected-note@-2 {{implicitly treating 
version as '28.1'}}
+
+__attribute__((availability(macos, introduced=15, deprecated=26)))
+__attribute__((availability(watchos, introduced=15)))
+__attribute__((availability(ios, introduced=15, deprecated=18)))
+void invalid_intro_multiple(void); // expected-warning@-2 {{invalid watchOS 
version '15' in availability attribute}}
+                                   // expected-note@-3 {{implicitly treating 
version as '29'}}
+ 
+__attribute__((availability(macCatalyst, introduced=19.2, deprecated=22.2))) 
+void invalid_dep(void); // expected-warning@-1 {{invalid macCatalyst version 
'19.2' in availability attribute}}
+                        // expected-note@-2 {{implicitly treating version as 
'26.2'}}
+                        // expected-warning@-3 {{invalid macCatalyst version 
'22.2' in availability attribute}}
+                        // expected-note@-4 {{implicitly treating version as 
'29.2'}}
+

diff  --git a/clang/test/Sema/attr-availability-ios-aligned-versions.c 
b/clang/test/Sema/attr-availability-ios-aligned-versions.c
new file mode 100644
index 0000000000000..703ef42d881d3
--- /dev/null
+++ b/clang/test/Sema/attr-availability-ios-aligned-versions.c
@@ -0,0 +1,116 @@
+/// This test verifies several 
diff erent patterns of iOS, and app extension, availability declarations & 
usages.
+// RUN: %clang_cc1 "-triple" "arm64-apple-ios26" -DNEW -fsyntax-only -verify %s
+// RUN: %clang_cc1 "-triple" "arm64-apple-ios18" -fsyntax-only -verify 
-fapplication-extension -DAPP_EXT %s
+// RUN: %clang_cc1 "-triple" "arm64-apple-ios18" -fsyntax-only -verify %s
+
+__attribute__((availability(ios,strict,introduced=19)))
+void fNew1();
+#ifndef NEW
+// expected-note@-2 {{here}}
+#endif
+
+__attribute__((availability(ios,strict,introduced=19)))
+void fNew();
+
+__attribute__((availability(ios,strict,introduced=26)))
+void fNew() { }
+#ifndef NEW
+// expected-note@-2 {{here}}
+#endif
+
+__attribute__((availability(ios,strict,deprecated=19)))
+void fDep();
+
+__attribute__((availability(ios,strict,deprecated=26)))
+void fDep() { }
+#ifdef NEW
+// expected-note@-2 {{here}}
+#endif
+
+__attribute__((availability(ios,strict,obsoleted=19)))
+void fObs();
+
+__attribute__((availability(ios,strict,obsoleted=26)))
+void fObs() { }
+#ifdef NEW
+// expected-note@-2 {{here}}
+#endif
+
+__attribute__((availability(ios_app_extension,strict,introduced=19)))
+void fAppExt();
+
+__attribute__((availability(ios_app_extension,strict,introduced=26)))
+void fAppExt() { }
+#ifdef APP_EXT
+// expected-note@-2 {{here}}
+#endif
+
+void testVersionRemapping() {
+  fNew1();
+#ifndef NEW
+  // expected-error@-2 {{'fNew1' is unavailable: introduced in iOS 26.0}}
+#endif
+  fNew();
+#ifndef NEW
+  // expected-error@-2 {{'fNew' is unavailable: introduced in iOS 26}}
+#endif
+  fDep();
+#ifdef NEW
+  // expected-warning@-2 {{'fDep' is deprecated: first deprecated in iOS 26}}
+#endif
+  fObs();
+#ifdef NEW
+  // expected-error@-2 {{'fObs' is unavailable: obsoleted in iOS 26}}
+#endif
+
+  fAppExt();
+#ifdef APP_EXT
+  // expected-error@-2 {{'fAppExt' is unavailable: introduced in iOS (App 
Extension) 26}}
+#endif
+}
+
+__attribute__((availability(ios,strict,introduced=18.5))) // expected-note 
{{here}}
+void fMatchErr();
+
+__attribute__((availability(ios,strict,introduced=26))) // expected-warning 
{{availability does not match previous declaration}}
+void fMatchErr() { }
+
+__attribute__((availability(ios_app_extension,strict,introduced=19))) // 
expected-note {{here}}
+void fAppExtErr();
+
+__attribute__((availability(ios_app_extension,strict,introduced=26.1))) // 
expected-warning {{availability does not match previous declaration}}
+void fAppExtErr() { }
+
+__attribute__((availability(ios,introduced=26)))
+void fNew2();
+#ifndef NEW
+  // expected-note@-2 {{'fNew2' has been marked as being introduced in iOS 26 
here, but the deployment target is iOS 18}}
+#endif
+__attribute__((availability(ios,introduced=19)))
+void fNew3();
+
+__attribute__((availability(ios,introduced=27)))
+void evenNewer();
+#ifdef NEW
+  // expected-note@-2 {{'evenNewer' has been marked as being introduced in iOS 
27 here, but the deployment target is iOS 26}}
+#endif
+
+void testAvailabilityCheck() {
+  if (__builtin_available(iOS 19, *)) {
+    fNew2();
+    fNew3();
+  }
+  if (__builtin_available(iOS 26, *)) {
+    fNew2();
+    fNew3();
+  }
+  fNew2();
+#ifndef NEW
+  // expected-warning@-2 {{'fNew2' is only available on iOS 26 or newer}} 
expected-note@-2 {{enclose}}
+#endif
+#ifdef NEW
+  evenNewer(); // expected-warning {{'evenNewer' is only available on iOS 27 
or newer}} expected-note {{enclose}}
+#endif
+}
+
+

diff  --git a/clang/test/Sema/attr-availability-ios-fallback-aligned-versions.c 
b/clang/test/Sema/attr-availability-ios-fallback-aligned-versions.c
new file mode 100644
index 0000000000000..8947bc7dda469
--- /dev/null
+++ b/clang/test/Sema/attr-availability-ios-fallback-aligned-versions.c
@@ -0,0 +1,32 @@
+// This validates that all expected OSVersions that allow fallbacks 
+// from iOS behave as expected against a common version bump.
+
+// RUN: %clang_cc1 "-triple" "arm64-apple-ios26" -fsyntax-only -verify %s
+// RUN: %clang_cc1 "-triple" "arm64-apple-watchos26" -fsyntax-only -verify %s
+// RUN: %clang_cc1 "-triple" "arm64-apple-tvos26" -fsyntax-only -verify %s
+
+// VisionOS requires SDKSettings support to enable remappings.
+// RUN: %clang_cc1 "-triple" "arm64-apple-visionos26" -isysroot 
%S/Inputs/XROS.sdk -fsyntax-only -verify %s
+
+// expected-no-diagnostics
+
+__attribute__((availability(ios,strict,introduced=19)))
+int iOSExistingAPI(void);
+
+__attribute__((availability(ios,strict,introduced=26)))
+int iOSExistingAPI2(void);
+
+void testAvailabilityCheck(void) {
+  
+  if (__builtin_available(iOS 19, *)) {
+    iOSExistingAPI();
+    iOSExistingAPI2();
+  }
+  
+  if (__builtin_available(iOS 26, *)) {
+    iOSExistingAPI();
+    iOSExistingAPI2();
+  }
+
+  iOSExistingAPI2();
+}

diff  --git a/clang/test/Sema/attr-availability-iosmac-infer-from-macos.c 
b/clang/test/Sema/attr-availability-iosmac-infer-from-macos.c
index 12c6d59b61ac2..73ff8c33ebe54 100644
--- a/clang/test/Sema/attr-availability-iosmac-infer-from-macos.c
+++ b/clang/test/Sema/attr-availability-iosmac-infer-from-macos.c
@@ -24,7 +24,7 @@ void fObs(void) __attribute__((availability(macOS, introduced 
= 10.11, obsoleted
 
 void fAPItoDepr(void) __attribute__((availability(macOS, introduced = 10.11, 
deprecated = 100000)));
 
-void dontRemapFutureVers(void) __attribute__((availability(macOS, introduced = 
20)));
+void dontRemapFutureVers(void) __attribute__((availability(macOS, introduced = 
30)));
 
 void usage(void) {
   f0();

diff  --git a/llvm/include/llvm/TargetParser/Triple.h 
b/llvm/include/llvm/TargetParser/Triple.h
index 351da0d6598c2..b56e6e18805e0 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
+++ b/llvm/include/llvm/TargetParser/Triple.h
@@ -1300,7 +1300,11 @@ class Triple {
 
   /// Returns a canonicalized OS version number for the specified OS.
   static VersionTuple getCanonicalVersionForOS(OSType OSKind,
-                                               const VersionTuple &Version);
+                                               const VersionTuple &Version,
+                                               bool IsInValidRange);
+
+  /// Returns whether an OS version is invalid and would not map to an Apple 
OS.
+  static bool isValidVersionForOS(OSType OSKind, const VersionTuple &Version);
 };
 
 } // End llvm namespace

diff  --git a/llvm/lib/TargetParser/Triple.cpp 
b/llvm/lib/TargetParser/Triple.cpp
index 6a559ff023caa..bd291e1918219 100644
--- a/llvm/lib/TargetParser/Triple.cpp
+++ b/llvm/lib/TargetParser/Triple.cpp
@@ -1446,9 +1446,12 @@ bool Triple::getMacOSXVersion(VersionTuple &Version) 
const {
     }
     if (Version.getMajor() <= 19) {
       Version = VersionTuple(10, Version.getMajor() - 4);
-    } else {
-      // darwin20+ corresponds to macOS 11+.
+    } else if (Version.getMajor() < 25) {
+      // darwin20-24 corresponds to macOS 11-15.
       Version = VersionTuple(11 + Version.getMajor() - 20);
+    } else {
+      // darwin25 corresponds with macOS26+.
+      Version = VersionTuple(Version.getMajor() + 1);
     }
     break;
   case MacOSX:
@@ -1492,14 +1495,33 @@ VersionTuple Triple::getiOSVersion() const {
     // Default to 5.0 (or 7.0 for arm64).
     if (Version.getMajor() == 0)
       return (getArch() == aarch64) ? VersionTuple(7) : VersionTuple(5);
-    return Version;
+    if (Version.getMajor() == 19)
+      // tvOS 19 corresponds to ios26.
+      return VersionTuple(26);
+    return getCanonicalVersionForOS(OSType::IOS, Version,
+                                    isValidVersionForOS(OSType::IOS, Version));
   }
   case XROS: {
+    VersionTuple Version = getOSVersion();
     // xrOS 1 is aligned with iOS 17.
+    if (Version.getMajor() < 3)
+      return Version.withMajorReplaced(Version.getMajor() + 16);
+    // visionOS 3 corresponds to ios 26+.
+    if (Version.getMajor() == 3)
+      return VersionTuple(26);
+    return getCanonicalVersionForOS(OSType::XROS, Version,
+                                    isValidVersionForOS(OSType::XROS, 
Version));
+  }
+  case WatchOS: {
     VersionTuple Version = getOSVersion();
-    return Version.withMajorReplaced(Version.getMajor() + 16);
+    // watchOS 12 corresponds to ios 26.
+    if (Version.getMajor() == 12)
+      return VersionTuple(26);
+    return getCanonicalVersionForOS(
+        OSType::WatchOS, Version,
+        isValidVersionForOS(OSType::WatchOS, Version));
   }
-  case WatchOS:
+  case BridgeOS:
     llvm_unreachable("conflicting triple info");
   case DriverKit:
     llvm_unreachable("DriverKit doesn't have an iOS version");
@@ -2116,12 +2138,12 @@ bool Triple::isMacOSXVersionLT(unsigned Major, unsigned 
Minor,
     return isOSVersionLT(Major, Minor, Micro);
 
   // Otherwise, compare to the "Darwin" number.
-  if (Major == 10) {
+  if (Major == 10)
     return isOSVersionLT(Minor + 4, Micro, 0);
-  } else {
-    assert(Major >= 11 && "Unexpected major version");
+  assert(Major >= 11 && "Unexpected major version");
+  if (Major < 25)
     return isOSVersionLT(Major - 11 + 20, Minor, Micro);
-  }
+  return isOSVersionLT(Major + 1, Minor, Micro);
 }
 
 VersionTuple Triple::getMinimumSupportedOSVersion() const {
@@ -2149,7 +2171,10 @@ VersionTuple Triple::getMinimumSupportedOSVersion() 
const {
     // ARM64 simulators are supported for watchOS 7+.
     if (isSimulatorEnvironment())
       return VersionTuple(7, 0, 0);
-    break;
+    // ARM64/ARM64e slices are supported starting from watchOS 26.
+    // ARM64_32 is older though.
+    assert(getArch() != Triple::aarch64_32);
+    return VersionTuple(26, 0, 0);
   case Triple::DriverKit:
     return VersionTuple(20, 0, 0);
   default:
@@ -2159,16 +2184,85 @@ VersionTuple Triple::getMinimumSupportedOSVersion() 
const {
 }
 
 VersionTuple Triple::getCanonicalVersionForOS(OSType OSKind,
-                                              const VersionTuple &Version) {
+                                              const VersionTuple &Version,
+                                              bool IsInValidRange) {
+  const unsigned MacOSRangeBump = 10;
+  const unsigned IOSRangeBump = 7;
+  const unsigned XROSRangeBump = 23;
+  const unsigned WatchOSRangeBump = 14;
   switch (OSKind) {
-  case MacOSX:
+  case MacOSX: {
     // macOS 10.16 is canonicalized to macOS 11.
     if (Version == VersionTuple(10, 16))
       return VersionTuple(11, 0);
-    [[fallthrough]];
+    // macOS 16 is canonicalized to macOS 26.
+    if (Version == VersionTuple(16, 0))
+      return VersionTuple(26, 0);
+    if (!IsInValidRange)
+      return Version.withMajorReplaced(Version.getMajor() + MacOSRangeBump);
+    break;
+  }
+  case IOS:
+  case TvOS: {
+    // Both iOS & tvOS 19.0 canonicalize to 26.
+    if (Version == VersionTuple(19, 0))
+      return VersionTuple(26, 0);
+    if (!IsInValidRange)
+      return Version.withMajorReplaced(Version.getMajor() + IOSRangeBump);
+    break;
+  }
+  case XROS: {
+    // visionOS3 is canonicalized to 26.
+    if (Version == VersionTuple(3, 0))
+      return VersionTuple(26, 0);
+    if (!IsInValidRange)
+      return Version.withMajorReplaced(Version.getMajor() + XROSRangeBump);
+    break;
+  }
+  case WatchOS: {
+    // watchOS 12 is canonicalized to 26.
+    if (Version == VersionTuple(12, 0))
+      return VersionTuple(26, 0);
+    if (!IsInValidRange)
+      return Version.withMajorReplaced(Version.getMajor() + WatchOSRangeBump);
+    break;
+  }
   default:
     return Version;
   }
+
+  return Version;
+}
+
+bool Triple::isValidVersionForOS(OSType OSKind, const VersionTuple &Version) {
+  /// This constant is used to capture gaps in versioning.
+  const VersionTuple CommonVersion(26);
+  auto IsValid = [&](const VersionTuple &StartingVersion) {
+    return !((Version > StartingVersion) && (Version < CommonVersion));
+  };
+  switch (OSKind) {
+  case WatchOS: {
+    const VersionTuple StartingWatchOS(12);
+    return IsValid(StartingWatchOS);
+  }
+  case IOS:
+  case TvOS: {
+    const VersionTuple StartingIOS(19);
+    return IsValid(StartingIOS);
+  }
+  case MacOSX: {
+    const VersionTuple StartingMacOS(16);
+    return IsValid(StartingMacOS);
+  }
+  case XROS: {
+    const VersionTuple StartingXROS(3);
+    return IsValid(StartingXROS);
+  }
+  default:
+    return true;
+  }
+
+  llvm_unreachable("unexpected or invalid os version");
 }
 
 // HLSL triple environment orders are relied on in the front end

diff  --git a/llvm/lib/TextAPI/Platform.cpp b/llvm/lib/TextAPI/Platform.cpp
index d7d391102ce69..d5c4e0a974d0b 100644
--- a/llvm/lib/TextAPI/Platform.cpp
+++ b/llvm/lib/TextAPI/Platform.cpp
@@ -124,7 +124,9 @@ VersionTuple mapToSupportedOSVersion(const Triple &Triple) {
   const VersionTuple MinSupportedOS = Triple.getMinimumSupportedOSVersion();
   if (MinSupportedOS > Triple.getOSVersion())
     return MinSupportedOS;
-  return Triple.getOSVersion();
+  return Triple::getCanonicalVersionForOS(
+      Triple.getOS(), Triple.getOSVersion(),
+      Triple::isValidVersionForOS(Triple.getOS(), Triple.getOSVersion()));
 }
 
 } // end namespace MachO.

diff  --git a/llvm/unittests/TargetParser/TripleTest.cpp 
b/llvm/unittests/TargetParser/TripleTest.cpp
index bbd12e6d0e412..0f6d07657c931 100644
--- a/llvm/unittests/TargetParser/TripleTest.cpp
+++ b/llvm/unittests/TargetParser/TripleTest.cpp
@@ -2354,6 +2354,79 @@ TEST(TripleTest, getOSVersion) {
   T.getMacOSXVersion(Version);
   EXPECT_EQ(VersionTuple(10, 16), Version);
 
+  // 16 forms a valid triple, even though it's not
+  // a version of a macOS.
+  T = Triple("x86_64-apple-macos16.0");
+  EXPECT_TRUE(T.isMacOSX());
+  T.getMacOSXVersion(Version);
+  EXPECT_EQ(VersionTuple(16, 0), Version);
+
+  T = Triple("arm64-apple-macosx26.1");
+  EXPECT_TRUE(T.isMacOSX());
+  EXPECT_FALSE(T.isiOS());
+  EXPECT_FALSE(T.isArch16Bit());
+  EXPECT_FALSE(T.isArch32Bit());
+  EXPECT_TRUE(T.isArch64Bit());
+  T.getMacOSXVersion(Version);
+  EXPECT_EQ(VersionTuple(26, 1), Version);
+
+  // 19.0 forms a valid triple, even though it's not
+  // a version of a iOS.
+  T = Triple("arm64-apple-ios19.0");
+  EXPECT_FALSE(T.isMacOSX());
+  EXPECT_TRUE(T.isiOS());
+  EXPECT_FALSE(T.isArch16Bit());
+  EXPECT_FALSE(T.isArch32Bit());
+  EXPECT_TRUE(T.isArch64Bit());
+  T.getiOSVersion();
+  EXPECT_EQ(VersionTuple(19, 0), T.getOSVersion());
+
+  T = Triple("arm64-apple-ios27.0");
+  EXPECT_FALSE(T.isMacOSX());
+  EXPECT_TRUE(T.isiOS());
+  EXPECT_FALSE(T.isArch16Bit());
+  EXPECT_FALSE(T.isArch32Bit());
+  EXPECT_TRUE(T.isArch64Bit());
+  EXPECT_EQ(VersionTuple(27, 0), T.getiOSVersion());
+
+  T = Triple("arm64-apple-watchos12.0");
+  EXPECT_FALSE(T.isMacOSX());
+  EXPECT_TRUE(T.isWatchOS());
+  EXPECT_TRUE(T.isArch64Bit());
+  EXPECT_EQ(VersionTuple(26, 0), T.getiOSVersion());
+
+  T = Triple("arm64-apple-visionos3.0");
+  EXPECT_FALSE(T.isMacOSX());
+  EXPECT_TRUE(T.isXROS());
+  EXPECT_TRUE(T.isArch64Bit());
+  EXPECT_EQ(VersionTuple(26, 0), T.getiOSVersion());
+
+  T = Triple("x86_64-apple-darwin26");
+  EXPECT_TRUE(T.isMacOSX());
+  T.getMacOSXVersion(Version);
+  EXPECT_EQ(VersionTuple(27), Version);
+
+  // Check invalid ranges are remapped.
+  T = Triple("arm64-apple-visionos6.0");
+  EXPECT_FALSE(T.isMacOSX());
+  EXPECT_TRUE(T.isXROS());
+  EXPECT_TRUE(T.isArch64Bit());
+  EXPECT_EQ(VersionTuple(29, 0), T.getiOSVersion());
+
+  T = Triple("arm64-apple-watchos14.0");
+  EXPECT_FALSE(T.isMacOSX());
+  EXPECT_TRUE(T.isWatchOS());
+  EXPECT_TRUE(T.isArch64Bit());
+  EXPECT_EQ(VersionTuple(28, 0), T.getiOSVersion());
+
+  T = Triple("arm64-apple-ios21.1");
+  EXPECT_FALSE(T.isMacOSX());
+  EXPECT_TRUE(T.isiOS());
+  EXPECT_FALSE(T.isArch16Bit());
+  EXPECT_FALSE(T.isArch32Bit());
+  EXPECT_TRUE(T.isArch64Bit());
+  EXPECT_EQ(VersionTuple(28, 1), T.getiOSVersion());
+
   T = Triple("x86_64-apple-darwin20");
   EXPECT_TRUE(T.isMacOSX());
   T.getMacOSXVersion(Version);
@@ -2468,11 +2541,76 @@ TEST(TripleTest, isMacOSVersionLT) {
 TEST(TripleTest, CanonicalizeOSVersion) {
   EXPECT_EQ(VersionTuple(10, 15, 4),
             Triple::getCanonicalVersionForOS(Triple::MacOSX,
-                                             VersionTuple(10, 15, 4)));
-  EXPECT_EQ(VersionTuple(11, 0), Triple::getCanonicalVersionForOS(
-                                     Triple::MacOSX, VersionTuple(10, 16)));
+                                             VersionTuple(10, 15, 4),
+                                             /*IsInValidRange=*/true));
+  EXPECT_EQ(VersionTuple(11, 0),
+            Triple::getCanonicalVersionForOS(
+                Triple::MacOSX, VersionTuple(10, 16), 
/*IsInValidRange=*/true));
   EXPECT_EQ(VersionTuple(20),
-            Triple::getCanonicalVersionForOS(Triple::Darwin, 
VersionTuple(20)));
+            Triple::getCanonicalVersionForOS(Triple::Darwin, VersionTuple(20),
+                                             /*IsInValidRange=*/true));
+
+  // Validate mappings for all expected OS versions remapping to 26.
+  EXPECT_EQ(VersionTuple(26),
+            Triple::getCanonicalVersionForOS(Triple::MacOSX, VersionTuple(16),
+                                             /*IsInValidRange=*/true));
+  EXPECT_EQ(VersionTuple(26),
+            Triple::getCanonicalVersionForOS(Triple::IOS, VersionTuple(19),
+                                             /*IsInValidRange=*/true));
+  EXPECT_EQ(VersionTuple(26),
+            Triple::getCanonicalVersionForOS(Triple::TvOS, VersionTuple(19),
+                                             /*IsInValidRange=*/true));
+  EXPECT_EQ(VersionTuple(26),
+            Triple::getCanonicalVersionForOS(Triple::WatchOS, VersionTuple(12),
+                                             /*IsInValidRange=*/true));
+  EXPECT_EQ(VersionTuple(26),
+            Triple::getCanonicalVersionForOS(Triple::XROS, VersionTuple(3),
+                                             /*IsInValidRange=*/true));
+  EXPECT_EQ(VersionTuple(26),
+            Triple::getCanonicalVersionForOS(Triple::Darwin, VersionTuple(26),
+                                             /*IsInValidRange=*/true));
+  EXPECT_EQ(VersionTuple(26),
+            Triple::getCanonicalVersionForOS(Triple::BridgeOS, 
VersionTuple(26),
+                                             /*IsInValidRange=*/true));
+  EXPECT_EQ(VersionTuple(26),
+            Triple::getCanonicalVersionForOS(Triple::BridgeOS, 
VersionTuple(26),
+                                             /*IsInValidRange=*/true));
+  EXPECT_EQ(VersionTuple(10),
+            Triple::getCanonicalVersionForOS(Triple::BridgeOS, 
VersionTuple(10),
+                                             /*IsInValidRange=*/true));
+
+  // Verify invalid ranges can be remapped.
+  EXPECT_EQ(VersionTuple(28),
+            Triple::getCanonicalVersionForOS(Triple::MacOSX, VersionTuple(18),
+                                             /*IsInValidRange=*/false));
+  EXPECT_EQ(VersionTuple(28),
+            Triple::getCanonicalVersionForOS(Triple::IOS, VersionTuple(21),
+                                             /*IsInValidRange=*/false));
+  EXPECT_EQ(VersionTuple(28),
+            Triple::getCanonicalVersionForOS(Triple::WatchOS, VersionTuple(14),
+                                             /*IsInValidRange=*/false));
+  EXPECT_EQ(VersionTuple(28),
+            Triple::getCanonicalVersionForOS(Triple::TvOS, VersionTuple(21),
+                                             /*IsInValidRange=*/false));
+}
+
+TEST(TripleTest, CheckValidOSVersion) {
+  EXPECT_TRUE(Triple::isValidVersionForOS(Triple::MacOSX, VersionTuple(16)));
+  EXPECT_TRUE(Triple::isValidVersionForOS(Triple::IOS, VersionTuple(19)));
+  EXPECT_TRUE(Triple::isValidVersionForOS(Triple::TvOS, VersionTuple(19)));
+  EXPECT_TRUE(Triple::isValidVersionForOS(Triple::TvOS, VersionTuple(18, 2)));
+  EXPECT_TRUE(Triple::isValidVersionForOS(Triple::WatchOS, VersionTuple(12)));
+  EXPECT_TRUE(Triple::isValidVersionForOS(Triple::XROS, VersionTuple(3)));
+  EXPECT_TRUE(Triple::isValidVersionForOS(Triple::Darwin, VersionTuple(26)));
+  EXPECT_TRUE(
+      Triple::isValidVersionForOS(Triple::BridgeOS, VersionTuple(26, 1, 1)));
+
+  EXPECT_FALSE(
+      Triple::isValidVersionForOS(Triple::MacOSX, VersionTuple(16, 1)));
+  EXPECT_FALSE(Triple::isValidVersionForOS(Triple::MacOSX, VersionTuple(18)));
+  EXPECT_FALSE(Triple::isValidVersionForOS(Triple::IOS, VersionTuple(21)));
+  EXPECT_FALSE(Triple::isValidVersionForOS(Triple::WatchOS, VersionTuple(14)));
+  EXPECT_FALSE(Triple::isValidVersionForOS(Triple::TvOS, VersionTuple(21)));
 }
 
 TEST(TripleTest, FileFormat) {


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to