Skip to content

Commit 6ac729e

Browse files
committed
Sema: Allow calls to @_unavailableInEmbedded functions in compatible contexts.
Treat `@_unavailableInEmbedded` as if it were `@available(Embedded, unavailable)` and apply platform compatibility logic in the availability checker. Revert back to disallowing calls to universally unavailable functions (`@available(*, unavailable)`) in all contexts.
1 parent 686ef29 commit 6ac729e

File tree

5 files changed

+45
-23
lines changed

5 files changed

+45
-23
lines changed

include/swift/AST/AvailabilityContext.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,19 @@ class AvailabilityContext {
4444

4545
AvailabilityContext(const Storage *info) : Info(info) { assert(info); };
4646

47-
public:
48-
/// Retrieves the default `AvailabilityContext`, which is maximally available.
49-
/// The platform availability range will be set to the deployment target (or
50-
/// minimum inlining target when applicable).
51-
static AvailabilityContext getDefault(ASTContext &ctx);
52-
5347
/// Retrieves a uniqued `AvailabilityContext` with the given platform
5448
/// availability parameters.
5549
static AvailabilityContext
5650
get(const AvailabilityRange &platformAvailability,
5751
std::optional<PlatformKind> unavailablePlatform, bool deprecated,
5852
ASTContext &ctx);
5953

54+
public:
55+
/// Retrieves the default `AvailabilityContext`, which is maximally available.
56+
/// The platform availability range will be set to the deployment target (or
57+
/// minimum inlining target when applicable).
58+
static AvailabilityContext getDefault(ASTContext &ctx);
59+
6060
/// Returns the range of platform versions which may execute code in the
6161
/// availability context, starting at its introduction version.
6262
AvailabilityRange getPlatformRange() const;
@@ -74,6 +74,9 @@ class AvailabilityContext {
7474
/// Returns true if this context is deprecated on the current platform.
7575
bool isDeprecated() const;
7676

77+
/// Returns true if this context is `@_unavailableInEmbedded`.
78+
bool isUnavailableInEmbedded() const;
79+
7780
/// Constrain with another `AvailabilityContext`.
7881
void constrainWithContext(const AvailabilityContext &other, ASTContext &ctx);
7982

include/swift/AST/AvailabilityContextStorage.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ struct AvailabilityContext::PlatformInfo {
3636
/// platform.
3737
unsigned IsUnavailable : 1;
3838

39+
/// Whether or not the context is `@_unavailableInEmbedded`.
40+
unsigned IsUnavailableInEmbedded : 1;
41+
3942
/// Whether or not the context is considered deprecated on the current
4043
/// platform.
4144
unsigned IsDeprecated : 1;
@@ -57,6 +60,7 @@ struct AvailabilityContext::PlatformInfo {
5760
void Profile(llvm::FoldingSetNodeID &ID) const {
5861
Range.getRawVersionRange().Profile(ID);
5962
ID.AddBoolean(IsUnavailable);
63+
ID.AddBoolean(IsUnavailableInEmbedded);
6064
ID.AddInteger(static_cast<uint8_t>(UnavailablePlatform));
6165
ID.AddBoolean(IsDeprecated);
6266
}

lib/AST/AvailabilityContext.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ bool AvailabilityContext::PlatformInfo::constrainWith(
4242
isConstrained |= constrainRange(Range, other.Range);
4343
if (other.IsUnavailable) {
4444
isConstrained |= constrainUnavailability(other.UnavailablePlatform);
45+
isConstrained |=
46+
CONSTRAIN_BOOL(IsUnavailableInEmbedded, other.IsUnavailableInEmbedded);
4547
}
4648
isConstrained |= CONSTRAIN_BOOL(IsDeprecated, other.IsDeprecated);
4749

@@ -55,8 +57,11 @@ bool AvailabilityContext::PlatformInfo::constrainWith(const Decl *decl) {
5557
if (auto range = AvailabilityInference::annotatedAvailableRange(decl))
5658
isConstrained |= constrainRange(Range, *range);
5759

58-
if (auto *attr = decl->getAttrs().getUnavailable(ctx))
60+
if (auto *attr = decl->getAttrs().getUnavailable(ctx)) {
5961
isConstrained |= constrainUnavailability(attr->Platform);
62+
isConstrained |=
63+
CONSTRAIN_BOOL(IsUnavailableInEmbedded, attr->isForEmbedded());
64+
}
6065

6166
isConstrained |=
6267
CONSTRAIN_BOOL(IsDeprecated, decl->getAttrs().isDeprecated(ctx));
@@ -104,6 +109,9 @@ bool AvailabilityContext::PlatformInfo::isContainedIn(
104109
inheritsAvailabilityFromPlatform(UnavailablePlatform,
105110
other.UnavailablePlatform))
106111
return false;
112+
113+
if (IsUnavailableInEmbedded && !other.IsUnavailableInEmbedded)
114+
return false;
107115
}
108116

109117
if (!IsDeprecated && other.IsDeprecated)
@@ -120,6 +128,7 @@ AvailabilityContext AvailabilityContext::getDefault(ASTContext &ctx) {
120128
PlatformInfo platformInfo{AvailabilityRange::forInliningTarget(ctx),
121129
PlatformKind::none,
122130
/*IsUnavailable*/ false,
131+
/*IsUnavailableInEmbedded*/ false,
123132
/*IsDeprecated*/ false};
124133
return AvailabilityContext(Storage::get(platformInfo, ctx));
125134
}
@@ -132,7 +141,8 @@ AvailabilityContext::get(const AvailabilityRange &platformAvailability,
132141
unavailablePlatform.has_value()
133142
? *unavailablePlatform
134143
: PlatformKind::none,
135-
unavailablePlatform.has_value(), deprecated};
144+
unavailablePlatform.has_value(),
145+
/*IsUnavailableInEmbedded*/ false, deprecated};
136146
return AvailabilityContext(Storage::get(platformInfo, ctx));
137147
}
138148

@@ -147,6 +157,10 @@ AvailabilityContext::getUnavailablePlatformKind() const {
147157
return std::nullopt;
148158
}
149159

160+
bool AvailabilityContext::isUnavailableInEmbedded() const {
161+
return Info->Platform.IsUnavailableInEmbedded;
162+
}
163+
150164
bool AvailabilityContext::isDeprecated() const {
151165
return Info->Platform.IsDeprecated;
152166
}

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -364,19 +364,20 @@ static bool isInsideCompatibleUnavailableDeclaration(
364364
if (!referencedPlatform)
365365
return false;
366366

367-
if (!attr->isUnconditionallyUnavailable()) {
367+
if (!attr->isUnconditionallyUnavailable())
368368
return false;
369-
}
370369

371-
// Unless in embedded Swift mode, refuse calling unavailable functions from
372-
// unavailable code, but allow the use of types.
370+
// Refuse calling universally unavailable functions from unavailable code,
371+
// but allow the use of types.
373372
PlatformKind platform = attr->Platform;
374-
if (!D->getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
375-
if (platform == PlatformKind::none && !isa<TypeDecl>(D) &&
376-
!isa<ExtensionDecl>(D)) {
377-
return false;
378-
}
379-
}
373+
if (platform == PlatformKind::none && !attr->isForEmbedded() &&
374+
!isa<TypeDecl>(D) && !isa<ExtensionDecl>(D))
375+
return false;
376+
377+
// @_unavailableInEmbedded declarations may be used in contexts that are
378+
// also @_unavailableInEmbedded.
379+
if (attr->isForEmbedded())
380+
return availabilityContext.isUnavailableInEmbedded();
380381

381382
return (*referencedPlatform == platform ||
382383
inheritsAvailabilityFromPlatform(platform, *referencedPlatform));

test/embedded/availability.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ public struct UniverallyUnavailable {}
1212

1313
@_unavailableInEmbedded
1414
public func unavailable_in_embedded() { }
15-
// expected-note@-1 {{'unavailable_in_embedded()' has been explicitly marked unavailable here}}
15+
// expected-note@-1 2 {{'unavailable_in_embedded()' has been explicitly marked unavailable here}}
1616

1717
@available(*, unavailable, message: "always unavailable")
1818
public func universally_unavailable() { }
19-
// expected-note@-1 {{'universally_unavailable()' has been explicitly marked unavailable here}}
19+
// expected-note@-1 3 {{'universally_unavailable()' has been explicitly marked unavailable here}}
2020

2121
@_unavailableInEmbedded
2222
public func unused() { } // no error
@@ -50,7 +50,7 @@ public func also_unavailable_in_embedded(
5050
_ uu: UniverallyUnavailable // FIXME: should be an error
5151
) {
5252
unavailable_in_embedded() // OK
53-
universally_unavailable() // FIXME: should be an error
53+
universally_unavailable() // expected-error {{'universally_unavailable()' is unavailable: always unavailable}}
5454
has_unavailable_in_embedded_overload(.init()) // FIXME: should be ambiguous
5555
has_universally_unavailable_overload(.init()) // not ambiguous, selects available overload
5656
}
@@ -60,8 +60,8 @@ public func also_universally_unavailable(
6060
_ uie: UnavailableInEmbedded, // OK
6161
_ uu: UniverallyUnavailable // OK
6262
) {
63-
unavailable_in_embedded() // FIXME: should be an error
64-
universally_unavailable() // FIXME: should be an error
63+
unavailable_in_embedded() // expected-error {{'unavailable_in_embedded()' is unavailable: unavailable in embedded Swift}}
64+
universally_unavailable() // expected-error {{'universally_unavailable()' is unavailable: always unavailable}}
6565
has_unavailable_in_embedded_overload(.init()) // not ambiguous, selects available overload
6666
has_universally_unavailable_overload(.init()) // not ambiguous, selects available overload
6767
}

0 commit comments

Comments
 (0)