[clang] eb26ba9 - [clang][darwin] add support for remapping macOS availability to Mac Catalyst availability

Alex Lorenz via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 21 11:32:49 PDT 2021


Author: Alex Lorenz
Date: 2021-07-21T11:32:25-07:00
New Revision: eb26ba9da8aeab8ecc1209034912f9f12a945128

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

LOG: [clang][darwin] add support for remapping macOS availability to Mac Catalyst availability

This commit adds supports for clang to remap macOS availability attributes that have introduced,
deprecated or obsoleted versions to appropriate Mac Catalyst availability attributes. This
mapping is done using the version mapping provided in the macOS SDK, in the SDKSettings.json file.
The mappings in the SDKSettings json file will also be used in the clang driver for the driver
Mac Catalyst patch, and they could also be used in the future for other platforms as well.

Differential Revision: https://reviews.llvm.org/D105257

Added: 
    clang/test/Sema/Inputs/MacOSX11.0.sdk/SDKSettings.json
    clang/test/Sema/attr-availability-iosmac-infer-from-macos-no-sdk-settings.c
    clang/test/Sema/attr-availability-iosmac-infer-from-macos.c

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/Basic/DarwinSDKInfo.cpp
    clang/lib/Sema/Sema.cpp
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/test/Driver/Inputs/MacOSX10.14.sdk/SDKSettings.json
    clang/test/Driver/Inputs/WatchOS6.0.sdk/SDKSettings.json
    clang/test/Driver/Inputs/iPhoneOS13.0.sdk/SDKSettings.json
    clang/test/Sema/attr-availability-maccatalyst.c

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 792313fed2a9f..108f1796415c8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3549,6 +3549,10 @@ def warn_at_available_unchecked_use : Warning<
   "use if (%select{@available|__builtin_available}0) instead">,
   InGroup<DiagGroup<"unsupported-availability-guard">>;
 
+def warn_missing_sdksettings_for_availability_checking : Warning<
+  "%0 availability is ignored without a valid 'SDKSettings.json' in the SDK">,
+  InGroup<DiagGroup<"ignored-availability-without-sdk-settings">>;
+
 // Thread Safety Attributes
 def warn_thread_attribute_ignored : Warning<
   "ignoring %0 attribute because its argument is invalid">,

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4ade04992a5f4..c200b9b246811 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -115,6 +115,7 @@ namespace clang {
   class CodeCompletionTUInfo;
   class CodeCompletionResult;
   class CoroutineBodyStmt;
+  class DarwinSDKInfo;
   class Decl;
   class DeclAccessPair;
   class DeclContext;
@@ -1525,6 +1526,8 @@ class Sema final {
   /// assignment.
   llvm::DenseMap<const VarDecl *, int> RefsMinusAssignments;
 
+  Optional<std::unique_ptr<DarwinSDKInfo>> CachedDarwinSDKInfo;
+
 public:
   Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
        TranslationUnitKind TUKind = TU_Complete,
@@ -1553,6 +1556,8 @@ class Sema final {
   ASTConsumer &getASTConsumer() const { return Consumer; }
   ASTMutationListener *getASTMutationListener() const;
   ExternalSemaSource* getExternalSource() const { return ExternalSource; }
+  DarwinSDKInfo *getDarwinSDKInfoForAvailabilityChecking(SourceLocation Loc,
+                                                         StringRef Platform);
 
   ///Registers an external source. If an external source already exists,
   /// creates a multiplex external source and appends to it.

diff  --git a/clang/lib/Basic/DarwinSDKInfo.cpp b/clang/lib/Basic/DarwinSDKInfo.cpp
index 6959b84e5c62a..fe3e8edbcd5cb 100644
--- a/clang/lib/Basic/DarwinSDKInfo.cpp
+++ b/clang/lib/Basic/DarwinSDKInfo.cpp
@@ -115,13 +115,8 @@ clang::parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, StringRef SDKRootPath) {
     return Result.takeError();
 
   if (const auto *Obj = Result->getAsObject()) {
-    // FIXME: Switch to use parseDarwinSDKSettingsJSON.
-    auto VersionString = Obj->getString("Version");
-    if (VersionString) {
-      VersionTuple Version;
-      if (!Version.tryParse(*VersionString))
-        return DarwinSDKInfo(Version, Version);
-    }
+    if (auto SDKInfo = DarwinSDKInfo::parseDarwinSDKSettingsJSON(Obj))
+      return std::move(SDKInfo);
   }
   return llvm::make_error<llvm::StringError>("invalid SDKSettings.json",
                                              llvm::inconvertibleErrorCode());

diff  --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 704b631f94003..fbbb347f57da3 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -22,12 +22,14 @@
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/PrettyDeclStackTrace.h"
 #include "clang/AST/StmtCXX.h"
+#include "clang/Basic/DarwinSDKInfo.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/Stack.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/CXXFieldCollector.h"
 #include "clang/Sema/DelayedDiagnostic.h"
@@ -55,6 +57,26 @@ SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) {
 
 ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); }
 
+DarwinSDKInfo *
+Sema::getDarwinSDKInfoForAvailabilityChecking(SourceLocation Loc,
+                                              StringRef Platform) {
+  if (CachedDarwinSDKInfo)
+    return CachedDarwinSDKInfo->get();
+  auto SDKInfo = parseDarwinSDKInfo(
+      PP.getFileManager().getVirtualFileSystem(),
+      PP.getHeaderSearchInfo().getHeaderSearchOpts().Sysroot);
+  if (SDKInfo && *SDKInfo) {
+    CachedDarwinSDKInfo = std::make_unique<DarwinSDKInfo>(std::move(**SDKInfo));
+    return CachedDarwinSDKInfo->get();
+  }
+  if (!SDKInfo)
+    llvm::consumeError(SDKInfo.takeError());
+  Diag(Loc, diag::warn_missing_sdksettings_for_availability_checking)
+      << Platform;
+  CachedDarwinSDKInfo = std::unique_ptr<DarwinSDKInfo>();
+  return nullptr;
+}
+
 IdentifierInfo *
 Sema::InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName,
                                                  unsigned int Index) {

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index c61afa750bc14..bb4ce8d4962e2 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -23,6 +23,7 @@
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/CharInfo.h"
+#include "clang/Basic/DarwinSDKInfo.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetBuiltins.h"
@@ -2559,23 +2560,26 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   } else if (S.Context.getTargetInfo().getTriple().getOS() ==
                  llvm::Triple::IOS &&
              S.Context.getTargetInfo().getTriple().isMacCatalystEnvironment()) {
+    auto GetSDKInfo = [&]() {
+      return S.getDarwinSDKInfoForAvailabilityChecking(AL.getRange().getBegin(),
+                                                       "macOS");
+    };
+
     // Transcribe "ios" to "maccatalyst" (and add a new attribute).
     IdentifierInfo *NewII = nullptr;
-    auto MinMacCatalystVersion = [](const VersionTuple &V) {
-      if (V.empty())
-        return V;
-      if (V.getMajor() < 13 ||
-          (V.getMajor() == 13 && V.getMinor() && *V.getMinor() < 1))
-        return VersionTuple(13, 1); // The minimum Mac Catalyst version is 13.1.
-      return V;
-    };
     if (II->getName() == "ios")
       NewII = &S.Context.Idents.get("maccatalyst");
     else if (II->getName() == "ios_app_extension")
       NewII = &S.Context.Idents.get("maccatalyst_app_extension");
-    // FIXME: Add support for transcribing macOS availability using mapping from
-    // SDKSettings.json.
     if (NewII) {
+      auto MinMacCatalystVersion = [](const VersionTuple &V) {
+        if (V.empty())
+          return V;
+        if (V.getMajor() < 13 ||
+            (V.getMajor() == 13 && V.getMinor() && *V.getMinor() < 1))
+          return VersionTuple(13, 1); // The min Mac Catalyst version is 13.1.
+        return V;
+      };
       AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
           ND, AL.getRange(), NewII, true /*Implicit*/,
           MinMacCatalystVersion(Introduced.Version),
@@ -2585,6 +2589,50 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
           PriorityModifier + Sema::AP_InferredFromOtherPlatform);
       if (NewAttr)
         D->addAttr(NewAttr);
+    } else if (II->getName() == "macos" && GetSDKInfo() &&
+               (!Introduced.Version.empty() || !Deprecated.Version.empty() ||
+                !Obsoleted.Version.empty())) {
+      if (const auto *MacOStoMacCatalystMapping =
+              GetSDKInfo()->getVersionMapping(
+                  DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) {
+        // Infer Mac Catalyst availability from the macOS availability attribute
+        // if it has versioned availability. Don't infer 'unavailable'. This
+        // inferred availability has lower priority than the other availability
+        // attributes that are inferred from 'ios'.
+        NewII = &S.Context.Idents.get("maccatalyst");
+        auto RemapMacOSVersion =
+            [&](const VersionTuple &V) -> Optional<VersionTuple> {
+          if (V.empty())
+            return None;
+          // API_TO_BE_DEPRECATED is 100000.
+          if (V.getMajor() == 100000)
+            return VersionTuple(100000);
+          // The minimum iosmac version is 13.1
+          return MacOStoMacCatalystMapping->map(V, VersionTuple(13, 1), None);
+        };
+        Optional<VersionTuple> NewIntroduced =
+                                   RemapMacOSVersion(Introduced.Version),
+                               NewDeprecated =
+                                   RemapMacOSVersion(Deprecated.Version),
+                               NewObsoleted =
+                                   RemapMacOSVersion(Obsoleted.Version);
+        if (NewIntroduced || NewDeprecated || NewObsoleted) {
+          auto VersionOrEmptyVersion =
+              [](const Optional<VersionTuple> &V) -> VersionTuple {
+            return V ? *V : VersionTuple();
+          };
+          AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
+              ND, AL.getRange(), NewII, true /*Implicit*/,
+              VersionOrEmptyVersion(NewIntroduced),
+              VersionOrEmptyVersion(NewDeprecated),
+              VersionOrEmptyVersion(NewObsoleted), /*IsUnavailable=*/false, Str,
+              IsStrict, Replacement, Sema::AMK_None,
+              PriorityModifier + Sema::AP_InferredFromOtherPlatform +
+                  Sema::AP_InferredFromOtherPlatform);
+          if (NewAttr)
+            D->addAttr(NewAttr);
+        }
+      }
     }
   }
 }

diff  --git a/clang/test/Driver/Inputs/MacOSX10.14.sdk/SDKSettings.json b/clang/test/Driver/Inputs/MacOSX10.14.sdk/SDKSettings.json
index bca56e4f1ee3a..b612107cef394 100644
--- a/clang/test/Driver/Inputs/MacOSX10.14.sdk/SDKSettings.json
+++ b/clang/test/Driver/Inputs/MacOSX10.14.sdk/SDKSettings.json
@@ -1 +1 @@
-{"Version":"10.14"}
+{"Version":"10.14", "MaximumDeploymentTarget": "10.14.99"}

diff  --git a/clang/test/Driver/Inputs/WatchOS6.0.sdk/SDKSettings.json b/clang/test/Driver/Inputs/WatchOS6.0.sdk/SDKSettings.json
index b78b8c1ca56d8..9e30a153cb5fb 100644
--- a/clang/test/Driver/Inputs/WatchOS6.0.sdk/SDKSettings.json
+++ b/clang/test/Driver/Inputs/WatchOS6.0.sdk/SDKSettings.json
@@ -1 +1 @@
-{"Version":"6.0.0"}
+{"Version":"6.0.0", "MaximumDeploymentTarget": "6.0.99"}

diff  --git a/clang/test/Driver/Inputs/iPhoneOS13.0.sdk/SDKSettings.json b/clang/test/Driver/Inputs/iPhoneOS13.0.sdk/SDKSettings.json
index 04cb1644cd70e..b05260f994868 100644
--- a/clang/test/Driver/Inputs/iPhoneOS13.0.sdk/SDKSettings.json
+++ b/clang/test/Driver/Inputs/iPhoneOS13.0.sdk/SDKSettings.json
@@ -1 +1 @@
-{"Version":"13.0"}
+{"Version":"13.0", "MaximumDeploymentTarget": "13.0.99"}

diff  --git a/clang/test/Sema/Inputs/MacOSX11.0.sdk/SDKSettings.json b/clang/test/Sema/Inputs/MacOSX11.0.sdk/SDKSettings.json
new file mode 100644
index 0000000000000..b40e35e882e60
--- /dev/null
+++ b/clang/test/Sema/Inputs/MacOSX11.0.sdk/SDKSettings.json
@@ -0,0 +1,23 @@
+{
+  "DefaultVariant": "macos", "DisplayName": "macOS 11",
+  "Version": "11.0",
+  "MaximumDeploymentTarget": "11.0.99",
+  "PropertyConditionFallbackNames": [], "VersionMap": {
+    "iOSMac_macOS": {
+      "13.2": "10.15.1",
+      "13.4": "10.15.4",
+      "13.3.1": "10.15.3",
+      "13.3": "10.15.2",
+      "13.1": "10.15",
+      "14.0": "11.0"
+    },
+    "macOS_iOSMac": {
+      "10.15.2": "13.3",
+      "11.0": "14.0",
+      "10.15": "13.1",
+      "10.15.3": "13.3.1",
+      "10.15.1": "13.2",
+      "10.15.4": "13.4"
+    }
+  }
+}

diff  --git a/clang/test/Sema/attr-availability-iosmac-infer-from-macos-no-sdk-settings.c b/clang/test/Sema/attr-availability-iosmac-infer-from-macos-no-sdk-settings.c
new file mode 100644
index 0000000000000..092889899206d
--- /dev/null
+++ b/clang/test/Sema/attr-availability-iosmac-infer-from-macos-no-sdk-settings.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 "-triple" "x86_64-apple-ios13.1-macabi" -fsyntax-only -verify %s
+
+void f0(void) __attribute__((availability(macOS, introduced = 10.11)));
+// expected-warning at -1 {{macOS availability is ignored without a valid 'SDKSettings.json' in the SDK}}
+void f1(void) __attribute__((availability(macOS, introduced = 10.15)));

diff  --git a/clang/test/Sema/attr-availability-iosmac-infer-from-macos.c b/clang/test/Sema/attr-availability-iosmac-infer-from-macos.c
new file mode 100644
index 0000000000000..899a7995f4b27
--- /dev/null
+++ b/clang/test/Sema/attr-availability-iosmac-infer-from-macos.c
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 "-triple" "x86_64-apple-ios13.1-macabi" -isysroot %S/Inputs/MacOSX11.0.sdk -fsyntax-only -verify %s
+// RUN: %clang_cc1 "-triple" "x86_64-apple-ios14-macabi" -isysroot %S/Inputs/MacOSX11.0.sdk -DIOS14 -fsyntax-only -verify %s
+
+void f0(void) __attribute__((availability(macOS, introduced = 10.11)));
+void f1(void) __attribute__((availability(macOS, introduced = 10.15)));
+void f2(void) __attribute__(( // expected-note {{'f2' has been explicitly marked deprecated here}}
+    availability(macOS, introduced = 10.11,
+                 deprecated = 10.12)));
+void f3(void)
+    __attribute__((availability(macOS, introduced = 10.11, deprecated = 10.14)))
+    __attribute__((availability(iOS, introduced = 11.0)));
+
+void f4(void)
+__attribute__((availability(macOS, introduced = 10, deprecated = 100000)));
+
+void fAvail() __attribute__((availability(macOS, unavailable)));
+
+void f16() __attribute__((availability(macOS, introduced = 11.0)));
+#ifndef IOS14
+// expected-note at -2 {{here}}
+#endif
+
+void fObs() __attribute__((availability(macOS, introduced = 10.11, obsoleted = 10.15))); // expected-note {{'fObs' has been explicitly marked unavailable here}}
+
+void fAPItoDepr() __attribute__((availability(macOS, introduced = 10.11, deprecated = 100000)));
+
+void dontRemapFutureVers() __attribute__((availability(macOS, introduced = 20)));
+
+void usage() {
+  f0();
+  f1();
+  f2(); // expected-warning {{'f2' is deprecated: first deprecated in macCatalyst 13.1}}
+  f3();
+  f4();
+  fAvail();
+  f16();
+#ifndef IOS14
+  // expected-warning at -2 {{'f16' is only available on macCatalyst 14.0 or newer}} expected-note at -2 {{enclose}}
+#endif
+  fObs(); // expected-error {{'fObs' is unavailable: obsoleted in macCatalyst 13.1}}
+  fAPItoDepr();
+  dontRemapFutureVers();
+}
+
+#ifdef IOS14
+
+void f15_4(void) __attribute__((availability(macOS, introduced = 10.15, deprecated = 10.15.4))); // expected-note {{here}}
+void f15_3(void) __attribute__((availability(macOS, introduced = 10.15, deprecated = 10.15.3))); // expected-note {{here}}
+void f15_2(void) __attribute__((availability(macOS, introduced = 10.15, deprecated = 10.15.2))); // expected-note {{here}}
+
+void usage16() {
+  f15_2(); // expected-warning {{'f15_2' is deprecated: first deprecated in macCatalyst 13.3}}
+  f15_3(); // expected-warning {{'f15_3' is deprecated: first deprecated in macCatalyst 13.3.1}}
+  f15_4(); // expected-warning {{'f15_4' is deprecated: first deprecated in macCatalyst 13.4}}
+  f16();
+}
+
+#endif

diff  --git a/clang/test/Sema/attr-availability-maccatalyst.c b/clang/test/Sema/attr-availability-maccatalyst.c
index c345443f24114..829b18c1a429c 100644
--- a/clang/test/Sema/attr-availability-maccatalyst.c
+++ b/clang/test/Sema/attr-availability-maccatalyst.c
@@ -12,8 +12,8 @@
 void f0(int) __attribute__((availability(maccatalyst,introduced=2.0,deprecated=9.1))); // expected-note {{'f0' has been explicitly marked deprecated here}}
 void f1(int) __attribute__((availability(maccatalyst,introduced=2.1)));
 void f2(int) __attribute__((availability(macCatalyst,introduced=2.0,deprecated=9.0))); // expected-note {{'f2' has been explicitly marked deprecated here}}
-void f3(int) __attribute__((availability(macosx,introduced=10.1),  availability(maccatalyst,introduced=3.0, obsoleted=9.0))); // expected-note {{'f3' has been explicitly marked unavailable here}}
-void f32(int) __attribute__((availability(macosx,introduced=10.1,deprecated=10.3,obsoleted=10.5),  availability(maccatalyst,introduced=3.0, obsoleted=9.0))); // expected-note {{'f32' has been explicitly marked unavailable here}}
+void f3(int) __attribute__((availability(maccatalyst,introduced=3.0, obsoleted=9.0))); // expected-note {{'f3' has been explicitly marked unavailable here}}
+void f32(int) __attribute__((availability(maccatalyst,introduced=3.0, obsoleted=9.0))); // expected-note {{'f32' has been explicitly marked unavailable here}}
 
 
 void f5(int) __attribute__((availability(maccatalyst,introduced=2.0))) __attribute__((availability(maccatalyst,deprecated=9.0))); // expected-note {{'f5' has been explicitly marked deprecated here}}


        


More information about the cfe-commits mailing list