Skip to content

Commit cb67424

Browse files
committed
[Sema]: improve noasync diagnostics in defer statement bodies
updates noasync diagnostics in TypeCheckAvailability.cpp to diagnose defer bodies as if they had the same `isAsyncContext()` value as their nearest non-defer parent scope. resolves: #73614
1 parent c7c244e commit cb67424

File tree

3 files changed

+41
-8
lines changed

3 files changed

+41
-8
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,27 @@ static bool shouldAllowReferenceToUnavailableInSwiftDeclaration(
397397
return false;
398398
}
399399

400+
// Utility function to help determine if noasync diagnostics are still
401+
// appropriate even if a `DeclContext` returns `false` from `isAsyncContext()`.
402+
static bool
403+
shouldTreatDeclContextAsAsyncForDiagnostics(const DeclContext *DC) {
404+
switch (DC->getContextKind()) {
405+
case DeclContextKind::AbstractFunctionDecl: {
406+
auto *FD = dyn_cast<FuncDecl>(DC->getAsDecl());
407+
if (FD && FD->isDeferBody()) {
408+
// If this is a defer body, we should delegate the determination
409+
// to its parent.
410+
return shouldTreatDeclContextAsAsyncForDiagnostics(DC->getParent());
411+
} else {
412+
return DC->isAsyncContext();
413+
}
414+
}
415+
416+
default:
417+
return DC->isAsyncContext();
418+
}
419+
}
420+
400421
namespace {
401422

402423
/// A class to walk the AST to build the type refinement context hierarchy.
@@ -3781,17 +3802,20 @@ bool ExprAvailabilityWalker::diagnoseDeclRefAvailability(
37813802
static bool
37823803
diagnoseDeclAsyncAvailability(const ValueDecl *D, SourceRange R,
37833804
const Expr *call, const ExportContext &Where) {
3784-
// If we are in a synchronous context, don't check it
3785-
if (!Where.getDeclContext()->isAsyncContext())
3805+
// If we are not in an (effective) async context, don't check it
3806+
if (!shouldTreatDeclContextAsAsyncForDiagnostics(Where.getDeclContext()))
37863807
return false;
37873808

37883809
ASTContext &ctx = Where.getDeclContext()->getASTContext();
37893810

3790-
if (const AbstractFunctionDecl *afd = dyn_cast<AbstractFunctionDecl>(D)) {
3791-
if (const AbstractFunctionDecl *asyncAlt = afd->getAsyncAlternative()) {
3792-
SourceLoc diagLoc = call ? call->getLoc() : R.Start;
3793-
ctx.Diags.diagnose(diagLoc, diag::warn_use_async_alternative);
3794-
asyncAlt->diagnose(diag::decl_declared_here, asyncAlt);
3811+
// Only suggest async alternatives if the DeclContext is truly async
3812+
if (Where.getDeclContext()->isAsyncContext()) {
3813+
if (const AbstractFunctionDecl *afd = dyn_cast<AbstractFunctionDecl>(D)) {
3814+
if (const AbstractFunctionDecl *asyncAlt = afd->getAsyncAlternative()) {
3815+
SourceLoc diagLoc = call ? call->getLoc() : R.Start;
3816+
ctx.Diags.diagnose(diagLoc, diag::warn_use_async_alternative);
3817+
asyncAlt->diagnose(diag::decl_declared_here, asyncAlt);
3818+
}
37953819
}
37963820
}
37973821

test/attr/attr_availability_async_rename_toplevel.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
if #available(SwiftStdlib 5.5, *) {
66
@available(*, renamed: "process(data:)")
77
func process(data: [Int], completion: @escaping ([Int]) -> Void) { completion(data) }
8-
// expected-note@+1{{'process(data:)' declared here}}
8+
// expected-note@+1 {{'process(data:)' declared here}}
99
func process(data: [Int]) async -> [Int] { return data }
1010

1111
func asyncFunc(data: [Int]) async {

test/attr/attr_availability_noasync.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ actor IOActor {
2727

2828
@available(SwiftStdlib 5.5, *)
2929
func asyncFunc() async {
30+
defer {
31+
defer {
32+
// expected-warning@+1 {{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode}}
33+
basicNoAsync()
34+
}
35+
// expected-warning@+1 {{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode}}
36+
basicNoAsync()
37+
}
38+
3039
// expected-warning@+1{{global function 'basicNoAsync' is unavailable from asynchronous contexts; this is an error in the Swift 6 language mode}}
3140
basicNoAsync()
3241

0 commit comments

Comments
 (0)