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()); 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/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/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -19187,15 +19187,28 @@ llvm::ArrayRef 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 { + 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/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/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/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/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/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 +} + +