arphaman created this revision.
arphaman added reviewers: erik.pilkington, steven_wu.
Herald added subscribers: ributzka, dexonsmith, jkorous.
Herald added a reviewer: aaron.ballman.

This patch canonicalizes the macOS versions in the `availability`, so that 
clang can treat macOS 10.16 availability as macOS 11 availability. The `if 
(@available (macOS 10.16, *)` checks still preserve their original version in 
the generated code to ensure that the software running on macOS Big Sur Beta 1 
can still exhibits the expected runtime behavior for the `10.16` availability 
checks.


https://reviews.llvm.org/D82823

Files:
  clang/include/clang/AST/ExprObjC.h
  clang/lib/CodeGen/CGExprScalar.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/test/CodeGen/attr-availability-new.c
  clang/test/CodeGenObjC/availability-check.m
  clang/test/Sema/attr-availability-macos-new.c

Index: clang/test/Sema/attr-availability-macos-new.c
===================================================================
--- /dev/null
+++ clang/test/Sema/attr-availability-macos-new.c
@@ -0,0 +1,116 @@
+// RUN: %clang_cc1 "-triple" "x86_64-apple-macos10.15" -fsyntax-only -verify %s
+// RUN: %clang_cc1 "-triple" "x86_64-apple-macos11" -DNEW -fsyntax-only -verify %s
+// RUN: %clang_cc1 "-triple" "x86_64-apple-darwin20" -DNEW -fsyntax-only -verify %s
+// RUN: %clang_cc1 "-triple" "x86_64-apple-macos10.15" -fsyntax-only -verify -fapplication-extension -DAPP_EXT %s
+
+__attribute__((availability(macos,strict,introduced=10.16)))
+void fNew1();
+#ifndef NEW
+// expected-note@-2 {{here}}
+#endif
+
+__attribute__((availability(macosx,strict,introduced=10.16)))
+void fNew();
+
+__attribute__((availability(macos,strict,introduced=11)))
+void fNew() { }
+#ifndef NEW
+// expected-note@-2 {{here}}
+#endif
+
+__attribute__((availability(macosx,strict,deprecated=10.16)))
+void fDep();
+
+__attribute__((availability(macos,strict,deprecated=11)))
+void fDep() { }
+#ifdef NEW
+// expected-note@-2 {{here}}
+#endif
+
+__attribute__((availability(macosx,strict,obsoleted=10.16)))
+void fObs();
+
+__attribute__((availability(macos,strict,obsoleted=11)))
+void fObs() { }
+#ifdef NEW
+// expected-note@-2 {{here}}
+#endif
+
+__attribute__((availability(macosx_app_extension,strict,introduced=10.16)))
+void fAppExt();
+
+__attribute__((availability(macos_app_extension,strict,introduced=11)))
+void fAppExt() { }
+#ifdef APP_EXT
+// expected-note@-2 {{here}}
+#endif
+
+void testVersionRemapping() {
+  fNew1();
+#ifndef NEW
+  // expected-error@-2 {{'fNew1' is unavailable: introduced in macOS 11.0}}
+#endif
+  fNew();
+#ifndef NEW
+  // expected-error@-2 {{'fNew' is unavailable: introduced in macOS 11}}
+#endif
+  fDep();
+#ifdef NEW
+  // expected-warning@-2 {{'fDep' is deprecated: first deprecated in macOS 11}}
+#endif
+  fObs();
+#ifdef NEW
+  // expected-error@-2 {{'fObs' is unavailable: obsoleted in macOS 11}}
+#endif
+
+  fAppExt();
+#ifdef APP_EXT
+  // expected-error@-2 {{'fAppExt' is unavailable: introduced in macOS (App Extension) 11}}
+#endif
+}
+
+__attribute__((availability(macosx,strict,introduced=10.16.1))) // expected-note {{here}}
+void fMatchErr();
+
+__attribute__((availability(macos,strict,introduced=11))) // expected-warning {{availability does not match previous declaration}}
+void fMatchErr() { }
+
+__attribute__((availability(macosx_app_extension,strict,introduced=10.16))) // expected-note {{here}}
+void fAppExtErr();
+
+__attribute__((availability(macos_app_extension,strict,introduced=11.1))) // expected-warning {{availability does not match previous declaration}}
+void fAppExtErr() { }
+
+__attribute__((availability(macos,introduced=11)))
+void fNew2();
+#ifndef NEW
+  // expected-note@-2 {{'fNew2' has been marked as being introduced in macOS 11 here, but the deployment target is macOS 10.15.0}}
+#endif
+__attribute__((availability(macos,introduced=10.16)))
+void fNew3();
+
+__attribute__((availability(macos,introduced=12)))
+void evenNewer();
+#ifdef NEW
+  // expected-note@-2 {{'evenNewer' has been marked as being introduced in macOS 12 here, but the deployment target is macOS 11.0.0}}
+#endif
+
+void testAvailabilityCheck() {
+  if (__builtin_available(macOS 10.16, *)) {
+    fNew2();
+    fNew3();
+  }
+  if (__builtin_available(macOS 11, *)) {
+    fNew2();
+    fNew3();
+  }
+  fNew2();
+#ifndef NEW
+  // expected-warning@-2 {{'fNew2' is only available on macOS 11 or newer}} expected-note@-2 {{enclose}}
+#endif
+#ifdef NEW
+  evenNewer(); // expected-warning {{'evenNewer' is only available on macOS 12 or newer}} expected-note {{enclose}}
+#endif
+}
+
+
Index: clang/test/CodeGenObjC/availability-check.m
===================================================================
--- clang/test/CodeGenObjC/availability-check.m
+++ clang/test/CodeGenObjC/availability-check.m
@@ -26,6 +26,15 @@
   // CHECK: br i1 true
   if (__builtin_available(macos 10.11, *))
     ;
+
+  // CHECK: call i32 @__isOSVersionAtLeast(i32 10, i32 16, i32 0)
+  // CHECK-NEXT: icmp ne
+  if (__builtin_available(macos 10.16, *))
+    ;
+  // CHECK: call i32 @__isOSVersionAtLeast(i32 11, i32 0, i32 0)
+  // CHECK-NEXT: icmp ne
+  if (__builtin_available(macos 11.0, *))
+    ;
 }
 
 // CHECK: declare i32 @__isOSVersionAtLeast(i32, i32, i32)
Index: clang/test/CodeGen/attr-availability-new.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/attr-availability-new.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fvisibility hidden "-triple" "x86_64-apple-macos11.0" -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fvisibility hidden "-triple" "x86_64-apple-macos10.15" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-OLD %s
+
+__attribute__((availability(macos,introduced=10.16)))
+void f0(void);
+
+__attribute__((availability(macos,introduced=11.0)))
+void f1(void);
+
+__attribute__((availability(macos,introduced=12.0)))
+void f2(void);
+
+// CHECK-OLD: declare extern_weak void @f0
+// CHECK-OLD: declare extern_weak void @f1
+// CHECK-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();
+}
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1490,6 +1490,7 @@
   VisitExpr(E);
   Record.AddSourceRange(E->getSourceRange());
   Record.AddVersionTuple(E->getVersion());
+  Record.AddVersionTuple(E->getVersionAsWritten());
   Code = serialization::EXPR_OBJC_AVAILABILITY_CHECK;
 }
 
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1605,7 +1605,8 @@
   SourceRange R = Record.readSourceRange();
   E->AtLoc = R.getBegin();
   E->RParen = R.getEnd();
-  E->VersionToCheck = Record.readVersionTuple();
+  E->VersionToCheck.Version = Record.readVersionTuple();
+  E->VersionToCheck.SourceVersion = Record.readVersionTuple();
 }
 
 //===----------------------------------------------------------------------===//
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -19187,15 +19187,28 @@
     llvm::ArrayRef<AvailabilitySpec> AvailSpecs, SourceLocation AtLoc,
     SourceLocation RParen) {
 
-  StringRef Platform = getASTContext().getTargetInfo().getPlatformName();
-
-  auto Spec = llvm::find_if(AvailSpecs, [&](const AvailabilitySpec &Spec) {
-    return Spec.getPlatform() == Platform;
-  });
+  auto FindSpecVersion = [&](StringRef Platform)
+      -> Optional<ObjCAvailabilityCheckExpr::VersionAsWritten> {
+    auto Spec = llvm::find_if(AvailSpecs, [&](const AvailabilitySpec &Spec) {
+      return Spec.getPlatform() == Platform;
+    });
+    if (Spec == AvailSpecs.end())
+      return None;
+    if (Platform == "macos") {
+      return ObjCAvailabilityCheckExpr::VersionAsWritten{
+          llvm::Triple::getCanonicalVersionForOS(llvm::Triple::MacOSX,
+                                                 Spec->getVersion()),
+          Spec->getVersion()};
+    }
+    return ObjCAvailabilityCheckExpr::VersionAsWritten{Spec->getVersion(),
+                                                       Spec->getVersion()};
+  };
 
-  VersionTuple Version;
-  if (Spec != AvailSpecs.end())
-    Version = Spec->getVersion();
+  auto MaybeVersion =
+      FindSpecVersion(Context.getTargetInfo().getPlatformName());
+  ObjCAvailabilityCheckExpr::VersionAsWritten Version;
+  if (MaybeVersion)
+    Version = *MaybeVersion;
 
   // The use of `@available` in the enclosing function should be analyzed to
   // warn when it's used inappropriately (i.e. not if(@available)).
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -2432,6 +2432,15 @@
   AvailabilityChange Introduced = AL.getAvailabilityIntroduced();
   AvailabilityChange Deprecated = AL.getAvailabilityDeprecated();
   AvailabilityChange Obsoleted = AL.getAvailabilityObsoleted();
+  if (II->getName() == "macos" || II->getName() == "macos_app_extension") {
+    // Canonicalize macOS availability versions.
+    Introduced.Version = llvm::Triple::getCanonicalVersionForOS(
+        llvm::Triple::MacOSX, Introduced.Version);
+    Deprecated.Version = llvm::Triple::getCanonicalVersionForOS(
+        llvm::Triple::MacOSX, Deprecated.Version);
+    Obsoleted.Version = llvm::Triple::getCanonicalVersionForOS(
+        llvm::Triple::MacOSX, Obsoleted.Version);
+  }
   bool IsUnavailable = AL.getUnavailableLoc().isValid();
   bool IsStrict = AL.getStrictLoc().isValid();
   StringRef Str;
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -525,7 +525,7 @@
   }
 
   Value *VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
-    VersionTuple Version = E->getVersion();
+    VersionTuple Version = E->getVersionAsWritten();
 
     // If we're checking for a platform older than our minimum deployment
     // target, we can fold the check away.
Index: clang/include/clang/AST/ExprObjC.h
===================================================================
--- clang/include/clang/AST/ExprObjC.h
+++ clang/include/clang/AST/ExprObjC.h
@@ -1684,14 +1684,24 @@
 /// expressions.
 ///
 class ObjCAvailabilityCheckExpr : public Expr {
+public:
+  struct VersionAsWritten {
+    /// Platform version canonicalized for use with availability checks.
+    VersionTuple Version;
+    /// Platform version as written in the source.
+    VersionTuple SourceVersion;
+  };
+
+private:
   friend class ASTStmtReader;
 
-  VersionTuple VersionToCheck;
+  VersionAsWritten VersionToCheck;
   SourceLocation AtLoc, RParen;
 
 public:
-  ObjCAvailabilityCheckExpr(VersionTuple VersionToCheck, SourceLocation AtLoc,
-                            SourceLocation RParen, QualType Ty)
+  ObjCAvailabilityCheckExpr(VersionAsWritten VersionToCheck,
+                            SourceLocation AtLoc, SourceLocation RParen,
+                            QualType Ty)
       : Expr(ObjCAvailabilityCheckExprClass, Ty, VK_RValue, OK_Ordinary),
         VersionToCheck(VersionToCheck), AtLoc(AtLoc), RParen(RParen) {
     setDependence(ExprDependence::None);
@@ -1705,8 +1715,9 @@
   SourceRange getSourceRange() const { return {AtLoc, RParen}; }
 
   /// This may be '*', in which case this should fold to true.
-  bool hasVersion() const { return !VersionToCheck.empty(); }
-  VersionTuple getVersion() { return VersionToCheck; }
+  bool hasVersion() const { return !VersionToCheck.Version.empty(); }
+  VersionTuple getVersion() { return VersionToCheck.Version; }
+  VersionTuple getVersionAsWritten() { return VersionToCheck.SourceVersion; }
 
   child_range children() {
     return child_range(child_iterator(), child_iterator());
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to