@@ -1858,33 +1858,14 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
1858
1858
if (Ctx.LangOpts .DisableAvailabilityChecking )
1859
1859
return ;
1860
1860
1861
+ // FIXME: This seems like it could be diagnosed during parsing instead.
1861
1862
while (attr->IsSPI ) {
1862
1863
if (attr->hasPlatform () && attr->Introduced .has_value ())
1863
1864
break ;
1864
1865
diagnoseAndRemoveAttr (attr, diag::spi_available_malformed);
1865
1866
break ;
1866
1867
}
1867
1868
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
-
1888
1869
if (attr->isNoAsync ()) {
1889
1870
const DeclContext * dctx = dyn_cast<DeclContext>(D);
1890
1871
bool isAsyncDeclContext = dctx && dctx->isAsyncContext ();
@@ -1911,19 +1892,45 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
1911
1892
D->getASTContext ().Diags .diagnose (
1912
1893
D->getLoc (), diag::invalid_decl_attribute, attr);
1913
1894
}
1914
-
1915
1895
}
1916
1896
1917
1897
// Skip the remaining diagnostics in swiftinterfaces.
1918
1898
auto *SF = D->getDeclContext ()->getParentSourceFile ();
1919
1899
if (SF && SF->Kind == SourceFileKind::Interface)
1920
1900
return ;
1921
1901
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 ())
1924
1906
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
+ }
1925
1927
}
1926
1928
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
+
1927
1934
// Make sure there isn't a more specific attribute we should be using instead.
1928
1935
// findMostSpecificActivePlatform() is O(N), so only do this if we're checking
1929
1936
// an iOS attribute while building for macCatalyst.
@@ -1934,8 +1941,6 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
1934
1941
}
1935
1942
}
1936
1943
1937
- SourceLoc attrLoc = attr->getLocation ();
1938
-
1939
1944
// Find the innermost enclosing declaration with an availability
1940
1945
// range annotation and ensure that this attribute's available version range
1941
1946
// is fully contained within that declaration's range. If there is no such
@@ -4459,6 +4464,10 @@ Optional<Diag<>>
4459
4464
TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable (const Decl *D) {
4460
4465
auto *DC = D->getDeclContext ();
4461
4466
4467
+ // A destructor is always called if declared.
4468
+ if (auto *DD = dyn_cast<DestructorDecl>(D))
4469
+ return diag::availability_deinit_no_potential;
4470
+
4462
4471
if (auto *VD = dyn_cast<VarDecl>(D)) {
4463
4472
if (!VD->hasStorageOrWrapsStorage ())
4464
4473
return None;
@@ -4493,6 +4502,27 @@ TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable(const Decl *D) {
4493
4502
return None;
4494
4503
}
4495
4504
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
+
4496
4526
static bool shouldBlockImplicitDynamic (Decl *D) {
4497
4527
if (D->getAttrs ().hasAttribute <NonObjCAttr>() ||
4498
4528
D->getAttrs ().hasAttribute <SILGenNameAttr>() ||
0 commit comments