Skip to content

Commit aa51bdf

Browse files
committed
Add noasync availability kind to available attr
This patch adds the `noasync` availability kind to `@available`. The spelling is `@available(*, noasync)`.
1 parent 1e2b94e commit aa51bdf

17 files changed

+222
-31
lines changed

include/swift/AST/Attr.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,8 @@ enum class PlatformAgnosticAvailabilityKind {
614614
PackageDescriptionVersionSpecific,
615615
/// The declaration is unavailable for other reasons.
616616
Unavailable,
617+
/// The declaration is unavailable from asynchronous contexts
618+
NoAsync,
617619
};
618620

619621
/// Defines the @available attribute.
@@ -702,6 +704,9 @@ class AvailableAttr : public DeclAttribute {
702704
/// Whether this is an unconditionally deprecated entity.
703705
bool isUnconditionallyDeprecated() const;
704706

707+
/// Whether this is a noasync attribute.
708+
bool isNoAsync() const;
709+
705710
/// Returns the platform-agnostic availability.
706711
PlatformAgnosticAvailabilityKind getPlatformAgnosticAvailability() const {
707712
return PlatformAgnostic;
@@ -2261,6 +2266,11 @@ class DeclAttributes {
22612266
/// a declaration will be deprecated in the future, or null otherwise.
22622267
const AvailableAttr *getSoftDeprecated(const ASTContext &ctx) const;
22632268

2269+
/// Returns the first @available attribute that indicates
2270+
/// a declaration is unavailable from asynchronous contexts, or null
2271+
/// otherwise.
2272+
const AvailableAttr *getNoAsync(const ASTContext &ctx) const;
2273+
22642274
SWIFT_DEBUG_DUMPER(dump(const Decl *D = nullptr));
22652275
void print(ASTPrinter &Printer, const PrintOptions &Options,
22662276
const Decl *D = nullptr) const;

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,9 +1497,8 @@ ERROR(attr_unsupported_on_target, none,
14971497
// availability
14981498
ERROR(attr_availability_platform,none,
14991499
"expected platform name or '*' for '%0' attribute", (StringRef))
1500-
ERROR(attr_availability_unavailable_deprecated,none,
1501-
"'%0' attribute cannot be both unconditionally 'unavailable' and "
1502-
"'deprecated'", (StringRef))
1500+
ERROR(attr_availability_multiple_kinds ,none,
1501+
"'%0' attribute cannot be both '%1' and '%2'", (StringRef, StringRef, StringRef))
15031502

15041503
WARNING(attr_availability_invalid_duplicate,none,
15051504
"'%0' argument has already been specified", (StringRef))

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4848,8 +4848,8 @@ ERROR(async_named_decl_must_be_available_from_async,none,
48484848
"asynchronous %0 %1 must be available from asynchronous contexts",
48494849
(DescriptiveDeclKind, DeclName))
48504850
ERROR(async_unavailable_decl,none,
4851-
"%0 %1 is unavailable from asynchronous contexts%select{|; %3}2",
4852-
(DescriptiveDeclKind, DeclBaseName, bool, StringRef))
4851+
"%0 %1 is unavailable from asynchronous contexts%select{|; %2}2",
4852+
(DescriptiveDeclKind, DeclBaseName, StringRef))
48534853

48544854
//------------------------------------------------------------------------------
48554855
// MARK: String Processing

include/swift/AST/PrintOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,9 @@ struct PrintOptions {
301301
/// Whether to print generic requirements in a where clause.
302302
bool PrintGenericRequirements = true;
303303

304+
/// Suppress emitting @available(*, noasync)
305+
bool SuppressNoAsyncAvailabilityAttr = false;
306+
304307
/// How to print opaque return types.
305308
enum class OpaqueReturnTypePrintingMode {
306309
/// 'some P1 & P2'.

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ LANGUAGE_FEATURE(BuiltinAssumeAlignment, 0, "Builtin.assumeAlignment", true)
7676
SUPPRESSIBLE_LANGUAGE_FEATURE(UnsafeInheritExecutor, 0, "@_unsafeInheritExecutor", true)
7777
SUPPRESSIBLE_LANGUAGE_FEATURE(PrimaryAssociatedTypes, 0, "Primary associated types", true)
7878
SUPPRESSIBLE_LANGUAGE_FEATURE(UnavailableFromAsync, 0, "@_unavailableFromAsync", true)
79+
SUPPRESSIBLE_LANGUAGE_FEATURE(NoAsyncAvailability, 340, "@available(*, noasync)", true)
7980

8081
#undef SUPPRESSIBLE_LANGUAGE_FEATURE
8182
#undef LANGUAGE_FEATURE

lib/AST/ASTPrinter.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3015,6 +3015,18 @@ suppressingFeatureUnavailableFromAsync(PrintOptions &options,
30153015
options.ExcludeAttrList.resize(originalExcludeAttrCount);
30163016
}
30173017

3018+
static bool usesFeatureNoAsyncAvailability(Decl *decl) {
3019+
return decl->getAttrs().getNoAsync(decl->getASTContext()) != nullptr;
3020+
}
3021+
3022+
static void
3023+
suppressingFeatureNoAsyncAvailability(PrintOptions &options,
3024+
llvm::function_ref<void()> action) {
3025+
llvm::SaveAndRestore<PrintOptions> orignalOptions(options);
3026+
options.SuppressNoAsyncAvailabilityAttr = true;
3027+
action();
3028+
}
3029+
30183030
/// Suppress the printing of a particular feature.
30193031
static void suppressingFeature(PrintOptions &options, Feature feature,
30203032
llvm::function_ref<void()> action) {

lib/AST/Attr.cpp

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ DeclAttributes::findMostSpecificActivePlatform(const ASTContext &ctx) const{
190190
continue;
191191

192192
// We have an attribute that is active for the platform, but
193-
// is it more specific than our curent best?
193+
// is it more specific than our current best?
194194
if (!bestAttr || inheritsAvailabilityFromPlatform(avAttr->Platform,
195195
bestAttr->Platform)) {
196196
bestAttr = avAttr;
@@ -356,6 +356,48 @@ DeclAttributes::getSoftDeprecated(const ASTContext &ctx) const {
356356
return conditional;
357357
}
358358

359+
const AvailableAttr *DeclAttributes::getNoAsync(const ASTContext &ctx) const {
360+
const AvailableAttr *bestAttr = nullptr;
361+
for (const DeclAttribute *attr : *this) {
362+
if (const AvailableAttr *avAttr = dyn_cast<AvailableAttr>(attr)) {
363+
if (avAttr->isInvalid())
364+
continue;
365+
366+
if (avAttr->getPlatformAgnosticAvailability() ==
367+
PlatformAgnosticAvailabilityKind::NoAsync) {
368+
// An API may only be unavailable on specific platforms.
369+
// If it doesn't have a platform associated with it, then it's
370+
// unavailable for all platforms, so we should include it. If it does
371+
// have a platform and we are not that platform, then it doesn't apply
372+
// to us.
373+
const bool isGoodForPlatform =
374+
(avAttr->hasPlatform() && avAttr->isActivePlatform(ctx)) ||
375+
!avAttr->hasPlatform();
376+
377+
if (!isGoodForPlatform)
378+
continue;
379+
380+
if (!bestAttr) {
381+
// If there is no best attr selected
382+
// and the attr either has an active platform, or doesn't have one at
383+
// all, select it.
384+
bestAttr = avAttr;
385+
} else if (bestAttr && avAttr->hasPlatform() &&
386+
bestAttr->hasPlatform() &&
387+
inheritsAvailabilityFromPlatform(avAttr->Platform,
388+
bestAttr->Platform)) {
389+
// if they both have a viable platform, use the better one
390+
bestAttr = avAttr;
391+
} else if (avAttr->hasPlatform() && !bestAttr->hasPlatform()) {
392+
// Use the one more specific
393+
bestAttr = avAttr;
394+
}
395+
}
396+
}
397+
}
398+
return bestAttr;
399+
}
400+
359401
void DeclAttributes::dump(const Decl *D) const {
360402
StreamPrinter P(llvm::errs());
361403
PrintOptions PO = PrintOptions::printDeclarations();
@@ -394,6 +436,7 @@ static bool isShortAvailable(const DeclAttribute *DA) {
394436
case PlatformAgnosticAvailabilityKind::Deprecated:
395437
case PlatformAgnosticAvailabilityKind::Unavailable:
396438
case PlatformAgnosticAvailabilityKind::UnavailableInSwift:
439+
case PlatformAgnosticAvailabilityKind::NoAsync:
397440
return false;
398441
case PlatformAgnosticAvailabilityKind::None:
399442
case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific:
@@ -771,6 +814,8 @@ static void printAvailableAttr(const AvailableAttr *Attr, ASTPrinter &Printer,
771814
Printer << ", unavailable";
772815
else if (Attr->isUnconditionallyDeprecated())
773816
Printer << ", deprecated";
817+
else if (Attr->isNoAsync())
818+
Printer << ", noasync";
774819

775820
if (Attr->Introduced)
776821
Printer << ", introduced: " << Attr->Introduced.getValue().getAsString();
@@ -974,6 +1019,8 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
9741019

9751020
case DAK_Available: {
9761021
auto Attr = cast<AvailableAttr>(this);
1022+
if (Options.SuppressNoAsyncAvailabilityAttr && Attr->isNoAsync())
1023+
return false;
9771024
if (!Options.PrintSPIs && Attr->IsSPI) {
9781025
assert(Attr->hasPlatform());
9791026
assert(Attr->Introduced.hasValue());
@@ -1705,6 +1752,7 @@ bool AvailableAttr::isUnconditionallyUnavailable() const {
17051752
case PlatformAgnosticAvailabilityKind::Deprecated:
17061753
case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific:
17071754
case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific:
1755+
case PlatformAgnosticAvailabilityKind::NoAsync:
17081756
return false;
17091757

17101758
case PlatformAgnosticAvailabilityKind::Unavailable:
@@ -1722,6 +1770,7 @@ bool AvailableAttr::isUnconditionallyDeprecated() const {
17221770
case PlatformAgnosticAvailabilityKind::UnavailableInSwift:
17231771
case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific:
17241772
case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific:
1773+
case PlatformAgnosticAvailabilityKind::NoAsync:
17251774
return false;
17261775

17271776
case PlatformAgnosticAvailabilityKind::Deprecated:
@@ -1731,6 +1780,10 @@ bool AvailableAttr::isUnconditionallyDeprecated() const {
17311780
llvm_unreachable("Unhandled PlatformAgnosticAvailabilityKind in switch.");
17321781
}
17331782

1783+
bool AvailableAttr::isNoAsync() const {
1784+
return PlatformAgnostic == PlatformAgnosticAvailabilityKind::NoAsync;
1785+
}
1786+
17341787
llvm::VersionTuple AvailableAttr::getActiveVersion(const ASTContext &ctx) const {
17351788
if (isLanguageVersionSpecific()) {
17361789
return ctx.LangOpts.EffectiveLanguageVersion;

lib/AST/Decl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7533,9 +7533,10 @@ AbstractFunctionDecl *AbstractFunctionDecl::getAsyncAlternative() const {
75337533
// rename parameter, falling back to the first with a rename. Note that
75347534
// `getAttrs` is in reverse source order, so the last attribute is the
75357535
// first in source
7536-
if (!attr->Rename.empty() && (attr->Platform == PlatformKind::none ||
7537-
!avAttr))
7536+
if (!attr->Rename.empty() &&
7537+
(attr->Platform == PlatformKind::none || !avAttr) && !attr->isNoAsync()) {
75387538
avAttr = attr;
7539+
}
75397540
}
75407541

75417542
auto *renamedDecl = evaluateOrDefault(

lib/Parse/ParseDecl.cpp

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -327,23 +327,48 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
327327
++ParamIndex;
328328

329329
enum {
330-
IsMessage, IsRenamed,
331-
IsIntroduced, IsDeprecated, IsObsoleted,
330+
IsMessage,
331+
IsRenamed,
332+
IsIntroduced,
333+
IsDeprecated,
334+
IsObsoleted,
332335
IsUnavailable,
336+
IsNoAsync,
333337
IsInvalid
334338
} ArgumentKind = IsInvalid;
335-
339+
336340
if (Tok.is(tok::identifier)) {
337-
ArgumentKind =
338-
llvm::StringSwitch<decltype(ArgumentKind)>(ArgumentKindStr)
339-
.Case("message", IsMessage)
340-
.Case("renamed", IsRenamed)
341-
.Case("introduced", IsIntroduced)
342-
.Case("deprecated", IsDeprecated)
343-
.Case("obsoleted", IsObsoleted)
344-
.Case("unavailable", IsUnavailable)
345-
.Default(IsInvalid);
346-
}
341+
ArgumentKind = llvm::StringSwitch<decltype(ArgumentKind)>(ArgumentKindStr)
342+
.Case("message", IsMessage)
343+
.Case("renamed", IsRenamed)
344+
.Case("introduced", IsIntroduced)
345+
.Case("deprecated", IsDeprecated)
346+
.Case("obsoleted", IsObsoleted)
347+
.Case("unavailable", IsUnavailable)
348+
.Case("noasync", IsNoAsync)
349+
.Default(IsInvalid);
350+
}
351+
352+
auto platformAgnosticKindToStr = [](PlatformAgnosticAvailabilityKind kind) {
353+
switch (kind) {
354+
case PlatformAgnosticAvailabilityKind::None:
355+
return "none";
356+
case PlatformAgnosticAvailabilityKind::Deprecated:
357+
return "deprecated";
358+
case PlatformAgnosticAvailabilityKind::Unavailable:
359+
return "unavailable";
360+
case PlatformAgnosticAvailabilityKind::NoAsync:
361+
return "noasync";
362+
363+
// These are possible platform agnostic availability kinds.
364+
// I'm not sure what their spellings are at the moment, so I'm
365+
// crashing instead of handling them.
366+
case PlatformAgnosticAvailabilityKind::UnavailableInSwift:
367+
case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific:
368+
case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific:
369+
llvm_unreachable("Unknown availability kind for parser");
370+
}
371+
};
347372

348373
if (ArgumentKind == IsInvalid) {
349374
diagnose(ArgumentLoc, diag::attr_availability_expected_option, AttrName)
@@ -419,8 +444,8 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
419444
case IsDeprecated:
420445
if (!findAttrValueDelimiter()) {
421446
if (PlatformAgnostic != PlatformAgnosticAvailabilityKind::None) {
422-
diagnose(Tok, diag::attr_availability_unavailable_deprecated,
423-
AttrName);
447+
diagnose(Tok, diag::attr_availability_multiple_kinds, AttrName,
448+
"deprecated", platformAgnosticKindToStr(PlatformAgnostic));
424449
}
425450

426451
PlatformAgnostic = PlatformAgnosticAvailabilityKind::Deprecated;
@@ -467,12 +492,21 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
467492

468493
case IsUnavailable:
469494
if (PlatformAgnostic != PlatformAgnosticAvailabilityKind::None) {
470-
diagnose(Tok, diag::attr_availability_unavailable_deprecated, AttrName);
495+
diagnose(Tok, diag::attr_availability_multiple_kinds, AttrName,
496+
"unavailable", platformAgnosticKindToStr(PlatformAgnostic));
471497
}
472498

473499
PlatformAgnostic = PlatformAgnosticAvailabilityKind::Unavailable;
474500
break;
475501

502+
case IsNoAsync:
503+
if (PlatformAgnostic != PlatformAgnosticAvailabilityKind::None) {
504+
diagnose(Tok, diag::attr_availability_multiple_kinds, AttrName,
505+
"noasync", platformAgnosticKindToStr(PlatformAgnostic));
506+
}
507+
PlatformAgnostic = PlatformAgnosticAvailabilityKind::NoAsync;
508+
break;
509+
476510
case IsInvalid:
477511
llvm_unreachable("handled above");
478512
}

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2608,6 +2608,9 @@ bool swift::diagnoseExplicitUnavailability(SourceLoc loc,
26082608
case PlatformAgnosticAvailabilityKind::Deprecated:
26092609
llvm_unreachable("shouldn't see deprecations in explicit unavailability");
26102610

2611+
case PlatformAgnosticAvailabilityKind::NoAsync:
2612+
llvm_unreachable("shouldn't see noasync in explicit unavailability");
2613+
26112614
case PlatformAgnosticAvailabilityKind::None:
26122615
case PlatformAgnosticAvailabilityKind::Unavailable:
26132616
if (attr->Platform != PlatformKind::none) {
@@ -2772,6 +2775,9 @@ bool swift::diagnoseExplicitUnavailability(
27722775
case PlatformAgnosticAvailabilityKind::Deprecated:
27732776
llvm_unreachable("shouldn't see deprecations in explicit unavailability");
27742777

2778+
case PlatformAgnosticAvailabilityKind::NoAsync:
2779+
llvm_unreachable("shouldn't see noasync with explicit unavailability");
2780+
27752781
case PlatformAgnosticAvailabilityKind::None:
27762782
case PlatformAgnosticAvailabilityKind::Unavailable:
27772783
if (Attr->Platform != PlatformKind::none) {
@@ -3296,16 +3302,32 @@ diagnoseDeclUnavailableFromAsync(const ValueDecl *D, SourceRange R,
32963302
// If we are in a synchronous context, don't check it
32973303
if (!Where.getDeclContext()->isAsyncContext())
32983304
return false;
3299-
if (!D->getAttrs().hasAttribute<UnavailableFromAsyncAttr>())
3300-
return false;
33013305

33023306
ASTContext &ctx = Where.getDeclContext()->getASTContext();
3307+
if (const AvailableAttr *attr = D->getAttrs().getNoAsync(ctx)) {
3308+
SourceLoc diagLoc = call ? call->getLoc() : R.Start;
3309+
auto diag = ctx.Diags.diagnose(diagLoc, diag::async_unavailable_decl,
3310+
D->getDescriptiveKind(), D->getBaseName(),
3311+
attr->Message);
3312+
3313+
if (!attr->Rename.empty()) {
3314+
fixItAvailableAttrRename(diag, R, D, attr, call);
3315+
}
3316+
return true;
3317+
}
3318+
3319+
const bool hasUnavailableAttr =
3320+
D->getAttrs().hasAttribute<UnavailableFromAsyncAttr>();
3321+
3322+
if (!hasUnavailableAttr)
3323+
return false;
3324+
// @available(noasync) spelling
33033325
const UnavailableFromAsyncAttr *attr =
33043326
D->getAttrs().getAttribute<UnavailableFromAsyncAttr>();
33053327
SourceLoc diagLoc = call ? call->getLoc() : R.Start;
33063328
ctx.Diags
33073329
.diagnose(diagLoc, diag::async_unavailable_decl, D->getDescriptiveKind(),
3308-
D->getBaseName(), attr->hasMessage(), attr->Message)
3330+
D->getBaseName(), attr->Message)
33093331
.warnUntilSwiftVersion(6);
33103332
D->diagnose(diag::decl_declared_here, D->getName());
33113333
return true;

0 commit comments

Comments
 (0)