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);
@@ -745,7 +751,12 @@ static bool couldBeLinkedStatically(DeclContext *funcCtxt, SILModule &module) {
745
751
// The stdlib module is always linked dynamically.
746
752
if (funcModule == module .getASTContext ().getStdlibModule ())
747
753
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
+
749
760
// Conservatively assume the function is in a statically linked module.
750
761
return true ;
751
762
}
@@ -755,7 +766,7 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
755
766
if (everything)
756
767
return true ;
757
768
758
- if (!M. getSwiftModule ()-> canBeUsedForCrossModuleOptimization (declCtxt))
769
+ if (!checkImports (declCtxt))
759
770
return false ;
760
771
761
772
// / If we are emitting a TBD file, the TBD file only contains public symbols
@@ -771,6 +782,52 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
771
782
return true ;
772
783
}
773
784
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
+
774
831
// / Returns true if the function \p func can be used from a serialized function.
775
832
bool CrossModuleOptimization::canUseFromInline (SILFunction *function) {
776
833
if (everything)
0 commit comments