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);
@@ -736,7 +742,12 @@ static bool couldBeLinkedStatically(DeclContext *funcCtxt, SILModule &module) {
736742 // The stdlib module is always linked dynamically.
737743 if (funcModule == module .getASTContext ().getStdlibModule ())
738744 return false ;
739-
745+
746+ // An sdk or system module should be linked dynamically.
747+ if (isPackageCMOEnabled (module .getSwiftModule ()) &&
748+ funcModule->isNonUserModule ())
749+ return false ;
750+
740751 // Conservatively assume the function is in a statically linked module.
741752 return true ;
742753}
@@ -746,7 +757,7 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
746757 if (everything)
747758 return true ;
748759
749- if (!M. getSwiftModule ()-> canBeUsedForCrossModuleOptimization (declCtxt))
760+ if (!checkImports (declCtxt))
750761 return false ;
751762
752763 // / If we are emitting a TBD file, the TBD file only contains public symbols
@@ -762,6 +773,52 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
762773 return true ;
763774}
764775
776+ bool CrossModuleOptimization::checkImports (DeclContext *ctxt) const {
777+ ModuleDecl *moduleOfCtxt = ctxt->getParentModule ();
778+
779+ // If the context defined in the same module - or is the same module, it's
780+ // fine.
781+ if (moduleOfCtxt == M.getSwiftModule ())
782+ return true ;
783+
784+ ModuleDecl::ImportFilter filter;
785+
786+ if (isPackageCMOEnabled (M.getSwiftModule ())) {
787+ // If Package CMO is enabled, decls imported with `package import`
788+ // or `@_spiOnly import` into this module should be allowed to be
789+ // serialized. They are used in decls with `package` or higher
790+ // access level, with or without @_spi; a client of this module
791+ // should be able to access them directly if in the same package.
792+ filter = { ModuleDecl::ImportFilterKind::ImplementationOnly };
793+ } else {
794+ // See if context is imported in a "regular" way, i.e. not with
795+ // @_implementationOnly, `package import` or @_spiOnly.
796+ filter = {
797+ ModuleDecl::ImportFilterKind::ImplementationOnly,
798+ ModuleDecl::ImportFilterKind::PackageOnly,
799+ ModuleDecl::ImportFilterKind::SPIOnly
800+ };
801+ }
802+ SmallVector<ImportedModule, 4 > results;
803+ M.getSwiftModule ()->getImportedModules (results, filter);
804+
805+ auto &imports = M.getSwiftModule ()->getASTContext ().getImportCache ();
806+ for (auto &desc : results) {
807+ if (imports.isImportedBy (moduleOfCtxt, desc.importedModule )) {
808+ // E.g. `@_implementationOnly import QuartzCore_Private.CALayerPrivate`
809+ // imports `Foundation` as its transitive dependency module; use of a
810+ // a `public` decl in `Foundation` such as `IndexSet` in a function
811+ // signature should not block serialization in Package CMO given the
812+ // function has `package` or higher access level.
813+ if (isPackageCMOEnabled (M.getSwiftModule ()) &&
814+ moduleOfCtxt->isNonUserModule ())
815+ continue ;
816+ return false ;
817+ }
818+ }
819+ return true ;
820+ }
821+
765822// / Returns true if the function \p func can be used from a serialized function.
766823bool CrossModuleOptimization::canUseFromInline (SILFunction *function) {
767824 if (everything)
0 commit comments