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);
@@ -736,7 +742,12 @@ static bool couldBeLinkedStatically(DeclContext *funcCtxt, SILModule &module) {
736
742
// The stdlib module is always linked dynamically.
737
743
if (funcModule == module .getASTContext ().getStdlibModule ())
738
744
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
+
740
751
// Conservatively assume the function is in a statically linked module.
741
752
return true ;
742
753
}
@@ -746,7 +757,7 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
746
757
if (everything)
747
758
return true ;
748
759
749
- if (!M. getSwiftModule ()-> canBeUsedForCrossModuleOptimization (declCtxt))
760
+ if (!checkImports (declCtxt))
750
761
return false ;
751
762
752
763
// / If we are emitting a TBD file, the TBD file only contains public symbols
@@ -762,6 +773,52 @@ bool CrossModuleOptimization::canUseFromInline(DeclContext *declCtxt) {
762
773
return true ;
763
774
}
764
775
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
+
765
822
// / Returns true if the function \p func can be used from a serialized function.
766
823
bool CrossModuleOptimization::canUseFromInline (SILFunction *function) {
767
824
if (everything)
0 commit comments