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@-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@-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@-2 {{'f16' is only available on macCatalyst 14.0 or 
newer}} expected-note@-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}}


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

Reply via email to