@@ -197,18 +197,18 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
197
197
}
198
198
199
199
static int compareImportModulesByName (const ImportModuleTy *left,
200
- const ImportModuleTy *right) {
200
+ const ImportModuleTy *right, bool isCxx ) {
201
201
auto *leftSwiftModule = left->dyn_cast <ModuleDecl *>();
202
202
auto *rightSwiftModule = right->dyn_cast <ModuleDecl *>();
203
203
204
204
if (leftSwiftModule && !rightSwiftModule)
205
- return -compareImportModulesByName (right, left);
205
+ return -compareImportModulesByName (right, left, isCxx );
206
206
207
207
if (leftSwiftModule && rightSwiftModule)
208
208
return leftSwiftModule->getName ().compare (rightSwiftModule->getName ());
209
209
210
210
auto *leftClangModule = left->get <const clang::Module *>();
211
- assert (leftClangModule->isSubModule () &&
211
+ assert ((isCxx || leftClangModule->isSubModule () ) &&
212
212
" top-level modules should use a normal swift::ModuleDecl" );
213
213
if (rightSwiftModule) {
214
214
// Because the Clang module is a submodule, its full name will never be
@@ -222,7 +222,7 @@ static int compareImportModulesByName(const ImportModuleTy *left,
222
222
}
223
223
224
224
auto *rightClangModule = right->get <const clang::Module *>();
225
- assert (rightClangModule->isSubModule () &&
225
+ assert ((isCxx || rightClangModule->isSubModule () ) &&
226
226
" top-level modules should use a normal swift::ModuleDecl" );
227
227
228
228
SmallVector<StringRef, 8 > leftReversePath (
@@ -363,12 +363,13 @@ static void collectClangModuleHeaderIncludes(
363
363
}
364
364
}
365
365
366
- static void writeImports (raw_ostream &out,
367
- llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
368
- ModuleDecl &M, StringRef bridgingHeader,
369
- const FrontendOptions &frontendOpts,
370
- clang::HeaderSearch &clangHeaderSearchInfo,
371
- bool useCxxImport = false ) {
366
+ static void
367
+ writeImports (raw_ostream &out, llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
368
+ ModuleDecl &M, StringRef bridgingHeader,
369
+ const FrontendOptions &frontendOpts,
370
+ clang::HeaderSearch &clangHeaderSearchInfo,
371
+ const llvm::StringMap<StringRef> &exposedModuleHeaderNames,
372
+ bool useCxxImport = false ) {
372
373
// Note: we can't use has_feature(modules) as it's always enabled in C++20
373
374
// mode.
374
375
out << " #if __has_feature(objc_modules)\n " ;
@@ -380,8 +381,11 @@ static void writeImports(raw_ostream &out,
380
381
// Sort alphabetically for determinism and consistency.
381
382
SmallVector<ImportModuleTy, 8 > sortedImports{imports.begin (),
382
383
imports.end ()};
383
- llvm::array_pod_sort (sortedImports.begin (), sortedImports.end (),
384
- &compareImportModulesByName);
384
+ std::stable_sort (
385
+ sortedImports.begin (), sortedImports.end (),
386
+ [&](const ImportModuleTy &left, const ImportModuleTy &right) -> bool {
387
+ return compareImportModulesByName (&left, &right, useCxxImport) < 0 ;
388
+ });
385
389
386
390
auto isUnderlyingModule = [&M, bridgingHeader](ModuleDecl *import ) -> bool {
387
391
if (bridgingHeader.empty ())
@@ -395,7 +399,9 @@ static void writeImports(raw_ostream &out,
395
399
clang::FileSystemOptions fileSystemOptions;
396
400
clang::FileManager fileManager{fileSystemOptions};
397
401
398
- llvm::SmallSet<llvm::SmallString<128 >, 10 > requiredTextualIncludes;
402
+ llvm::SmallSet<llvm::SmallString<128 >, 10 >
403
+ requiredTextualIncludes; // Only included without modules.
404
+ llvm::SmallVector<StringRef, 1 > textualIncludes; // always included.
399
405
llvm::SmallSet<const clang::Module *, 10 > visitedModules;
400
406
llvm::SmallSet<llvm::SmallString<128 >, 10 > includeDirs;
401
407
@@ -438,6 +444,14 @@ static void writeImports(raw_ostream &out,
438
444
useCxxImport ? " #pragma clang module import" : " @import" ;
439
445
for (auto import : sortedImports) {
440
446
if (auto *swiftModule = import .dyn_cast <ModuleDecl *>()) {
447
+ if (useCxxImport) {
448
+ // Do not import Swift modules into the C++ section of the generated
449
+ // header unless explicitly exposed.
450
+ auto it = exposedModuleHeaderNames.find (swiftModule->getName ().str ());
451
+ if (it != exposedModuleHeaderNames.end ())
452
+ textualIncludes.push_back (it->getValue ());
453
+ continue ;
454
+ }
441
455
auto Name = swiftModule->getName ();
442
456
if (isUnderlyingModule (swiftModule)) {
443
457
includeUnderlying = true ;
@@ -463,7 +477,7 @@ static void writeImports(raw_ostream &out,
463
477
}
464
478
} else {
465
479
const auto *clangModule = import .get <const clang::Module *>();
466
- assert (clangModule->isSubModule () &&
480
+ assert ((useCxxImport || clangModule->isSubModule () ) &&
467
481
" top-level modules should use a normal swift::ModuleDecl" );
468
482
out << importDirective << ' ' ;
469
483
ModuleDecl::ReverseFullNameIterator (clangModule).printForward (out);
@@ -484,6 +498,9 @@ static void writeImports(raw_ostream &out,
484
498
}
485
499
}
486
500
out << " #endif\n\n " ;
501
+ for (const auto header : textualIncludes) {
502
+ out << " #include <" << header << " >\n " ;
503
+ }
487
504
488
505
if (includeUnderlying) {
489
506
if (bridgingHeader.empty ())
@@ -548,8 +565,9 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
548
565
printModuleContentsAsObjC (objcModuleContents, imports, *M, interopContext);
549
566
writePrologue (os, M->getASTContext (), computeMacroGuard (M));
550
567
emitObjCConditional (os, [&] {
568
+ llvm::StringMap<StringRef> exposedModuleHeaderNames;
551
569
writeImports (os, imports, *M, bridgingHeader, frontendOpts,
552
- clangHeaderSearchInfo);
570
+ clangHeaderSearchInfo, exposedModuleHeaderNames );
553
571
});
554
572
writePostImportPrologue (os, *M);
555
573
emitObjCConditional (os, [&] { os << objcModuleContents.str (); });
@@ -559,6 +577,11 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
559
577
M->DeclContext ::getASTContext ().LangOpts .EnableCXXInterop ;
560
578
if (!enableCxx)
561
579
return ;
580
+
581
+ llvm::StringSet<> exposedModules;
582
+ for (const auto &mod : frontendOpts.clangHeaderExposedImports )
583
+ exposedModules.insert (mod.moduleName );
584
+
562
585
// Include the shim header only in the C++ mode.
563
586
ClangSyntaxPrinter (os).printIncludeForShimHeader (
564
587
" _SwiftCxxInteroperability.h" );
@@ -586,10 +609,14 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
586
609
llvm::raw_string_ostream moduleContents{moduleContentsBuf};
587
610
auto deps = printModuleContentsAsCxx (
588
611
moduleContents, *M, interopContext,
589
- /* requiresExposedAttribute=*/ requiresExplicitExpose);
612
+ /* requiresExposedAttribute=*/ requiresExplicitExpose, exposedModules );
590
613
// FIXME: In ObjC++ mode, we do not need to reimport duplicate modules.
614
+ llvm::StringMap<StringRef> exposedModuleHeaderNames;
615
+ for (const auto &mod : frontendOpts.clangHeaderExposedImports )
616
+ exposedModuleHeaderNames.insert ({mod.moduleName , mod.headerName });
591
617
writeImports (os, deps.imports , *M, bridgingHeader, frontendOpts,
592
- clangHeaderSearchInfo, /* useCxxImport=*/ true );
618
+ clangHeaderSearchInfo, exposedModuleHeaderNames,
619
+ /* useCxxImport=*/ true );
593
620
// Embed the standard library directly.
594
621
if (addStdlibDepsInline && deps.dependsOnStandardLibrary ) {
595
622
assert (!M->isStdlibModule ());
@@ -598,9 +625,9 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
598
625
auto macroGuard = computeMacroGuard (M->getASTContext ().getStdlibModule ());
599
626
os << " #ifndef " << macroGuard << " \n " ;
600
627
os << " #define " << macroGuard << " \n " ;
601
- printModuleContentsAsCxx (os, *M-> getASTContext (). getStdlibModule (),
602
- interopContext,
603
- /* requiresExposedAttribute=*/ true );
628
+ printModuleContentsAsCxx (
629
+ os, *M-> getASTContext (). getStdlibModule (), interopContext,
630
+ /* requiresExposedAttribute=*/ true , exposedModules );
604
631
os << " #endif // " << macroGuard << " \n " ;
605
632
}
606
633
0 commit comments