Skip to content

Commit 7fcc72f

Browse files
authored
Merge pull request swiftlang#81859 from swiftlang/swiftify-inherit-imports
[MacrosOnImports][Swiftify] Copy module imports from clang node's module to its Swift macro SourceFile
2 parents ac3339f + edb48df commit 7fcc72f

30 files changed

+1230
-54
lines changed

include/swift/AST/Import.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,20 @@ class ImportPath : public detail::ImportPathBase<ImportPath> {
457457
Access getAccessPath(ImportKind importKind) const {
458458
return getAccessPath(isScopedImportKind(importKind));
459459
}
460+
461+
private:
462+
struct UnsafePrivateConstructorTag {};
463+
464+
// Doesn't require a module name like the public constructor.
465+
// Only used for getEmptyKey() and getTombstoneKey().
466+
ImportPath(Raw raw, UnsafePrivateConstructorTag tag) : ImportPathBase(raw) {}
467+
public:
468+
static ImportPath getEmptyKey() {
469+
return swift::ImportPath(llvm::DenseMapInfo<Raw>::getEmptyKey(), UnsafePrivateConstructorTag{});
470+
}
471+
static ImportPath getTombstoneKey() {
472+
return swift::ImportPath(llvm::DenseMapInfo<Raw>::getTombstoneKey(), UnsafePrivateConstructorTag{});
473+
}
460474
};
461475

462476
// MARK: - Abstractions of imports
@@ -810,6 +824,27 @@ struct DenseMapInfo<swift::AttributedImport<ModuleInfo>> {
810824
a.accessLevelRange == b.accessLevelRange;
811825
}
812826
};
827+
828+
template <>
829+
class DenseMapInfo<swift::ImportPath> {
830+
using ImportPath = swift::ImportPath;
831+
public:
832+
static ImportPath getEmptyKey() {
833+
return swift::ImportPath::getEmptyKey();
834+
}
835+
static ImportPath getTombstoneKey() {
836+
return swift::ImportPath::getTombstoneKey();
837+
}
838+
839+
static unsigned getHashValue(const ImportPath &val) {
840+
return llvm::DenseMapInfo<ImportPath::Raw>::getHashValue(val.getRaw());
841+
}
842+
843+
static bool isEqual(const ImportPath &lhs,
844+
const ImportPath &rhs) {
845+
return lhs == rhs;
846+
}
847+
};
813848
}
814849

815850
#endif

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,9 @@ namespace swift {
648648
/// Enables dumping macro expansions.
649649
bool DumpMacroExpansions = false;
650650

651+
/// Enables dumping imports for each SourceFile.
652+
bool DumpSourceFileImports = false;
653+
651654
/// The model of concurrency to be used.
652655
ConcurrencyModel ActiveConcurrencyModel = ConcurrencyModel::Standard;
653656

include/swift/Basic/Located.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ struct DenseMapInfo<swift::Located<T>> {
7171
}
7272

7373
static unsigned getHashValue(const swift::Located<T> &LocatedVal) {
74-
return combineHashValue(DenseMapInfo<T>::getHashValue(LocatedVal.Item),
74+
return detail::combineHashValue(DenseMapInfo<T>::getHashValue(LocatedVal.Item),
7575
DenseMapInfo<swift::SourceLoc>::getHashValue(LocatedVal.Loc));
7676
}
7777

@@ -82,4 +82,12 @@ struct DenseMapInfo<swift::Located<T>> {
8282
};
8383
} // namespace llvm
8484

85+
namespace swift {
86+
template<typename T>
87+
llvm::hash_code hash_value(const Located<T> &LocatedVal) {
88+
return llvm::DenseMapInfo<Located<T>>::getHashValue(LocatedVal);
89+
}
90+
} // namespace swift
91+
92+
8593
#endif // SWIFT_BASIC_LOCATED_H

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,9 @@ def dump_macro_expansions : Flag<["-"], "dump-macro-expansions">,
433433
def emit_macro_expansion_files : Separate<["-"], "emit-macro-expansion-files">,
434434
HelpText<"Specify when to emit macro expansion file: 'none', 'debug', or 'diagnostics'">;
435435

436+
def dump_source_file_imports : Flag<["-"], "dump-source-file-imports">,
437+
HelpText<"Dumps the list of imports for each source file">;
438+
436439
def analyze_request_evaluator : Flag<["-"], "analyze-request-evaluator">,
437440
Flags<[FrontendOption, HelpHidden, DoesNotAffectIncrementalBuild]>,
438441
HelpText<"Print out request evaluator cache statistics at the end of the compilation job">;

include/swift/Subsystems.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,7 @@ namespace swift {
126126
/// Resolve imports for a source file generated to adapt a given
127127
/// Clang module.
128128
void performImportResolutionForClangMacroBuffer(
129-
SourceFile &SF, ModuleDecl *clangModule
130-
);
129+
SourceFile &SF, ModuleDecl *explicitOriginModule);
131130

132131
/// Once type-checking is complete, this instruments code with calls to an
133132
/// intrinsic that record the expected values of local variables so they can

lib/AST/Module.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2689,6 +2689,11 @@ void
26892689
SourceFile::setImports(ArrayRef<AttributedImport<ImportedModule>> imports) {
26902690
assert(!Imports && "Already computed imports");
26912691
Imports = getASTContext().AllocateCopy(imports);
2692+
if (getASTContext().LangOpts.DumpSourceFileImports) {
2693+
llvm::errs() << "imports for " << getFilename() << ":\n";
2694+
for (auto Import : imports)
2695+
llvm::errs() << "\t" << Import.module.importedModule->getName() << "\n";
2696+
}
26922697
}
26932698

26942699
std::optional<AttributedImport<ImportedModule>>

lib/ClangImporter/ClangImporter.cpp

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2834,6 +2834,74 @@ ClangModuleUnit *ClangImporter::Implementation::getWrapperForModule(
28342834
if (auto mainModule = SwiftContext.MainModule) {
28352835
implicitImportInfo = mainModule->getImplicitImportInfo();
28362836
}
2837+
2838+
if (!underlying->isSubModule()) {
2839+
// Make sure that synthesized Swift code in the clang module wrapper
2840+
// (e.g. _SwiftifyImport macro expansions) can access the same symbols
2841+
// as if it were actually in the clang module, by copying the imports.
2842+
// Because this top-level module wrapper contains all the imported decls
2843+
// of the clang submodules, we need to add the imports of all the
2844+
// transitive submodules, since we don't know at this point of the
2845+
// compilation which submodules will contain relevant macros.
2846+
// We also need to add (transitive) explicit submodules as imports,
2847+
// to make sure that they are marked as imported *somewhere* (clang modules
2848+
// including them don't count) - otherwise their decls won't be found after
2849+
// non-visible clang decls are filtered out.
2850+
llvm::SmallVector<const clang::Module *, 32> SubmoduleWorklist;
2851+
llvm::DenseSet<ImportPath> Imported;
2852+
SubmoduleWorklist.push_back(underlying);
2853+
ImportPath::Builder underlyingSwiftModulePath =
2854+
getSwiftModulePath(underlying);
2855+
Imported.insert(underlyingSwiftModulePath.get());
2856+
for (auto UI : implicitImportInfo.AdditionalUnloadedImports)
2857+
Imported.insert(UI.module.getImportPath());
2858+
assert(implicitImportInfo.AdditionalImports.empty());
2859+
2860+
auto addImplicitImport = [&implicitImportInfo, &Imported,
2861+
this](const clang::Module *M,
2862+
bool guaranteedUnique) {
2863+
ImportPath::Builder builder = getSwiftModulePath(M);
2864+
if (!guaranteedUnique && Imported.count(builder.get()))
2865+
return;
2866+
2867+
// Don't perform this clone for modules already added to the list
2868+
ImportPath importedModulePath = builder.copyTo(SwiftContext);
2869+
2870+
#ifndef NDEBUG
2871+
const bool performSanityCheck = true;
2872+
#else
2873+
const bool performSanityCheck = false;
2874+
#endif
2875+
if (!guaranteedUnique || performSanityCheck) {
2876+
bool WasInserted = Imported.insert(importedModulePath).second;
2877+
assert(WasInserted);
2878+
}
2879+
2880+
UnloadedImportedModule importedModule(importedModulePath,
2881+
ImportKind::Module);
2882+
implicitImportInfo.AdditionalUnloadedImports.push_back(
2883+
std::move(importedModule));
2884+
};
2885+
2886+
while (!SubmoduleWorklist.empty()) {
2887+
const clang::Module *CurrModule = SubmoduleWorklist.pop_back_val();
2888+
if (CurrModule->IsExplicit) {
2889+
// We don't add imports under the same TLM, and submodules form
2890+
// a tree, so these don't require deduplication.
2891+
addImplicitImport(CurrModule, /*guaranteedUnique=*/true);
2892+
}
2893+
for (auto *I : CurrModule->Imports) {
2894+
// `underlying` is the current TLM. Only explicit submodules need to
2895+
// be imported under the same TLM, which is handled above.
2896+
if (I->getTopLevelModule() == underlying)
2897+
continue;
2898+
addImplicitImport(I, /*guaranteedUnique=*/false);
2899+
}
2900+
for (auto *Submodule : CurrModule->submodules())
2901+
SubmoduleWorklist.push_back(Submodule);
2902+
}
2903+
}
2904+
28372905
ClangModuleUnit *file = nullptr;
28382906
auto wrapper = ModuleDecl::create(name, SwiftContext, implicitImportInfo,
28392907
[&](ModuleDecl *wrapper, auto addFile) {
@@ -3742,7 +3810,11 @@ ImportDecl *swift::createImportDecl(ASTContext &Ctx,
37423810
while (TmpMod) {
37433811
// If this is a C++ stdlib module, print its name as `CxxStdlib` instead of
37443812
// `std`. `CxxStdlib` is the only accepted spelling of the C++ stdlib module
3745-
// name in Swift.
3813+
// name in Swift. In libc++ versions 17-19 there are multiple TLMs, named
3814+
// std_vector, std_array etc. We don't support importing those modules, but
3815+
// when printing the module interface it'd be weird to print "import
3816+
// CxxStdlib" over and over, so those are still printed as "import
3817+
// std_vector". This only affects the module interface for CxxStdlib.
37463818
Identifier moduleName = !TmpMod->isSubModule() && TmpMod->Name == "std"
37473819
? Ctx.Id_CxxStdlib
37483820
: Ctx.getIdentifier(TmpMod->Name);
@@ -4597,8 +4669,8 @@ void ClangModuleUnit::getImportedModulesForLookup(
45974669
if (owner.SwiftContext.LangOpts.EnableCXXInterop && topLevel &&
45984670
isCxxStdModule(topLevel) && wrapper->clangModule &&
45994671
isCxxStdModule(wrapper->clangModule)) {
4600-
// The CxxStdlib overlay re-exports the clang module std, which in recent
4601-
// libc++ versions re-exports top-level modules for different std headers
4672+
// The CxxStdlib overlay re-exports the clang module std, which in libc++
4673+
// versions 17-19 re-exports top-level modules for different std headers
46024674
// (std_string, std_vector, etc). The overlay module for each of the std
46034675
// modules is the CxxStdlib module itself. Make sure we return the actual
46044676
// clang modules (std_xyz) as transitive dependencies instead of just
@@ -8663,7 +8735,7 @@ bool importer::isCxxStdModule(const clang::Module *module) {
86638735
bool importer::isCxxStdModule(StringRef moduleName, bool IsSystem) {
86648736
if (moduleName == "std")
86658737
return true;
8666-
// In recent libc++ versions the module is split into multiple top-level
8738+
// In libc++ versions 17-19 the module is split into multiple top-level
86678739
// modules (std_vector, std_utility, etc).
86688740
if (IsSystem && moduleName.starts_with("std_")) {
86698741
if (moduleName == "std_errno_h")
@@ -8673,6 +8745,19 @@ bool importer::isCxxStdModule(StringRef moduleName, bool IsSystem) {
86738745
return false;
86748746
}
86758747

8748+
ImportPath::Builder ClangImporter::Implementation::getSwiftModulePath(const clang::Module *M) {
8749+
ImportPath::Builder builder;
8750+
while (M) {
8751+
if (!M->isSubModule() && isCxxStdModule(M))
8752+
builder.push_back(SwiftContext.Id_CxxStdlib);
8753+
else
8754+
builder.push_back(SwiftContext.getIdentifier(M->Name));
8755+
M = M->Parent;
8756+
}
8757+
std::reverse(builder.begin(), builder.end());
8758+
return builder;
8759+
}
8760+
86768761
std::optional<clang::QualType>
86778762
importer::getCxxReferencePointeeTypeOrNone(const clang::Type *type) {
86788763
if (type->isReferenceType())

lib/ClangImporter/ImporterImpl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,8 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
12781278
/// \returns The named module, or null if the module has not been imported.
12791279
ModuleDecl *getNamedModule(StringRef name);
12801280

1281+
ImportPath::Builder getSwiftModulePath(const clang::Module *M);
1282+
12811283
/// Returns the "Foundation" module, if it can be loaded.
12821284
///
12831285
/// After this has been called, the Foundation module will or won't be loaded

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
17361736
Opts.DumpMacroExpansions = Args.hasArg(
17371737
OPT_dump_macro_expansions);
17381738

1739+
Opts.DumpSourceFileImports = Args.hasArg(
1740+
OPT_dump_source_file_imports);
1741+
17391742
if (const Arg *A = Args.getLastArg(OPT_debug_requirement_machine))
17401743
Opts.DebugRequirementMachine = A->getValue();
17411744

lib/Sema/ImportResolution.cpp

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ class ImportResolver final : public DeclVisitor<ImportResolver> {
163163
/// The list of fully bound imports.
164164
SmallVector<AttributedImport<ImportedModule>, 16> boundImports;
165165

166+
/// Set of imported top-level clang modules. We normally don't expect
167+
/// duplicated imports, but importing multiple submodules of the same clang
168+
/// TLM would cause the same TLM to be imported once per submodule.
169+
SmallPtrSet<const ModuleDecl*, 16> seenClangTLMs;
170+
166171
/// All imported modules which should be considered when cross-importing.
167172
/// This is basically the transitive import graph, but with only top-level
168173
/// modules and without reexports from Objective-C modules.
@@ -192,6 +197,14 @@ class ImportResolver final : public DeclVisitor<ImportResolver> {
192197
addImplicitImports();
193198
}
194199

200+
// FIXME: Remove this ctor once namespace contents are imported to their
201+
// corresponding module instead of the __ObjC module
202+
ImportResolver(SourceFile &SF, ModuleDecl *explicitUnderlyingClangModule)
203+
: SF(SF), ctx(SF.getASTContext()),
204+
underlyingClangModule(explicitUnderlyingClangModule) {
205+
addImplicitImports();
206+
}
207+
195208
void addImplicitImports();
196209

197210
void addImplicitImport(ModuleDecl *module) {
@@ -322,26 +335,23 @@ void swift::performImportResolution(SourceFile &SF) {
322335
}
323336

324337
void swift::performImportResolutionForClangMacroBuffer(
325-
SourceFile &SF, ModuleDecl *clangModule
326-
) {
327-
// If we've already performed import resolution, bail.
328-
if (SF.ASTStage == SourceFile::ImportsResolved)
329-
return;
330-
331-
ImportResolver resolver(SF);
332-
resolver.addImplicitImport(clangModule);
333-
334-
// FIXME: This is a hack that we shouldn't need, but be sure that we can
335-
// see the Swift standard library.
336-
if (auto stdlib = SF.getASTContext().getStdlibModule())
337-
resolver.addImplicitImport(stdlib);
338+
SourceFile &SF, ModuleDecl *explicitOriginModule) {
339+
assert(SF.ASTStage == SourceFile::Unprocessed);
338340

341+
// `getWrapperForModule` has already declared all the implicit clang module
342+
// imports we need
343+
ImportResolver resolver(SF, explicitOriginModule);
339344
SF.setImports(resolver.getFinishedImports());
340345
SF.setImportedUnderlyingModule(resolver.getUnderlyingClangModule());
341346

342347
SF.ASTStage = SourceFile::ImportsResolved;
343348
}
344349

350+
static bool isSubmodule(const ModuleDecl* M) {
351+
auto clangMod = M->findUnderlyingClangModule();
352+
return clangMod && clangMod->Parent;
353+
}
354+
345355
//===----------------------------------------------------------------------===//
346356
// MARK: Import handling generally
347357
//===----------------------------------------------------------------------===//
@@ -389,14 +399,23 @@ void ImportResolver::bindImport(UnboundImport &&I) {
389399

390400
I.validateOptions(topLevelModule, SF);
391401

392-
if (topLevelModule && topLevelModule != M) {
393-
// If we have distinct submodule and top-level module, add both.
394-
addImport(I, M);
395-
addImport(I, topLevelModule.get());
396-
}
397-
else {
398-
// Add only the import itself.
402+
auto alreadyImportedTLM = [ID,this](const ModuleDecl *MD) {
403+
ASSERT(!isSubmodule(MD));
404+
// Scoped imports don't import all symbols from the module, so a scoped
405+
// import does not count the module as imported
406+
if (ID && isScopedImportKind(ID.get()->getImportKind()))
407+
return false;
408+
return !seenClangTLMs.insert(MD).second;
409+
};
410+
if (!M->isNonSwiftModule() || topLevelModule != M || !alreadyImportedTLM(M)) {
399411
addImport(I, M);
412+
if (topLevelModule && topLevelModule != M &&
413+
!alreadyImportedTLM(topLevelModule.get())) {
414+
// If we have distinct submodule and top-level module, add both.
415+
// Importing the submodule ensures that it gets loaded, but the decls
416+
// are imported to the TLM, so import that for visibility.
417+
addImport(I, topLevelModule.get());
418+
}
400419
}
401420

402421
crossImport(M, I);
@@ -592,7 +611,19 @@ ModuleImplicitImportsRequest::evaluate(Evaluator &evaluator,
592611
}
593612

594613
void ImportResolver::addImplicitImports() {
595-
auto implicitImports = SF.getParentModule()->getImplicitImports();
614+
// This is a workaround for the fact that namespaces are imported into the
615+
// bridging header module. To allow correct lookup, we expose a ctor with an
616+
// explicit underlying clang module input, which is the clang module that this
617+
// macro expansion actually originates in.
618+
const ModuleDecl *moduleToInherit = nullptr;
619+
if (underlyingClangModule) {
620+
moduleToInherit = underlyingClangModule;
621+
boundImports.push_back(
622+
AttributedImport(ImportedModule(underlyingClangModule)));
623+
} else {
624+
moduleToInherit = SF.getParentModule();
625+
}
626+
auto implicitImports = moduleToInherit->getImplicitImports();
596627

597628
// TODO: Support cross-module imports.
598629
for (auto &import : implicitImports.imports) {
@@ -1590,11 +1621,6 @@ void ImportResolver::findCrossImports(
15901621
}
15911622
}
15921623

1593-
static bool isSubmodule(ModuleDecl* M) {
1594-
auto clangMod = M->findUnderlyingClangModule();
1595-
return clangMod && clangMod->Parent;
1596-
}
1597-
15981624
void ImportResolver::addCrossImportableModules(
15991625
AttributedImport<ImportedModule> importDesc) {
16001626
// FIXME: namelookup::getAllImports() doesn't quite do what we need (mainly

0 commit comments

Comments
 (0)