16
16
17
17
#define DEBUG_TYPE " cross-module-serialization-setup"
18
18
#include " swift/AST/Module.h"
19
+ #include " swift/AST/ImportCache.h"
19
20
#include " swift/Basic/Assertions.h"
20
21
#include " swift/IRGen/TBDGen.h"
21
22
#include " swift/SIL/ApplySite.h"
@@ -103,6 +104,11 @@ class CrossModuleOptimization {
103
104
bool canSerializeType (CanType type);
104
105
bool canSerializeDecl (NominalTypeDecl *decl);
105
106
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
+
106
112
bool canUseFromInline (DeclContext *declCtxt);
107
113
108
114
bool canUseFromInline (SILFunction *func);
@@ -734,7 +740,12 @@ static bool couldBeLinkedStatically(DeclContext *funcCtxt, SILModule &module) {
734
740
// The stdlib module is always linked dynamically.
735
741
if (funcModule == module .getASTContext ().getStdlibModule ())
736
742
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
+
738
749
// Conservatively assume the function is in a statically linked module.
739
750
return true ;
740
751
}
@@ -744,7 +755,7 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
744
755
if (everything)
745
756
return true ;
746
757
747
- if (!M. getSwiftModule ()-> canBeUsedForCrossModuleOptimization (declCtxt))
758
+ if (!checkImports (declCtxt))
748
759
return false ;
749
760
750
761
// / If we are emitting a TBD file, the TBD file only contains public symbols
@@ -760,6 +771,52 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
760
771
return true ;
761
772
}
762
773
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
+
763
820
// / Returns true if the function \p func can be used from a serialized function.
764
821
bool CrossModuleOptimization::canUseFromInline (SILFunction *function) {
765
822
if (everything)
0 commit comments