Skip to content

Commit c52314b

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 c52314b

File tree

2 files changed

+39
-7
lines changed

2 files changed

+39
-7
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,26 @@ 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 shouldTreatDeclContextAsAsyncForDiagnostics(const DeclContext *DC) {
403+
switch (DC->getContextKind()) {
404+
case DeclContextKind::AbstractFunctionDecl: {
405+
auto *FD = dyn_cast<FuncDecl>(DC->getAsDecl());
406+
if (FD && FD->isDeferBody()) {
407+
// If this is a defer body, we should delegate the determination
408+
// to its parent.
409+
return shouldTreatDeclContextAsAsyncForDiagnostics(DC->getParent());
410+
} else {
411+
return DC->isAsyncContext();
412+
}
413+
}
414+
415+
default:
416+
return DC->isAsyncContext();
417+
}
418+
}
419+
400420
namespace {
401421

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

37883808
ASTContext &ctx = Where.getDeclContext()->getASTContext();
37893809

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);
3810+
// Only suggest async alternatives if the DeclContext is truly async
3811+
if (Where.getDeclContext()->isAsyncContext()) {
3812+
if (const AbstractFunctionDecl *afd = dyn_cast<AbstractFunctionDecl>(D)) {
3813+
if (const AbstractFunctionDecl *asyncAlt = afd->getAsyncAlternative()) {
3814+
SourceLoc diagLoc = call ? call->getLoc() : R.Start;
3815+
ctx.Diags.diagnose(diagLoc, diag::warn_use_async_alternative);
3816+
asyncAlt->diagnose(diag::decl_declared_here, asyncAlt);
3817+
}
37953818
}
37963819
}
37973820

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)