Skip to content

Commit 249c2a1

Browse files
committed
Typecheck noasync attr
This patch adds validation to ensure that the noasync attribute is only applied to useful declarations. Specifically, the `noasync` attribute cannot be applied to `deinit` declarations, asynchronous functions, or asynchronous properties.
1 parent aa51bdf commit 249c2a1

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,6 +1640,35 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
16401640
}
16411641
}
16421642

1643+
if (attr->isNoAsync()) {
1644+
const DeclContext * dctx = dyn_cast<DeclContext>(D);
1645+
bool isAsyncDeclContext = dctx && dctx->isAsyncContext();
1646+
1647+
if (const AbstractStorageDecl *decl = dyn_cast<AbstractStorageDecl>(D)) {
1648+
const AccessorDecl * accessor = decl->getEffectfulGetAccessor();
1649+
isAsyncDeclContext |= accessor && accessor->isAsyncContext();
1650+
}
1651+
1652+
if (isAsyncDeclContext) {
1653+
if (const ValueDecl *vd = dyn_cast<ValueDecl>(D)) {
1654+
D->getASTContext().Diags.diagnose(
1655+
D->getLoc(), diag::async_named_decl_must_be_available_from_async,
1656+
D->getDescriptiveKind(), vd->getName());
1657+
} else {
1658+
D->getASTContext().Diags.diagnose(
1659+
D->getLoc(), diag::async_decl_must_be_available_from_async,
1660+
D->getDescriptiveKind());
1661+
}
1662+
}
1663+
1664+
// deinit's may not be unavailable from async contexts
1665+
if (isa<DestructorDecl>(D)) {
1666+
D->getASTContext().Diags.diagnose(
1667+
D->getLoc(), diag::invalid_decl_attribute, attr);
1668+
}
1669+
1670+
}
1671+
16431672
if (!attr->hasPlatform() || !attr->isActivePlatform(Ctx) ||
16441673
!attr->Introduced.hasValue()) {
16451674
return;

test/attr/attr_availability_noasync.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,24 @@ func asyncFunc() async {
3939
// expected-error@+1{{global function 'readStringFromIO' is unavailable from asynchronous contexts}}{{13-29=IOActor.readString}}
4040
let _ = readStringFromIO()
4141
}
42+
43+
// expected-error@+2{{asynchronous global function 'unavailableAsyncFunc()' must be available from asynchronous contexts}}
44+
@available(*, noasync)
45+
func unavailableAsyncFunc() async {
46+
}
47+
48+
protocol BadSyncable {
49+
// expected-error@+2{{asynchronous property 'isSyncd' must be available from asynchronous contexts}}
50+
@available(*, noasync)
51+
var isSyncd: Bool { get async }
52+
53+
// expected-error@+2{{asynchronous instance method 'sync' must be available from asynchronous contexts}}
54+
@available(*, noasync)
55+
func sync(_ str: String) async
56+
}
57+
58+
class TestClass {
59+
// expected-error@+2{{'@available' attribute cannot be applied to this declaration}}
60+
@available(*, noasync)
61+
deinit { }
62+
}

0 commit comments

Comments
 (0)