Skip to content

Commit abac42b

Browse files
committed
Serialization: Encode custom availability domains.
When serializing `@available` attributes, if the attribute applies to a custom domain include enough information to deserialize the reference to that domain. Resolves rdar://138441265.
1 parent 6527a06 commit abac42b

File tree

15 files changed

+277
-97
lines changed

15 files changed

+277
-97
lines changed

include/swift/AST/AvailabilityDomain.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
namespace swift {
3333
class ASTContext;
3434
class CustomAvailabilityDomain;
35+
class Decl;
3536
class DeclContext;
3637
class ModuleDecl;
3738

@@ -148,6 +149,11 @@ class AvailabilityDomain final {
148149
return AvailabilityDomain(Kind::Embedded);
149150
}
150151

152+
/// If `decl` represents an availability domain, returns the corresponding
153+
/// `AvailabilityDomain` value. Otherwise, returns `std::nullopt`.
154+
static std::optional<AvailabilityDomain> forCustom(Decl *decl,
155+
const ASTContext &ctx);
156+
151157
static AvailabilityDomain forCustom(const CustomAvailabilityDomain *domain) {
152158
return AvailabilityDomain(domain);
153159
}
@@ -236,6 +242,10 @@ class AvailabilityDomain final {
236242
/// Returns the string to use when printing an `@available` attribute.
237243
llvm::StringRef getNameForAttributePrinting() const;
238244

245+
/// Returns the decl that represents the domain, or `nullptr` if the domain
246+
/// does not have a decl.
247+
Decl *getDecl() const;
248+
239249
/// Returns the module that the domain belongs to, if it is a custom domain.
240250
ModuleDecl *getModule() const;
241251

@@ -307,24 +317,26 @@ class CustomAvailabilityDomain : public llvm::FoldingSetNode {
307317
Identifier name;
308318
Kind kind;
309319
ModuleDecl *mod;
320+
Decl *decl;
310321

311-
CustomAvailabilityDomain(Identifier name, ModuleDecl *mod, Kind kind);
322+
CustomAvailabilityDomain(Identifier name, Kind kind, ModuleDecl *mod,
323+
Decl *decl);
312324

313325
public:
314-
static const CustomAvailabilityDomain *get(StringRef name, ModuleDecl *mod,
315-
Kind kind, const ASTContext &ctx);
326+
static const CustomAvailabilityDomain *get(StringRef name, Kind kind,
327+
ModuleDecl *mod, Decl *decl,
328+
const ASTContext &ctx);
316329

317330
Identifier getName() const { return name; }
318331
Kind getKind() const { return kind; }
319332
ModuleDecl *getModule() const { return mod; }
333+
Decl *getDecl() const { return decl; }
320334

321335
/// Uniquing for `ASTContext`.
322336
static void Profile(llvm::FoldingSetNodeID &ID, Identifier name,
323-
ModuleDecl *mod, Kind kind);
337+
ModuleDecl *mod);
324338

325-
void Profile(llvm::FoldingSetNodeID &ID) const {
326-
Profile(ID, name, mod, kind);
327-
}
339+
void Profile(llvm::FoldingSetNodeID &ID) const { Profile(ID, name, mod); }
328340
};
329341

330342
/// Represents either a resolved availability domain or an identifier written

lib/AST/ASTContext.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5866,11 +5866,11 @@ const AvailabilityContext::Storage *AvailabilityContext::Storage::get(
58665866
}
58675867

58685868
const CustomAvailabilityDomain *
5869-
CustomAvailabilityDomain::get(StringRef name, ModuleDecl *mod, Kind kind,
5870-
const ASTContext &ctx) {
5869+
CustomAvailabilityDomain::get(StringRef name, Kind kind, ModuleDecl *mod,
5870+
Decl *decl, const ASTContext &ctx) {
58715871
auto identifier = ctx.getIdentifier(name);
58725872
llvm::FoldingSetNodeID id;
5873-
CustomAvailabilityDomain::Profile(id, identifier, mod, kind);
5873+
CustomAvailabilityDomain::Profile(id, identifier, mod);
58745874

58755875
auto &foldingSet = ctx.getImpl().CustomAvailabilityDomains;
58765876
void *insertPos;
@@ -5880,7 +5880,8 @@ CustomAvailabilityDomain::get(StringRef name, ModuleDecl *mod, Kind kind,
58805880

58815881
void *mem = ctx.Allocate(sizeof(CustomAvailabilityDomain),
58825882
alignof(CustomAvailabilityDomain));
5883-
auto *newNode = ::new (mem) CustomAvailabilityDomain(identifier, mod, kind);
5883+
auto *newNode =
5884+
::new (mem) CustomAvailabilityDomain(identifier, kind, mod, decl);
58845885
foldingSet.InsertNode(newNode, insertPos);
58855886

58865887
return newNode;

lib/AST/AvailabilityDomain.cpp

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,61 @@
1717
#include "swift/AST/Module.h"
1818
#include "swift/AST/TypeCheckRequests.h"
1919
#include "swift/Basic/Assertions.h"
20+
#include "clang/AST/ASTContext.h"
21+
#include "clang/AST/Decl.h"
2022
#include "llvm/ADT/StringSwitch.h"
2123

2224
using namespace swift;
2325

26+
CustomAvailabilityDomain::Kind
27+
getCustomDomainKind(clang::FeatureAvailKind featureAvailKind) {
28+
switch (featureAvailKind) {
29+
case clang::FeatureAvailKind::None:
30+
llvm_unreachable("unexpected kind");
31+
case clang::FeatureAvailKind::Available:
32+
return CustomAvailabilityDomain::Kind::Enabled;
33+
case clang::FeatureAvailKind::Unavailable:
34+
return CustomAvailabilityDomain::Kind::Disabled;
35+
case clang::FeatureAvailKind::Dynamic:
36+
return CustomAvailabilityDomain::Kind::Dynamic;
37+
}
38+
}
39+
40+
static const CustomAvailabilityDomain *
41+
customDomainForClangDecl(Decl *decl, const ASTContext &ctx) {
42+
auto *clangDecl = decl->getClangDecl();
43+
ASSERT(clangDecl);
44+
45+
auto featureInfo = clangDecl->getASTContext().getFeatureAvailInfo(
46+
const_cast<clang::Decl *>(clangDecl));
47+
48+
// Ensure the decl actually represents an availability domain.
49+
if (featureInfo.first.empty())
50+
return nullptr;
51+
52+
if (featureInfo.second.Kind == clang::FeatureAvailKind::None)
53+
return nullptr;
54+
55+
return CustomAvailabilityDomain::get(
56+
featureInfo.first, getCustomDomainKind(featureInfo.second.Kind),
57+
decl->getModuleContext(), decl, ctx);
58+
}
59+
60+
std::optional<AvailabilityDomain>
61+
AvailabilityDomain::forCustom(Decl *decl, const ASTContext &ctx) {
62+
if (!decl)
63+
return std::nullopt;
64+
65+
if (decl->hasClangNode()) {
66+
if (auto *customDomain = customDomainForClangDecl(decl, ctx))
67+
return AvailabilityDomain::forCustom(customDomain);
68+
} else {
69+
// FIXME: [availability] Handle Swift availability domains decls.
70+
}
71+
72+
return std::nullopt;
73+
}
74+
2475
std::optional<AvailabilityDomain>
2576
AvailabilityDomain::builtinDomainForString(StringRef string,
2677
const DeclContext *declContext) {
@@ -166,6 +217,13 @@ llvm::StringRef AvailabilityDomain::getNameForAttributePrinting() const {
166217
}
167218
}
168219

220+
Decl *AvailabilityDomain::getDecl() const {
221+
if (auto *customDomain = getCustomDomain())
222+
return customDomain->getDecl();
223+
224+
return nullptr;
225+
}
226+
169227
ModuleDecl *AvailabilityDomain::getModule() const {
170228
if (auto customDomain = getCustomDomain())
171229
return customDomain->getModule();
@@ -268,19 +326,17 @@ bool StableAvailabilityDomainComparator::operator()(
268326
}
269327
}
270328

271-
CustomAvailabilityDomain::CustomAvailabilityDomain(Identifier name,
272-
ModuleDecl *mod, Kind kind)
273-
: name(name), kind(kind), mod(mod) {
329+
CustomAvailabilityDomain::CustomAvailabilityDomain(Identifier name, Kind kind,
330+
ModuleDecl *mod, Decl *decl)
331+
: name(name), kind(kind), mod(mod), decl(decl) {
274332
ASSERT(!name.empty());
275333
ASSERT(mod);
276334
}
277335

278336
void CustomAvailabilityDomain::Profile(llvm::FoldingSetNodeID &ID,
279-
Identifier name, ModuleDecl *mod,
280-
Kind kind) {
337+
Identifier name, ModuleDecl *mod) {
281338
ID.AddPointer(name.getAsOpaquePointer());
282339
ID.AddPointer(mod);
283-
ID.AddInteger(static_cast<unsigned>(kind));
284340
}
285341

286342
std::optional<AvailabilityDomain>

lib/ClangImporter/ClangImporter.cpp

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4115,49 +4115,28 @@ void ClangModuleUnit::lookupObjCMethods(
41154115
void ClangModuleUnit::lookupAvailabilityDomains(
41164116
Identifier identifier, SmallVectorImpl<AvailabilityDomain> &results) const {
41174117
auto domainName = identifier.str();
4118+
auto &ctx = getASTContext();
41184119
auto &clangASTContext = getClangASTContext();
41194120

4120-
// First, check the Clang AST context for a decl matching this availability
4121-
// domain name. If the domain was defined in the bridging header and that
4122-
// bridging header wasn't precompiled, this is where it will be found.
4123-
auto *domainDecl = clangASTContext.getFeatureAvailDecl(domainName);
4124-
if (!domainDecl) {
4125-
// Next, try external sources (.pcm/.pch).
4126-
auto externalSource = clangASTContext.getExternalSource();
4127-
if (externalSource)
4128-
domainDecl = dyn_cast_or_null<clang::VarDecl>(
4129-
externalSource->getAvailabilityDomainDecl(domainName));
4130-
}
4121+
auto domainInfo = clangASTContext.getFeatureAvailInfo(domainName);
4122+
if (domainInfo.Kind == clang::FeatureAvailKind::None)
4123+
return;
41314124

4132-
if (!domainDecl)
4125+
auto *varDecl = dyn_cast_or_null<clang::VarDecl>(domainInfo.Decl);
4126+
if (!varDecl)
41334127
return;
41344128

41354129
// The decl that was found may belong to a different Clang module.
4136-
if (domainDecl->getOwningModule() != getClangModule())
4130+
if (varDecl->getOwningModule() != getClangModule())
41374131
return;
41384132

4139-
// Construct a CustomAvailabilityDomain for the decl that was found.
4140-
auto featureInfo = clangASTContext.getFeatureAvailInfo(domainDecl);
4141-
if (featureInfo.first.empty())
4133+
auto *imported = ctx.getClangModuleLoader()->importDeclDirectly(varDecl);
4134+
if (!imported)
41424135
return;
41434136

4144-
auto getDomainKind = [](clang::FeatureAvailKind featureAvailKind) {
4145-
switch (featureAvailKind) {
4146-
case clang::FeatureAvailKind::None:
4147-
llvm_unreachable("unexpected kind");
4148-
case clang::FeatureAvailKind::Available:
4149-
return CustomAvailabilityDomain::Kind::Enabled;
4150-
case clang::FeatureAvailKind::Unavailable:
4151-
return CustomAvailabilityDomain::Kind::Disabled;
4152-
case clang::FeatureAvailKind::Dynamic:
4153-
return CustomAvailabilityDomain::Kind::Dynamic;
4154-
}
4155-
};
4156-
4157-
auto domain = AvailabilityDomain::forCustom(CustomAvailabilityDomain::get(
4158-
featureInfo.first, getParentModule(),
4159-
getDomainKind(featureInfo.second.Kind), getASTContext()));
4160-
results.push_back(domain);
4137+
auto customDomain = AvailabilityDomain::forCustom(imported, ctx);
4138+
ASSERT(customDomain);
4139+
results.push_back(*customDomain);
41614140
}
41624141

41634142
void ClangModuleUnit::collectLinkLibraries(

lib/Frontend/Frontend.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,8 @@ static void configureAvailabilityDomains(const ASTContext &ctx,
14091409
llvm::SmallDenseMap<Identifier, const CustomAvailabilityDomain *> domainMap;
14101410
auto createAndInsertDomain = [&](const std::string &name,
14111411
CustomAvailabilityDomain::Kind kind) {
1412-
auto *domain = CustomAvailabilityDomain::get(name, mainModule, kind, ctx);
1412+
auto *domain =
1413+
CustomAvailabilityDomain::get(name, kind, mainModule, nullptr, ctx);
14131414
bool inserted = domainMap.insert({domain->getName(), domain}).second;
14141415
ASSERT(inserted); // Domains must be unique.
14151416
};

lib/Serialization/Deserialization.cpp

Lines changed: 65 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ const char InvalidEnumValueError::ID = '\0';
181181
void InvalidEnumValueError::anchor() {}
182182
const char ConformanceXRefError::ID = '\0';
183183
void ConformanceXRefError::anchor() {}
184+
const char InavalidAvailabilityDomainError::ID = '\0';
185+
void InavalidAvailabilityDomainError::anchor() {}
184186

185187
/// Skips a single record in the bitstream.
186188
///
@@ -5720,35 +5722,79 @@ ModuleFile::getDeclChecked(
57205722
return declOrOffset;
57215723
}
57225724

5725+
static std::optional<AvailabilityDomainKind>
5726+
decodeDomainKind(uint8_t kind) {
5727+
switch (kind) {
5728+
case static_cast<uint8_t>(AvailabilityDomainKind::Universal):
5729+
return AvailabilityDomainKind::Universal;
5730+
case static_cast<uint8_t>(AvailabilityDomainKind::SwiftLanguage):
5731+
return AvailabilityDomainKind::SwiftLanguage;
5732+
case static_cast<uint8_t>(AvailabilityDomainKind::PackageDescription):
5733+
return AvailabilityDomainKind::PackageDescription;
5734+
case static_cast<uint8_t>(AvailabilityDomainKind::Embedded):
5735+
return AvailabilityDomainKind::Embedded;
5736+
case static_cast<uint8_t>(AvailabilityDomainKind::Platform):
5737+
return AvailabilityDomainKind::Platform;
5738+
case static_cast<uint8_t>(AvailabilityDomainKind::Custom):
5739+
return AvailabilityDomainKind::Custom;
5740+
default:
5741+
return std::nullopt;
5742+
}
5743+
}
5744+
5745+
static std::optional<AvailabilityDomain>
5746+
decodeAvailabilityDomain(AvailabilityDomainKind domainKind,
5747+
PlatformKind platformKind, Decl *decl,
5748+
const ASTContext &ctx) {
5749+
switch (domainKind) {
5750+
case AvailabilityDomainKind::Universal:
5751+
return AvailabilityDomain::forUniversal();
5752+
case AvailabilityDomainKind::SwiftLanguage:
5753+
return AvailabilityDomain::forSwiftLanguage();
5754+
case AvailabilityDomainKind::PackageDescription:
5755+
return AvailabilityDomain::forPackageDescription();
5756+
case AvailabilityDomainKind::Embedded:
5757+
return AvailabilityDomain::forEmbedded();
5758+
case AvailabilityDomainKind::Platform:
5759+
return AvailabilityDomain::forPlatform(platformKind);
5760+
case AvailabilityDomainKind::Custom:
5761+
return AvailabilityDomain::forCustom(decl, ctx);
5762+
}
5763+
}
5764+
57235765
Expected<AvailableAttr *>
57245766
DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl<uint64_t> &scratch,
57255767
StringRef blobData) {
57265768
bool isImplicit;
57275769
bool isUnavailable;
57285770
bool isDeprecated;
57295771
bool isNoAsync;
5730-
bool isPackageDescriptionVersionSpecific;
57315772
bool isSPI;
5732-
bool isForEmbedded;
5773+
uint8_t rawDomainKind;
5774+
unsigned rawPlatform;
5775+
DeclID domainDeclID;
57335776
DEF_VER_TUPLE_PIECES(Introduced);
57345777
DEF_VER_TUPLE_PIECES(Deprecated);
57355778
DEF_VER_TUPLE_PIECES(Obsoleted);
5736-
unsigned rawPlatform, messageSize, renameSize;
5779+
unsigned messageSize, renameSize;
57375780

57385781
// Decode the record, pulling the version tuple information.
57395782
serialization::decls_block::AvailableDeclAttrLayout::readRecord(
5740-
scratch, isImplicit, isUnavailable, isDeprecated, isNoAsync,
5741-
isPackageDescriptionVersionSpecific, isSPI, isForEmbedded,
5783+
scratch, isImplicit, isUnavailable, isDeprecated, isNoAsync, isSPI,
5784+
rawDomainKind, rawPlatform, domainDeclID,
57425785
LIST_VER_TUPLE_PIECES(Introduced), LIST_VER_TUPLE_PIECES(Deprecated),
5743-
LIST_VER_TUPLE_PIECES(Obsoleted), rawPlatform, messageSize,
5744-
renameSize);
5786+
LIST_VER_TUPLE_PIECES(Obsoleted), messageSize, renameSize);
5787+
5788+
auto maybeDomainKind = decodeDomainKind(rawDomainKind);
5789+
if (!maybeDomainKind)
5790+
return llvm::make_error<InvalidEnumValueError>(rawDomainKind, "AvailabilityDomainKind");
57455791

57465792
auto maybePlatform = platformFromUnsigned(rawPlatform);
57475793
if (!maybePlatform.has_value())
57485794
return llvm::make_error<InvalidEnumValueError>(rawPlatform, "PlatformKind");
57495795

5750-
PlatformKind platform = maybePlatform.value();
5751-
5796+
AvailabilityDomainKind domainKind = *maybeDomainKind;
5797+
PlatformKind platform = *maybePlatform;
57525798
StringRef message = blobData.substr(0, messageSize);
57535799
blobData = blobData.substr(messageSize);
57545800
StringRef rename = blobData.substr(0, renameSize);
@@ -5767,23 +5813,19 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl<uint64_t> &scratch,
57675813
else
57685814
kind = AvailableAttr::Kind::Default;
57695815

5770-
AvailabilityDomain domain;
5771-
if (platform != PlatformKind::none) {
5772-
domain = AvailabilityDomain::forPlatform(platform);
5773-
} else if (!Introduced.empty() || !Deprecated.empty() || !Obsoleted.empty()) {
5774-
domain = isPackageDescriptionVersionSpecific
5775-
? AvailabilityDomain::forPackageDescription()
5776-
: AvailabilityDomain::forSwiftLanguage();
5777-
} else if (isForEmbedded) {
5778-
domain = AvailabilityDomain::forEmbedded();
5779-
} else {
5780-
domain = AvailabilityDomain::forUniversal();
5816+
Decl *domainDecl = nullptr;
5817+
if (domainDeclID) {
5818+
SET_OR_RETURN_ERROR(domainDecl, MF.getDeclChecked(domainDeclID));
57815819
}
57825820

5821+
auto domain = decodeAvailabilityDomain(domainKind, platform, domainDecl, ctx);
5822+
if (!domain)
5823+
return llvm::make_error<InavalidAvailabilityDomainError>();
5824+
57835825
auto attr = new (ctx)
5784-
AvailableAttr(SourceLoc(), SourceRange(), domain, SourceLoc(), kind, message, rename,
5785-
Introduced, SourceRange(), Deprecated, SourceRange(),
5786-
Obsoleted, SourceRange(), isImplicit, isSPI);
5826+
AvailableAttr(SourceLoc(), SourceRange(), *domain, SourceLoc(), kind,
5827+
message, rename, Introduced, SourceRange(), Deprecated,
5828+
SourceRange(), Obsoleted, SourceRange(), isImplicit, isSPI);
57875829
return attr;
57885830
}
57895831

0 commit comments

Comments
 (0)