Skip to content

Commit 017dae3

Browse files
committed
ClangImporter: Look up availability domains defined in bridging headers.
This is very brittle in this first iteration. For now we require the declaration representing the availability domain be deserialized before it can be looked up by name since Clang does not have a lookup table for availabilty domains in its module representation. As a result, it only works for bridging headers that are not precompiled. Part of rdar://138441266.
1 parent 275a679 commit 017dae3

File tree

12 files changed

+153
-32
lines changed

12 files changed

+153
-32
lines changed

include/swift/AST/DeclContext.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#define SWIFT_DECLCONTEXT_H
2121

2222
#include "swift/AST/ASTAllocated.h"
23+
#include "swift/AST/AvailabilityDomain.h"
2324
#include "swift/AST/Identifier.h"
2425
#include "swift/AST/LookupKinds.h"
2526
#include "swift/AST/ResilienceExpansion.h"
@@ -667,6 +668,12 @@ class alignas(1 << DeclContextAlignInBits) DeclContext
667668
ObjCSelector selector,
668669
SmallVectorImpl<AbstractFunctionDecl *> &results) const;
669670

671+
/// Look up the custom availability domains matching the given identifier that
672+
/// are visible from this context.
673+
void
674+
lookupAvailabilityDomains(Identifier identifier,
675+
SmallVectorImpl<AvailabilityDomain> &results) const;
676+
670677
/// Looks up an infix operator with a given \p name.
671678
///
672679
/// This returns a vector of results, as it's possible to find multiple infix

include/swift/AST/FileUnit.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@ class FileUnit : public DeclContext, public ASTAllocated<FileUnit> {
126126
const ModuleDecl *importedModule,
127127
llvm::SmallSetVector<Identifier, 4> &spiGroups) const {};
128128

129+
/// Find all availability domains defined in this module with the given
130+
/// identifier.
131+
///
132+
/// This does a simple local lookup, not recursively looking through imports.
133+
virtual void lookupAvailabilityDomains(
134+
Identifier identifier,
135+
SmallVectorImpl<AvailabilityDomain> &results) const {};
136+
129137
virtual std::optional<Fingerprint>
130138
loadFingerprint(const IterableDeclContext *IDC) const {
131139
return std::nullopt;

include/swift/AST/Module.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,12 @@ class ModuleDecl
970970
const ModuleDecl *importedModule,
971971
llvm::SmallSetVector<Identifier, 4> &spiGroups) const;
972972

973+
/// Finds the custom availability domain defined by this module with the
974+
/// given identifier and if one exists adds it to results.
975+
void
976+
lookupAvailabilityDomains(Identifier identifier,
977+
SmallVectorImpl<AvailabilityDomain> &results) const;
978+
973979
// Is \p attr accessible as an explicitly imported SPI from this module?
974980
bool isImportedAsSPI(const SpecializeAttr *attr,
975981
const ValueDecl *targetDecl) const;
@@ -1234,11 +1240,6 @@ class ModuleDecl
12341240
/// An empty `Version` is returned if the information is not available.
12351241
version::Version getLanguageVersionBuiltWith() const;
12361242

1237-
/// Returns the custom availability domain defined by this module with the
1238-
/// given identifier, if one exists.
1239-
std::optional<AvailabilityDomain>
1240-
getAvailabilityDomainForIdentifier(Identifier identifier) const;
1241-
12421243
void setAvailabilityDomains(const AvailabilityDomainMap &&map) {
12431244
AvailabilityDomains = std::move(map);
12441245
}

include/swift/ClangImporter/ClangModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ class ClangModuleUnit final : public LoadedFile {
9090
ObjCSelector selector,
9191
SmallVectorImpl<AbstractFunctionDecl *> &results) const override;
9292

93+
void lookupAvailabilityDomains(
94+
Identifier identifier,
95+
SmallVectorImpl<AvailabilityDomain> &results) const override;
96+
9397
virtual void getTopLevelDecls(SmallVectorImpl<Decl*> &results) const override;
9498

9599
virtual void getDisplayDecls(SmallVectorImpl<Decl*> &results, bool recursive = false) const override;

lib/AST/AvailabilityDomain.cpp

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -288,21 +288,6 @@ void CustomAvailabilityDomain::Profile(llvm::FoldingSetNodeID &ID,
288288
ID.AddInteger(static_cast<unsigned>(kind));
289289
}
290290

291-
static std::optional<AvailabilityDomain>
292-
getAvailabilityDomainForName(Identifier identifier,
293-
const DeclContext *declContext) {
294-
if (auto builtinDomain = AvailabilityDomain::builtinDomainForString(
295-
identifier.str(), declContext))
296-
return builtinDomain;
297-
298-
auto &ctx = declContext->getASTContext();
299-
if (auto customDomain =
300-
ctx.MainModule->getAvailabilityDomainForIdentifier(identifier))
301-
return customDomain;
302-
303-
return std::nullopt;
304-
}
305-
306291
std::optional<AvailabilityDomain>
307292
AvailabilityDomainOrIdentifier::lookUpInDeclContext(
308293
SourceLoc loc, const DeclContext *declContext) const {
@@ -312,7 +297,13 @@ AvailabilityDomainOrIdentifier::lookUpInDeclContext(
312297
auto &diags = ctx.Diags;
313298
std::optional<AvailabilityDomain> domain;
314299
auto identifier = getAsIdentifier().value();
315-
domain = getAvailabilityDomainForName(identifier, declContext);
300+
301+
llvm::SmallVector<AvailabilityDomain> results;
302+
declContext->lookupAvailabilityDomains(identifier, results);
303+
if (results.size() > 0) {
304+
// FIXME: [availability] Diagnose ambiguity if necessary.
305+
domain = results.front();
306+
}
316307

317308
if (!domain) {
318309
auto domainString = identifier.str();

lib/AST/Module.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,18 @@ void ModuleDecl::lookupImportedSPIGroups(
10901090
FORWARD(lookupImportedSPIGroups, (importedModule, spiGroups));
10911091
}
10921092

1093+
void ModuleDecl::lookupAvailabilityDomains(
1094+
Identifier identifier,
1095+
llvm::SmallVectorImpl<AvailabilityDomain> &results) const {
1096+
auto iter = AvailabilityDomains.find(identifier);
1097+
if (iter != AvailabilityDomains.end()) {
1098+
results.push_back(AvailabilityDomain::forCustom(iter->getSecond()));
1099+
return;
1100+
}
1101+
1102+
FORWARD(lookupAvailabilityDomains, (identifier, results));
1103+
}
1104+
10931105
void BuiltinUnit::lookupValue(DeclName name, NLKind lookupKind,
10941106
OptionSet<ModuleLookupFlags> Flags,
10951107
SmallVectorImpl<ValueDecl*> &result) const {
@@ -4172,15 +4184,6 @@ version::Version ModuleDecl::getLanguageVersionBuiltWith() const {
41724184
return version::Version();
41734185
}
41744186

4175-
std::optional<AvailabilityDomain>
4176-
ModuleDecl::getAvailabilityDomainForIdentifier(Identifier identifier) const {
4177-
auto iter = AvailabilityDomains.find(identifier);
4178-
if (iter == AvailabilityDomains.end())
4179-
return std::nullopt;
4180-
4181-
return AvailabilityDomain::forCustom(iter->getSecond());
4182-
}
4183-
41844187
//===----------------------------------------------------------------------===//
41854188
// MARK: SwiftSettings
41864189
//===----------------------------------------------------------------------===//

lib/AST/NameLookup.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2893,6 +2893,21 @@ void DeclContext::lookupAllObjCMethods(
28932893
results.end());
28942894
}
28952895

2896+
void DeclContext::lookupAvailabilityDomains(
2897+
Identifier identifier, SmallVectorImpl<AvailabilityDomain> &results) const {
2898+
if (auto builtinDomain =
2899+
AvailabilityDomain::builtinDomainForString(identifier.str(), this)) {
2900+
results.push_back(*builtinDomain);
2901+
return;
2902+
}
2903+
2904+
// FIXME: [availability] Find the file/module scope decl context and look up
2905+
// the domain in that context using a request to cache the results.
2906+
for (auto import : namelookup::getAllImports(this)) {
2907+
import.importedModule->lookupAvailabilityDomains(identifier, results);
2908+
}
2909+
}
2910+
28962911
/// Given a set of type declarations, find all of the nominal type declarations
28972912
/// that they reference, looking through typealiases as appropriate.
28982913
static TinyPtrVector<NominalTypeDecl *>

lib/ClangImporter/ClangImporter.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4103,6 +4103,39 @@ void ClangModuleUnit::lookupObjCMethods(
41034103
}
41044104
}
41054105

4106+
void ClangModuleUnit::lookupAvailabilityDomains(
4107+
Identifier identifier, SmallVectorImpl<AvailabilityDomain> &results) const {
4108+
auto lookupTable = owner.findLookupTable(clangModule);
4109+
if (!lookupTable)
4110+
return;
4111+
4112+
auto varDecl = lookupTable->lookupAvailabilityDomainDecl(identifier.str());
4113+
if (!varDecl)
4114+
return;
4115+
4116+
auto featureInfo = getClangASTContext().getFeatureAvailInfo(varDecl);
4117+
if (featureInfo.first.empty())
4118+
return;
4119+
4120+
auto getDomainKind = [](clang::FeatureAvailKind featureAvailKind) {
4121+
switch (featureAvailKind) {
4122+
case clang::FeatureAvailKind::None:
4123+
llvm_unreachable("unexpected kind");
4124+
case clang::FeatureAvailKind::Available:
4125+
return CustomAvailabilityDomain::Kind::Enabled;
4126+
case clang::FeatureAvailKind::Unavailable:
4127+
return CustomAvailabilityDomain::Kind::Disabled;
4128+
case clang::FeatureAvailKind::Dynamic:
4129+
return CustomAvailabilityDomain::Kind::Dynamic;
4130+
}
4131+
};
4132+
4133+
auto domain = AvailabilityDomain::forCustom(CustomAvailabilityDomain::get(
4134+
featureInfo.first, getParentModule(),
4135+
getDomainKind(featureInfo.second.Kind), getASTContext()));
4136+
results.push_back(domain);
4137+
}
4138+
41064139
void ClangModuleUnit::collectLinkLibraries(
41074140
ModuleDecl::LinkLibraryCallback callback) const {
41084141
if (!clangModule)

lib/ClangImporter/SwiftLookupTable.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,11 @@ void SwiftLookupTable::addCategory(clang::ObjCCategoryDecl *category) {
350350
Categories.push_back(category);
351351
}
352352

353+
void SwiftLookupTable::addAvailabilityDomainDecl(StringRef name,
354+
clang::VarDecl *decl) {
355+
AvailabilityDomains.insert({name, StoredSingleEntry(decl)});
356+
}
357+
353358
bool SwiftLookupTable::resolveUnresolvedEntries(
354359
SmallVectorImpl<SingleEntry> &unresolved) {
355360
// Common case: nothing left to resolve.
@@ -712,6 +717,17 @@ SwiftLookupTable::lookupGlobalsAsMembers(SerializedSwiftName baseName,
712717
return lookupGlobalsAsMembersImpl(baseName, *storedContext);
713718
}
714719

720+
clang::VarDecl *SwiftLookupTable::lookupAvailabilityDomainDecl(StringRef name) {
721+
// FIXME: [availability] Remove this once Clang has a lookup table.
722+
auto result = AvailabilityDomains.find(name);
723+
if (result == AvailabilityDomains.end())
724+
return nullptr;
725+
726+
auto &entry = result->second;
727+
DEBUG_ASSERT(entry.isASTNodeEntry());
728+
return static_cast<clang::VarDecl *>(entry.getASTNode());
729+
}
730+
715731
SmallVector<SwiftLookupTable::SingleEntry, 4>
716732
SwiftLookupTable::allGlobalsAsMembersInContext(EffectiveClangContext context) {
717733
if (!context) return { };
@@ -1868,9 +1884,9 @@ SwiftNameLookupExtension::hashExtension(ExtensionHashBuilder &HBuilder) const {
18681884
void importer::addEntryToLookupTable(SwiftLookupTable &table,
18691885
clang::NamedDecl *named,
18701886
NameImporter &nameImporter) {
1887+
auto &clangContext = nameImporter.getClangContext();
18711888
clang::PrettyStackTraceDecl trace(
1872-
named, named->getLocation(),
1873-
nameImporter.getClangContext().getSourceManager(),
1889+
named, named->getLocation(), clangContext.getSourceManager(),
18741890
"while adding SwiftName lookup table entries for clang declaration");
18751891

18761892
// Determine whether this declaration is suppressed in Swift.
@@ -2009,6 +2025,16 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table,
20092025
addEntryToLookupTable(table, usingShadowDecl, nameImporter);
20102026
}
20112027
}
2028+
2029+
// If this decl represents an availability domain, add it to the lookup table
2030+
// as one.
2031+
// FIXME: [availability] Remove this once Clang has a lookup table.
2032+
if (auto varDecl = dyn_cast<clang::VarDecl>(named)) {
2033+
auto mutableVar = const_cast<clang::VarDecl *>(varDecl);
2034+
auto domainInfo = clangContext.getFeatureAvailInfo(mutableVar);
2035+
if (!domainInfo.first.empty())
2036+
table.addAvailabilityDomainDecl(domainInfo.first, mutableVar);
2037+
}
20122038
}
20132039

20142040
/// Returns the nearest parent of \p module that is marked \c explicit in its

lib/ClangImporter/SwiftLookupTable.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,10 @@ class SwiftLookupTable {
486486
/// The list of Objective-C categories and extensions.
487487
llvm::SmallVector<clang::ObjCCategoryDecl *, 4> Categories;
488488

489+
/// A mapping from availability domain name strings to their corresponding
490+
/// declarations.
491+
llvm::SmallDenseMap<StringRef, StoredSingleEntry> AvailabilityDomains;
492+
489493
/// A mapping from stored contexts to the set of global declarations that
490494
/// are mapped to members within that context.
491495
///
@@ -550,6 +554,9 @@ class SwiftLookupTable {
550554
/// Add an Objective-C category or extension to the table.
551555
void addCategory(clang::ObjCCategoryDecl *category);
552556

557+
/// Add an entry for a Clang availability domain.
558+
void addAvailabilityDomainDecl(StringRef name, clang::VarDecl *decl);
559+
553560
/// Resolve any unresolved entries.
554561
///
555562
/// \param unresolved Will be populated with the list of entries
@@ -632,6 +639,10 @@ class SwiftLookupTable {
632639
lookupGlobalsAsMembers(SerializedSwiftName baseName,
633640
EffectiveClangContext searchContext);
634641

642+
/// Retrieve the `VarDecl` that represents the availability domain with the
643+
/// given name, or `nullptr` if there isn't one.
644+
clang::VarDecl *lookupAvailabilityDomainDecl(StringRef name);
645+
635646
SmallVector<SingleEntry, 4>
636647
allGlobalsAsMembersInContext(EffectiveClangContext context);
637648

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <feature-availability.h>
2+
3+
static struct __AvailabilityDomain __BayBridge
4+
__attribute__((availability_domain(BayBridge))) = {
5+
__AVAILABILITY_DOMAIN_ENABLED, 0};
6+
static struct __AvailabilityDomain __GoldenGateBridge
7+
__attribute__((availability_domain(GoldenGateBridge))) = {
8+
__AVAILABILITY_DOMAIN_DISABLED, 0};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %target-swift-frontend -typecheck -verify -import-objc-header %S/Inputs/availability_domains_bridging_header.h -enable-experimental-feature CustomAvailability %s
2+
3+
// REQUIRES: swift_feature_CustomAvailability
4+
5+
@available(BayBridge)
6+
func availableInBayBridge() {}
7+
8+
@available(BayBridge, unavailable)
9+
func unavailableInBayBridge() {} // expected-note {{'unavailableInBayBridge()' has been explicitly marked unavailable here}}
10+
11+
func testSwiftDecls() {
12+
availableInBayBridge() // expected-error {{'availableInBayBridge()' is only available in BayBridge}}
13+
unavailableInBayBridge() // expected-error {{'unavailableInBayBridge()' is unavailable}}
14+
}

0 commit comments

Comments
 (0)