@@ -1858,33 +1858,14 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
18581858 if (Ctx.LangOpts .DisableAvailabilityChecking )
18591859 return ;
18601860
1861+ // FIXME: This seems like it could be diagnosed during parsing instead.
18611862 while (attr->IsSPI ) {
18621863 if (attr->hasPlatform () && attr->Introduced .has_value ())
18631864 break ;
18641865 diagnoseAndRemoveAttr (attr, diag::spi_available_malformed);
18651866 break ;
18661867 }
18671868
1868- if (auto *PD = dyn_cast<ProtocolDecl>(D->getDeclContext ())) {
1869- if (auto *VD = dyn_cast<ValueDecl>(D)) {
1870- if (VD->isProtocolRequirement ()) {
1871- if (attr->isActivePlatform (Ctx) ||
1872- attr->isLanguageVersionSpecific () ||
1873- attr->isPackageDescriptionVersionSpecific ()) {
1874- auto versionAvailability = attr->getVersionAvailability (Ctx);
1875- if (attr->isUnconditionallyUnavailable () ||
1876- versionAvailability == AvailableVersionComparison::Obsoleted ||
1877- versionAvailability == AvailableVersionComparison::Unavailable) {
1878- if (!PD->isObjC ()) {
1879- diagnoseAndRemoveAttr (attr, diag::unavailable_method_non_objc_protocol);
1880- return ;
1881- }
1882- }
1883- }
1884- }
1885- }
1886- }
1887-
18881869 if (attr->isNoAsync ()) {
18891870 const DeclContext * dctx = dyn_cast<DeclContext>(D);
18901871 bool isAsyncDeclContext = dctx && dctx->isAsyncContext ();
@@ -1911,19 +1892,45 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
19111892 D->getASTContext ().Diags .diagnose (
19121893 D->getLoc (), diag::invalid_decl_attribute, attr);
19131894 }
1914-
19151895 }
19161896
19171897 // Skip the remaining diagnostics in swiftinterfaces.
19181898 auto *SF = D->getDeclContext ()->getParentSourceFile ();
19191899 if (SF && SF->Kind == SourceFileKind::Interface)
19201900 return ;
19211901
1922- if (!attr->hasPlatform () || !attr->isActivePlatform (Ctx) ||
1923- !attr->Introduced .has_value ()) {
1902+ // The remaining diagnostics are only for attributes that are active for the
1903+ // current target triple.
1904+ if (!attr->isActivePlatform (Ctx) && !attr->isLanguageVersionSpecific () &&
1905+ !attr->isPackageDescriptionVersionSpecific ())
19241906 return ;
1907+
1908+ SourceLoc attrLoc = attr->getLocation ();
1909+ auto versionAvailability = attr->getVersionAvailability (Ctx);
1910+ if (versionAvailability == AvailableVersionComparison::Obsoleted ||
1911+ versionAvailability == AvailableVersionComparison::Unavailable) {
1912+ if (auto cannotBeUnavailable =
1913+ TypeChecker::diagnosticIfDeclCannotBeUnavailable (D)) {
1914+ diagnose (attrLoc, cannotBeUnavailable.value ());
1915+ return ;
1916+ }
1917+
1918+ if (auto *PD = dyn_cast<ProtocolDecl>(D->getDeclContext ())) {
1919+ if (auto *VD = dyn_cast<ValueDecl>(D)) {
1920+ if (VD->isProtocolRequirement () && !PD->isObjC ()) {
1921+ diagnoseAndRemoveAttr (attr,
1922+ diag::unavailable_method_non_objc_protocol);
1923+ return ;
1924+ }
1925+ }
1926+ }
19251927 }
19261928
1929+ // The remaining diagnostics are only for attributes with introduced versions
1930+ // for specific platforms.
1931+ if (!attr->hasPlatform () || !attr->Introduced .has_value ())
1932+ return ;
1933+
19271934 // Make sure there isn't a more specific attribute we should be using instead.
19281935 // findMostSpecificActivePlatform() is O(N), so only do this if we're checking
19291936 // an iOS attribute while building for macCatalyst.
@@ -1934,8 +1941,6 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
19341941 }
19351942 }
19361943
1937- SourceLoc attrLoc = attr->getLocation ();
1938-
19391944 // Find the innermost enclosing declaration with an availability
19401945 // range annotation and ensure that this attribute's available version range
19411946 // is fully contained within that declaration's range. If there is no such
@@ -4459,6 +4464,10 @@ Optional<Diag<>>
44594464TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable (const Decl *D) {
44604465 auto *DC = D->getDeclContext ();
44614466
4467+ // A destructor is always called if declared.
4468+ if (auto *DD = dyn_cast<DestructorDecl>(D))
4469+ return diag::availability_deinit_no_potential;
4470+
44624471 if (auto *VD = dyn_cast<VarDecl>(D)) {
44634472 if (!VD->hasStorageOrWrapsStorage ())
44644473 return None;
@@ -4493,6 +4502,27 @@ TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable(const Decl *D) {
44934502 return None;
44944503}
44954504
4505+ Optional<Diag<>>
4506+ TypeChecker::diagnosticIfDeclCannotBeUnavailable (const Decl *D) {
4507+ auto parentIsUnavailable = [](const Decl *D) -> bool {
4508+ if (auto *parent =
4509+ AvailabilityInference::parentDeclForInferredAvailability (D)) {
4510+ return parent->getSemanticUnavailableAttr () != None;
4511+ }
4512+ return false ;
4513+ };
4514+
4515+ // A destructor is always called if declared.
4516+ if (auto *DD = dyn_cast<DestructorDecl>(D)) {
4517+ if (parentIsUnavailable (D))
4518+ return None;
4519+
4520+ return diag::availability_deinit_no_unavailable;
4521+ }
4522+
4523+ return None;
4524+ }
4525+
44964526static bool shouldBlockImplicitDynamic (Decl *D) {
44974527 if (D->getAttrs ().hasAttribute <NonObjCAttr>() ||
44984528 D->getAttrs ().hasAttribute <SILGenNameAttr>() ||
0 commit comments