1616
1717#define DEBUG_TYPE " cross-module-serialization-setup"
1818#include " swift/AST/Module.h"
19+ #include " swift/AST/ImportCache.h"
1920#include " swift/Basic/Assertions.h"
2021#include " swift/IRGen/TBDGen.h"
2122#include " swift/SIL/ApplySite.h"
@@ -103,6 +104,11 @@ class CrossModuleOptimization {
103104 bool canSerializeType (CanType type);
104105 bool canSerializeDecl (NominalTypeDecl *decl);
105106
107+ // / Check whether decls imported with certain access levels or attributes
108+ // / can be serialized.
109+ // / The \p ctxt can e.g. be a NominalType or the context of a function.
110+ bool checkImports (DeclContext *ctxt) const ;
111+
106112 bool canUseFromInline (DeclContext *declCtxt);
107113
108114 bool canUseFromInline (SILFunction *func);
@@ -734,7 +740,12 @@ static bool couldBeLinkedStatically(DeclContext *funcCtxt, SILModule &module) {
734740 // The stdlib module is always linked dynamically.
735741 if (funcModule == module .getASTContext ().getStdlibModule ())
736742 return false ;
737-
743+
744+ // An sdk or system module should be linked dynamically.
745+ if (isPackageCMOEnabled (module .getSwiftModule ()) &&
746+ funcModule->isNonUserModule ())
747+ return false ;
748+
738749 // Conservatively assume the function is in a statically linked module.
739750 return true ;
740751}
@@ -744,7 +755,7 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
744755 if (everything)
745756 return true ;
746757
747- if (!M. getSwiftModule ()-> canBeUsedForCrossModuleOptimization (declCtxt))
758+ if (!checkImports (declCtxt))
748759 return false ;
749760
750761 // / If we are emitting a TBD file, the TBD file only contains public symbols
@@ -760,6 +771,52 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
760771 return true ;
761772}
762773
774+ bool CrossModuleOptimization::checkImports (DeclContext *ctxt) const {
775+ ModuleDecl *moduleOfCtxt = ctxt->getParentModule ();
776+
777+ // If the context defined in the same module - or is the same module, it's
778+ // fine.
779+ if (moduleOfCtxt == M.getSwiftModule ())
780+ return true ;
781+
782+ ModuleDecl::ImportFilter filter;
783+
784+ if (isPackageCMOEnabled (M.getSwiftModule ())) {
785+ // If Package CMO is enabled, decls imported with `package import`
786+ // or `@_spiOnly import` into this module should be allowed to be
787+ // serialized. They are used in decls with `package` or higher
788+ // access level, with or without @_spi; a client of this module
789+ // should be able to access them directly if in the same package.
790+ filter = { ModuleDecl::ImportFilterKind::ImplementationOnly };
791+ } else {
792+ // See if context is imported in a "regular" way, i.e. not with
793+ // @_implementationOnly, `package import` or @_spiOnly.
794+ filter = {
795+ ModuleDecl::ImportFilterKind::ImplementationOnly,
796+ ModuleDecl::ImportFilterKind::PackageOnly,
797+ ModuleDecl::ImportFilterKind::SPIOnly
798+ };
799+ }
800+ SmallVector<ImportedModule, 4 > results;
801+ M.getSwiftModule ()->getImportedModules (results, filter);
802+
803+ auto &imports = M.getSwiftModule ()->getASTContext ().getImportCache ();
804+ for (auto &desc : results) {
805+ if (imports.isImportedBy (moduleOfCtxt, desc.importedModule )) {
806+ // E.g. `@_implementationOnly import QuartzCore_Private.CALayerPrivate`
807+ // imports `Foundation` as its transitive dependency module; use of a
808+ // a `public` decl in `Foundation` such as `IndexSet` in a function
809+ // signature should not block serialization in Package CMO given the
810+ // function has `package` or higher access level.
811+ if (isPackageCMOEnabled (M.getSwiftModule ()) &&
812+ moduleOfCtxt->isNonUserModule ())
813+ continue ;
814+ return false ;
815+ }
816+ }
817+ return true ;
818+ }
819+
763820// / Returns true if the function \p func can be used from a serialized function.
764821bool CrossModuleOptimization::canUseFromInline (SILFunction *function) {
765822 if (everything)
0 commit comments