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);
@@ -745,7 +751,12 @@ static bool couldBeLinkedStatically(DeclContext *funcCtxt, SILModule &module) {
745751 // The stdlib module is always linked dynamically.
746752 if (funcModule == module .getASTContext ().getStdlibModule ())
747753 return false ;
748-
754+
755+ // An sdk or system module should be linked dynamically.
756+ if (isPackageCMOEnabled (module .getSwiftModule ()) &&
757+ funcModule->isNonUserModule ())
758+ return false ;
759+
749760 // Conservatively assume the function is in a statically linked module.
750761 return true ;
751762}
@@ -755,7 +766,7 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
755766 if (everything)
756767 return true ;
757768
758- if (!M. getSwiftModule ()-> canBeUsedForCrossModuleOptimization (declCtxt))
769+ if (!checkImports (declCtxt))
759770 return false ;
760771
761772 // / If we are emitting a TBD file, the TBD file only contains public symbols
@@ -771,6 +782,52 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
771782 return true ;
772783}
773784
785+ bool CrossModuleOptimization::checkImports (DeclContext *ctxt) const {
786+ ModuleDecl *moduleOfCtxt = ctxt->getParentModule ();
787+
788+ // If the context defined in the same module - or is the same module, it's
789+ // fine.
790+ if (moduleOfCtxt == M.getSwiftModule ())
791+ return true ;
792+
793+ ModuleDecl::ImportFilter filter;
794+
795+ if (isPackageCMOEnabled (M.getSwiftModule ())) {
796+ // If Package CMO is enabled, decls imported with `package import`
797+ // or `@_spiOnly import` into this module should be allowed to be
798+ // serialized. They are used in decls with `package` or higher
799+ // access level, with or without @_spi; a client of this module
800+ // should be able to access them directly if in the same package.
801+ filter = { ModuleDecl::ImportFilterKind::ImplementationOnly };
802+ } else {
803+ // See if context is imported in a "regular" way, i.e. not with
804+ // @_implementationOnly, `package import` or @_spiOnly.
805+ filter = {
806+ ModuleDecl::ImportFilterKind::ImplementationOnly,
807+ ModuleDecl::ImportFilterKind::PackageOnly,
808+ ModuleDecl::ImportFilterKind::SPIOnly
809+ };
810+ }
811+ SmallVector<ImportedModule, 4 > results;
812+ M.getSwiftModule ()->getImportedModules (results, filter);
813+
814+ auto &imports = M.getSwiftModule ()->getASTContext ().getImportCache ();
815+ for (auto &desc : results) {
816+ if (imports.isImportedBy (moduleOfCtxt, desc.importedModule )) {
817+ // E.g. `@_implementationOnly import QuartzCore_Private.CALayerPrivate`
818+ // imports `Foundation` as its transitive dependency module; use of a
819+ // a `public` decl in `Foundation` such as `IndexSet` in a function
820+ // signature should not block serialization in Package CMO given the
821+ // function has `package` or higher access level.
822+ if (isPackageCMOEnabled (M.getSwiftModule ()) &&
823+ moduleOfCtxt->isNonUserModule ())
824+ continue ;
825+ return false ;
826+ }
827+ }
828+ return true ;
829+ }
830+
774831// / Returns true if the function \p func can be used from a serialized function.
775832bool CrossModuleOptimization::canUseFromInline (SILFunction *function) {
776833 if (everything)
0 commit comments