@@ -276,16 +276,18 @@ static bool shouldAllowReferenceToUnavailableInSwiftDeclaration(
276276 return false ;
277277}
278278
279- // Utility function to help determine if noasync diagnostics are still
280- // appropriate even if a `DeclContext` returns `false` from `isAsyncContext()`.
281- static bool shouldTreatDeclContextAsAsyncForDiagnostics (const DeclContext *DC) {
282- if (auto *D = DC->getAsDecl ())
283- if (auto *FD = dyn_cast<FuncDecl>(D))
279+ // / Retrieve the innermost DeclContext that should be consulted for noasync
280+ // / checking.
281+ static const DeclContext *
282+ getInnermostDeclContextForNoAsync (const DeclContext *DC) {
283+ if (auto *D = DC->getAsDecl ()) {
284+ if (auto *FD = dyn_cast<FuncDecl>(D)) {
284285 if (FD->isDeferBody ())
285286 // If this is a defer body, we should delegate to its parent.
286- return shouldTreatDeclContextAsAsyncForDiagnostics (DC->getParent ());
287-
288- return DC->isAsyncContext ();
287+ return getInnermostDeclContextForNoAsync (DC->getParent ());
288+ }
289+ }
290+ return DC;
289291}
290292
291293// / A class that walks the AST to find the innermost (i.e., deepest) node that
@@ -2758,7 +2760,8 @@ static bool
27582760diagnoseDeclAsyncAvailability (const ValueDecl *D, SourceRange R,
27592761 const Expr *call, const ExportContext &Where) {
27602762 // If we are not in an (effective) async context, don't check it
2761- if (!shouldTreatDeclContextAsAsyncForDiagnostics (Where.getDeclContext ()))
2763+ auto *noAsyncDC = getInnermostDeclContextForNoAsync (Where.getDeclContext ());
2764+ if (!noAsyncDC->isAsyncContext ())
27622765 return false ;
27632766
27642767 ASTContext &ctx = Where.getDeclContext ()->getASTContext ();
@@ -2774,14 +2777,27 @@ diagnoseDeclAsyncAvailability(const ValueDecl *D, SourceRange R,
27742777 }
27752778 }
27762779
2780+ // In Swift 6 we previously didn't coerce macro arguments to parameter types,
2781+ // so closure arguments may be treated as async in cases where they weren't in
2782+ // Swift 6. As such we need to warn if the use is within a closure macro
2783+ // argument until the next language mode.
2784+ auto shouldWarnUntilFutureVersion = [&]() {
2785+ auto *CE = dyn_cast<ClosureExpr>(noAsyncDC);
2786+ return CE && CE->isMacroArgument ();
2787+ };
2788+
27772789 // @available(noasync) spelling
27782790 if (auto attr = D->getNoAsyncAttr ()) {
27792791 SourceLoc diagLoc = call ? call->getLoc () : R.Start ;
27802792 auto diag = ctx.Diags .diagnose (diagLoc, diag::async_unavailable_decl, D,
27812793 attr->getMessage ());
2782- diag.warnUntilSwiftVersion (6 );
2783- diag.limitBehaviorWithPreconcurrency (DiagnosticBehavior::Warning,
2784- D->preconcurrency ());
2794+ if (D->preconcurrency ()) {
2795+ diag.limitBehavior (DiagnosticBehavior::Warning);
2796+ } else if (shouldWarnUntilFutureVersion ()) {
2797+ diag.warnUntilFutureSwiftVersion ();
2798+ } else {
2799+ diag.warnUntilSwiftVersion (6 );
2800+ }
27852801
27862802 if (!attr->getRename ().empty ()) {
27872803 fixItAvailableAttrRename (diag, R, D, attr->getRename (), call);
@@ -2797,10 +2813,16 @@ diagnoseDeclAsyncAvailability(const ValueDecl *D, SourceRange R,
27972813 // @_unavailableFromAsync spelling
27982814 const UnavailableFromAsyncAttr *attr =
27992815 D->getAttrs ().getAttribute <UnavailableFromAsyncAttr>();
2800- SourceLoc diagLoc = call ? call->getLoc () : R.Start ;
2801- ctx.Diags
2802- .diagnose (diagLoc, diag::async_unavailable_decl, D, attr->Message )
2803- .warnUntilSwiftVersion (6 );
2816+ {
2817+ SourceLoc diagLoc = call ? call->getLoc () : R.Start ;
2818+ auto diag = ctx.Diags .diagnose (diagLoc, diag::async_unavailable_decl, D,
2819+ attr->Message );
2820+ if (shouldWarnUntilFutureVersion ()) {
2821+ diag.warnUntilFutureSwiftVersion ();
2822+ } else {
2823+ diag.warnUntilSwiftVersion (6 );
2824+ }
2825+ }
28042826 D->diagnose (diag::decl_declared_here, D);
28052827 return true ;
28062828}
0 commit comments