@@ -197,18 +197,18 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
197197}
198198
199199static int compareImportModulesByName (const ImportModuleTy *left,
200- const ImportModuleTy *right) {
200+ const ImportModuleTy *right, bool isCxx ) {
201201 auto *leftSwiftModule = left->dyn_cast <ModuleDecl *>();
202202 auto *rightSwiftModule = right->dyn_cast <ModuleDecl *>();
203203
204204 if (leftSwiftModule && !rightSwiftModule)
205- return -compareImportModulesByName (right, left);
205+ return -compareImportModulesByName (right, left, isCxx );
206206
207207 if (leftSwiftModule && rightSwiftModule)
208208 return leftSwiftModule->getName ().compare (rightSwiftModule->getName ());
209209
210210 auto *leftClangModule = left->get <const clang::Module *>();
211- assert (leftClangModule->isSubModule () &&
211+ assert ((isCxx || leftClangModule->isSubModule () ) &&
212212 " top-level modules should use a normal swift::ModuleDecl" );
213213 if (rightSwiftModule) {
214214 // Because the Clang module is a submodule, its full name will never be
@@ -222,7 +222,7 @@ static int compareImportModulesByName(const ImportModuleTy *left,
222222 }
223223
224224 auto *rightClangModule = right->get <const clang::Module *>();
225- assert (rightClangModule->isSubModule () &&
225+ assert ((isCxx || rightClangModule->isSubModule () ) &&
226226 " top-level modules should use a normal swift::ModuleDecl" );
227227
228228 SmallVector<StringRef, 8 > leftReversePath (
@@ -363,12 +363,13 @@ static void collectClangModuleHeaderIncludes(
363363 }
364364}
365365
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 ) {
372373 // Note: we can't use has_feature(modules) as it's always enabled in C++20
373374 // mode.
374375 out << " #if __has_feature(objc_modules)\n " ;
@@ -380,8 +381,11 @@ static void writeImports(raw_ostream &out,
380381 // Sort alphabetically for determinism and consistency.
381382 SmallVector<ImportModuleTy, 8 > sortedImports{imports.begin (),
382383 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+ });
385389
386390 auto isUnderlyingModule = [&M, bridgingHeader](ModuleDecl *import ) -> bool {
387391 if (bridgingHeader.empty ())
@@ -395,7 +399,9 @@ static void writeImports(raw_ostream &out,
395399 clang::FileSystemOptions fileSystemOptions;
396400 clang::FileManager fileManager{fileSystemOptions};
397401
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.
399405 llvm::SmallSet<const clang::Module *, 10 > visitedModules;
400406 llvm::SmallSet<llvm::SmallString<128 >, 10 > includeDirs;
401407
@@ -438,6 +444,14 @@ static void writeImports(raw_ostream &out,
438444 useCxxImport ? " #pragma clang module import" : " @import" ;
439445 for (auto import : sortedImports) {
440446 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+ }
441455 auto Name = swiftModule->getName ();
442456 if (isUnderlyingModule (swiftModule)) {
443457 includeUnderlying = true ;
@@ -463,7 +477,7 @@ static void writeImports(raw_ostream &out,
463477 }
464478 } else {
465479 const auto *clangModule = import .get <const clang::Module *>();
466- assert (clangModule->isSubModule () &&
480+ assert ((useCxxImport || clangModule->isSubModule () ) &&
467481 " top-level modules should use a normal swift::ModuleDecl" );
468482 out << importDirective << ' ' ;
469483 ModuleDecl::ReverseFullNameIterator (clangModule).printForward (out);
@@ -484,6 +498,9 @@ static void writeImports(raw_ostream &out,
484498 }
485499 }
486500 out << " #endif\n\n " ;
501+ for (const auto header : textualIncludes) {
502+ out << " #include <" << header << " >\n " ;
503+ }
487504
488505 if (includeUnderlying) {
489506 if (bridgingHeader.empty ())
@@ -548,8 +565,9 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
548565 printModuleContentsAsObjC (objcModuleContents, imports, *M, interopContext);
549566 writePrologue (os, M->getASTContext (), computeMacroGuard (M));
550567 emitObjCConditional (os, [&] {
568+ llvm::StringMap<StringRef> exposedModuleHeaderNames;
551569 writeImports (os, imports, *M, bridgingHeader, frontendOpts,
552- clangHeaderSearchInfo);
570+ clangHeaderSearchInfo, exposedModuleHeaderNames );
553571 });
554572 writePostImportPrologue (os, *M);
555573 emitObjCConditional (os, [&] { os << objcModuleContents.str (); });
@@ -559,6 +577,11 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
559577 M->DeclContext ::getASTContext ().LangOpts .EnableCXXInterop ;
560578 if (!enableCxx)
561579 return ;
580+
581+ llvm::StringSet<> exposedModules;
582+ for (const auto &mod : frontendOpts.clangHeaderExposedImports )
583+ exposedModules.insert (mod.moduleName );
584+
562585 // Include the shim header only in the C++ mode.
563586 ClangSyntaxPrinter (os).printIncludeForShimHeader (
564587 " _SwiftCxxInteroperability.h" );
@@ -586,10 +609,14 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
586609 llvm::raw_string_ostream moduleContents{moduleContentsBuf};
587610 auto deps = printModuleContentsAsCxx (
588611 moduleContents, *M, interopContext,
589- /* requiresExposedAttribute=*/ requiresExplicitExpose);
612+ /* requiresExposedAttribute=*/ requiresExplicitExpose, exposedModules );
590613 // 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 });
591617 writeImports (os, deps.imports , *M, bridgingHeader, frontendOpts,
592- clangHeaderSearchInfo, /* useCxxImport=*/ true );
618+ clangHeaderSearchInfo, exposedModuleHeaderNames,
619+ /* useCxxImport=*/ true );
593620 // Embed the standard library directly.
594621 if (addStdlibDepsInline && deps.dependsOnStandardLibrary ) {
595622 assert (!M->isStdlibModule ());
@@ -598,9 +625,9 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
598625 auto macroGuard = computeMacroGuard (M->getASTContext ().getStdlibModule ());
599626 os << " #ifndef " << macroGuard << " \n " ;
600627 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 );
604631 os << " #endif // " << macroGuard << " \n " ;
605632 }
606633
0 commit comments