Skip to content

Commit 2e02ef2

Browse files
authored
Merge pull request #77307 from tshortli/round-trip-unavailable-in-embedded
Embedded: Distinguish `@_unavailableInEmbedded` from `@availble(*, unavailable)`
2 parents 20dd837 + daf87c0 commit 2e02ef2

File tree

12 files changed

+112
-36
lines changed

12 files changed

+112
-36
lines changed

include/swift/AST/Attr.h

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,14 @@ class DeclAttribute : public AttributeBase {
147147
Value : 32
148148
);
149149

150+
SWIFT_INLINE_BITFIELD(AvailableAttr, DeclAttribute, 1+1,
151+
/// Whether this attribute was spelled `@_spi_available`.
152+
IsSPI : 1,
153+
154+
/// Whether this attribute was spelled `@_unavailableInEmbedded`.
155+
IsForEmbedded : 1
156+
);
157+
150158
SWIFT_INLINE_BITFIELD(ClangImporterSynthesizedTypeAttr, DeclAttribute, 1,
151159
kind : 1
152160
);
@@ -674,8 +682,6 @@ enum class PlatformAgnosticAvailabilityKind {
674682
/// Defines the @available attribute.
675683
class AvailableAttr : public DeclAttribute {
676684
public:
677-
#define INIT_VER_TUPLE(X) X(X.empty() ? std::optional<llvm::VersionTuple>() : X)
678-
679685
AvailableAttr(SourceLoc AtLoc, SourceRange Range, PlatformKind Platform,
680686
StringRef Message, StringRef Rename, ValueDecl *RenameDecl,
681687
const llvm::VersionTuple &Introduced,
@@ -684,15 +690,7 @@ class AvailableAttr : public DeclAttribute {
684690
SourceRange DeprecatedRange,
685691
const llvm::VersionTuple &Obsoleted, SourceRange ObsoletedRange,
686692
PlatformAgnosticAvailabilityKind PlatformAgnostic,
687-
bool Implicit, bool IsSPI)
688-
: DeclAttribute(DeclAttrKind::Available, AtLoc, Range, Implicit),
689-
Message(Message), Rename(Rename), RenameDecl(RenameDecl),
690-
INIT_VER_TUPLE(Introduced), IntroducedRange(IntroducedRange),
691-
INIT_VER_TUPLE(Deprecated), DeprecatedRange(DeprecatedRange),
692-
INIT_VER_TUPLE(Obsoleted), ObsoletedRange(ObsoletedRange),
693-
PlatformAgnostic(PlatformAgnostic), Platform(Platform), IsSPI(IsSPI) {}
694-
695-
#undef INIT_VER_TUPLE
693+
bool Implicit, bool IsSPI, bool IsForEmbedded = false);
696694

697695
/// The optional message.
698696
const StringRef Message;
@@ -735,9 +733,6 @@ class AvailableAttr : public DeclAttribute {
735733
/// The platform of the availability.
736734
const PlatformKind Platform;
737735

738-
/// Whether this is available as SPI.
739-
const bool IsSPI;
740-
741736
/// Whether this is a language-version-specific entity.
742737
bool isLanguageVersionSpecific() const;
743738

@@ -753,6 +748,12 @@ class AvailableAttr : public DeclAttribute {
753748
/// Whether this is a noasync attribute.
754749
bool isNoAsync() const;
755750

751+
/// Whether this attribute was spelled `@_spi_available`.
752+
bool isSPI() const { return Bits.AvailableAttr.IsSPI; }
753+
754+
/// Whether this attribute was spelled `@_unavailableInEmbedded`.
755+
bool isForEmbedded() const { return Bits.AvailableAttr.IsForEmbedded; }
756+
756757
/// Returns the platform-agnostic availability.
757758
PlatformAgnosticAvailabilityKind getPlatformAgnosticAvailability() const {
758759
return PlatformAgnostic;

include/swift/Strings.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ constexpr static const StringLiteral CLANG_MODULE_DEFAULT_SPI_GROUP_NAME =
8585
constexpr static const StringLiteral SPI_AVAILABLE_ATTRNAME =
8686
"_spi_available";
8787

88+
/// The attribute name for @_unavailableInEmbedded
89+
constexpr static const StringLiteral UNAVAILABLE_IN_EMBEDDED_ATTRNAME =
90+
"_unavailableInEmbedded";
91+
8892
/// A composition class containing a StringLiteral for the names of
8993
/// Swift builtins. The reason we use this is to ensure that we when
9094
/// necessary slice off the "Builtin." prefix from these names in a

lib/AST/Attr.cpp

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ static bool isShortAvailable(const DeclAttribute *DA) {
662662
if (!AvailAttr)
663663
return false;
664664

665-
if (AvailAttr->IsSPI)
665+
if (AvailAttr->isSPI())
666666
return false;
667667

668668
if (!AvailAttr->Introduced.has_value())
@@ -1371,7 +1371,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
13711371
auto Attr = cast<AvailableAttr>(this);
13721372
if (Options.SuppressNoAsyncAvailabilityAttr && Attr->isNoAsync())
13731373
return false;
1374-
if (Options.printPublicInterface() && Attr->IsSPI) {
1374+
if (Options.printPublicInterface() && Attr->isSPI()) {
13751375
assert(Attr->hasPlatform());
13761376
assert(Attr->Introduced.has_value());
13771377
Printer.printAttrName("@available");
@@ -1380,7 +1380,14 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
13801380
Printer << ", unavailable)";
13811381
break;
13821382
}
1383-
if (Attr->IsSPI) {
1383+
if (Attr->isForEmbedded()) {
1384+
std::string atUnavailableInEmbedded =
1385+
(llvm::Twine("@") + UNAVAILABLE_IN_EMBEDDED_ATTRNAME).str();
1386+
Printer.printAttrName(atUnavailableInEmbedded);
1387+
break;
1388+
}
1389+
1390+
if (Attr->isSPI()) {
13841391
std::string atSPI = (llvm::Twine("@") + SPI_AVAILABLE_ATTRNAME).str();
13851392
Printer.printAttrName(atSPI);
13861393
} else {
@@ -2243,6 +2250,34 @@ Type RawLayoutAttr::getResolvedCountType(StructDecl *sd) const {
22432250
ErrorType::get(ctx));
22442251
}
22452252

2253+
#define INIT_VER_TUPLE(X) X(X.empty() ? std::optional<llvm::VersionTuple>() : X)
2254+
2255+
AvailableAttr::AvailableAttr(
2256+
SourceLoc AtLoc, SourceRange Range, PlatformKind Platform,
2257+
StringRef Message, StringRef Rename, ValueDecl *RenameDecl,
2258+
const llvm::VersionTuple &Introduced, SourceRange IntroducedRange,
2259+
const llvm::VersionTuple &Deprecated, SourceRange DeprecatedRange,
2260+
const llvm::VersionTuple &Obsoleted, SourceRange ObsoletedRange,
2261+
PlatformAgnosticAvailabilityKind PlatformAgnostic, bool Implicit,
2262+
bool IsSPI, bool IsForEmbedded)
2263+
: DeclAttribute(DeclAttrKind::Available, AtLoc, Range, Implicit),
2264+
Message(Message), Rename(Rename), RenameDecl(RenameDecl),
2265+
INIT_VER_TUPLE(Introduced), IntroducedRange(IntroducedRange),
2266+
INIT_VER_TUPLE(Deprecated), DeprecatedRange(DeprecatedRange),
2267+
INIT_VER_TUPLE(Obsoleted), ObsoletedRange(ObsoletedRange),
2268+
PlatformAgnostic(PlatformAgnostic), Platform(Platform) {
2269+
Bits.AvailableAttr.IsSPI = IsSPI;
2270+
2271+
if (IsForEmbedded) {
2272+
// FIXME: The IsForEmbedded bit should be removed when library availability
2273+
// conditions are implemented (rdar://138802876)
2274+
Bits.AvailableAttr.IsForEmbedded = true;
2275+
assert(Platform == PlatformKind::none);
2276+
}
2277+
}
2278+
2279+
#undef INIT_VER_TUPLE
2280+
22462281
AvailableAttr *
22472282
AvailableAttr::createPlatformAgnostic(ASTContext &C,
22482283
StringRef Message,
@@ -2294,7 +2329,8 @@ AvailableAttr *AvailableAttr::clone(ASTContext &C, bool implicit) const {
22942329
implicit ? SourceRange() : ObsoletedRange,
22952330
PlatformAgnostic,
22962331
implicit,
2297-
IsSPI);
2332+
isSPI(),
2333+
isForEmbedded());
22982334
}
22992335

23002336
std::optional<OriginallyDefinedInAttr::ActiveVersion>

lib/AST/Availability.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ static void mergeWithInferredAvailability(const AvailableAttr *Attr,
114114

115115
// The merge of two introduction versions is the maximum of the two versions.
116116
if (mergeIntoInferredVersion(Attr->Introduced, Inferred.Introduced, std::max)) {
117-
Inferred.IsSPI = Attr->IsSPI;
117+
Inferred.IsSPI = Attr->isSPI();
118118
}
119119

120120
// The merge of deprecated and obsoleted versions takes the minimum.
@@ -596,7 +596,7 @@ AvailabilityRange AvailabilityInference::availableRange(const Decl *D) {
596596

597597
bool AvailabilityInference::isAvailableAsSPI(const Decl *D) {
598598
if (auto attr = attrForAvailableRange(D))
599-
return attr->IsSPI;
599+
return attr->isSPI();
600600

601601
return false;
602602
}

lib/Parse/ParseDecl.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4501,18 +4501,16 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
45014501

45024502
// Rewrite @_unavailableInEmbedded into @available(*, unavailable) when in
45034503
// embedded Swift mode, or into nothing when in regular mode.
4504-
if (!DK && Tok.getText() == "_unavailableInEmbedded") {
4504+
if (!DK && Tok.getText() == UNAVAILABLE_IN_EMBEDDED_ATTRNAME) {
45054505
SourceLoc attrLoc = consumeToken();
45064506
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
45074507
StringRef Message = "unavailable in embedded Swift", Renamed;
4508-
auto attr = new (Context) AvailableAttr(AtLoc, SourceRange(AtLoc, attrLoc),
4509-
PlatformKind::none,
4510-
Message, Renamed, /*RenameDecl=*/nullptr,
4511-
llvm::VersionTuple(), SourceRange(),
4512-
llvm::VersionTuple(), SourceRange(),
4513-
llvm::VersionTuple(), SourceRange(),
4514-
PlatformAgnosticAvailabilityKind::Unavailable,
4515-
/*Implicit=*/false, /*IsSPI=*/false);
4508+
auto attr = new (Context) AvailableAttr(
4509+
AtLoc, SourceRange(AtLoc, attrLoc), PlatformKind::none, Message,
4510+
Renamed, /*RenameDecl=*/nullptr, llvm::VersionTuple(), SourceRange(),
4511+
llvm::VersionTuple(), SourceRange(), llvm::VersionTuple(),
4512+
SourceRange(), PlatformAgnosticAvailabilityKind::Unavailable,
4513+
/*Implicit=*/false, /*IsSPI=*/false, /*IsForEmbedded=*/true);
45164514
Attributes.add(attr);
45174515
}
45184516
return makeParserSuccess();

lib/Sema/TypeCheckAttr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2105,7 +2105,7 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
21052105
return;
21062106

21072107
// FIXME: This seems like it could be diagnosed during parsing instead.
2108-
while (attr->IsSPI) {
2108+
while (attr->isSPI()) {
21092109
if (attr->hasPlatform() && attr->Introduced.has_value())
21102110
break;
21112111
diagnoseAndRemoveAttr(attr, diag::spi_available_malformed);
@@ -4673,7 +4673,7 @@ void AttributeChecker::checkAvailableAttrs(ArrayRef<AvailableAttr *> Attrs) {
46734673
if (!D->getDeclContext()->getInnermostDeclarationDeclContext()) {
46744674
// If all available are spi available, we should use @_spi instead.
46754675
if (std::all_of(Attrs.begin(), Attrs.end(), [](AvailableAttr *AV) {
4676-
return AV->IsSPI;
4676+
return AV->isSPI();
46774677
})) {
46784678
diagnose(D->getLoc(), diag::spi_preferred_over_spi_available);
46794679
}

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6604,7 +6604,7 @@ static void addUnavailableAttrs(ExtensionDecl *ext, NominalTypeDecl *nominal) {
66046604
available->Obsoleted.value_or(noVersion), SourceRange(),
66056605
PlatformAgnosticAvailabilityKind::Unavailable,
66066606
/*implicit=*/true,
6607-
available->IsSPI);
6607+
available->isSPI());
66086608
ext->getAttrs().add(attr);
66096609
anyPlatformSpecificAttrs = true;
66106610
}

lib/Serialization/Deserialization.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5602,6 +5602,7 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl<uint64_t> &scratch,
56025602
bool isNoAsync;
56035603
bool isPackageDescriptionVersionSpecific;
56045604
bool isSPI;
5605+
bool isForEmbedded;
56055606
DEF_VER_TUPLE_PIECES(Introduced);
56065607
DEF_VER_TUPLE_PIECES(Deprecated);
56075608
DEF_VER_TUPLE_PIECES(Obsoleted);
@@ -5611,7 +5612,7 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl<uint64_t> &scratch,
56115612
// Decode the record, pulling the version tuple information.
56125613
serialization::decls_block::AvailableDeclAttrLayout::readRecord(
56135614
scratch, isImplicit, isUnavailable, isDeprecated, isNoAsync,
5614-
isPackageDescriptionVersionSpecific, isSPI,
5615+
isPackageDescriptionVersionSpecific, isSPI, isForEmbedded,
56155616
LIST_VER_TUPLE_PIECES(Introduced), LIST_VER_TUPLE_PIECES(Deprecated),
56165617
LIST_VER_TUPLE_PIECES(Obsoleted), rawPlatform, renameDeclID, messageSize,
56175618
renameSize);
@@ -5655,7 +5656,7 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl<uint64_t> &scratch,
56555656
auto attr = new (ctx) AvailableAttr(
56565657
SourceLoc(), SourceRange(), platform, message, rename, renameDecl,
56575658
Introduced, SourceRange(), Deprecated, SourceRange(), Obsoleted,
5658-
SourceRange(), platformAgnostic, isImplicit, isSPI);
5659+
SourceRange(), platformAgnostic, isImplicit, isSPI, isForEmbedded);
56595660
return attr;
56605661
}
56615662

lib/Serialization/ModuleFormat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 899; // Builtin.FixedArray serialize
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 900; // @_unavailableInEmbedded
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
@@ -2351,6 +2351,7 @@ namespace decls_block {
23512351
BCFixed<1>, // is unavailable from async?
23522352
BCFixed<1>, // is this PackageDescription version-specific kind?
23532353
BCFixed<1>, // is SPI?
2354+
BCFixed<1>, // is for Embedded
23542355
BC_AVAIL_TUPLE, // Introduced
23552356
BC_AVAIL_TUPLE, // Deprecated
23562357
BC_AVAIL_TUPLE, // Obsoleted

lib/Serialization/Serialization.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3031,7 +3031,8 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
30313031
theAttr->isUnconditionallyDeprecated(),
30323032
theAttr->isNoAsync(),
30333033
theAttr->isPackageDescriptionVersionSpecific(),
3034-
theAttr->IsSPI,
3034+
theAttr->isSPI(),
3035+
theAttr->isForEmbedded(),
30353036
LIST_VER_TUPLE_PIECES(Introduced),
30363037
LIST_VER_TUPLE_PIECES(Deprecated),
30373038
LIST_VER_TUPLE_PIECES(Obsoleted),
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %target-swift-frontend -typecheck %s -parse-stdlib -print-ast | %FileCheck %s --check-prefix=CHECK-NON-EMBEDDED
2+
// RUN: %target-swift-frontend -typecheck %s -parse-stdlib -enable-experimental-feature Embedded -print-ast | %FileCheck %s --check-prefix=CHECK-EMBEDDED
3+
4+
// CHECK-NON-EMBEDDED-NOT: @available
5+
// CHECK-NON-EMBEDDED-NOT: @_unavailableInEmbedded
6+
// CHECK-NON-EMBEDDED: public func unavailable()
7+
8+
// CHECK-EMBEDDED-NOT: @available
9+
// CHECK-EMBEDDED: @_unavailableInEmbedded
10+
// CHECK-EMBEDDED-NEXT: public func unavailable()
11+
12+
@_unavailableInEmbedded
13+
public func unavailable() {}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %{python} %utils/split_file.py -o %t %s
3+
4+
// RUN: %target-swift-frontend -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift -enable-experimental-feature Embedded -parse-as-library
5+
// RUN: %target-swift-frontend -typecheck -verify -I %t %t/Main.swift -enable-experimental-feature Embedded
6+
7+
// REQUIRES: swift_in_compiler
8+
9+
// BEGIN MyModule.swift
10+
11+
@_unavailableInEmbedded
12+
public func unavailable() { }
13+
14+
// BEGIN Main.swift
15+
16+
import MyModule
17+
18+
func available() {
19+
unavailable() // expected-error {{'unavailable()' is unavailable: unavailable in embedded Swift}}
20+
}
21+

0 commit comments

Comments
 (0)