@@ -276,16 +276,18 @@ static bool shouldAllowReferenceToUnavailableInSwiftDeclaration(
276
276
return false ;
277
277
}
278
278
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)) {
284
285
if (FD->isDeferBody ())
285
286
// 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;
289
291
}
290
292
291
293
// / A class that walks the AST to find the innermost (i.e., deepest) node that
@@ -2758,7 +2760,8 @@ static bool
2758
2760
diagnoseDeclAsyncAvailability (const ValueDecl *D, SourceRange R,
2759
2761
const Expr *call, const ExportContext &Where) {
2760
2762
// 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 ())
2762
2765
return false ;
2763
2766
2764
2767
ASTContext &ctx = Where.getDeclContext ()->getASTContext ();
@@ -2774,14 +2777,27 @@ diagnoseDeclAsyncAvailability(const ValueDecl *D, SourceRange R,
2774
2777
}
2775
2778
}
2776
2779
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
+
2777
2789
// @available(noasync) spelling
2778
2790
if (auto attr = D->getNoAsyncAttr ()) {
2779
2791
SourceLoc diagLoc = call ? call->getLoc () : R.Start ;
2780
2792
auto diag = ctx.Diags .diagnose (diagLoc, diag::async_unavailable_decl, D,
2781
2793
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
+ }
2785
2801
2786
2802
if (!attr->getRename ().empty ()) {
2787
2803
fixItAvailableAttrRename (diag, R, D, attr->getRename (), call);
@@ -2797,10 +2813,16 @@ diagnoseDeclAsyncAvailability(const ValueDecl *D, SourceRange R,
2797
2813
// @_unavailableFromAsync spelling
2798
2814
const UnavailableFromAsyncAttr *attr =
2799
2815
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
+ }
2804
2826
D->diagnose (diag::decl_declared_here, D);
2805
2827
return true ;
2806
2828
}
0 commit comments