Skip to content

Commit 244717b

Browse files
Merge pull request swiftlang#71857 from cachemeifyoucan/eng/PR-122356964
[ScanDependency] Do not use public/private swiftinterface in the same package
2 parents 918bd3d + 3e90368 commit 244717b

File tree

10 files changed

+101
-76
lines changed

10 files changed

+101
-76
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,9 @@ namespace swift {
440440
/// The name of the package this module belongs to.
441441
std::string PackageName;
442442

443+
/// Allow importing a non-package interface from the same package.
444+
bool AllowNonPackageInterfaceImportFromSamePackage = false;
445+
443446
/// Diagnose implicit 'override'.
444447
bool WarnImplicitOverrides = false;
445448

include/swift/Frontend/FrontendInputsAndOutputs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ class FrontendInputsAndOutputs {
172172
bool shouldTreatAsLLVM() const;
173173
bool shouldTreatAsSIL() const;
174174
bool shouldTreatAsModuleInterface() const;
175+
bool shouldTreatAsNonPackageModuleInterface() const;
175176
bool shouldTreatAsObjCHeader() const;
176177

177178
bool areAllNonPrimariesSIB() const;

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ struct SerializedModuleBaseName {
6868
std::optional<std::string> findInterfacePath(llvm::vfs::FileSystem &fs,
6969
ASTContext &ctx) const;
7070

71+
/// Returns the package-name of the interface file.
72+
std::optional<std::string>
73+
getPackageNameFromInterface(StringRef interfacePath,
74+
llvm::vfs::FileSystem &fs) const;
75+
7176
/// Returns the .package.swiftinterface path if its package-name also applies to
7277
/// the the importing module. Returns an empty optional otherwise.
7378
std::optional<std::string>

lib/Frontend/CompilerInvocation.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -974,8 +974,15 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
974974
auto pkgName = A->getValue();
975975
if (StringRef(pkgName).empty())
976976
Diags.diagnose(SourceLoc(), diag::error_empty_package_name);
977-
else
977+
else {
978978
Opts.PackageName = pkgName;
979+
// Unless the input type is public or private swift interface, do not
980+
// allow non package interface imports for dependencies in the same
981+
// package.
982+
Opts.AllowNonPackageInterfaceImportFromSamePackage =
983+
FrontendOpts.InputsAndOutputs
984+
.shouldTreatAsNonPackageModuleInterface();
985+
}
979986
}
980987

981988
if (const Arg *A = Args.getLastArg(OPT_require_explicit_availability_EQ)) {

lib/Frontend/FrontendInputsAndOutputs.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,16 @@ bool FrontendInputsAndOutputs::shouldTreatAsModuleInterface() const {
203203
return InputType == file_types::TY_SwiftModuleInterfaceFile;
204204
}
205205

206+
bool FrontendInputsAndOutputs::shouldTreatAsNonPackageModuleInterface() const {
207+
if (!hasSingleInput())
208+
return false;
209+
210+
file_types::ID InputType =
211+
file_types::lookupTypeFromFilename(getFilenameOfFirstInput());
212+
return InputType == file_types::TY_SwiftModuleInterfaceFile ||
213+
InputType == file_types::TY_PrivateSwiftModuleInterfaceFile;
214+
}
215+
206216
bool FrontendInputsAndOutputs::shouldTreatAsSIL() const {
207217
if (hasSingleInput()) {
208218
// If we have exactly one input filename, and its extension is "sil",

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,8 +1244,8 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory(
12441244

12451245
// First check to see if the .swiftinterface exists at all. Bail if not.
12461246
auto &fs = *Ctx.SourceMgr.getFileSystem();
1247-
std::string InPath = BaseName.findInterfacePath(fs, Ctx).value_or("");
1248-
if (InPath.empty()) {
1247+
auto InPath = BaseName.findInterfacePath(fs, Ctx);
1248+
if (!InPath) {
12491249
if (fs.exists(ModPath)) {
12501250
LLVM_DEBUG(llvm::dbgs()
12511251
<< "No .swiftinterface file found adjacent to module file "
@@ -1256,22 +1256,22 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory(
12561256
}
12571257

12581258
if (ModuleInterfaceSourcePath)
1259-
ModuleInterfaceSourcePath->assign(InPath.begin(), InPath.end());
1259+
ModuleInterfaceSourcePath->assign(InPath->begin(), InPath->end());
12601260

12611261
// If we've been told to skip building interfaces, we are done here and do
12621262
// not need to have the module actually built. For example, if we are
12631263
// currently answering a `canImport` query, it is enough to have found
12641264
// the interface.
12651265
if (skipBuildingInterface) {
12661266
if (ModuleInterfacePath)
1267-
ModuleInterfacePath->assign(InPath.begin(), InPath.end());
1267+
ModuleInterfacePath->assign(InPath->begin(), InPath->end());
12681268
return std::error_code();
12691269
}
12701270

12711271
// Create an instance of the Impl to do the heavy lifting.
12721272
auto ModuleName = ModuleID.Item.str();
12731273
ModuleInterfaceLoaderImpl Impl(
1274-
Ctx, ModPath, InPath, ModuleName, InterfaceChecker.CacheDir,
1274+
Ctx, ModPath, *InPath, ModuleName, InterfaceChecker.CacheDir,
12751275
InterfaceChecker.PrebuiltCacheDir, InterfaceChecker.BackupInterfaceDir,
12761276
ModuleID.Loc, InterfaceChecker.Opts,
12771277
InterfaceChecker.RequiresOSSAModules,
@@ -1290,7 +1290,7 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory(
12901290
if (ModuleBuffer) {
12911291
*ModuleBuffer = std::move(*ModuleBufferOrErr);
12921292
if (ModuleInterfacePath)
1293-
ModuleInterfacePath->assign(InPath.begin(), InPath.end());
1293+
ModuleInterfacePath->assign(InPath->begin(), InPath->end());
12941294
}
12951295

12961296
// Open .swiftsourceinfo file if it's present.

lib/Serialization/ScanningLoaders.cpp

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ std::error_code SwiftModuleScanner::findModuleFilesInDirectory(
5050
auto &fs = *Ctx.SourceMgr.getFileSystem();
5151

5252
auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile);
53-
auto InPath = BaseName.getName(file_types::TY_SwiftModuleInterfaceFile);
53+
auto InPath = BaseName.findInterfacePath(fs, Ctx);
5454

55-
if (LoadMode == ModuleLoadingMode::OnlySerialized || !fs.exists(InPath)) {
55+
if (LoadMode == ModuleLoadingMode::OnlySerialized || !InPath) {
5656
if (fs.exists(ModPath)) {
5757
// The module file will be loaded directly.
5858
auto dependencies = scanModuleFile(ModPath, IsFramework);
@@ -61,26 +61,12 @@ std::error_code SwiftModuleScanner::findModuleFilesInDirectory(
6161
return std::error_code();
6262
}
6363
return dependencies.getError();
64-
} else {
65-
return std::make_error_code(std::errc::no_such_file_or_directory);
6664
}
65+
return std::make_error_code(std::errc::no_such_file_or_directory);
6766
}
68-
assert(fs.exists(InPath));
67+
assert(InPath);
6968

70-
// Use package.swiftinterface if it exists and its package-name applies to
71-
// the importer module.
72-
auto PkgInPath = BaseName.getPackageInterfacePathIfInSamePackage(fs, Ctx).value_or("");
73-
if (!PkgInPath.empty() && fs.exists(PkgInPath)) {
74-
InPath = PkgInPath;
75-
} else {
76-
// If not in package, use the private interface file if exits.
77-
auto PrivateInPath =
78-
BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile);
79-
if (fs.exists(PrivateInPath)) {
80-
InPath = PrivateInPath;
81-
}
82-
}
83-
auto dependencies = scanInterfaceFile(InPath, IsFramework);
69+
auto dependencies = scanInterfaceFile(*InPath, IsFramework);
8470
if (dependencies) {
8571
this->dependencies = std::move(dependencies.get());
8672
return std::error_code();

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 55 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -604,35 +604,43 @@ std::optional<std::string>
604604
SerializedModuleBaseName::getPackageInterfacePathIfInSamePackage(
605605
llvm::vfs::FileSystem &fs, ASTContext &ctx) const {
606606
if (!ctx.LangOpts.EnablePackageInterfaceLoad)
607-
return {};
607+
return std::nullopt;
608608

609609
std::string packagePath{
610-
getName(file_types::TY_PackageSwiftModuleInterfaceFile)};
610+
getName(file_types::TY_PackageSwiftModuleInterfaceFile)};
611611

612612
if (fs.exists(packagePath)) {
613613
// Read the interface file and extract its package-name argument value
614-
std::string result;
615-
if (auto packageFile = llvm::MemoryBuffer::getFile(packagePath)) {
616-
llvm::BumpPtrAllocator alloc;
617-
llvm::StringSaver argSaver(alloc);
618-
SmallVector<const char*, 8> args;
619-
(void)extractCompilerFlagsFromInterface(packagePath,
620-
(*packageFile)->getBuffer(), argSaver, args);
621-
for (unsigned I = 0, N = args.size(); I + 1 < N; I++) {
622-
StringRef current(args[I]), next(args[I + 1]);
623-
if (current == "-package-name") {
624-
// Instead of `break` here, continue to get the last value in case of dupes,
625-
// to be consistent with the default parsing logic.
626-
result = next;
627-
}
614+
if (auto packageName = getPackageNameFromInterface(packagePath, fs)) {
615+
// Return the .package.swiftinterface path if the package name applies to
616+
// the importer module.
617+
if (*packageName == ctx.LangOpts.PackageName)
618+
return packagePath;
619+
}
620+
}
621+
return std::nullopt;
622+
}
623+
624+
std::optional<std::string>
625+
SerializedModuleBaseName::getPackageNameFromInterface(
626+
StringRef interfacePath, llvm::vfs::FileSystem &fs) const {
627+
std::optional<std::string> result;
628+
if (auto interfaceFile = fs.getBufferForFile(interfacePath)) {
629+
llvm::BumpPtrAllocator alloc;
630+
llvm::StringSaver argSaver(alloc);
631+
SmallVector<const char *, 8> args;
632+
(void)extractCompilerFlagsFromInterface(
633+
interfacePath, (*interfaceFile)->getBuffer(), argSaver, args);
634+
for (unsigned I = 0, N = args.size(); I + 1 < N; I++) {
635+
StringRef current(args[I]), next(args[I + 1]);
636+
if (current == "-package-name") {
637+
// Instead of `break` here, continue to get the last value in case of
638+
// dupes, to be consistent with the default parsing logic.
639+
result = next;
628640
}
629641
}
630-
// Return the .package.swiftinterface path if the package name applies to
631-
// the importer module.
632-
if (!result.empty() && result == ctx.LangOpts.PackageName)
633-
return packagePath;
634642
}
635-
return {};
643+
return result;
636644
}
637645

638646
std::optional<std::string>
@@ -642,16 +650,18 @@ SerializedModuleBaseName::findInterfacePath(llvm::vfs::FileSystem &fs,
642650
// Ensure the public swiftinterface already exists, otherwise bail early
643651
// as it's considered the module doesn't exist.
644652
if (!fs.exists(interfacePath))
645-
return {};
646-
647-
// Check if a package interface exists and if the package name applies to
648-
// the importer module.
649-
auto pkgPath = getPackageInterfacePathIfInSamePackage(fs, ctx).value_or("");
650-
if (!pkgPath.empty() && fs.exists(pkgPath))
651-
return pkgPath;
653+
return std::nullopt;
654+
655+
// If in the same package, try return the package interface path if not
656+
// preferring the interface file.
657+
if (!ctx.LangOpts.AllowNonPackageInterfaceImportFromSamePackage) {
658+
if (auto packageName = getPackageNameFromInterface(interfacePath, fs)) {
659+
if (*packageName == ctx.LangOpts.PackageName)
660+
return getPackageInterfacePathIfInSamePackage(fs, ctx);
661+
}
662+
}
652663

653-
// If above fails, use the existing logic as fallback.
654-
// If present, use the private interface instead of the public one.
664+
// Otherwise, use the private interface instead of the public one.
655665
std::string privatePath{
656666
getName(file_types::TY_PrivateSwiftModuleInterfaceFile)};
657667
if (fs.exists(privatePath))
@@ -704,35 +714,33 @@ bool SerializedModuleLoaderBase::findModule(
704714
std::optional<SerializedModuleBaseName> firstAbsoluteBaseName;
705715

706716
for (const auto &targetSpecificBaseName : targetSpecificBaseNames) {
707-
SerializedModuleBaseName
708-
absoluteBaseName{currPath, targetSpecificBaseName};
717+
SerializedModuleBaseName absoluteBaseName{currPath,
718+
targetSpecificBaseName};
709719

710720
if (!firstAbsoluteBaseName.has_value())
711721
firstAbsoluteBaseName.emplace(absoluteBaseName);
712722

713723
auto result = findModuleFilesInDirectory(
714724
moduleID, absoluteBaseName, moduleInterfacePath,
715725
moduleInterfaceSourcePath, moduleBuffer, moduleDocBuffer,
716-
moduleSourceInfoBuffer, skipBuildingInterface,
717-
IsFramework, isTestableDependencyLookup);
718-
if (!result) {
726+
moduleSourceInfoBuffer, skipBuildingInterface, IsFramework,
727+
isTestableDependencyLookup);
728+
if (!result)
719729
return SearchResult::Found;
720-
} else if (result == std::errc::not_supported) {
730+
if (result == std::errc::not_supported)
721731
return SearchResult::Error;
722-
} else if (result != std::errc::no_such_file_or_directory) {
732+
if (result != std::errc::no_such_file_or_directory)
723733
return SearchResult::NotFound;
724-
}
725734
}
726735

727736
// We can only get here if all targetFileNamePairs failed with
728737
// 'std::errc::no_such_file_or_directory'.
729-
if (firstAbsoluteBaseName
730-
&& maybeDiagnoseTargetMismatch(moduleID.Loc, moduleName,
731-
*firstAbsoluteBaseName)) {
738+
if (firstAbsoluteBaseName &&
739+
maybeDiagnoseTargetMismatch(moduleID.Loc, moduleName,
740+
*firstAbsoluteBaseName))
732741
return SearchResult::Error;
733-
} else {
734-
return SearchResult::NotFound;
735-
}
742+
743+
return SearchResult::NotFound;
736744
};
737745

738746
SmallVector<std::string, 4> InterestingFilenames = {
@@ -788,13 +796,11 @@ bool SerializedModuleLoaderBase::findModule(
788796
moduleID, absoluteBaseName, moduleInterfacePath,
789797
moduleInterfaceSourcePath, moduleBuffer, moduleDocBuffer,
790798
moduleSourceInfoBuffer, skipBuildingInterface, isFramework);
791-
if (!result) {
799+
if (!result)
792800
return true;
793-
} else if (result == std::errc::not_supported) {
801+
if (result == std::errc::not_supported)
794802
return false;
795-
} else {
796-
continue;
797-
}
803+
continue;
798804
}
799805
case ModuleSearchPathKind::Framework:
800806
case ModuleSearchPathKind::DarwinImplicitFramework: {

test/ScanDependencies/package_interface.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// RUN: %target-swift-frontend -emit-module %t/Bar.swift -I %t \
55
// RUN: -module-name Bar -package-name barpkg \
66
// RUN: -enable-library-evolution -swift-version 5 \
7+
// RUN: -o %t/Bar.swiftmodule \
78
// RUN: -emit-module-interface-path %t/Bar.swiftinterface \
89
// RUN: -emit-private-module-interface-path %t/Bar.private.swiftinterface \
910
// RUN: -emit-package-module-interface-path %t/Bar.package.swiftinterface
@@ -21,10 +22,16 @@
2122
// RUN: %t/Client.swift -module-name Client -swift-version 5
2223
// RUN: %FileCheck %s --input-file=%t/deps3.json --check-prefix CHECK --check-prefix CHECK-PRIVATE
2324

25+
/// If -experimental-package-interface-load is not used but in the same package, it should find the binary module
26+
// RUN: %target-swift-frontend -scan-dependencies -I %t \
27+
// RUN: %t/Client.swift -module-name Client -package-name barpkg -swift-version 5 | \
28+
// RUN: %FileCheck %s --check-prefix CHECK-BINARY
29+
2430
// CHECK: "swift": "Bar"
2531
// CHECK: "modulePath": "{{.*}}{{/|\\}}Bar-{{.*}}.swiftmodule"
2632
// CHECK-PACKAGE: "moduleInterfacePath": "{{.*}}{{/|\\}}Bar.package.swiftinterface"
2733
// CHECK-PRIVATE: "moduleInterfacePath": "{{.*}}{{/|\\}}Bar.private.swiftinterface"
34+
// CHECK-BINARY: "swiftPrebuiltExternal": "Bar"
2835

2936
//--- Bar.swift
3037
public enum PubEnum {

test/Serialization/load_package_module.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
// RUN: not %target-swift-frontend -typecheck %t/ClientLoadInterface.swift -package-name libPkg -I %t 2> %t/resultY.output
3333
// RUN: %FileCheck %s -check-prefix CHECK-Y < %t/resultY.output
34-
// CHECK-Y: error: module 'LibInterface' is in package 'libPkg' but was built from a non-package interface; modules of the same package can only be loaded if built from source or package interface: {{.*}}LibInterface.private.swiftinterface
34+
// CHECK-Y: error: no such module 'LibInterface'
3535

3636

3737
//--- Lib.swift

0 commit comments

Comments
 (0)