diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 792313fed2a9f0..108f1796415c89 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>; +def warn_missing_sdksettings_for_availability_checking : Warning< + "%0 availability is ignored without a valid 'SDKSettings.json' in the SDK">, + InGroup>; + // 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 4ade04992a5f49..c200b9b246811f 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 RefsMinusAssignments; + Optional> 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 6959b84e5c62af..fe3e8edbcd5cb1 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("invalid SDKSettings.json", llvm::inconvertibleErrorCode()); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 704b631f94003c..fbbb347f57da36 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(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(); + 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 c61afa750bc14c..bb4ce8d4962e25 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 { + 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 NewIntroduced = + RemapMacOSVersion(Introduced.Version), + NewDeprecated = + RemapMacOSVersion(Deprecated.Version), + NewObsoleted = + RemapMacOSVersion(Obsoleted.Version); + if (NewIntroduced || NewDeprecated || NewObsoleted) { + auto VersionOrEmptyVersion = + [](const Optional &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 bca56e4f1ee3ac..b612107cef3947 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 b78b8c1ca56d87..9e30a153cb5fbe 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 04cb1644cd70e0..b05260f9948687 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 00000000000000..b40e35e882e60d --- /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 00000000000000..092889899206d4 --- /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 00000000000000..899a7995f4b274 --- /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 c345443f24114f..829b18c1a429c4 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}}