Look to enclosing declarations for @available attributes on @_nonSendable types

`@_nonSendable` types get a synthesized, unavailable extension that
declares the Sendable conformance. This extension also needs to have
appropriate platform availability for the type that is being marked
non-Sendable, so the platform-specific attributes are copied from the
nominal type declaration. However, for nested types, we might need to
copy those attributes from an enclosing declarations. Do so when
appropriate.

Fixes rdar://90330588.
This commit is contained in:
Doug Gregor
2022-07-06 22:16:16 -07:00
parent bc8bd4ea60
commit 8ff7e0b3ab
2 changed files with 48 additions and 16 deletions

View File

@@ -4341,23 +4341,37 @@ static void addUnavailableAttrs(ExtensionDecl *ext, NominalTypeDecl *nominal) {
ASTContext &ctx = nominal->getASTContext();
llvm::VersionTuple noVersion;
// Add platform-version-specific @available attributes.
for (auto available : nominal->getAttrs().getAttributes<AvailableAttr>()) {
if (available->Platform == PlatformKind::none)
continue;
// Add platform-version-specific @available attributes. Search from nominal
// type declaration through its enclosing declarations to find the first one
// with platform-specific attributes.
for (Decl *enclosing = nominal;
enclosing;
enclosing = enclosing->getDeclContext()
? enclosing->getDeclContext()->getAsDecl()
: nullptr) {
bool anyPlatformSpecificAttrs = false;
for (auto available: enclosing->getAttrs().getAttributes<AvailableAttr>()) {
if (available->Platform == PlatformKind::none)
continue;
auto attr = new (ctx) AvailableAttr(
SourceLoc(), SourceRange(),
available->Platform,
available->Message,
"", nullptr,
available->Introduced.getValueOr(noVersion), SourceRange(),
available->Deprecated.getValueOr(noVersion), SourceRange(),
available->Obsoleted.getValueOr(noVersion), SourceRange(),
PlatformAgnosticAvailabilityKind::Unavailable,
/*implicit=*/true,
available->IsSPI);
ext->getAttrs().add(attr);
auto attr = new (ctx) AvailableAttr(
SourceLoc(), SourceRange(),
available->Platform,
available->Message,
"", nullptr,
available->Introduced.getValueOr(noVersion), SourceRange(),
available->Deprecated.getValueOr(noVersion), SourceRange(),
available->Obsoleted.getValueOr(noVersion), SourceRange(),
PlatformAgnosticAvailabilityKind::Unavailable,
/*implicit=*/true,
available->IsSPI);
ext->getAttrs().add(attr);
anyPlatformSpecificAttrs = true;
}
// If we found any platform-specific availability attributes, we're done.
if (anyPlatformSpecificAttrs)
break;
}
// Add the blanket "unavailable".

View File

@@ -12,6 +12,16 @@ public struct X { }
@_nonSendable
public struct Y { }
@available(macOS 11.0, *)
extension X {
@available(macOS 12.0, *)
@_nonSendable
public struct A { }
@_nonSendable
public struct B { }
}
// RUN: %FileCheck %s <%t/Library.swiftinterface
// CHECK: @available(macOS 11.0, *)
// CHECK-NEXT: public struct X
@@ -23,6 +33,14 @@ public struct Y { }
// CHECK: @available(*, unavailable)
// CHECK-NEXT: extension Library.Y{{( )?}}: @unchecked Swift.Sendable {
// CHECK: @available(macOS, unavailable, introduced: 12.0)
// CHECK-NEXT: @available(*, unavailable)
// CHECK-NEXT: extension Library.X.A{{( )?}}: @unchecked Swift.Sendable {
// CHECK: @available(macOS, unavailable, introduced: 11.0)
// CHECK-NEXT: @available(*, unavailable)
// CHECK-NEXT: extension Library.X.B{{( )?}}: @unchecked Swift.Sendable {
// RUN: %target-swift-emit-module-interface(%t/Library.swiftinterface) %s -target %target-cpu-apple-macosx12.0 -DLIBRARY -module-name Library -module-interface-preserve-types-as-written
// RUN: %target-swift-typecheck-module-from-interface(%t/Library.swiftinterface) -module-name Library
// RUN: %FileCheck %s <%t/Library.swiftinterface